Fossil

Check-in [8841f6d4]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Merge latest trunk. This branch is more a "proof-of-concept" then a final implementation.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | file-filter
Files: files | file ages | folders
SHA1:8841f6d48fa215ec18e0fe5ed00a31dfb6221285
User & Date: baruch 2015-02-01 07:18:26
Context
2015-02-01
07:18
Merge latest trunk. This branch is more a "proof-of-concept" then a final implementation. Leaf check-in: 8841f6d4 user: baruch tags: file-filter
00:15
The /search page now covers wiki and check-in comments. And the formatting of snippets is improved. The search is still done by full-scan but the infrastructure is coming into place to handle the search using an index. check-in: 8e02c26a user: drh tags: trunk
2014-12-24
08:44
Fix for older browsers check-in: 59062c3d user: baruch tags: file-filter
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Added .dockerignore.





















































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
_FOSSIL_
.fslckout
ajax
art
autosetup
bld
compat
debian
fossil
fossil.exe
setup
src
test
tools
win
wbld
win
www
*.a
*.lib
*.log
*.manifest
*.o
*.obj
*.pdb
*.res

Changes to Dockerfile.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
###
#   Dockerfile for Fossil
###
FROM fedora:21

### Now install some additional parts we will need for the build
# RUN yum update -y && yum clean all
RUN yum install -y gcc make zlib-devel openssl-devel tcl-devel && yum clean all
RUN groupadd -r fossil -g 433 && useradd -u 431 -r -g fossil -d /opt/fossil -s /sbin/nologin -c "Fossil user" fossil

### If you want to build "release", change the next line accordingly.
ENV FOSSIL_INSTALL_VERSION trunk

RUN curl "http://www.fossil-scm.org/index.html/tarball/fossil-src.tar.gz?name=fossil-src&uuid=${FOSSIL_INSTALL_VERSION}" | tar zx
RUN cd fossil-src && ./configure --lineedit=0 --json --with-tcl --with-tcl-stubs --with-tcl-private-stubs && make;
RUN cp fossil-src/fossil /usr/bin
RUN rm -rf fossil-src
RUN chmod a+rx /usr/bin/fossil
RUN mkdir -p /opt/fossil
RUN chown fossil:fossil /opt/fossil

### Build is done, remove modules no longer needed
RUN yum remove -y gcc make zlib-devel openssl-devel tcl-devel && yum clean all

USER fossil

ENV HOME /opt/fossil

RUN fossil new --docker -A admin /opt/fossil/repository.fossil
RUN fossil user password -R /opt/fossil/repository.fossil admin admin
RUN fossil cache init -R /opt/fossil/repository.fossil

EXPOSE 8080

CMD ["/usr/bin/fossil", "server", "/opt/fossil/repository.fossil"]







<
<
|





|
|
<
<
<
<


|





|
<
<




<
1
2
3
4
5
6


7
8
9
10
11
12
13
14




15
16
17
18
19
20
21
22
23


24
25
26
27

###
#   Dockerfile for Fossil
###
FROM fedora:21

### Now install some additional parts we will need for the build


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

### If you want to build "release", change the next line accordingly.
ENV FOSSIL_INSTALL_VERSION trunk

RUN curl "http://www.fossil-scm.org/index.html/tarball/fossil-src.tar.gz?name=fossil-src&uuid=${FOSSIL_INSTALL_VERSION}" | tar zx
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;
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





### Build is done, remove modules no longer needed
RUN yum remove -y gcc make zlib-devel openssl-devel tar && yum clean all

USER fossil

ENV HOME /opt/fossil

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



EXPOSE 8080

CMD ["/usr/bin/fossil", "server", "/opt/fossil/repository.fossil"]

Changes to VERSION.

1
1.30
|
1
1.31

Changes to auto.def.

66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
    user-error "system sqlite3 not found"
  }

  find_internal_sqlite
}

if {[string match *-solaris* [get-define host]]} {
    define-append EXTRA_CFLAGS -D_XOPEN_SOURCE=500
}

if {[opt-bool fossil-debug]} {
    define-append EXTRA_CFLAGS -DFOSSIL_DEBUG
    msg-result "Debugging support enabled"
}








|







66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
    user-error "system sqlite3 not found"
  }

  find_internal_sqlite
}

if {[string match *-solaris* [get-define host]]} {
    define-append EXTRA_CFLAGS {-D_XOPEN_SOURCE=500 -D__EXTENSIONS__}
}

if {[opt-bool fossil-debug]} {
    define-append EXTRA_CFLAGS -DFOSSIL_DEBUG
    msg-result "Debugging support enabled"
}

Added skins/README.md.























































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Built-in Skins
==============

Each subdirectory under this folder describes a built-in "skin".
There are three files in each subdirectory for the CSS, the header,
and the footer for the skin.

To improve an existing built-in skin, simply edit the appropriate
files and recompile.

To add a new skin:

   1.   Create a new subdirectory under skins/.  (The new directory is
        called "skins/newskin" below but you should use a new original
        name, of course.)

   2.   Add files skins/newskin/css.txt, skins/newskin/header.txt,
        and skins/newskin/footer.txt.  Be sure to "fossil add" these files.

   3.   Go to the src/ directory and rerun "tclsh makemake.tcl".  This
        step rebuilds the various makefiles so that they have dependencies
        on the skin files you just installed.

   4.   Edit the BuiltinSkin[] array near the top of the src/skins.c source
        file so that it describes and references the "newskin" skin.

   5.   Type "make" to rebuild.

Added skins/black_and_white/css.txt.





























































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
/* General settings for the entire page */
body {
    margin:0px 0px 0px 0px;
    padding:0px;
    font-family:verdana, arial, helvetica, "sans serif";
    color:#333;
    background-color:white;
}

/* consistent colours */
h2 {
  color: #333;
}
h3 {
  color: #333;
}

/* The project logo in the upper left-hand corner of each page */
div.logo {
  display: table-cell;
  text-align: left;
  vertical-align: bottom;
  font-weight: bold;
  color: #333;
  white-space: nowrap;
}

/* The page title centered at the top of each page */
div.title {
  display: table-cell;
  font-size: 2em;
  font-weight: bold;
  text-align: center;
  color: #333;
  vertical-align: bottom;
  width: 100%;
}

/* The login status message in the top right-hand corner */
div.status {
  display: table-cell;
  padding-right: 10px;
  text-align: right;
  vertical-align: bottom;
  padding-bottom: 5px;
  color: #333;
  font-size: 0.8em;
  font-weight: bold;
  white-space: nowrap;
}

/* The header across the top of the page */
div.header {
    margin:10px 0px 10px 0px;
    padding:1px 0px 0px 20px;
    border-style:solid;
    border-color:black;
    border-width:1px 0px;
    background-color:#eee;
}

/* The main menu bar that appears at the top left of the page beneath
** the header. Width must be co-ordinated with the container below */
div.mainmenu {
  float: left;
  margin-left: 10px;
  margin-right: 10px;
  font-size: 0.9em;
  font-weight: bold;
  padding:5px;
  background-color:#eee;
  border:1px solid #999;
  width:8em;
}

/* Main menu is now a list */
div.mainmenu ul {
  padding: 0;
  list-style:none;
}
div.mainmenu a, div.mainmenu a:visited{
  padding: 1px 10px 1px 10px;
  color: #333;
  text-decoration: none;
}
div.mainmenu a:hover {
  color: #eee;
  background-color: #333;
}

/* Container for the sub-menu and content so they don't spread
** out underneath the main menu */
#container {
  padding-left: 9em;
}

/* The submenu bar that *sometimes* appears below the main menu */
div.submenu, div.sectionmenu {
  padding: 3px 10px 3px 10px;
  font-size: 0.9em;
  text-align: center;
  border:1px solid #999;
  border-width:1px 0px;
  background-color: #eee;
  color: #333;
}
div.submenu a, div.submenu a:visited, div.sectionmenu>a.button:link,
div.sectionmenu>a.button:visited {
  padding: 3px 10px 3px 10px;
  color: #333;
  text-decoration: none;
}
div.submenu a:hover, div.sectionmenu>a.button:hover {
  color: #eee;
  background-color: #333;
}

/* All page content from the bottom of the menu or submenu down to
** the footer */
div.content {
  padding: 2ex 1ex 0ex 2ex;
}

/* Some pages have section dividers */
div.section {
  margin-bottom: 0px;
  margin-top: 1em;
  padding: 1px 1px 1px 1px;
  font-size: 1.2em;
  font-weight: bold;
  border-style:solid;
  border-color:#999;
  border-width:1px 0px;
  background-color: #eee;
  color: #333;
  white-space: nowrap;
}

/* The "Date" that occurs on the left hand side of timelines */
div.divider {
  background: #eee;
  border: 2px #999 solid;
  font-size: 1em; font-weight: normal;
  padding: .25em;
  margin: .2em 0 .2em 0;
  float: left;
  clear: left;
  color: #333;
  white-space: nowrap;
}

/* The footer at the very bottom of the page */
div.footer {
  font-size: 0.8em;
  margin-top: 12px;
  padding: 5px 10px 5px 10px;
  text-align: right;
  background-color: #eee;
  color: #555;
}

/* <verbatim> blocks */
pre.verbatim {
  background-color: #f5f5f5;
  padding: 0.5em;
  white-space: pre-wrap;
}

/* The label/value pairs on (for example) the ci page */
table.label-value th {
  vertical-align: top;
  text-align: right;
  padding: 0.2ex 2ex;
}

Added skins/black_and_white/footer.txt.









>
>
>
>
1
2
3
4
<div class="footer">
Fossil version $manifest_version $manifest_date
</div>
</body></html>

Added skins/black_and_white/header.txt.













































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<html>
<head>
<base href="$baseurl/$current_page" />
<title>$<project_name>: $<title></title>
<link rel="alternate" type="application/rss+xml" title="RSS Feed"
      href="$home/timeline.rss">
<link rel="stylesheet" href="$stylesheet_url" type="text/css"
      media="screen">
</head>
<body>
<div class="header">
  <div class="logo">
    <img src="$logo_image_url" alt="logo">
    <br />$<project_name>
  </div>
  <div class="title">$<title></div>
  <div class="status"><th1>
     if {[info exists login]} {
       puts "Logged in as $login"
     } else {
       puts "Not logged in"
     }
  </th1></div>
</div>
<div class="mainmenu">
<th1>
html "<a href='$home$index_page'>Home</a>\n"
if {[anycap jor]} {
  html "<a href='$home/timeline'>Timeline</a>\n"
}
if {[hascap oh]} {
  html "<a href='$home/tree?ci=tip'>Files</a>\n"
}
if {[hascap o]} {
  html "<a href='$home/brlist'>Branches</a>\n"
  html "<a href='$home/taglist'>Tags</a>\n"
}
if {[hascap r]} {
  html "<a href='$home/reportlist'>Tickets</a>\n"
}
if {[hascap j]} {
  html "<a href='$home/wiki'>Wiki</a>\n"
}
if {[hascap s]} {
  html "<a href='$home/setup'>Admin</a>\n"
} elseif {[hascap a]} {
  html "<a href='$home/setup_ulist'>Users</a>\n"
}
if {[info exists login]} {
  html "<a href='$home/login'>Logout</a>\n"
} else {
  html "<a href='$home/login'>Login</a>\n"
}
</th1></ul></div>

Added skins/default/css.txt.



































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/* General settings for the entire page */
body {
  margin: 0ex 1ex;
  padding: 0px;
  background-color: white;
  font-family: sans-serif;
}

/* The project logo in the upper left-hand corner of each page */
div.logo {
  display: table-cell;
  text-align: center;
  vertical-align: bottom;
  font-weight: bold;
  color: #558195;
  min-width: 200px;
  white-space: nowrap;
}

/* The page title centered at the top of each page */
div.title {
  display: table-cell;
  font-size: 2em;
  font-weight: bold;
  text-align: center;
  padding: 0 0 0 1em;
  color: #558195;
  vertical-align: bottom;
  width: 100%;
}

/* The login status message in the top right-hand corner */
div.status {
  display: table-cell;
  text-align: right;
  vertical-align: bottom;
  color: #558195;
  font-size: 0.8em;
  font-weight: bold;
  min-width: 200px;
  white-space: nowrap;
}

/* The header across the top of the page */
div.header {
  display: table;
  width: 100%;
}

/* The main menu bar that appears at the top of the page beneath
** the header */
div.mainmenu {
  padding: 5px 10px 5px 10px;
  font-size: 0.9em;
  font-weight: bold;
  text-align: center;
  letter-spacing: 1px;
  background-color: #558195;
  border-top-left-radius: 8px;
  border-top-right-radius: 8px;
  color: white;
}

/* The submenu bar that *sometimes* appears below the main menu */
div.submenu, div.sectionmenu {
  padding: 3px 10px 3px 0px;
  font-size: 0.9em;
  text-align: center;
  background-color: #456878;
  color: white;
}
div.mainmenu a, div.mainmenu a:visited, div.submenu a, div.submenu a:visited,
div.sectionmenu>a.button:link, div.sectionmenu>a.button:visited {
  padding: 3px 10px 3px 10px;
  color: white;
  text-decoration: none;
}
div.mainmenu a:hover, div.submenu a:hover, div.sectionmenu>a.button:hover {
  color: #558195;
  background-color: white;
}

/* All page content from the bottom of the menu or submenu down to
** the footer */
div.content {
  padding: 0ex 1ex 1ex 1ex;
  border: solid #aaa;
  border-width: 1px;
}

/* Some pages have section dividers */
div.section {
  margin-bottom: 0px;
  margin-top: 1em;
  padding: 1px 1px 1px 1px;
  font-size: 1.2em;
  font-weight: bold;
  background-color: #558195;
  color: white;
  white-space: nowrap;
}

/* The "Date" that occurs on the left hand side of timelines */
div.divider {
  background: #a1c4d4;
  border: 2px #558195 solid;
  font-size: 1em; font-weight: normal;
  padding: .25em;
  margin: .2em 0 .2em 0;
  float: left;
  clear: left;
  white-space: nowrap;
}

/* The footer at the very bottom of the page */
div.footer {
  clear: both;
  font-size: 0.8em;
  padding: 5px 10px 5px 10px;
  text-align: right;
  background-color: #558195;
  border-bottom-left-radius: 8px;
  border-bottom-right-radius: 8px;
  color: white;
}

/* Hyperlink colors in the footer */
div.footer a { color: white; }
div.footer a:link { color: white; }
div.footer a:visited { color: white; }
div.footer a:hover { background-color: white; color: #558195; }

/* verbatim blocks */
pre.verbatim {
  background-color: #f5f5f5;
  padding: 0.5em;
  white-space: pre-wrap;
}

/* The label/value pairs on (for example) the ci page */
table.label-value th {
  vertical-align: top;
  text-align: right;
  padding: 0.2ex 2ex;
}

Added skins/default/footer.txt.













>
>
>
>
>
>
1
2
3
4
5
6
<div class="footer">
This page was generated in about
<th1>puts [expr {([utime]+[stime]+1000)/1000*0.001}]</th1>s by
Fossil version $manifest_version $manifest_date
</div>
</body></html>

Added skins/default/header.txt.











































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<html>
<head>
<base href="$baseurl/$current_page" />
<title>$<project_name>: $<title></title>
<link rel="alternate" type="application/rss+xml" title="RSS Feed"
      href="$home/timeline.rss" />
<link rel="stylesheet" href="$stylesheet_url" type="text/css"
      media="screen" />
</head>
<body>
<div class="header">
  <div class="logo">
    <img src="$logo_image_url" alt="logo" />
  </div>
  <div class="title"><small>$<project_name></small><br />$<title></div>
  <div class="status"><th1>
     if {[info exists login]} {
       puts "Logged in as $login"
     } else {
       puts "Not logged in"
     }
  </th1></div>
</div>
<div class="mainmenu">
<th1>
html "<a href='$home$index_page'>Home</a>\n"
if {[anycap jor]} {
  html "<a href='$home/timeline'>Timeline</a>\n"
}
if {[hascap oh]} {
  html "<a href='$home/tree?ci=tip'>Files</a>\n"
}
if {[hascap o]} {
  html "<a href='$home/brlist'>Branches</a>\n"
  html "<a href='$home/taglist'>Tags</a>\n"
}
if {[hascap r]} {
  html "<a href='$home/reportlist'>Tickets</a>\n"
}
if {[hascap j]} {
  html "<a href='$home/wiki'>Wiki</a>\n"
}
if {[hascap s]} {
  html "<a href='$home/setup'>Admin</a>\n"
} elseif {[hascap a]} {
  html "<a href='$home/setup_ulist'>Users</a>\n"
}
if {[info exists login]} {
  html "<a href='$home/login'>Logout</a>\n"
} else {
  html "<a href='$home/login'>Login</a>\n"
}
</th1></div>

Added skins/eagle/css.txt.















































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
/* General settings for the entire page */
body {
  margin: 0ex 1ex;
  padding: 0px;
  background-color: #485D7B;
  font-family: sans-serif;
  color: white;
}

/* The project logo in the upper left-hand corner of each page */
div.logo {
  display: table-cell;
  text-align: center;
  vertical-align: bottom;
  font-weight: bold;
  color: white;
  padding: 5 0 5 0em;
  white-space: nowrap;
}

/* The page title centered at the top of each page */
div.title {
  display: table-cell;
  font-size: 2em;
  font-weight: bold;
  text-align: left;
  padding: 0 0 0 1em;
  color: white;
  vertical-align: bottom;
  width: 100%;
}

/* The login status message in the top right-hand corner */
div.status {
  display: table-cell;
  text-align: right;
  vertical-align: bottom;
  color: white;
  font-size: 0.8em;
  font-weight: bold;
  min-width: 200px;
  white-space: nowrap;
}

/* The header across the top of the page */
div.header {
  display: table;
  width: 100%;
}

/* The main menu bar that appears at the top of the page beneath
** the header */
div.mainmenu {
  padding: 5px 10px 5px 10px;
  font-size: 0.9em;
  font-weight: bold;
  text-align: center;
  letter-spacing: 1px;
  background-color: #76869D;
  border-top-left-radius: 8px;
  border-top-right-radius: 8px;
  color: white;
}

/* The submenu bar that *sometimes* appears below the main menu */
div.submenu, div.sectionmenu {
  padding: 3px 10px 3px 0px;
  font-size: 0.9em;
  font-weight: bold;
  text-align: center;
  background-color: #485D7B;
  color: white;
}
div.mainmenu a, div.mainmenu a:visited, div.submenu a, div.submenu a:visited,
div.sectionmenu>a.button:link, div.sectionmenu>a.button:visited {
  padding: 3px 10px 3px 10px;
  color: white;
  text-decoration: none;
}
div.mainmenu a:hover, div.submenu a:hover, div.sectionmenu>a.button:hover {
  text-decoration: underline;
}

/* All page content from the bottom of the menu or submenu down to
** the footer */
div.content {
  padding: 0ex 1ex 0ex 2ex;
}

/* Some pages have section dividers */
div.section {
  margin-bottom: 0px;
  margin-top: 1em;
  padding: 1px 1px 1px 1px;
  font-size: 1.2em;
  font-weight: bold;
  background-color: #485D7B;
  color: white;
  white-space: nowrap;
}

/* The "Date" that occurs on the left hand side of timelines */
div.divider {
  background: #9DB0CC;
  color: white;
  border: 2px white solid;
  font-size: 1em; font-weight: normal;
  padding: .25em;
  margin: .2em 0 .2em 0;
  float: left;
  clear: left;
  white-space: nowrap;
}

/* The footer at the very bottom of the page */
div.footer {
  clear: both;
  font-size: 0.8em;
  margin-top: 12px;
  padding: 5px 10px 5px 10px;
  text-align: right;
  background-color: #485D7B;
  border-bottom-left-radius: 8px;
  border-bottom-right-radius: 8px;
  color: white;
}

/* Hyperlink colors in the footer */
a { color: white; }
a:link { color: white; }
a:visited { color: white; }
a:hover { color: #9DB0CC; }

/* verbatim blocks */
pre.verbatim {
  background-color: #485D7B;
  color: white;
  padding: 0.5em;
  white-space: pre-wrap;
}

/* The label/value pairs on (for example) the ci page */
table.label-value th {
  vertical-align: top;
  text-align: right;
  padding: 0.2ex 2ex;
}

/* The nomenclature sidebox for branches,.. */
div.sidebox {
  float: right;
  background-color: #485D7B;
  border-width: medium;
  border-style: double;
  margin: 10px;
}

/* the format for the timeline data table */
table.timelineTable {
  cellspacing: 0;
  border: 0;
  cellpadding: 0;
  font-family: "courier new";
}

/* Side-by-side diff */
table.sbsdiff {
  background-color: #485D7B;
  font-family: fixed, Dejavu Sans Mono, Monaco, Lucida Console, monospace;
  font-size: 8pt;
  border-collapse:collapse;
  white-space: pre;
  width: 98%;
  border: 1px #000 dashed;
  margin-left: auto;
  margin-right: auto;
}

/* format for the layout table, used for the captcha display */
table.captcha {
  margin: auto;
  padding: 10px;
  border-width: 4px;
  border-style: double;
  border-color: white;
}

/* format for the user list table on the user setup page */
table.usetupUserList {
  outline-style: double;
  outline-width: 1px;
  outline-color: white;
  padding: 10px;
}

/* color for capabilities, inherited by reader */
span.ueditInheritReader {
  color: white;
}

/* format for values on ticket display page */
td.tktDspValue {
  text-align: left;
  vertical-align: top;
  background-color: #485D7B;
}

/* format for example table cells on the report edit page */
td.rpteditex {
  border-width: thin;
  border-color: white;
  border-style: solid;
}

/* List of files in a timeline */
ul.filelist {
  margin-top: 3px;
  line-height: 100%;
}

/* side-by-side diff display */
div.sbsdiff {
  font-family: monospace;
  font-size: smaller;
  white-space: pre;
}

/* context diff display */
div.udiff {
  font-family: monospace;
  white-space: pre;
}

/* changes in a diff */
span.diffchng {
  background-color: rgb(170, 170, 140);
}

/* added code in a diff */
span.diffadd {
  background-color: rgb(100, 200, 100);
}

/* deleted in a diff */
span.diffrm {
  background-color: rgb(230, 110, 110);
}

/* suppressed lines in a diff */
span.diffhr {
  display: inline-block;
  margin: .5em 0 1em;
  color: rgb(150, 150, 140);
}

/* line numbers in a diff */
span.diffln {
  color: white;
}

#canvas {
  background-color: #485D7B;
}

Added skins/eagle/footer.txt.



















































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<div class="footer">
  <th1>
  proc getTclVersion {} {
    if {[catch {tclEval info patchlevel} tclVersion] == 0} {
      return "<a href=\"http://www.tcl.tk/\">Tcl</a> version $tclVersion"
    }
    return ""
  }
  proc getVersion { version } {
    set length [string length $version]
    return [string range $version 1 [expr {$length - 2}]]
  }
  set version [getVersion $manifest_version]
  set tclVersion [getTclVersion]
  set fossilUrl https://www.fossil-scm.org
  set fossilDate [string range $manifest_date 0 9]T[string range $manifest_date 11 end]
  </th1>
  This page was generated in about
  <th1>puts [expr {([utime]+[stime]+1000)/1000*0.001}]</th1>s by
  <a href="$fossilUrl/">Fossil</a>
  version $release_version $tclVersion
  <a href="$fossilUrl/index.html/info/$version">$manifest_version</a>
  <a href="$fossilUrl/index.html/timeline?c=$fossilDate&amp;y=ci">$manifest_date</a>
</div>
</body></html>

Added skins/eagle/header.txt.













































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
<html>
<head>
<base href="$baseurl/$current_page" />
<title>$<project_name>: $<title></title>
<link rel="alternate" type="application/rss+xml" title="RSS Feed"
      href="$home/timeline.rss" />
<link rel="stylesheet" href="$stylesheet_url" type="text/css"
      media="screen" />
</head>
<body>
<div class="header">
  <div class="logo">
    <th1>
    ##
    ## NOTE: The purpose of this procedure is to take the base URL of the
    ##       Fossil project and return the root of the entire web site using
    ##       the same URI scheme as the base URL (e.g. http or https).
    ##
    proc getLogoUrl { baseurl } {
      set idx(first) [string first // $baseurl]
      if {$idx(first) != -1} {
        ##
        ## NOTE: Skip second slash.
        ##
        set idx(first+1) [expr {$idx(first) + 2}]
        ##
        ## NOTE: (part 1) The [string first] command does NOT actually
        ##       support the optional startIndex argument as specified
        ##       in the TH1 support manual; therefore, we fake it by
        ##       using the [string range] command and then adding the
        ##       necessary offset to the resulting index manually
        ##       (below).  In Tcl, we could use the following instead:
        ##
        ##       set idx(next) [string first / $baseurl $idx(first+1)]
        ##
        set idx(nextRange) [string range $baseurl $idx(first+1) end]
        set idx(next) [string first / $idx(nextRange)]
        if {$idx(next) != -1} {
          ##
          ## NOTE: (part 2) Add the necessary offset to the result of
          ##       the search for the next slash (i.e. the one after
          ##       the initial search for the two slashes).
          ##
          set idx(next) [expr {$idx(next) + $idx(first+1)}]
          ##
          ## NOTE: Back up one character from the next slash.
          ##
          set idx(next-1) [expr {$idx(next) - 1}]
          ##
          ## NOTE: Extract the URI scheme and host from the base URL.
          ##
          set scheme [string range $baseurl 0 $idx(first)]
          set host [string range $baseurl $idx(first+1) $idx(next-1)]
          ##
          ## NOTE: Try to stay in SSL mode if we are there now.
          ##
          if {[string compare $scheme http:/] == 0} {
            set scheme http://
          } else {
            set scheme https://
          }
          set logourl $scheme$host/
        } else {
          set logourl $baseurl
        }
      } else {
        set logourl $baseurl
      }
      return $logourl
    }
    set logourl [getLogoUrl $baseurl]
    </th1>
    <a href="$logourl">
      <img src="$logo_image_url" border="0" alt="$project_name">
    </a>
  </div>
  <div class="title">$<title></div>
  <div class="status"><nobr><th1>
     if {[info exists login]} {
       puts "Logged in as $login"
     } else {
       puts "Not logged in"
     }
  </th1></nobr><small><div id="clock"></div></small></div>
</div>
<script>
function updateClock(){
  var e = document.getElementById("clock");
  if(e){
    var d = new Date();
    function f(n) {
      return n < 10 ? '0' + n : n;
    }
    e.innerHTML = d.getUTCFullYear()+ '-' +
      f(d.getUTCMonth() + 1) + '-' +
      f(d.getUTCDate())      + ' ' +
      f(d.getUTCHours())     + ':' +
      f(d.getUTCMinutes());
    setTimeout("updateClock();",(60-d.getUTCSeconds())*1000);
  }
}
updateClock();
</script>
<div class="mainmenu">
<th1>
html "<a href='$home$index_page'>Home</a>\n"
html "<a href='$home/help'>Help</a>\n"
if {[anycap jor]} {
  html "<a href='$home/timeline'>Timeline</a>\n"
}
if {[hascap oh]} {
  html "<a href='$home/tree?ci=tip'>Files</a>\n"
}
if {[hascap o]} {
  html "<a href='$home/brlist'>Branches</a>\n"
  html "<a href='$home/taglist'>Tags</a>\n"
}
if {[hascap r]} {
  html "<a href='$home/reportlist'>Tickets</a>\n"
}
if {[hascap j]} {
  html "<a href='$home/wiki'>Wiki</a>\n"
}
if {[hascap s]} {
  html "<a href='$home/setup'>Admin</a>\n"
} elseif {[hascap a]} {
  html "<a href='$home/setup_ulist'>Users</a>\n"
}
if {[info exists login]} {
  html "<a href='$home/login'>Logout</a>\n"
} else {
  html "<a href='$home/login'>Login</a>\n"
}
</th1></div>

Added skins/enhanced1/css.txt.



































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/* General settings for the entire page */
body {
  margin: 0ex 1ex;
  padding: 0px;
  background-color: white;
  font-family: sans-serif;
}

/* The project logo in the upper left-hand corner of each page */
div.logo {
  display: table-cell;
  text-align: center;
  vertical-align: bottom;
  font-weight: bold;
  color: #558195;
  min-width: 200px;
  white-space: nowrap;
}

/* The page title centered at the top of each page */
div.title {
  display: table-cell;
  font-size: 2em;
  font-weight: bold;
  text-align: center;
  padding: 0 0 0 1em;
  color: #558195;
  vertical-align: bottom;
  width: 100%;
}

/* The login status message in the top right-hand corner */
div.status {
  display: table-cell;
  text-align: right;
  vertical-align: bottom;
  color: #558195;
  font-size: 0.8em;
  font-weight: bold;
  min-width: 200px;
  white-space: nowrap;
}

/* The header across the top of the page */
div.header {
  display: table;
  width: 100%;
}

/* The main menu bar that appears at the top of the page beneath
** the header */
div.mainmenu {
  padding: 5px 10px 5px 10px;
  font-size: 0.9em;
  font-weight: bold;
  text-align: center;
  letter-spacing: 1px;
  background-color: #558195;
  border-top-left-radius: 8px;
  border-top-right-radius: 8px;
  color: white;
}

/* The submenu bar that *sometimes* appears below the main menu */
div.submenu, div.sectionmenu {
  padding: 3px 10px 3px 0px;
  font-size: 0.9em;
  text-align: center;
  background-color: #456878;
  color: white;
}
div.mainmenu a, div.mainmenu a:visited, div.submenu a, div.submenu a:visited,
div.sectionmenu>a.button:link, div.sectionmenu>a.button:visited {
  padding: 3px 10px 3px 10px;
  color: white;
  text-decoration: none;
}
div.mainmenu a:hover, div.submenu a:hover, div.sectionmenu>a.button:hover {
  color: #558195;
  background-color: white;
}

/* All page content from the bottom of the menu or submenu down to
** the footer */
div.content {
  padding: 0ex 1ex 1ex 1ex;
  border: solid #aaa;
  border-width: 1px;
}

/* Some pages have section dividers */
div.section {
  margin-bottom: 0px;
  margin-top: 1em;
  padding: 1px 1px 1px 1px;
  font-size: 1.2em;
  font-weight: bold;
  background-color: #558195;
  color: white;
  white-space: nowrap;
}

/* The "Date" that occurs on the left hand side of timelines */
div.divider {
  background: #a1c4d4;
  border: 2px #558195 solid;
  font-size: 1em; font-weight: normal;
  padding: .25em;
  margin: .2em 0 .2em 0;
  float: left;
  clear: left;
  white-space: nowrap;
}

/* The footer at the very bottom of the page */
div.footer {
  clear: both;
  font-size: 0.8em;
  padding: 5px 10px 5px 10px;
  text-align: right;
  background-color: #558195;
  border-bottom-left-radius: 8px;
  border-bottom-right-radius: 8px;
  color: white;
}

/* Hyperlink colors in the footer */
div.footer a { color: white; }
div.footer a:link { color: white; }
div.footer a:visited { color: white; }
div.footer a:hover { background-color: white; color: #558195; }

/* verbatim blocks */
pre.verbatim {
  background-color: #f5f5f5;
  padding: 0.5em;
  white-space: pre-wrap;
}

/* The label/value pairs on (for example) the ci page */
table.label-value th {
  vertical-align: top;
  text-align: right;
  padding: 0.2ex 2ex;
}

Added skins/enhanced1/footer.txt.

















































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<div class="footer">
  <th1>
  proc getTclVersion {} {
    if {[catch {tclEval info patchlevel} tclVersion] == 0} {
      return "<a href=\"http://www.tcl.tk/\">Tcl</a> version $tclVersion"
    }
    return ""
  }
  proc getVersion { version } {
    set length [string length $version]
    return [string range $version 1 [expr {$length - 2}]]
  }
  set version [getVersion $manifest_version]
  set tclVersion [getTclVersion]
  set fossilUrl https://www.fossil-scm.org
  </th1>
  This page was generated in about
  <th1>puts [expr {([utime]+[stime]+1000)/1000*0.001}]</th1>s by
  <a href="$fossilUrl/">Fossil</a>
  version $release_version $tclVersion
  <a href="$fossilUrl/index.html/info/$version">$manifest_version</a>
  <a href="$fossilUrl/index.html/timeline?c=$manifest_date&amp;y=ci">$manifest_date</a>
</div>
</body></html>

Added skins/enhanced1/header.txt.













































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
<html>
<head>
<base href="$baseurl/$current_page" />
<title>$<project_name>: $<title></title>
<link rel="alternate" type="application/rss+xml" title="RSS Feed"
      href="$home/timeline.rss" />
<link rel="stylesheet" href="$stylesheet_url" type="text/css"
      media="screen" />
</head>
<body>
<div class="header">
  <div class="logo">
    <th1>
    ##
    ## NOTE: The purpose of this procedure is to take the base URL of the
    ##       Fossil project and return the root of the entire web site using
    ##       the same URI scheme as the base URL (e.g. http or https).
    ##
    proc getLogoUrl { baseurl } {
      set idx(first) [string first // $baseurl]
      if {$idx(first) != -1} {
        ##
        ## NOTE: Skip second slash.
        ##
        set idx(first+1) [expr {$idx(first) + 2}]
        ##
        ## NOTE: (part 1) The [string first] command does NOT actually
        ##       support the optional startIndex argument as specified
        ##       in the TH1 support manual; therefore, we fake it by
        ##       using the [string range] command and then adding the
        ##       necessary offset to the resulting index manually
        ##       (below).  In Tcl, we could use the following instead:
        ##
        ##       set idx(next) [string first / $baseurl $idx(first+1)]
        ##
        set idx(nextRange) [string range $baseurl $idx(first+1) end]
        set idx(next) [string first / $idx(nextRange)]
        if {$idx(next) != -1} {
          ##
          ## NOTE: (part 2) Add the necessary offset to the result of
          ##       the search for the next slash (i.e. the one after
          ##       the initial search for the two slashes).
          ##
          set idx(next) [expr {$idx(next) + $idx(first+1)}]
          ##
          ## NOTE: Back up one character from the next slash.
          ##
          set idx(next-1) [expr {$idx(next) - 1}]
          ##
          ## NOTE: Extract the URI scheme and host from the base URL.
          ##
          set scheme [string range $baseurl 0 $idx(first)]
          set host [string range $baseurl $idx(first+1) $idx(next-1)]
          ##
          ## NOTE: Try to stay in SSL mode if we are there now.
          ##
          if {[string compare $scheme http:/] == 0} {
            set scheme http://
          } else {
            set scheme https://
          }
          set logourl $scheme$host/
        } else {
          set logourl $baseurl
        }
      } else {
        set logourl $baseurl
      }
      return $logourl
    }
    set logourl [getLogoUrl $baseurl]
    </th1>
    <a href="$logourl">
      <img src="$logo_image_url" border="0" alt="$project_name">
    </a>
  </div>
  <div class="title">$<title></div>
  <div class="status"><th1>
     if {[info exists login]} {
       puts "Logged in as $login"
     } else {
       puts "Not logged in"
     }
  </th1></nobr><small><div id="clock"></div></small></div>
</div>
<script>
function updateClock(){
  var e = document.getElementById("clock");
  if(e){
    var d = new Date();
    function f(n) {
      return n < 10 ? '0' + n : n;
    }
    e.innerHTML = d.getUTCFullYear()+ '-' +
      f(d.getUTCMonth() + 1) + '-' +
      f(d.getUTCDate())      + ' ' +
      f(d.getUTCHours())     + ':' +
      f(d.getUTCMinutes());
    setTimeout("updateClock();",(60-d.getUTCSeconds())*1000);
  }
}
updateClock();
</script>
<div class="mainmenu">
<th1>
html "<a href='$home$index_page'>Home</a>\n"
html "<a href='$home/help'>Help</a>\n"
if {[anycap jor]} {
  html "<a href='$home/timeline'>Timeline</a>\n"
}
if {[hascap oh]} {
  html "<a href='$home/tree?ci=tip'>Files</a>\n"
}
if {[hascap o]} {
  html "<a href='$home/brlist'>Branches</a>\n"
  html "<a href='$home/taglist'>Tags</a>\n"
}
if {[hascap r]} {
  html "<a href='$home/reportlist'>Tickets</a>\n"
}
if {[hascap j]} {
  html "<a href='$home/wiki'>Wiki</a>\n"
}
if {[hascap s]} {
  html "<a href='$home/setup'>Admin</a>\n"
} elseif {[hascap a]} {
  html "<a href='$home/setup_ulist'>Users</a>\n"
}
if {[info exists login]} {
  html "<a href='$home/login'>Logout</a>\n"
} else {
  html "<a href='$home/login'>Login</a>\n"
}
</th1></div>

Added skins/etienne1/README.md.



>
1
This skin was contributed by Étienne Deparis.

Added skins/etienne1/css.txt.

























































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
body {
    margin: 0 auto;
    width: 960px;
    font-family: sans-serif;
    font-size:14pt;
}

a {
    color: #4183C4;
    text-decoration: none;
}
a:hover {
    color: #4183C4;
    text-decoration: underline;
}

hr {
    border: 0px;
}

.title {
    color: #4183C4;
    float:left;
    padding-top: 30px;
    padding-bottom: 10px;
}
.title h1 {
    display:inline;
}
.title h1:after {
    content: " / ";
    color: #777;
    font-weight: normal;
}

.content h1 {
    font-size: 1.25em;
}
.content h2 {
    font-size: 1.15em;
}
.content h2 {
    font-size: 1.05em;
    font-weight: bold;
}

.section {
    font-size: 1em;
    font-weight: bold;
    background-color: #f5f5f5;
    border: 1px solid #d8d8d8;
    border-radius: 3px 3px 0 0;
    padding: 9px 10px 10px;
    margin: 10px 0;
}

.sectionmenu {
    border: 1px solid #d8d8d8;
    border-radius: 0 0 3px 3px;
    border-top: 0;
    margin-top: -10px;
    margin-bottom: 10px;
    padding: 10px;
}
.sectionmenu a {
    display: inline-block;
    margin-right: 1em;
}

.status {
    float:right;
    font-size:.7em;
    padding-top:50px;
}

.mainmenu {
    font-size:.8em;
    clear:both;
    padding:10px;
    background:#eaeaea linear-gradient(#fafafa, #eaeaea) repeat-x;
    border:1px solid #eaeaea;
    border-radius:5px;
}

.mainmenu a {
    padding: 10px 20px;
    text-decoration:none;
    color: #777;
    border-right:1px solid #eaeaea;
}
.mainmenu a.active,
.mainmenu a:hover {
    color: #000;
    border-bottom:2px solid #D26911;
}

.submenu {
    font-size: .7em;
    margin-top: 10px;
    padding: 10px;
    border-bottom: 1px solid #ccc;
}

.submenu a {
    padding: 10px;
    text-decoration:none;
    color: #777;
}

.submenu a:hover {
    border: 1px solid #ccc;
    border-bottom: 1px solid #fff;
    border-top-left-radius: 5px;
    border-top-right-radius: 5px;
}

.content {
    padding-top: 10px;
    font-size:.8em;
    color: #444;
}

.udiff, .sbsdiff,
.content blockquote {
    font-size: .85em !important;
    overflow: auto;
    border: 1px solid #ccc;
    border-radius: 5px;
}
.content blockquote {
    padding: 0 15px;
}

table.report {
    cursor: auto;
    border-radius: 5px;
    border: 1px solid #ccc;
    margin: 1em 0;
}
.report td, .report th {
   border: 0;
   font-size: .8em;
   padding: 10px;
}
.report td:first-child {
    border-top-left-radius: 5px;
}
.report tbody tr:last-child td:first-child {
    border-bottom-left-radius: 5px;
}
.report td:last-child {
    border-top-right-radius: 5px;
}
.report tbody tr:last-child {
    border-bottom-left-radius: 5px;
    border-bottom-right-radius: 5px;
}
.report tbody tr:last-child td:last-child {
    border-bottom-right-radius: 5px;
}
.report th {
    cursor: pointer;
}
.report thead+tbody tr:hover {
    background-color: #f5f9fc !important;
}

td.tktDspLabel {
    max-width: 70px;
    text-align: right;
}
td.tktDspValue {
    max-width: 800px;
    text-align: left;
    vertical-align: top;
    background-color: #f5f9fc;
}
td.tktDspValue pre {
    white-space: pre-wrap;
}

.footer {
    border-top: 1px solid #ccc;
    padding: 10px;
    font-size:.7em;
    margin-top: 10px;
    color: #ccc;
}

Added skins/etienne1/footer.txt.













>
>
>
>
>
>
1
2
3
4
5
6
<div class="footer">
This page was generated in about
<th1>puts [expr {([utime]+[stime]+1000)/1000*0.001}]</th1>s by
Fossil version $manifest_version $manifest_date
</div>
</body></html>

Added skins/etienne1/header.txt.

















































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
<html>
  <head>
    <base href="$baseurl/$current_page" />
    <title>$<project_name>: $<title></title>
      <link rel="alternate" type="application/rss+xml" title="RSS Feed"
            href="$home/timeline.rss" />
      <link rel="stylesheet" href="$home/style.css?default" type="text/css"
            media="screen" />
  </head>

  <body>
    <div class="header">
      <div class="title"><h1>$<project_name></h1>$<title></div>
        <div class="status"><th1>
     if {[info exists login]} {
       html "$login — <a href='$home/login'>Logout</a>\n"
     } else {
       html "<a href='$home/login'>Login</a>\n"
     }
        </th1></div>
    </div>

    <div class="mainmenu">
      <th1>
proc isin {val lst} {
    set tot [llength $lst]
    for {set i 0} {$i < $tot} {set i [expr {$i + 1}]} {
        set cur [lindex $lst $i]
        if {$val eq $cur} {
            return 0
        }
    }
    return 1
}

proc menulink {pagename url name} {
    upvar current_page current
    upvar home home

    set compsetup [string compare [string range $current 0 4] setup]
    set comphome [string compare [string range $current 0 3] home]
    set comptag [string compare $current tagtimeline]
    set compbr [string compare $current brtimeline]
    set compdir [isin $current "artifact ci finfo hexdump"]
    set comptl [string compare $current info]
    set comptkt [isin $current "modreq rptedit tktnew rptsql rptview"]

    html "<a href='$home$url'"

    if {$pagename eq $current
        || ($pagename eq "home" && $comphome == 0)
        || ($pagename eq "setup" && $compsetup == 0)
        || ($pagename eq "taglist" && $comptag == 0)
        || ($pagename eq "dir" && $compdir == 0)
        || ($pagename eq "timeline" && $comptl == 0)
        || ($pagename eq "reportlist" && $comptkt == 0)
        || ($pagename eq "brlist" && $compbr == 0)
    } {
        html " class='active' "
    }

    html ">$name</a>"
}

menulink "home" $index_page Home

if {[anycap jor]} {
    menulink "timeline" "/timeline" Timeline
}
if {[hascap oh]} {
    menulink "dir" "/dir?ci=tip" Files
}
if {[hascap o]} {
    menulink "brlist" "/brlist" Branches
    menulink "taglist" "/taglist" Tags
}
if {[hascap r]} {
    menulink "reportlist" "/reportlist" Tickets
}
if {[hascap j]} {
    menulink "wiki" "/wiki" Wiki
}
if {[hascap s]} {
    menulink "setup" "/setup" Admin
} elseif {[hascap a]} {
    menulink "setup_ulist" "/setup_ulist" Users
}
</th1></div>

Added skins/khaki/css.txt.































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/* General settings for the entire page */
body {
  margin: 0ex 0ex;
  padding: 0px;
  background-color: #fef3bc;
  font-family: sans-serif;
}

/* The project logo in the upper left-hand corner of each page */
div.logo {
  display: inline;
  text-align: center;
  vertical-align: bottom;
  font-weight: bold;
  font-size: 2.5em;
  color: #a09048;
  white-space: nowrap;
}

/* The page title centered at the top of each page */
div.title {
  display: table-cell;
  font-size: 2em;
  font-weight: bold;
  text-align: left;
  padding: 0 0 0 5px;
  color: #a09048;
  vertical-align: bottom;
  width: 100%;
}

/* The login status message in the top right-hand corner */
div.status {
  display: table-cell;
  text-align: right;
  vertical-align: bottom;
  color: #a09048;
  padding: 5px 5px 0 0;
  font-size: 0.8em;
  font-weight: bold;
  white-space: nowrap;
}

/* The header across the top of the page */
div.header {
  display: table;
  width: 100%;
}

/* The main menu bar that appears at the top of the page beneath
** the header */
div.mainmenu {
  padding: 5px 10px 5px 10px;
  font-size: 0.9em;
  font-weight: bold;
  text-align: center;
  letter-spacing: 1px;
  background-color: #a09048;
  color: black;
}

/* The submenu bar that *sometimes* appears below the main menu */
div.submenu, div.sectionmenu {
  padding: 3px 10px 3px 0px;
  font-size: 0.9em;
  text-align: center;
  background-color: #c0af58;
  color: white;
}
div.mainmenu a, div.mainmenu a:visited, div.submenu a, div.submenu a:visited,
div.sectionmenu>a.button:link, div.sectionmenu>a.button:visited {
  padding: 3px 10px 3px 10px;
  color: white;
  text-decoration: none;
}
div.mainmenu a:hover, div.submenu a:hover, div.sectionmenu>a.button:hover {
  color: #a09048;
  background-color: white;
}

/* All page content from the bottom of the menu or submenu down to
** the footer */
div.content {
  padding: 1ex 5px;
}
div.content a { color: #706532; }
div.content a:link { color: #706532; }
div.content a:visited { color: #704032; }
div.content a:hover { background-color: white; color: #706532; }

/* Some pages have section dividers */
div.section {
  margin-bottom: 0px;
  margin-top: 1em;
  padding: 3px 3px 0 3px;
  font-size: 1.2em;
  font-weight: bold;
  background-color: #a09048;
  color: white;
  white-space: nowrap;
}

/* The "Date" that occurs on the left hand side of timelines */
div.divider {
  background: #e1d498;
  border: 2px #a09048 solid;
  font-size: 1em; font-weight: normal;
  padding: .25em;
  margin: .2em 0 .2em 0;
  float: left;
  clear: left;
  white-space: nowrap;
}

/* The footer at the very bottom of the page */
div.footer {
  font-size: 0.8em;
  margin-top: 12px;
  padding: 5px 10px 5px 10px;
  text-align: right;
  background-color: #a09048;
  color: white;
}

/* Hyperlink colors */
div.footer a { color: white; }
div.footer a:link { color: white; }
div.footer a:visited { color: white; }
div.footer a:hover { background-color: white; color: #558195; }

/* <verbatim> blocks */
pre.verbatim {
  background-color: #f5f5f5;
  padding: 0.5em;
  white-space: pre-wrap;
}

/* The label/value pairs on (for example) the ci page */
table.label-value th {
  vertical-align: top;
  text-align: right;
  padding: 0.2ex 2ex;
}

Added skins/khaki/footer.txt.









>
>
>
>
1
2
3
4
<div class="footer">
Fossil version $manifest_version $manifest_date
</div>
</body></html>

Added skins/khaki/header.txt.









































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<html>
<head>
<base href="$baseurl/$current_page" />
<title>$<project_name>: $<title></title>
<link rel="alternate" type="application/rss+xml" title="RSS Feed"
      href="$home/timeline.rss">
<link rel="stylesheet" href="$stylesheet_url" type="text/css"
      media="screen">
</head>
<body>
<div class="header">
  <div class="title">$<title></div>
  <div class="status">
    <div class="logo">$<project_name></div><br/>
    <th1>
     if {[info exists login]} {
       puts "Logged in as $login"
     } else {
       puts "Not logged in"
     }
  </th1></div>
</div>
<div class="mainmenu">
<th1>
html "<a href='$home$index_page'>Home</a>\n"
if {[anycap jor]} {
  html "<a href='$home/timeline'>Timeline</a>\n"
}
if {[hascap oh]} {
  html "<a href='$home/tree?ci=tip'>Files</a>\n"
}
if {[hascap o]} {
  html "<a href='$home/brlist'>Branches</a>\n"
  html "<a href='$home/taglist'>Tags</a>\n"
}
if {[hascap r]} {
  html "<a href='$home/reportlist'>Tickets</a>\n"
}
if {[hascap j]} {
  html "<a href='$home/wiki'>Wiki</a>\n"
}
if {[hascap s]} {
  html "<a href='$home/setup'>Admin</a>\n"
} elseif {[hascap a]} {
  html "<a href='$home/setup_ulist'>Users</a>\n"
}
if {[info exists login]} {
  html "<a href='$home/login'>Logout</a>\n"
} else {
  html "<a href='$home/login'>Login</a>\n"
}
</th1></div>

Added skins/plain_gray/css.txt.























































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
/* General settings for the entire page */
body {
  margin: 0ex 1ex;
  padding: 0px;
  background-color: white;
  font-family: sans-serif;
}

/* The project logo in the upper left-hand corner of each page */
div.logo {
  display: table-row;
  text-align: center;
  /* vertical-align: bottom;*/
  font-size: 2em;
  font-weight: bold;
  background-color: #707070;
  color: #ffffff;
  min-width: 200px;
  white-space: nowrap;
}

/* The page title centered at the top of each page */
div.title {
  display: table-cell;
  font-size: 1.5em;
  font-weight: bold;
  text-align: center;
  padding: 0 0 0 10px;
  color: #404040;
  vertical-align: bottom;
  width: 100%;
}

/* The login status message in the top right-hand corner */
div.status {
  display: table-cell;
  text-align: right;
  vertical-align: bottom;
  color: #404040;
  font-size: 0.8em;
  font-weight: bold;
  min-width: 200px;
  white-space: nowrap;
}

/* The header across the top of the page */
div.header {
  display: table;
  width: 100%;
}

/* The main menu bar that appears at the top of the page beneath
** the header */
div.mainmenu {
  padding: 5px 10px 5px 10px;
  font-size: 0.9em;
  font-weight: bold;
  text-align: center;
  letter-spacing: 1px;
  background-color: #404040;
  color: white;
}

/* The submenu bar that *sometimes* appears below the main menu */
div.submenu, div.sectionmenu {
  padding: 3px 10px 3px 0px;
  font-size: 0.9em;
  text-align: center;
  background-color: #606060;
  color: white;
}
div.mainmenu a, div.mainmenu a:visited, div.submenu a, div.submenu a:visited,
div.sectionmenu>a.button:link, div.sectionmenu>a.button:visited {
  padding: 3px 10px 3px 10px;
  color: white;
  text-decoration: none;
}
div.mainmenu a:hover, div.submenu a:hover, div.sectionmenu>a.button:hover {
  color: #404040;
  background-color: white;
}

/* All page content from the bottom of the menu or submenu down to
** the footer */
div.content {
  padding: 0ex 0ex 0ex 0ex;
}
/* Hyperlink colors */
div.content a { color: #604000; }
div.content a:link { color: #604000;}
div.content a:visited { color: #600000; }

/* <verbatim> blocks */
pre.verbatim {
  background-color: #ffffff;
  padding: 0.5em;
  white-space: pre-wrap;
}

/* Some pages have section dividers */
div.section {
  margin-bottom: 0px;
  margin-top: 1em;
  padding: 1px 1px 1px 1px;
  font-size: 1.2em;
  font-weight: bold;
  background-color: #404040;
  color: white;
  white-space: nowrap;
}

/* The "Date" that occurs on the left hand side of timelines */
div.divider {
  background: #a0a0a0;
  border: 2px #505050 solid;
  font-size: 1em; font-weight: normal;
  padding: .25em;
  margin: .2em 0 .2em 0;
  float: left;
  clear: left;
  white-space: nowrap;
}

/* The footer at the very bottom of the page */
div.footer {
  font-size: 0.8em;
  margin-top: 12px;
  padding: 5px 10px 5px 10px;
  text-align: right;
  background-color: #404040;
  color: white;
}

/* The label/value pairs on (for example) the vinfo page */
table.label-value th {
  vertical-align: top;
  text-align: right;
  padding: 0.2ex 2ex;
}

Added skins/plain_gray/footer.txt.









>
>
>
>
1
2
3
4
<div class="footer">
Fossil version $manifest_version $manifest_date
</div>
</body></html>

Added skins/plain_gray/header.txt.





































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<html>
<head>
<base href="$baseurl/$current_page" />
<title>$<project_name>: $<title></title>
<link rel="alternate" type="application/rss+xml" title="RSS Feed"
      href="$home/timeline.rss">
<link rel="stylesheet" href="$stylesheet_url" type="text/css"
      media="screen">
</head>
<body>
<div class="header">
  <div class="title"><small>$<project_name></small><br />$<title></div>
  <div class="status"><th1>
     if {[info exists login]} {
       puts "Logged in as $login"
     } else {
       puts "Not logged in"
     }
  </th1></div>
</div>
<div class="mainmenu">
<th1>
html "<a href='$home$index_page'>Home</a>\n"
if {[anycap jor]} {
  html "<a href='$home/timeline'>Timeline</a>\n"
}
if {[hascap oh]} {
  html "<a href='$home/tree?ci=tip'>Files</a>\n"
}
if {[hascap o]} {
  html "<a href='$home/brlist'>Branches</a>\n"
  html "<a href='$home/taglist'>Tags</a>\n"
}
if {[hascap r]} {
  html "<a href='$home/reportlist'>Tickets</a>\n"
}
if {[hascap j]} {
  html "<a href='$home/wiki'>Wiki</a>\n"
}
if {[hascap s]} {
  html "<a href='$home/setup'>Admin</a>\n"
} elseif {[hascap a]} {
  html "<a href='$home/setup_ulist'>Users</a>\n"
}
if {[info exists login]} {
  html "<a href='$home/login'>Logout</a>\n"
} else {
  html "<a href='$home/login'>Login</a>\n"
}
</th1></div>

Added skins/rounded1/css.txt.







































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
/* General settings for the entire page */
html {
  min-height: 100%;
}
body {
  margin: 0ex 1ex;
  padding: 0px;
  background-color: white;
  color: #333;
  font-family: Verdana, sans-serif;
  font-size: 0.8em;
}

/* The project logo in the upper left-hand corner of each page */
div.logo {
  display: table-cell;
  text-align: right;
  vertical-align: bottom;
  font-weight: normal;
  white-space: nowrap;
}

/* Widths */
div.header, div.mainmenu, div.submenu, div.content, div.footer {
  max-width: 900px;
  margin: auto;
  padding: 3px 20px 3px 20px;
  clear: both;
}

/* The page title at the top of each page */
div.title {
  display: table-cell;
  padding-left: 10px;
  font-size: 2em;
  margin: 10px 0 10px -20px;
  vertical-align: bottom;
  text-align: left;
  width: 80%;
  font-family: Verdana, sans-serif;
  font-weight: bold;
  color: #558195;
  text-shadow: 0px 2px 2px #999999;
}

/* The login status message in the top right-hand corner */
div.status {
  display: table-cell;
  text-align: right;
  vertical-align: bottom;
  color: #333;
  margin-right: -20px;
  white-space: nowrap;
}

/* The main menu bar that appears at the top of the page beneath
 ** the header */
div.mainmenu {
  text-align: center;
  color: white;
  border-top-left-radius: 5px;
  border-top-right-radius: 5px;
  vertical-align: middle;
  padding-top: 8px;
  padding-bottom: 8px;
  background-color: #446979;
  box-shadow: 0px 3px 4px #333333;
}

/* The submenu bar that *sometimes* appears below the main menu */
div.submenu {
  padding-top:10px;
  padding-bottom:0;
  text-align: right;
  color: #000;
  background-color: #fff;
  height: 1.5em;
  vertical-align:middle;
  box-shadow: 0px 3px 4px #999;
}
div.mainmenu a, div.mainmenu a:visited {
  padding: 3px 10px 3px 10px;
  color: white;
  text-decoration: none;
}
div.submenu a, div.submenu a:visited, a.button,
div.sectionmenu>a.button:link, div.sectionmenu>a.button:visited {
  padding: 2px 8px;
  color: #000;
  font-family: Arial;
  text-decoration: none;
  margin:auto;
  border-radius: 5px;
  background-color: #e0e0e0;
  text-shadow: 0px -1px 0px #eee;
  border: 1px solid #000;
}

div.mainmenu a:hover {
  color: #000;
  background-color: white;
}

div.submenu a:hover, div.sectionmenu>a.button:hover {
  background-color: #c0c0c0;
}

/* All page content from the bottom of the menu or submenu down to
 ** the footer */
div.content {
  background-color: #fff;
  box-shadow: 0px 3px 4px #999;
  border-bottom-right-radius: 5px;
  border-bottom-left-radius: 5px;
  padding-bottom: 1em;
  min-height:40%;
}


/* Some pages have section dividers */
div.section {
  margin-bottom: 0.5em;
  margin-top: 1em;
  margin-right: auto;
  padding: 1px 1px 1px 1px;
  font-size: 1.2em;
  font-weight: bold;
  text-align: center;
  color: white;
  border-radius: 5px;
  background-color: #446979;
  box-shadow: 0px 3px 4px #333333;
  white-space: nowrap;
}

/* The "Date" that occurs on the left hand side of timelines */
div.divider {
  font-size: 1.2em;
  font-family: Georgia, serif;
  font-weight: bold;
  margin-top: 1em;
  white-space: nowrap;
}

/* The footer at the very bottom of the page */
div.footer {
  font-size: 0.9em;
  text-align: right;
  margin-bottom: 1em;
  color: #666;
}

/* Hyperlink colors in the footer */
div.footer a { color: white; }
div.footer a:link { color: white; }
div.footer a:visited { color: white; }
div.footer a:hover { background-color: white; color: #558195; }

/* <verbatim> blocks */
pre.verbatim, blockquote pre {
  font-family: Dejavu Sans Mono, Monaco, Lucida Console, monospace;
  background-color: #f3f3f3;
  padding: 0.5em;
  white-space: pre-wrap;
}

blockquote pre {
  border: 1px #000 dashed;
}

/* The label/value pairs on (for example) the ci page */
table.label-value th {
  vertical-align: top;
  text-align: right;
  padding: 0.2ex 2ex;
}

table.report tr th {
  padding: 3px 5px;
  text-transform: capitalize;
  cursor: pointer;
}

table.report tr td {
  padding: 3px 5px;
  cursor: pointer;
}

textarea {
  font-size: 1em;
}

.fullsize-text {
  font-size: 1.25em;
}

Added skins/rounded1/footer.txt.









>
>
>
>
1
2
3
4
<div class="footer">
Fossil version $manifest_version $manifest_date
</div>
</body></html>

Added skins/rounded1/header.txt.













































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<html>
<head>
<base href="$baseurl/$current_page" />
<title>$<project_name>: $<title></title>
<link rel="alternate" type="application/rss+xml" title="RSS Feed"
      href="$home/timeline.rss">
<link rel="stylesheet" href="$stylesheet_url" type="text/css"
      media="screen">
</head>
<body>
<div class="header">
  <div class="logo">
    <img src="$logo_image_url" alt="logo">
    <br />$<project_name>
  </div>
  <div class="title">$<title></div>
  <div class="status"><th1>
     if {[info exists login]} {
       puts "Logged in as $login"
     } else {
       puts "Not logged in"
     }
  </th1></div>
</div>
<div class="mainmenu">
<th1>
html "<a href='$home$index_page'>Home</a>\n"
if {[anycap jor]} {
  html "<a href='$home/timeline'>Timeline</a>\n"
}
if {[hascap oh]} {
  html "<a href='$home/tree?ci=tip'>Files</a>\n"
}
if {[hascap o]} {
  html "<a href='$home/brlist'>Branches</a>\n"
  html "<a href='$home/taglist'>Tags</a>\n"
}
if {[hascap r]} {
  html "<a href='$home/reportlist'>Tickets</a>\n"
}
if {[hascap j]} {
  html "<a href='$home/wiki'>Wiki</a>\n"
}
if {[hascap s]} {
  html "<a href='$home/setup'>Admin</a>\n"
} elseif {[hascap a]} {
  html "<a href='$home/setup_ulist'>Users</a>\n"
}
if {[info exists login]} {
  html "<a href='$home/login'>Logout</a>\n"
} else {
  html "<a href='$home/login'>Login</a>\n"
}
</th1></div>

Changes to src/attach.c.

88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
      zUrlTail = mprintf("page=%t&file=%t", zTarget, zFilename);
    }
    @ <li><p>
    @ Attachment %z(href("%R/ainfo/%s",zUuid))%S(zUuid)</a>
    if( moderation_pending(attachid) ){
      @ <span class="modpending">*** Awaiting Moderator Approval ***</span>
    }
    @ <br><a href="/attachview?%s(zUrlTail)">%h(zFilename)</a>
    @ [<a href="/attachdownload/%t(zFilename)?%s(zUrlTail)">download</a>]<br />
    if( zComment ) while( fossil_isspace(zComment[0]) ) zComment++;
    if( zComment && zComment[0] ){
      @ %!w(zComment)<br />
    }
    if( zPage==0 && zTkt==0 ){
      if( zSrc==0 || zSrc[0]==0 ){
        zSrc = "Deleted from";







|
|







88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
      zUrlTail = mprintf("page=%t&file=%t", zTarget, zFilename);
    }
    @ <li><p>
    @ Attachment %z(href("%R/ainfo/%s",zUuid))%S(zUuid)</a>
    if( moderation_pending(attachid) ){
      @ <span class="modpending">*** Awaiting Moderator Approval ***</span>
    }
    @ <br><a href="%R/attachview?%s(zUrlTail)">%h(zFilename)</a>
    @ [<a href="%R/attachdownload/%t(zFilename)?%s(zUrlTail)">download</a>]<br />
    if( zComment ) while( fossil_isspace(zComment[0]) ) zComment++;
    if( zComment && zComment[0] ){
      @ %!w(zComment)<br />
    }
    if( zPage==0 && zTkt==0 ){
      if( zSrc==0 || zSrc[0]==0 ){
        zSrc = "Deleted from";

Changes to src/branch.c.

177
178
179
180
181
182
183

184












185
186
187
188
189
190
191
192


193
194
195
196
197
198
199
200
201
202
203
204



205
206
207
208
209
210
211
212



213
214
215
216
217
218
219
220


221
222
223
224
225
226
227
...
258
259
260
261
262
263
264

265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285

























286

























































287


288
289




290
291
292
293
294
295

296

297




298
299
300
301
302
303


304
305
306
307
308
309
310
311
312
313
314
315
316
317
...
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
  /* Commit */
  db_end_transaction(0);

  /* Do an autosync push, if requested */
  if( !isPrivate ) autosync_loop(SYNC_PUSH, db_get_int("autosync-tries", 1));
}


/*












** Prepare a query that will list branches.
**
** If (which<0) then the query pulls only closed branches. If
** (which>0) then the query pulls all (closed and opened)
** branches. Else the query pulls currently-opened branches.
*/
void branch_prepare_list_query(Stmt *pQuery, int which ){
  if( which < 0 ){


    db_prepare(pQuery,
      "SELECT value FROM tagxref"
      " WHERE tagid=%d AND value NOT NULL "
      "EXCEPT "
      "SELECT value FROM tagxref"
      " WHERE tagid=%d"
      "   AND rid IN leaf"
      "   AND NOT %z"
      " ORDER BY value COLLATE nocase /*sort*/",
      TAG_BRANCH, TAG_BRANCH, leaf_is_closed_sql("tagxref.rid")
    );
  }else if( which>0 ){



    db_prepare(pQuery,
      "SELECT DISTINCT value FROM tagxref"
      " WHERE tagid=%d AND value NOT NULL"
      "   AND rid IN leaf"
      " ORDER BY value COLLATE nocase /*sort*/",
      TAG_BRANCH
    );
  }else{



    db_prepare(pQuery,
      "SELECT DISTINCT value FROM tagxref"
      " WHERE tagid=%d AND value NOT NULL"
      "   AND rid IN leaf"
      "   AND NOT %z"
      " ORDER BY value COLLATE nocase /*sort*/",
      TAG_BRANCH, leaf_is_closed_sql("tagxref.rid")
    );


  }
}


/*
** COMMAND: branch
**
................................................................................
  n = strlen(zCmd);
  if( strncmp(zCmd,"new",n)==0 ){
    branch_new();
  }else if( (strncmp(zCmd,"list",n)==0)||(strncmp(zCmd, "ls", n)==0) ){
    Stmt q;
    int vid;
    char *zCurrent = 0;

    int showAll = find_option("all","a",0)!=0;
    int showClosed = find_option("closed","c",0)!=0;

    if( g.localOpen ){
      vid = db_lget_int("checkout", 0);
      zCurrent = db_text(0, "SELECT value FROM tagxref"
                            " WHERE rid=%d AND tagid=%d", vid, TAG_BRANCH);
    }
    branch_prepare_list_query(&q, showAll?1:(showClosed?-1:0));
    while( db_step(&q)==SQLITE_ROW ){
      const char *zBr = db_column_text(&q, 0);
      int isCur = zCurrent!=0 && fossil_strcmp(zCurrent,zBr)==0;
      fossil_print("%s%s\n", (isCur ? "* " : "  "), zBr);
    }
    db_finalize(&q);
  }else{
    fossil_fatal("branch subcommand should be one of: "
                 "new list ls");
  }
}


























/*

























































** WEBPAGE: brlist


**
** Show a timeline of all branches




*/
void brlist_page(void){
  Stmt q;
  int cnt;
  int showClosed = P("closed")!=0;
  int showAll = P("all")!=0;

  int colorTest = P("colortest")!=0;






  login_check_credentials();
  if( !g.perm.Read ){ login_needed(); return; }
  if( colorTest ){
    showClosed = 0;
    showAll = 1;
  }



  style_header("%s", showClosed ? "Closed Branches" :
                        showAll ? "All Branches" : "Open Branches");
  style_submenu_element("Timeline", "Timeline", "brtimeline");
  if( showClosed ){
    style_submenu_element("All", "All", "brlist?all");
    style_submenu_element("Open","Open","brlist");
  }else if( showAll ){
    style_submenu_element("Closed", "Closed", "brlist?closed");
    style_submenu_element("Open","Open","brlist");
  }else{
    style_submenu_element("All", "All", "brlist?all");
    style_submenu_element("Closed","Closed","brlist?closed");
  }
................................................................................
  @ <div class="sideboxDescribed">%z(href("leaves?closed"))
  @ closed leaves</a></div>.
  @ Closed branches are fixed and do not change (unless they are first
  @ reopened).</li>
  @ </ol>
  style_sidebox_end();

  branch_prepare_list_query(&q, showAll?1:(showClosed?-1:0));
  cnt = 0;
  while( db_step(&q)==SQLITE_ROW ){
    const char *zBr = db_column_text(&q, 0);
    if( cnt==0 ){
      if( colorTest ){
        @ <h2>Default background colors for all branches:</h2>
      }else if( showAll ){
        @ <h2>All Branches:</h2>
      }else if( showClosed ){
        @ <h2>Closed Branches:</h2>
      }else{
        @ <h2>Open Branches:</h2>
      }
      @ <ul>
      cnt++;
    }
    if( colorTest ){







>

>
>
>
>
>
>
>
>
>
>
>
>






|
<
>
>
|
|
|
|
|
|
|
|
|
|
|
<
>
>
>
|
|
|
|
|
|
|
<
>
>
>
|
|
|
|
|
|
|
|
>
>







 







>
|
|






|












>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

>
>

<
>
>
>
>






>

>

>
>
>
>






>
>






|







 







|






|
|
|
|







177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204

205
206
207
208
209
210
211
212
213
214
215
216
217

218
219
220
221
222
223
224
225
226
227

228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
...
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393

394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
...
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
  /* Commit */
  db_end_transaction(0);

  /* Do an autosync push, if requested */
  if( !isPrivate ) autosync_loop(SYNC_PUSH, db_get_int("autosync-tries", 1));
}

#if INTERFACE
/*
** Allows bits in the mBplqFlags parameter to branch_prepare_list_query().
*/
#define BRL_CLOSED_ONLY      0x001 /* Show only closed branches */
#define BRL_OPEN_ONLY        0x002 /* Show only open branches */
#define BRL_BOTH             0x003 /* Show both open and closed branches */
#define BRL_OPEN_CLOSED_MASK 0x003
#define BRL_MTIME            0x004 /* Include lastest check-in time */
#dfeine BRL_ORDERBY_MTIME    0x008 /* Sort by MTIME. (otherwise sort by name)*/

#endif /* INTERFACE */

/*
** Prepare a query that will list branches.
**
** If (which<0) then the query pulls only closed branches. If
** (which>0) then the query pulls all (closed and opened)
** branches. Else the query pulls currently-opened branches.
*/
void branch_prepare_list_query(Stmt *pQuery, int brFlags){

  switch( brFlags & BRL_OPEN_CLOSED_MASK ){
    case BRL_CLOSED_ONLY: {
      db_prepare(pQuery,
        "SELECT value FROM tagxref"
        " WHERE tagid=%d AND value NOT NULL "
        "EXCEPT "
        "SELECT value FROM tagxref"
        " WHERE tagid=%d"
        "   AND rid IN leaf"
        "   AND NOT %z"
        " ORDER BY value COLLATE nocase /*sort*/",
        TAG_BRANCH, TAG_BRANCH, leaf_is_closed_sql("tagxref.rid")
      );

      break;
    }
    case BRL_BOTH: {
      db_prepare(pQuery,
        "SELECT DISTINCT value FROM tagxref"
        " WHERE tagid=%d AND value NOT NULL"
        "   AND rid IN leaf"
        " ORDER BY value COLLATE nocase /*sort*/",
        TAG_BRANCH
      );

      break;
    }
    case BRL_OPEN_ONLY: {
      db_prepare(pQuery,
        "SELECT DISTINCT value FROM tagxref"
        " WHERE tagid=%d AND value NOT NULL"
        "   AND rid IN leaf"
        "   AND NOT %z"
        " ORDER BY value COLLATE nocase /*sort*/",
        TAG_BRANCH, leaf_is_closed_sql("tagxref.rid")
      );
      break;
    }
  }
}


/*
** COMMAND: branch
**
................................................................................
  n = strlen(zCmd);
  if( strncmp(zCmd,"new",n)==0 ){
    branch_new();
  }else if( (strncmp(zCmd,"list",n)==0)||(strncmp(zCmd, "ls", n)==0) ){
    Stmt q;
    int vid;
    char *zCurrent = 0;
    int brFlags = BRL_OPEN_ONLY;
    if( find_option("all","a",0)!=0 ) brFlags = BRL_BOTH;
    if( find_option("closed","c",0)!=0 ) brFlags = BRL_CLOSED_ONLY;

    if( g.localOpen ){
      vid = db_lget_int("checkout", 0);
      zCurrent = db_text(0, "SELECT value FROM tagxref"
                            " WHERE rid=%d AND tagid=%d", vid, TAG_BRANCH);
    }
    branch_prepare_list_query(&q, brFlags);
    while( db_step(&q)==SQLITE_ROW ){
      const char *zBr = db_column_text(&q, 0);
      int isCur = zCurrent!=0 && fossil_strcmp(zCurrent,zBr)==0;
      fossil_print("%s%s\n", (isCur ? "* " : "  "), zBr);
    }
    db_finalize(&q);
  }else{
    fossil_fatal("branch subcommand should be one of: "
                 "new list ls");
  }
}

static const char brlistQuery[] =
@ SELECT
@   tagxref.value,
@   max(event.mtime),
@   EXISTS(SELECT 1 FROM tagxref AS tx
@           WHERE tx.rid=tagxref.rid
@             AND tx.tagid=(SELECT tagid FROM tag WHERE tagname='closed')
@             AND tx.tagtype>0),
@   (SELECT tagxref.value
@      FROM plink CROSS JOIN tagxref
@    WHERE plink.pid=event.objid
@       AND tagxref.rid=plink.cid
@      AND tagxref.tagid=(SELECT tagid FROM tag WHERE tagname='branch')
@      AND tagtype>0),
@   count(*),
@   (SELECT uuid FROM blob WHERE rid=tagxref.rid)
@  FROM tagxref, tag, event
@ WHERE tagxref.tagid=tag.tagid
@   AND tagxref.tagtype>0
@   AND tag.tagname='branch'
@   AND event.objid=tagxref.rid
@ GROUP BY 1
@ ORDER BY 2 DESC;
;

/*
** This is the new-style branch-list page that shows the branch names
** together with their ages (time of last check-in) and whether or not
** they are closed or merged to another branch.
**
** Control jumps to this routine from brlist_page() (the /brlist handler)
** if there are no query parameters.
*/
static void new_brlist_page(void){
  Stmt q;
  double rNow;
  login_check_credentials();
  if( !g.perm.Read ){ login_needed(); return; }
  style_header("Branches");
  style_adunit_config(ADUNIT_RIGHT_OK);
  login_anonymous_available();

  db_prepare(&q, brlistQuery/*works-like:""*/);
  rNow = db_double(0.0, "SELECT julianday('now')");
  @ <div class="brlist"><table id="branchlisttable">
  @ <thead><tr>
  @ <th>Branch Name</th>
  @ <th>Age</th>
  @ <th>Checkins</th>
  @ <th>Status</th>
  @ <th>Resolution</th>
  @ </tr></thead><tbody>
  while( db_step(&q)==SQLITE_ROW ){
    const char *zBranch = db_column_text(&q, 0);
    double rMtime = db_column_double(&q, 1);
    int isClosed = db_column_int(&q, 2);
    const char *zMergeTo = db_column_text(&q, 3);
    int nCkin = db_column_int(&q, 4);
    const char *zLastCkin = db_column_text(&q, 5);
    char *zAge = human_readable_age(rNow - rMtime);
    sqlite3_int64 iMtime = (sqlite3_int64)(rMtime*86400.0);
    if( zMergeTo && zMergeTo[0]==0 ) zMergeTo = 0;
    @ <tr>
    @ <td>%z(href("%R/timeline?n=100&r=%T",zBranch))%h(zBranch)</a></td>
    @ <td data-sortkey="%016llx(-iMtime)">%s(zAge)</td>
    @ <td>%d(nCkin)</td>
    fossil_free(zAge);
    @ <td>%s(isClosed?"closed":"")</td>
    if( zMergeTo ){
      @ <td>merged into
      @ %z(href("%R/timeline?f=%s",zLastCkin))%h(zMergeTo)</a></td>
    }else{
      @ <td></td>
    }
    @ </tr>
  }
  @ </tbody></table></div>
  db_finalize(&q);
  output_table_sorting_javascript("branchlisttable","tkNtt",2);
  style_footer();
}

/*
** WEBPAGE: brlist
** Show a list of branches
** Query parameters:
**

**     all         Show all branches
**     closed      Show only closed branches
**     open        Show only open branches (default behavior)
**     colortest   Show all branches with automatic color
*/
void brlist_page(void){
  Stmt q;
  int cnt;
  int showClosed = P("closed")!=0;
  int showAll = P("all")!=0;
  int showOpen = P("open")!=0;
  int colorTest = P("colortest")!=0;
  int brFlags = BRL_OPEN_ONLY;

  if( showClosed==0 && showAll==0 && showOpen==0 && colorTest==0 ){
    new_brlist_page();
    return;
  }
  login_check_credentials();
  if( !g.perm.Read ){ login_needed(); return; }
  if( colorTest ){
    showClosed = 0;
    showAll = 1;
  }
  if( showAll ) brFlags = BRL_BOTH;
  if( showClosed ) brFlags = BRL_CLOSED_ONLY;

  style_header("%s", showClosed ? "Closed Branches" :
                        showAll ? "All Branches" : "Open Branches");
  style_submenu_element("Timeline", "Timeline", "brtimeline");
  if( showClosed ){
    style_submenu_element("All", "All", "brlist?all");
    style_submenu_element("Open","Open","brlist?open");
  }else if( showAll ){
    style_submenu_element("Closed", "Closed", "brlist?closed");
    style_submenu_element("Open","Open","brlist");
  }else{
    style_submenu_element("All", "All", "brlist?all");
    style_submenu_element("Closed","Closed","brlist?closed");
  }
................................................................................
  @ <div class="sideboxDescribed">%z(href("leaves?closed"))
  @ closed leaves</a></div>.
  @ Closed branches are fixed and do not change (unless they are first
  @ reopened).</li>
  @ </ol>
  style_sidebox_end();

  branch_prepare_list_query(&q, brFlags);
  cnt = 0;
  while( db_step(&q)==SQLITE_ROW ){
    const char *zBr = db_column_text(&q, 0);
    if( cnt==0 ){
      if( colorTest ){
        @ <h2>Default background colors for all branches:</h2>
      }else if( showClosed ){
        @ <h2>Closed Branches:</h2>
      }else if( showAll ){
        @ <h2>All Branches:</h2>
      }else{
        @ <h2>Open Branches:</h2>
      }
      @ <ul>
      cnt++;
    }
    if( colorTest ){

Changes to src/browse.c.

131
132
133
134
135
136
137

138
139
140
141
142
143
144
...
553
554
555
556
557
558
559

560
561
562
563
564
565
566
...
633
634
635
636
637
638
639


640
641
642
643
644
645
646
...
650
651
652
653
654
655
656



657
658
659
660
661
662
663
...
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
....
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
  HQuery sURI;

  if( strcmp(PD("type",""),"tree")==0 ){ page_tree(); return; }
  login_check_credentials();
  if( !g.perm.Read ){ login_needed(); return; }
  while( nD>1 && zD[nD-2]=='/' ){ zD[(--nD)-1] = 0; }
  style_header("File List");

  sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0,
                          pathelementFunc, 0, 0);
  url_initialize(&sURI, "dir");

  /* If the name= parameter is an empty string, make it a NULL pointer */
  if( zD && strlen(zD)==0 ){ zD = 0; }

................................................................................
    showDirOnly = 1;
    url_add_parameter(&sURI, "nofiles", "1");
    style_header("Folder Hierarchy");
  }else{
    showDirOnly = 0;
    style_header("File Tree");
  }

  if( P("expand")!=0 ){
    startExpanded = 1;
    url_add_parameter(&sURI, "expand", "1");
  }else{
    startExpanded = 0;
  }

................................................................................
    style_submenu_element("Trunk", "Trunk", "%s",
                          url_render(&sURI, "ci", "trunk", 0, 0));
  }
  if( linkTip ){
    style_submenu_element("Tip", "Tip", "%s",
                          url_render(&sURI, "ci", "tip", 0, 0));
  }



  /* Compute the file hierarchy.
  */
  if( zCI ){
    Stmt q;
    compute_fileage(rid, 0);
    db_prepare(&q,
................................................................................
       "   AND blob.rid=fileage.fid\n"
       " ORDER BY filename.name COLLATE nocase;"
    );
    while( db_step(&q)==SQLITE_ROW ){
      const char *zFile = db_column_text(&q,0);
      const char *zUuid = db_column_text(&q,1);
      double mtime = db_column_double(&q,2);



      if( pRE && re_match(pRE, (const unsigned char*)zFile, -1)==0 ) continue;
      tree_add_node(&sTree, zFile, zUuid, mtime);
      nFile++;
    }
    db_finalize(&q);
  }else{
    Stmt q;
................................................................................
  return zClass;
}

/*
** SQL used to compute the age of all files in checkin :ckin whose
** names match :glob
*/
static const char zComputeFileAgeSetup[] = 
@ CREATE TABLE IF NOT EXISTS temp.fileage(
@   fnid INTEGER PRIMARY KEY,
@   fid INTEGER,
@   mid INTEGER,
@   mtime DATETIME,
@   pathname TEXT
@ );
@ CREATE VIRTUAL TABLE IF NOT EXISTS temp.foci USING files_of_checkin;
;

static const char zComputeFileAgeRun[] = 
@ WITH RECURSIVE
@   ckin(x) AS (VALUES(:ckin) UNION ALL
@                 SELECT pid FROM ckin, plink WHERE cid=x AND isprim)
@ INSERT OR IGNORE INTO fileage(fnid, fid, mid, mtime, pathname)
@   SELECT mlink.fnid, mlink.fid, x, event.mtime, filename.name
@     FROM ckin, mlink, event, filename
@    WHERE mlink.mid=ckin.x
................................................................................
  style_submenu_element("Tree-View", "Tree-View", "%R/tree?ci=%T&mtime=1",
                        zName);
  style_header("File Ages");
  zGlob = P("glob");
  compute_fileage(rid,zGlob);
  db_multi_exec("CREATE INDEX fileage_ix1 ON fileage(mid,pathname);");

  @ <h2>Files in 
  @ %z(href("%R/info?name=%T",zUuid))[%S(zUuid)]</a>
  if( zGlob && zGlob[0] ){
    @ that match "%h(zGlob)" and
  }
  @ ordered by check-in time</h2>
  @
  @ <p>Times are relative to the checkin time for







>







 







>







 







>
>







 







>
>
>







 







|










|







 







|







131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
...
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
...
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
...
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
...
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
....
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
  HQuery sURI;

  if( strcmp(PD("type",""),"tree")==0 ){ page_tree(); return; }
  login_check_credentials();
  if( !g.perm.Read ){ login_needed(); return; }
  while( nD>1 && zD[nD-2]=='/' ){ zD[(--nD)-1] = 0; }
  style_header("File List");
  style_adunit_config(ADUNIT_RIGHT_OK);
  sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0,
                          pathelementFunc, 0, 0);
  url_initialize(&sURI, "dir");

  /* If the name= parameter is an empty string, make it a NULL pointer */
  if( zD && strlen(zD)==0 ){ zD = 0; }

................................................................................
    showDirOnly = 1;
    url_add_parameter(&sURI, "nofiles", "1");
    style_header("Folder Hierarchy");
  }else{
    showDirOnly = 0;
    style_header("File Tree");
  }
  style_adunit_config(ADUNIT_RIGHT_OK);
  if( P("expand")!=0 ){
    startExpanded = 1;
    url_add_parameter(&sURI, "expand", "1");
  }else{
    startExpanded = 0;
  }

................................................................................
    style_submenu_element("Trunk", "Trunk", "%s",
                          url_render(&sURI, "ci", "trunk", 0, 0));
  }
  if( linkTip ){
    style_submenu_element("Tip", "Tip", "%s",
                          url_render(&sURI, "ci", "tip", 0, 0));
  }
  style_submenu_element("Flat-View", "Flat-View", "%s",
                        url_render(&sURI, "type", "flat", 0, 0));

  /* Compute the file hierarchy.
  */
  if( zCI ){
    Stmt q;
    compute_fileage(rid, 0);
    db_prepare(&q,
................................................................................
       "   AND blob.rid=fileage.fid\n"
       " ORDER BY filename.name COLLATE nocase;"
    );
    while( db_step(&q)==SQLITE_ROW ){
      const char *zFile = db_column_text(&q,0);
      const char *zUuid = db_column_text(&q,1);
      double mtime = db_column_double(&q,2);
      if( nD>0 && (fossil_strncmp(zFile, zD, nD-1)!=0 || zFile[nD-1]!='/') ){
        continue;
      }
      if( pRE && re_match(pRE, (const unsigned char*)zFile, -1)==0 ) continue;
      tree_add_node(&sTree, zFile, zUuid, mtime);
      nFile++;
    }
    db_finalize(&q);
  }else{
    Stmt q;
................................................................................
  return zClass;
}

/*
** SQL used to compute the age of all files in checkin :ckin whose
** names match :glob
*/
static const char zComputeFileAgeSetup[] =
@ CREATE TABLE IF NOT EXISTS temp.fileage(
@   fnid INTEGER PRIMARY KEY,
@   fid INTEGER,
@   mid INTEGER,
@   mtime DATETIME,
@   pathname TEXT
@ );
@ CREATE VIRTUAL TABLE IF NOT EXISTS temp.foci USING files_of_checkin;
;

static const char zComputeFileAgeRun[] =
@ WITH RECURSIVE
@   ckin(x) AS (VALUES(:ckin) UNION ALL
@                 SELECT pid FROM ckin, plink WHERE cid=x AND isprim)
@ INSERT OR IGNORE INTO fileage(fnid, fid, mid, mtime, pathname)
@   SELECT mlink.fnid, mlink.fid, x, event.mtime, filename.name
@     FROM ckin, mlink, event, filename
@    WHERE mlink.mid=ckin.x
................................................................................
  style_submenu_element("Tree-View", "Tree-View", "%R/tree?ci=%T&mtime=1",
                        zName);
  style_header("File Ages");
  zGlob = P("glob");
  compute_fileage(rid,zGlob);
  db_multi_exec("CREATE INDEX fileage_ix1 ON fileage(mid,pathname);");

  @ <h2>Files in
  @ %z(href("%R/info?name=%T",zUuid))[%S(zUuid)]</a>
  if( zGlob && zGlob[0] ){
    @ that match "%h(zGlob)" and
  }
  @ ordered by check-in time</h2>
  @
  @ <p>Times are relative to the checkin time for

Changes to src/builtin.c.

29
30
31
32
33
34
35
36
37
38
39
40
41





42
43
44
45
46
47



48
49
50
51
52
53
54
*/
#include "builtin_data.h"

/*
** Return a pointer to built-in content
*/
const unsigned char *builtin_file(const char *zFilename, int *piSize){
  int lwr, upr, i;
  lwr = 0;
  upr = sizeof(aBuiltinFiles)/sizeof(aBuiltinFiles[0]) - 1;
  while( upr>=lwr ){
    i = (upr+lwr)/2;
    if( strcmp(aBuiltinFiles[i].zName,zFilename)==0 ){





      if( piSize ) *piSize = aBuiltinFiles[i].nByte;
      return aBuiltinFiles[i].pData;
    }
  }
  if( piSize ) *piSize = 0;
  return 0;



}

/*
** COMMAND: test-builtin-list
**
** List the names and sizes of all built-in resources
*/







|




|
>
>
>
>
>






>
>
>







29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
*/
#include "builtin_data.h"

/*
** Return a pointer to built-in content
*/
const unsigned char *builtin_file(const char *zFilename, int *piSize){
  int lwr, upr, i, c;
  lwr = 0;
  upr = sizeof(aBuiltinFiles)/sizeof(aBuiltinFiles[0]) - 1;
  while( upr>=lwr ){
    i = (upr+lwr)/2;
    c = strcmp(aBuiltinFiles[i].zName,zFilename);
    if( c<0 ){
      lwr = i+1;
    }else if( c>0 ){
      upr = i-1;
    }else{
      if( piSize ) *piSize = aBuiltinFiles[i].nByte;
      return aBuiltinFiles[i].pData;
    }
  }
  if( piSize ) *piSize = 0;
  return 0;
}
const char *builtin_text(const char *zFilename){
  return (char*)builtin_file(zFilename, 0);
}

/*
** COMMAND: test-builtin-list
**
** List the names and sizes of all built-in resources
*/

Changes to src/cgi.c.

106
107
108
109
110
111
112



113
114
115
116
117
118
119
....
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
/*
** Check to see if the header contains the zNeedle string.  Return true
** if it does and false if it does not.
*/
int cgi_header_contains(const char *zNeedle){
  return strstr(blob_str(&cgiContent[0]), zNeedle)!=0;
}




/*
** Append reply content to what already exists.
*/
void cgi_append_content(const char *zData, int nAmt){
  blob_append(pContent, zData, nAmt);
}
................................................................................
          int nErr = 0, fd;
          close(0);
          fd = dup(connection);
          if( fd!=0 ) nErr++;
          close(1);
          fd = dup(connection);
          if( fd!=1 ) nErr++;
          if( !g.fHttpTrace && !g.fSqlTrace ){
            close(2);
            fd = dup(connection);
            if( fd!=2 ) nErr++;
          }
          close(connection);
          return nErr;
        }







>
>
>







 







|







106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
....
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
/*
** Check to see if the header contains the zNeedle string.  Return true
** if it does and false if it does not.
*/
int cgi_header_contains(const char *zNeedle){
  return strstr(blob_str(&cgiContent[0]), zNeedle)!=0;
}
int cgi_body_contains(const char *zNeedle){
  return strstr(blob_str(&cgiContent[1]), zNeedle)!=0;
}

/*
** Append reply content to what already exists.
*/
void cgi_append_content(const char *zData, int nAmt){
  blob_append(pContent, zData, nAmt);
}
................................................................................
          int nErr = 0, fd;
          close(0);
          fd = dup(connection);
          if( fd!=0 ) nErr++;
          close(1);
          fd = dup(connection);
          if( fd!=1 ) nErr++;
          if( !g.fAnyTrace ){
            close(2);
            fd = dup(connection);
            if( fd!=2 ) nErr++;
          }
          close(connection);
          return nErr;
        }

Changes to src/checkin.c.

211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
...
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
...
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
...
496
497
498
499
500
501
502

503
504
505
506
507
508
509
...
561
562
563
564
565
566
567

568
569
570
571
572
573
574
...
599
600
601
602
603
604
605





606
607
608
609
610
611
612
...
613
614
615
616
617
618
619

620
621
622
623
624
625
626
....
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
void changes_cmd(void){
  int useSha1sum = find_option("sha1sum", 0, 0)!=0;
  int showHdr = find_option("header",0,0)!=0;
  int verboseFlag = find_option("verbose","v",0)!=0;
  int cwdRelative = 0;
  db_must_be_within_tree();
  cwdRelative = determine_cwd_relative_option();
  
  /* We should be done with options.. */
  verify_all_options();

  print_changes(useSha1sum, showHdr, verboseFlag, cwdRelative);
}

/*
................................................................................
  int useSha1sum = find_option("sha1sum", 0, 0)!=0;
  int showHdr = find_option("header",0,0)!=0;
  int verboseFlag = find_option("verbose","v",0)!=0;
  int cwdRelative = 0;
  db_must_be_within_tree();
       /* 012345678901234 */
  cwdRelative = determine_cwd_relative_option();
  
  /* We should be done with options.. */
  verify_all_options();

  fossil_print("repository:   %s\n", db_repository_filename());
  fossil_print("local-root:   %s\n", g.zLocalRoot);
  if( g.zConfigDbName ){
    fossil_print("config-db:    %s\n", g.zConfigDbName);
  }
  vid = db_lget_int("checkout", 0);
  if( vid ){
    show_common_info(vid, "checkout:", 1, 1);
  }
  db_record_repository_filename(0); 
  print_changes(useSha1sum, showHdr, verboseFlag, cwdRelative);
}

/*
** COMMAND: ls
**
** Usage: %fossil ls ?OPTIONS? ?VERSION? ?FILENAMES?
................................................................................
  Glob *pIgnore;
  Blob rewrittenPathname;
  const char *zPathname, *zDisplayName;

  if( find_option("temp",0,0)!=0 ) scanFlags |= SCAN_TEMP;
  db_must_be_within_tree();
  cwdRelative = determine_cwd_relative_option();
  
  /* We should be done with options.. */
  verify_all_options();

  if( zIgnoreFlag==0 ){
    zIgnoreFlag = db_get("ignore-glob", 0);
  }
  pIgnore = glob_create(zIgnoreFlag);
................................................................................
      "SELECT x FROM sfile"
      " WHERE x NOT IN (%s)"
      " ORDER BY 1",
      fossil_all_reserved_names(0)
  );
  db_multi_exec("DELETE FROM sfile WHERE x IN (SELECT pathname FROM vfile)");
  blob_zero(&rewrittenPathname);

  while( db_step(&q)==SQLITE_ROW ){
    zDisplayName = zPathname = db_column_text(&q, 0);
    if( cwdRelative ) {
      char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
      file_relative_name(zFullName, &rewrittenPathname, 0);
      free(zFullName);
      zDisplayName = blob_str(&rewrittenPathname);
................................................................................
**                     explicitly exempted via the empty-dirs setting
**                     or another applicable setting or command line
**                     argument.  Matching files, if any, are removed
**                     prior to checking for any empty directories;
**                     therefore, directories that contain only files
**                     that were removed will be removed as well.
**    -f|--force       Remove files without prompting.

**    --clean <CSG>    Never prompt for files matching this
**                     comma separated list of glob patterns.
**    --ignore <CSG>   Ignore files matching patterns from the
**                     comma separated list of glob patterns.
**    --keep <CSG>     Keep files matching this comma separated
**                     list of glob patterns.
**    -n|--dry-run     If given, display instead of run actions.
................................................................................
  if( find_option("temp",0,0)!=0 ) scanFlags |= SCAN_TEMP;
  if( find_option("allckouts",0,0)!=0 ) scanFlags |= SCAN_NESTED;
  zIgnoreFlag = find_option("ignore",0,1);
  verboseFlag = find_option("verbose","v",0)!=0;
  zKeepFlag = find_option("keep",0,1);
  zCleanFlag = find_option("clean",0,1);
  db_must_be_within_tree();





  if( zIgnoreFlag==0 ){
    zIgnoreFlag = db_get("ignore-glob", 0);
  }
  if( zKeepFlag==0 ){
    zKeepFlag = db_get("keep-glob", 0);
  }
  if( zCleanFlag==0 ){
................................................................................
    zCleanFlag = db_get("clean-glob", 0);
  }
  verify_all_options();
  pIgnore = glob_create(zIgnoreFlag);
  pKeep = glob_create(zKeepFlag);
  pClean = glob_create(zCleanFlag);
  nRoot = (int)strlen(g.zLocalRoot);

  if( !dirsOnlyFlag ){
    Stmt q;
    Blob repo;
    locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags, pIgnore, 0);
    db_prepare(&q,
        "SELECT %Q || x FROM sfile"
        " WHERE x NOT IN (%s)"
................................................................................
    fossil_fatal("would fork.  \"update\" first or use --allow-fork.");
  }

  /*
  ** Do not allow a commit against a closed leaf unless the commit
  ** ends up on a different branch.
  */
  if( 
      /* parent checkin has the "closed" tag... */
      db_exists("SELECT 1 FROM tagxref"
                " WHERE tagid=%d AND rid=%d AND tagtype>0",
                TAG_CLOSED, vid)
      /* ... and the new checkin has no --branch option or the --branch
      ** option does not actually change the branch */
   && (sCiInfo.zBranch==0







|







 







|












|







 







|







 







>







 







>







 







>
>
>
>
>







 







>







 







|







211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
...
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
...
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
...
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
...
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
...
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
...
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
....
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
void changes_cmd(void){
  int useSha1sum = find_option("sha1sum", 0, 0)!=0;
  int showHdr = find_option("header",0,0)!=0;
  int verboseFlag = find_option("verbose","v",0)!=0;
  int cwdRelative = 0;
  db_must_be_within_tree();
  cwdRelative = determine_cwd_relative_option();

  /* We should be done with options.. */
  verify_all_options();

  print_changes(useSha1sum, showHdr, verboseFlag, cwdRelative);
}

/*
................................................................................
  int useSha1sum = find_option("sha1sum", 0, 0)!=0;
  int showHdr = find_option("header",0,0)!=0;
  int verboseFlag = find_option("verbose","v",0)!=0;
  int cwdRelative = 0;
  db_must_be_within_tree();
       /* 012345678901234 */
  cwdRelative = determine_cwd_relative_option();

  /* We should be done with options.. */
  verify_all_options();

  fossil_print("repository:   %s\n", db_repository_filename());
  fossil_print("local-root:   %s\n", g.zLocalRoot);
  if( g.zConfigDbName ){
    fossil_print("config-db:    %s\n", g.zConfigDbName);
  }
  vid = db_lget_int("checkout", 0);
  if( vid ){
    show_common_info(vid, "checkout:", 1, 1);
  }
  db_record_repository_filename(0);
  print_changes(useSha1sum, showHdr, verboseFlag, cwdRelative);
}

/*
** COMMAND: ls
**
** Usage: %fossil ls ?OPTIONS? ?VERSION? ?FILENAMES?
................................................................................
  Glob *pIgnore;
  Blob rewrittenPathname;
  const char *zPathname, *zDisplayName;

  if( find_option("temp",0,0)!=0 ) scanFlags |= SCAN_TEMP;
  db_must_be_within_tree();
  cwdRelative = determine_cwd_relative_option();

  /* We should be done with options.. */
  verify_all_options();

  if( zIgnoreFlag==0 ){
    zIgnoreFlag = db_get("ignore-glob", 0);
  }
  pIgnore = glob_create(zIgnoreFlag);
................................................................................
      "SELECT x FROM sfile"
      " WHERE x NOT IN (%s)"
      " ORDER BY 1",
      fossil_all_reserved_names(0)
  );
  db_multi_exec("DELETE FROM sfile WHERE x IN (SELECT pathname FROM vfile)");
  blob_zero(&rewrittenPathname);
  g.allowSymlinks = 1;  /* Report on symbolic links */
  while( db_step(&q)==SQLITE_ROW ){
    zDisplayName = zPathname = db_column_text(&q, 0);
    if( cwdRelative ) {
      char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
      file_relative_name(zFullName, &rewrittenPathname, 0);
      free(zFullName);
      zDisplayName = blob_str(&rewrittenPathname);
................................................................................
**                     explicitly exempted via the empty-dirs setting
**                     or another applicable setting or command line
**                     argument.  Matching files, if any, are removed
**                     prior to checking for any empty directories;
**                     therefore, directories that contain only files
**                     that were removed will be removed as well.
**    -f|--force       Remove files without prompting.
**    --verily         Shorthand for: -f --emptydirs --dotfiles
**    --clean <CSG>    Never prompt for files matching this
**                     comma separated list of glob patterns.
**    --ignore <CSG>   Ignore files matching patterns from the
**                     comma separated list of glob patterns.
**    --keep <CSG>     Keep files matching this comma separated
**                     list of glob patterns.
**    -n|--dry-run     If given, display instead of run actions.
................................................................................
  if( find_option("temp",0,0)!=0 ) scanFlags |= SCAN_TEMP;
  if( find_option("allckouts",0,0)!=0 ) scanFlags |= SCAN_NESTED;
  zIgnoreFlag = find_option("ignore",0,1);
  verboseFlag = find_option("verbose","v",0)!=0;
  zKeepFlag = find_option("keep",0,1);
  zCleanFlag = find_option("clean",0,1);
  db_must_be_within_tree();
  if( find_option("verily",0,0)!=0 ){
    allFileFlag = allDirFlag = 1;
    emptyDirsFlag = 1;
    scanFlags |= SCAN_ALL;
  }
  if( zIgnoreFlag==0 ){
    zIgnoreFlag = db_get("ignore-glob", 0);
  }
  if( zKeepFlag==0 ){
    zKeepFlag = db_get("keep-glob", 0);
  }
  if( zCleanFlag==0 ){
................................................................................
    zCleanFlag = db_get("clean-glob", 0);
  }
  verify_all_options();
  pIgnore = glob_create(zIgnoreFlag);
  pKeep = glob_create(zKeepFlag);
  pClean = glob_create(zCleanFlag);
  nRoot = (int)strlen(g.zLocalRoot);
  g.allowSymlinks = 1;  /* Find symlinks too */
  if( !dirsOnlyFlag ){
    Stmt q;
    Blob repo;
    locate_unmanaged_files(g.argc-2, g.argv+2, scanFlags, pIgnore, 0);
    db_prepare(&q,
        "SELECT %Q || x FROM sfile"
        " WHERE x NOT IN (%s)"
................................................................................
    fossil_fatal("would fork.  \"update\" first or use --allow-fork.");
  }

  /*
  ** Do not allow a commit against a closed leaf unless the commit
  ** ends up on a different branch.
  */
  if(
      /* parent checkin has the "closed" tag... */
      db_exists("SELECT 1 FROM tagxref"
                " WHERE tagid=%d AND rid=%d AND tagtype>0",
                TAG_CLOSED, vid)
      /* ... and the new checkin has no --branch option or the --branch
      ** option does not actually change the branch */
   && (sCiInfo.zBranch==0

Changes to src/clone.c.

81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114

115
116
117
118
119
120
121
122
123
124

125

126
127

128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
...
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
...
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
...
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278

/*
** COMMAND: clone
**
** Usage: %fossil clone ?OPTIONS? URL FILENAME
**
** Make a clone of a repository specified by URL in the local
** file named FILENAME.  
**
** URL must be in one of the following form: ([...] mean optional)
**   HTTP/HTTPS protocol:
**     http[s]://[userid[:password]@]host[:port][/path]
**
**   SSH protocol:
**     ssh://[userid[:password]@]host[:port]/path/to/repo.fossil\\
**     [?fossil=path/to/fossil.exe]
**
**   Filesystem:
**     [file://]path/to/repo.fossil
**
**   Note: For ssh and filesystem, path must have an extra leading 
**         '/' to use an absolute path.
**
** By default, your current login name is used to create the default
** admin user. This can be overridden using the -A|--admin-user
** parameter.
**
** Options:
**    --admin-user|-A USERNAME   Make USERNAME the administrator
**    --once                     Don't save url.
**    --private                  Also clone private branches 
**    --ssl-identity=filename    Use the SSL identity if requested by the server
**    --ssh-command|-c 'command' Use this SSH command
**    --httpauth|-B 'user:pass'  Add HTTP Basic Authorization to requests

**
** See also: init
*/
void clone_cmd(void){
  char *zPassword;
  const char *zDefaultUser;   /* Optional name of the default user */
  const char *zHttpAuth;      /* HTTP Authorization user:pass information */
  int nErr = 0;
  int bPrivate = 0;           /* Also clone private branches */
  int urlFlags = URL_PROMPT_PW | URL_REMEMBER;



  if( find_option("private",0,0)!=0 ) bPrivate = SYNC_PRIVATE;
  if( find_option("once",0,0)!=0) urlFlags &= ~URL_REMEMBER;

  zHttpAuth = find_option("httpauth","B",1);
  zDefaultUser = find_option("admin-user","A",1);
  clone_ssh_find_options();
  url_proxy_options();
  
  /* We should be done with options.. */
  verify_all_options();

  if( g.argc < 4 ){
    usage("?OPTIONS? FILE-OR-URL NEW-REPOSITORY");
  }
  db_open_config(0);
  if( file_size(g.argv[3])>0 ){
    fossil_fatal("file already exists: %s", g.argv[3]);
  }

  url_parse(g.argv[2], urlFlags);
  if( zDefaultUser==0 && g.url.user!=0 ) zDefaultUser = g.url.user;
  if( g.url.isFile ){
    file_copy(g.url.name, g.argv[3]);
    db_close(1);
    db_open_repository(g.argv[3]);
    db_record_repository_filename(g.argv[3]);
    url_remember();
    if( !bPrivate ) delete_private_content();
    shun_artifacts();
    db_create_default_users(1, zDefaultUser);
    if( zDefaultUser ){
      g.zLogin = zDefaultUser;
    }else{
      g.zLogin = db_text(0, "SELECT login FROM user WHERE cap LIKE '%%s%%'");
    }
................................................................................
      "REPLACE INTO config(name,value,mtime)"
      " VALUES('server-code', lower(hex(randomblob(20))), now());"
    );
    url_enable_proxy(0);
    clone_ssh_db_set_options();
    url_get_password_if_needed();
    g.xlinkClusterOnly = 1;
    nErr = client_sync(SYNC_CLONE | bPrivate,CONFIGSET_ALL,0);
    g.xlinkClusterOnly = 0;
    verify_cancel();
    db_end_transaction(0);
    db_close(1);
    if( nErr ){
      file_delete(g.argv[3]);
      fossil_fatal("server returned an error - clone aborted");
................................................................................
  zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin);
  fossil_print("admin-user: %s (password is \"%s\")\n", g.zLogin, zPassword);
  db_end_transaction(0);
}

/*
** If user chooses to use HTTP Authentication over unencrypted HTTP,
** remember decision.  Otherwise, if the URL is being changed and no 
** preference has been indicated, err on the safe side and revert the
** decision. Set the global preference if the URL is not being changed.
*/
void remember_or_get_http_auth(
  const char *zHttpAuth,  /* Credentials in the form "user:password" */
  int fRemember,          /* True to remember credentials for later reuse */
  const char *zUrl        /* URL for which these credentials apply */
................................................................................
  zSshCmd = find_option("ssh-command","c",1);
  if( zSshCmd && zSshCmd[0] ){
    g.zSshCmd = mprintf("%s", zSshCmd);
  }
}

/*
** Set SSH options discovered in global variables (set from command line 
** options).
*/
void clone_ssh_db_set_options(void){
  if( g.zSshCmd && g.zSshCmd[0] ){
    db_set("ssh-command", g.zSshCmd, 0);
  }
}







|












|









|



>








<

>

>
|

>




|







|











|







 







|







 







|







 







|







81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123

124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
...
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
...
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
...
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281

/*
** COMMAND: clone
**
** Usage: %fossil clone ?OPTIONS? URL FILENAME
**
** Make a clone of a repository specified by URL in the local
** file named FILENAME.
**
** URL must be in one of the following form: ([...] mean optional)
**   HTTP/HTTPS protocol:
**     http[s]://[userid[:password]@]host[:port][/path]
**
**   SSH protocol:
**     ssh://[userid[:password]@]host[:port]/path/to/repo.fossil\\
**     [?fossil=path/to/fossil.exe]
**
**   Filesystem:
**     [file://]path/to/repo.fossil
**
**   Note: For ssh and filesystem, path must have an extra leading
**         '/' to use an absolute path.
**
** By default, your current login name is used to create the default
** admin user. This can be overridden using the -A|--admin-user
** parameter.
**
** Options:
**    --admin-user|-A USERNAME   Make USERNAME the administrator
**    --once                     Don't save url.
**    --private                  Also clone private branches
**    --ssl-identity=filename    Use the SSL identity if requested by the server
**    --ssh-command|-c 'command' Use this SSH command
**    --httpauth|-B 'user:pass'  Add HTTP Basic Authorization to requests
**    --verbose                  Show more statistics in output
**
** See also: init
*/
void clone_cmd(void){
  char *zPassword;
  const char *zDefaultUser;   /* Optional name of the default user */
  const char *zHttpAuth;      /* HTTP Authorization user:pass information */
  int nErr = 0;

  int urlFlags = URL_PROMPT_PW | URL_REMEMBER;
  int syncFlags = SYNC_CLONE;

  /* Also clone private branches */
  if( find_option("private",0,0)!=0 ) syncFlags |= SYNC_PRIVATE;
  if( find_option("once",0,0)!=0) urlFlags &= ~URL_REMEMBER;
  if( find_option("verbose",0,0)!=0) syncFlags |= SYNC_VERBOSE;
  zHttpAuth = find_option("httpauth","B",1);
  zDefaultUser = find_option("admin-user","A",1);
  clone_ssh_find_options();
  url_proxy_options();

  /* We should be done with options.. */
  verify_all_options();

  if( g.argc < 4 ){
    usage("?OPTIONS? FILE-OR-URL NEW-REPOSITORY");
  }
  db_open_config(0);
  if( -1 != file_size(g.argv[3]) ){
    fossil_fatal("file already exists: %s", g.argv[3]);
  }

  url_parse(g.argv[2], urlFlags);
  if( zDefaultUser==0 && g.url.user!=0 ) zDefaultUser = g.url.user;
  if( g.url.isFile ){
    file_copy(g.url.name, g.argv[3]);
    db_close(1);
    db_open_repository(g.argv[3]);
    db_record_repository_filename(g.argv[3]);
    url_remember();
    if( !(syncFlags & SYNC_PRIVATE) ) delete_private_content();
    shun_artifacts();
    db_create_default_users(1, zDefaultUser);
    if( zDefaultUser ){
      g.zLogin = zDefaultUser;
    }else{
      g.zLogin = db_text(0, "SELECT login FROM user WHERE cap LIKE '%%s%%'");
    }
................................................................................
      "REPLACE INTO config(name,value,mtime)"
      " VALUES('server-code', lower(hex(randomblob(20))), now());"
    );
    url_enable_proxy(0);
    clone_ssh_db_set_options();
    url_get_password_if_needed();
    g.xlinkClusterOnly = 1;
    nErr = client_sync(syncFlags,CONFIGSET_ALL,0);
    g.xlinkClusterOnly = 0;
    verify_cancel();
    db_end_transaction(0);
    db_close(1);
    if( nErr ){
      file_delete(g.argv[3]);
      fossil_fatal("server returned an error - clone aborted");
................................................................................
  zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin);
  fossil_print("admin-user: %s (password is \"%s\")\n", g.zLogin, zPassword);
  db_end_transaction(0);
}

/*
** If user chooses to use HTTP Authentication over unencrypted HTTP,
** remember decision.  Otherwise, if the URL is being changed and no
** preference has been indicated, err on the safe side and revert the
** decision. Set the global preference if the URL is not being changed.
*/
void remember_or_get_http_auth(
  const char *zHttpAuth,  /* Credentials in the form "user:password" */
  int fRemember,          /* True to remember credentials for later reuse */
  const char *zUrl        /* URL for which these credentials apply */
................................................................................
  zSshCmd = find_option("ssh-command","c",1);
  if( zSshCmd && zSshCmd[0] ){
    g.zSshCmd = mprintf("%s", zSshCmd);
  }
}

/*
** Set SSH options discovered in global variables (set from command line
** options).
*/
void clone_ssh_db_set_options(void){
  if( g.zSshCmd && g.zSshCmd[0] ){
    db_set("ssh-command", g.zSshCmd, 0);
  }
}

Changes to src/codecheck1.c.

274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
...
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
...
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
...
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
  /* A string literal is safe for use with %s */
  if( is_string_lit(z) ) return 1;

  /* Certain functions are guaranteed to return a string that is safe
  ** for use with %s */
  z = next_non_whitespace(z, &len, &eType);
  for(i=0; i<sizeof(azSafeFunc)/sizeof(azSafeFunc[0]); i++){
    if( eType==TK_ID 
     && strncmp(z, azSafeFunc[i], len)==0
     && strlen(azSafeFunc[i])==len
    ){
      return 1;
    }
  }

................................................................................
  /* Expressions of the form:  EXPR ? "..." : "...." can count as
  ** a string literal. */
  if( is_string_expr(z) ) return 1;

  /* If the "safe-for-%s" comment appears in the argument, then
  ** let it through */
  if( strstr(z, "/*safe-for-%s*/")!=0 ) return 1;
    
  return 0;
}

/*
** Processing flags
*/
#define FMT_NO_S   0x00001     /* Do not allow %s substitutions */
................................................................................
    if( z[len]==0 ) break;
    z[len] = 0;
    for(i=len-1; i>0 && isspace(z[i]); i--){ z[i] = 0; }
    z += len + 1;
  }
  acType = (char*)&azArg[nArg];
  if( fmtArg>nArg ){
    printf("%s:%d: too few arguments to %.*s()\n", 
           zFilename, lnFCall, szFName, zFCall);
    nErr++;
  }else{
    const char *zFmt = azArg[fmtArg-1];
    const char *zOverride = strstr(zFmt, "/*works-like:");
    if( zOverride ) zFmt = zOverride + sizeof("/*works-like:")-1;
    if( !is_string_lit(zFmt) ){
................................................................................
        nCurly++;
      }else if( z[0]=='}' ){
        nCurly--;
      }else if( nCurly>0 && z[0]=='(' && ePrev==TK_ID
            && (x = isFormatFunc(zPrev,szPrev,&fmtFlags))>0 ){
        nErr += checkFormatFunc(zName, zPrev, lnPrev, x, fmtFlags);
      }
    }    
    zPrev = z;
    ePrev = eToken;
    szPrev = szToken;
    lnPrev = ln;
  }
  return nErr;
}







|







 







|







 







|







 







|







274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
...
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
...
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
...
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
  /* A string literal is safe for use with %s */
  if( is_string_lit(z) ) return 1;

  /* Certain functions are guaranteed to return a string that is safe
  ** for use with %s */
  z = next_non_whitespace(z, &len, &eType);
  for(i=0; i<sizeof(azSafeFunc)/sizeof(azSafeFunc[0]); i++){
    if( eType==TK_ID
     && strncmp(z, azSafeFunc[i], len)==0
     && strlen(azSafeFunc[i])==len
    ){
      return 1;
    }
  }

................................................................................
  /* Expressions of the form:  EXPR ? "..." : "...." can count as
  ** a string literal. */
  if( is_string_expr(z) ) return 1;

  /* If the "safe-for-%s" comment appears in the argument, then
  ** let it through */
  if( strstr(z, "/*safe-for-%s*/")!=0 ) return 1;

  return 0;
}

/*
** Processing flags
*/
#define FMT_NO_S   0x00001     /* Do not allow %s substitutions */
................................................................................
    if( z[len]==0 ) break;
    z[len] = 0;
    for(i=len-1; i>0 && isspace(z[i]); i--){ z[i] = 0; }
    z += len + 1;
  }
  acType = (char*)&azArg[nArg];
  if( fmtArg>nArg ){
    printf("%s:%d: too few arguments to %.*s()\n",
           zFilename, lnFCall, szFName, zFCall);
    nErr++;
  }else{
    const char *zFmt = azArg[fmtArg-1];
    const char *zOverride = strstr(zFmt, "/*works-like:");
    if( zOverride ) zFmt = zOverride + sizeof("/*works-like:")-1;
    if( !is_string_lit(zFmt) ){
................................................................................
        nCurly++;
      }else if( z[0]=='}' ){
        nCurly--;
      }else if( nCurly>0 && z[0]=='(' && ePrev==TK_ID
            && (x = isFormatFunc(zPrev,szPrev,&fmtFlags))>0 ){
        nErr += checkFormatFunc(zName, zPrev, lnPrev, x, fmtFlags);
      }
    }
    zPrev = z;
    ePrev = eToken;
    szPrev = szToken;
    lnPrev = ln;
  }
  return nErr;
}

Changes to src/configure.c.

95
96
97
98
99
100
101

102
103
104
105
106
107
108
...
987
988
989
990
991
992
993































































































































































































  { "index-page",             CONFIGSET_SKIN },
  { "timeline-block-markup",  CONFIGSET_SKIN },
  { "timeline-max-comment",   CONFIGSET_SKIN },
  { "timeline-plaintext",     CONFIGSET_SKIN },
  { "adunit",                 CONFIGSET_SKIN },
  { "adunit-omit-if-admin",   CONFIGSET_SKIN },
  { "adunit-omit-if-user",    CONFIGSET_SKIN },

#ifdef FOSSIL_ENABLE_TH1_DOCS
  { "th1-docs",               CONFIGSET_TH1 },
#endif
#ifdef FOSSIL_ENABLE_TH1_HOOKS
  { "th1-hooks",              CONFIGSET_TH1 },
#endif
  { "th1-setup",              CONFIGSET_TH1 },
................................................................................
  }else
  {
    fossil_fatal("METHOD should be one of:"
                 " export import merge pull push reset");
  }
  configure_rebuild();
}






































































































































































































>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
...
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
  { "index-page",             CONFIGSET_SKIN },
  { "timeline-block-markup",  CONFIGSET_SKIN },
  { "timeline-max-comment",   CONFIGSET_SKIN },
  { "timeline-plaintext",     CONFIGSET_SKIN },
  { "adunit",                 CONFIGSET_SKIN },
  { "adunit-omit-if-admin",   CONFIGSET_SKIN },
  { "adunit-omit-if-user",    CONFIGSET_SKIN },
  { "white-foreground",       CONFIGSET_SKIN },
#ifdef FOSSIL_ENABLE_TH1_DOCS
  { "th1-docs",               CONFIGSET_TH1 },
#endif
#ifdef FOSSIL_ENABLE_TH1_HOOKS
  { "th1-hooks",              CONFIGSET_TH1 },
#endif
  { "th1-setup",              CONFIGSET_TH1 },
................................................................................
  }else
  {
    fossil_fatal("METHOD should be one of:"
                 " export import merge pull push reset");
  }
  configure_rebuild();
}


/*
** COMMAND: test-var-list
**
** Usage: %fossil test-var-list ?PATTERN? ?--unset? ?--mtime?
**
** Show the content of the CONFIG table in a repository.  If PATTERN is
** specified, then only show the entries that match that glob pattern.
** Last modification time is shown if the --mtime option is present.
**
** If the --unset option is included, then entries are deleted rather than
** being displayed.  WARNING! This cannot be undone.  Be sure you know what
** you are doing!  The --unset option only works if there is a PATTERN.
** Probably you should run the command once without --unset to make sure
** you know exactly what is being deleted.
**
** If not in an open check-out, use the -R REPO option to specify a
** a repository.
*/
void test_var_list_cmd(void){
  Stmt q;
  int i, j;
  const char *zPattern = 0;
  int doUnset;
  int showMtime;
  Blob sql;
  Blob ans;
  unsigned char zTrans[1000];

  doUnset = find_option("unset",0,0)!=0;
  showMtime = find_option("mtime",0,0)!=0;
  db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
  verify_all_options();
  if( g.argc>=3 ){
    zPattern = g.argv[2];
  }
  blob_init(&sql,0,0);
  blob_appendf(&sql, "SELECT name, value, datetime(mtime,'unixepoch')"
                     " FROM config");
  if( zPattern ){
    blob_appendf(&sql, " WHERE name GLOB %Q", zPattern);
  }
  if( showMtime ){
    blob_appendf(&sql, " ORDER BY mtime, name");
  }else{
    blob_appendf(&sql, " ORDER BY name");
  }
  db_prepare(&q, "%s", blob_str(&sql)/*safe-for-%s*/);
  blob_reset(&sql);
#define MX_VAL 40
#define MX_NM  28
#define MX_LONGNM 60
  while( db_step(&q)==SQLITE_ROW ){
    const char *zName = db_column_text(&q,0);
    int nName = db_column_bytes(&q,0);
    const char *zValue = db_column_text(&q,1);
    int szValue = db_column_bytes(&q,1);
    const char *zMTime = db_column_text(&q,2);
    for(i=j=0; j<MX_VAL && zValue[i]; i++){
      unsigned char c = (unsigned char)zValue[i];
      if( c>=' ' && c<='~' ){
        zTrans[j++] = c;
      }else{
        zTrans[j++] = '\\';
        if( c=='\n' ){
          zTrans[j++] = 'n';
        }else if( c=='\r' ){
          zTrans[j++] = 'r';
        }else if( c=='\t' ){
          zTrans[j++] = 't';
        }else{      
          zTrans[j++] = '0' + ((c>>6)&7);
          zTrans[j++] = '0' + ((c>>3)&7);
          zTrans[j++] = '0' + (c&7);
        }
      }
    }
    zTrans[j] = 0;
    if( i<szValue ){
      sqlite3_snprintf(sizeof(zTrans)-j, (char*)zTrans+j, "...+%d", szValue-i);
      j += (int)strlen((char*)zTrans+j);
    }
    if( showMtime ){
      fossil_print("%s:%*s%s\n", zName, 58-nName, "", zMTime);
    }else if( nName<MX_NM-2 ){
      fossil_print("%s:%*s%s\n", zName, MX_NM-1-nName, "", zTrans);
    }else if( nName<MX_LONGNM-2 && j<10 ){
      fossil_print("%s:%*s%s\n", zName, MX_LONGNM-1-nName, "", zTrans);
    }else{
      fossil_print("%s:\n%*s%s\n", zName, MX_NM, "", zTrans);
    }
  }
  db_finalize(&q);
  if( zPattern && doUnset ){
    prompt_user("Delete all of the above? (y/N)? ", &ans);
    if( blob_str(&ans)[0]=='y' || blob_str(&ans)[0]=='Y' ){
      db_multi_exec("DELETE FROM config WHERE name GLOB %Q", zPattern);
    }
    blob_reset(&ans);
  }
}

/*
** COMMAND: test-var-get
**
** Usage: %fossil test-var-get VAR ?FILE?
**
** Write the text of the VAR variable into FILE.  If FILE is "-" 
** or is omitted then output goes to standard output.  VAR can be a
** GLOB pattern.
**
** If not in an open check-out, use the -R REPO option to specify a
** a repository.
*/
void test_var_get_cmd(void){
  const char *zVar;
  const char *zFile;
  int n;
  Blob x;
  db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
  verify_all_options();
  if( g.argc<3 ){
    usage("VAR ?FILE?");
  }
  zVar = g.argv[2];
  zFile = g.argc>=4 ? g.argv[3] : "-";
  n = db_int(0, "SELECT count(*) FROM config WHERE name GLOB %Q", zVar);
  if( n==0 ){
    fossil_fatal("no match for %Q", zVar);
  }
  if( n>1 ){
    fossil_fatal("multiple matches: %s",
      db_text(0, "SELECT group_concat(quote(name),', ') FROM ("
                 " SELECT name FROM config WHERE name GLOB %Q ORDER BY 1)",
                 zVar));
  }
  blob_init(&x,0,0);
  db_blob(&x, "SELECT value FROM config WHERE name GLOB %Q", zVar);
  blob_write_to_file(&x, zFile);
}

/*
** COMMAND: test-var-set
**
** Usage: %fossil test-var-set VAR ?VALUE? ?--file FILE?
**
** Store VALUE or the content of FILE (exactly one of which must be
** supplied) into variable VAR.  Use a FILE of "-" to read from
** standard input.
**
** WARNING: changing the value of a variable can interfere with the
** operation of Fossil.  Be sure you know what you are doing.
**
** Use "--blob FILE" instead of "--file FILE" to load a binary blob
** such as a GIF.
*/
void test_var_set_cmd(void){
  const char *zVar;
  const char *zFile;
  const char *zBlob;
  Blob x;
  Stmt ins;
  zFile = find_option("file",0,1);
  zBlob = find_option("blob",0,1);
  db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
  verify_all_options();
  if( g.argc<3 || (zFile==0 && zBlob==0 && g.argc<4) ){
    usage("VAR ?VALUE? ?--file FILE?");
  }
  zVar = g.argv[2];
  if( zFile ){
    if( zBlob ) fossil_fatal("cannot do both --file or --blob");
    blob_read_from_file(&x, zFile);
  }else if( zBlob ){
    blob_read_from_file(&x, zBlob);
  }else{
    blob_init(&x,g.argv[3],-1);
  }
  db_prepare(&ins,
     "REPLACE INTO config(name,value,mtime)"
     "VALUES(%Q,:val,now())", zVar);
  if( zBlob ){
    db_bind_blob(&ins, ":val", &x);
  }else{
    db_bind_text(&ins, ":val", blob_str(&x));
  }
  db_step(&ins);
  db_finalize(&ins);
  blob_reset(&x);
}

Changes to src/db.c.

733
734
735
736
737
738
739








740
741
742
743
744
745
746
...
747
748
749
750
751
752
753








754
755
756
757
758
759
760
761
762
763
764
765
766
767
...
776
777
778
779
780
781
782















783
784
785
786
787
788
789
...
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824

825
826
827
828
829
830
831
832
833
...
904
905
906
907
908
909
910

911

912
913
914
915
916
917
918

919
920
921
922
923
924
925
926

927

928
929
930
931
932
933
934
935
936
937
....
1147
1148
1149
1150
1151
1152
1153



























1154
1155
1156
1157
1158
1159
1160
....
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
....
1332
1333
1334
1335
1336
1337
1338












1339
1340
1341
1342
1343
1344
1345
....
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
....
1616
1617
1618
1619
1620
1621
1622





1623
1624
1625
1626
1627
1628
1629
....
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
  sqlite3_value **argv
){
  sqlite3_result_int64(context, time(0));
}

/*
** Function to return the check-in time for a file.








*/
void db_checkin_mtime_function(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  i64 mtime;
................................................................................
  int rc = mtime_of_manifest_file(sqlite3_value_int(argv[0]),
                                  sqlite3_value_int(argv[1]), &mtime);
  if( rc==0 ){
    sqlite3_result_int64(context, mtime);
  }
}









void db_sym2rid_function(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  char const * arg;
  char const * type;
  if(1 != argc && 2 != argc){
    sqlite3_result_error(context, "Expecting one or two arguments", -1);
    return;
  }
  arg = (const char*)sqlite3_value_text(argv[0]);
  if(!arg){
    sqlite3_result_error(context, "Expecting a STRING argument", -1);
................................................................................
      sqlite3_result_null(context);
    }else{
      sqlite3_result_int64(context, rid);
    }
  }
}

















/*
** Open a database file.  Return a pointer to the new database
** connection.  An error results in process abort.
*/
LOCAL sqlite3 *db_open(const char *zDbName){
  int rc;
................................................................................
       g.zVfsName
  );
  if( rc!=SQLITE_OK ){
    db_err("[%s]: %s", zDbName, sqlite3_errmsg(db));
  }
  sqlite3_busy_timeout(db, 5000);
  sqlite3_wal_autocheckpoint(db, 1);  /* Set to checkpoint frequently */
  sqlite3_create_function(db, "now", 0, SQLITE_UTF8, 0, db_now_function, 0, 0);
  sqlite3_create_function(db, "checkin_mtime", 2, SQLITE_UTF8, 0,
                          db_checkin_mtime_function, 0, 0);
  sqlite3_create_function(db, "user", 0, SQLITE_UTF8, 0, db_sql_user, 0, 0);
  sqlite3_create_function(db, "cgi", 1, SQLITE_UTF8, 0, db_sql_cgi, 0, 0);
  sqlite3_create_function(db, "cgi", 2, SQLITE_UTF8, 0, db_sql_cgi, 0, 0);
  sqlite3_create_function(db, "print", -1, SQLITE_UTF8, 0,db_sql_print,0,0);
  sqlite3_create_function(
    db, "is_selected", 1, SQLITE_UTF8, 0, file_is_selected,0,0
  );
  sqlite3_create_function(
    db, "if_selected", 3, SQLITE_UTF8, 0, file_is_selected,0,0
  );
  sqlite3_create_function(
    db, "symbolic_name_to_rid", 1, SQLITE_UTF8, 0, db_sym2rid_function,
    0, 0
  );
  sqlite3_create_function(
    db, "symbolic_name_to_rid", 2, SQLITE_UTF8, 0, db_sym2rid_function,
    0, 0
  );
  if( g.fSqlTrace ) sqlite3_trace(db, db_sql_trace, 0);

  re_add_sql_func(db);
  foci_register(db);
  sqlite3_exec(db, "PRAGMA foreign_keys=OFF;", 0, 0, 0);
  return db;
}


/*
** Detaches the zLabel database.
................................................................................
void db_open_config(int useAttach){
  char *zDbName;
  char *zHome;
  if( g.zConfigDbName ){
    if( useAttach==g.useAttach ) return;
    db_close_config();
  }

#if defined(_WIN32) || defined(__CYGWIN__)

  zHome = fossil_getenv("LOCALAPPDATA");
  if( zHome==0 ){
    zHome = fossil_getenv("APPDATA");
    if( zHome==0 ){
      char *zDrive = fossil_getenv("HOMEDRIVE");
      zHome = fossil_getenv("HOMEPATH");
      if( zDrive && zHome ) zHome = mprintf("%s%s", zDrive, zHome);

    }
  }
  if( zHome==0 ){
    fossil_fatal("cannot locate home directory - "
                "please set the LOCALAPPDATA or APPDATA or HOMEPATH "
                "environment variables");
  }
#else

  zHome = fossil_getenv("HOME");

  if( zHome==0 ){
    fossil_fatal("cannot locate home directory - "
                 "please set the HOME environment variable");
  }
#endif
  if( file_isdir(zHome)!=1 ){
    fossil_fatal("invalid home directory: %s", zHome);
  }
#if defined(_WIN32) || defined(__CYGWIN__)
  /* . filenames give some window systems problems and many apps problems */
................................................................................
    }
  }
  g.zRepositoryName = mprintf("%s", zDbName);
  db_open_or_attach(g.zRepositoryName, "repository", 0);
  g.repositoryOpen = 1;
  /* Cache "allow-symlinks" option, because we'll need it on every stat call */
  g.allowSymlinks = db_get_boolean("allow-symlinks", 0);



























}

/*
** Flags for the db_find_and_open_repository() function.
*/
#if INTERFACE
#define OPEN_OK_NOT_FOUND    0x001      /* Do not error out if not found */
................................................................................
  return zDb;
}

/*
** Return TRUE if the schema is out-of-date
*/
int db_schema_is_outofdate(void){
  if( g.zAuxSchema==0 ) g.zAuxSchema = db_get("aux-schema","");
  return strcmp(g.zAuxSchema,AUX_SCHEMA_MIN)<0
      || strcmp(g.zAuxSchema,AUX_SCHEMA_MAX)>0;
}

/*
** Return true if the database is writeable
*/
................................................................................
  pStmt = 0;
  if( reportErrors ){
    while( (pStmt = sqlite3_next_stmt(g.db, pStmt))!=0 ){
      fossil_warning("unfinalized SQL statement: [%s]", sqlite3_sql(pStmt));
    }
  }
  db_close_config();












  if( g.db ){
    sqlite3_wal_checkpoint(g.db, 0);
    sqlite3_close(g.db);
    g.db = 0;
    g.zMainDbType = 0;
  }
  g.repositoryOpen = 0;
................................................................................
  db_multi_exec(
     "UPDATE user SET cap='s', pw=lower(hex(randomblob(3)))"
     " WHERE login=%Q", zUser
  );
  if( !setupUserOnly ){
    db_multi_exec(
       "INSERT OR IGNORE INTO user(login,pw,cap,info)"
       "   VALUES('anonymous',hex(randomblob(8)),'hmncz','Anon');"
       "INSERT OR IGNORE INTO user(login,pw,cap,info)"
       "   VALUES('nobody','','gjor','Nobody');"
       "INSERT OR IGNORE INTO user(login,pw,cap,info)"
       "   VALUES('developer','','dei','Dev');"
       "INSERT OR IGNORE INTO user(login,pw,cap,info)"
       "   VALUES('reader','','kptw','Reader');"
    );
  }
}
................................................................................
  find_option("empty", 0, 0); /* deprecated */
  /* We should be done with options.. */
  verify_all_options();

  if( g.argc!=3 ){
    usage("REPOSITORY-NAME");
  }





  db_create_repository(g.argv[2]);
  db_open_repository(g.argv[2]);
  db_open_config(0);
  if( zTemplate ) db_attach(zTemplate, "settingSrc");
  db_begin_transaction();
  db_initial_setup(zTemplate, zDate, zDefaultUser, makeServerCodes);
  db_end_transaction(0);
................................................................................
        }else{
          db_set(ctrlSettings[i].name, g.argv[3], globalFlag);
        }
      }
    }else{
      isManifest = 0;
      while( ctrlSettings[i].name
            && strncmp(ctrlSettings[i].name, zName, n)==0
      ){
        print_setting(&ctrlSettings[i], db_open_local(0));
        i++;
      }
    }
    if( isManifest && g.localOpen ){
      manifest_to_disk(db_lget_int("checkout", 0));







>
>
>
>
>
>
>
>







 







>
>
>
>
>
>
>
>





|
|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







<
<
<










<
<
<
<
<
<
<
<

>
|
|







 







>

>
|
|
|
|
|
|
|
>



|
|
|


>
|
>

|
|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







<







 







>
>
>
>
>
>
>
>
>
>
>
>







 







|

|







 







>
>
>
>
>







 







|







733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
...
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
...
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
...
827
828
829
830
831
832
833



834
835
836
837
838
839
840
841
842
843








844
845
846
847
848
849
850
851
852
853
854
...
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
....
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
....
1267
1268
1269
1270
1271
1272
1273

1274
1275
1276
1277
1278
1279
1280
....
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
....
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
....
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
....
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
  sqlite3_value **argv
){
  sqlite3_result_int64(context, time(0));
}

/*
** Function to return the check-in time for a file.
**
**      checkin_mtime(CKINID,RID)
**
** CKINID:  The RID for the manifest for a check-in.
** RID:     The RID of a file in CKINID for which the check-in time
**          is desired.
**
** Returns: The check-in time in seconds since 1970.
*/
void db_checkin_mtime_function(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  i64 mtime;
................................................................................
  int rc = mtime_of_manifest_file(sqlite3_value_int(argv[0]),
                                  sqlite3_value_int(argv[1]), &mtime);
  if( rc==0 ){
    sqlite3_result_int64(context, mtime);
  }
}

/*
** SQL wrapper around the symbolic_name_to_rid() C-language API.
** Examples:
**
**     symbolic_name_to_rid('trunk');
**     symbolic_name_to_rid('trunk','w');
**
*/
void db_sym2rid_function(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  const char *arg;
  const char *type;
  if(1 != argc && 2 != argc){
    sqlite3_result_error(context, "Expecting one or two arguments", -1);
    return;
  }
  arg = (const char*)sqlite3_value_text(argv[0]);
  if(!arg){
    sqlite3_result_error(context, "Expecting a STRING argument", -1);
................................................................................
      sqlite3_result_null(context);
    }else{
      sqlite3_result_int64(context, rid);
    }
  }
}

/*
** Register the SQL functions that are useful both to the internal
** representation and to the "fossil sql" command.
*/
void db_add_aux_functions(sqlite3 *db){
  sqlite3_create_function(db, "checkin_mtime", 2, SQLITE_UTF8, 0,
                          db_checkin_mtime_function, 0, 0);
  sqlite3_create_function(db, "symbolic_name_to_rid", 1, SQLITE_UTF8, 0,
                          db_sym2rid_function, 0, 0);
  sqlite3_create_function(db, "symbolic_name_to_rid", 2, SQLITE_UTF8, 0,
                          db_sym2rid_function, 0, 0);
  sqlite3_create_function(db, "now", 0, SQLITE_UTF8, 0,
                                 db_now_function, 0, 0);
}


/*
** Open a database file.  Return a pointer to the new database
** connection.  An error results in process abort.
*/
LOCAL sqlite3 *db_open(const char *zDbName){
  int rc;
................................................................................
       g.zVfsName
  );
  if( rc!=SQLITE_OK ){
    db_err("[%s]: %s", zDbName, sqlite3_errmsg(db));
  }
  sqlite3_busy_timeout(db, 5000);
  sqlite3_wal_autocheckpoint(db, 1);  /* Set to checkpoint frequently */



  sqlite3_create_function(db, "user", 0, SQLITE_UTF8, 0, db_sql_user, 0, 0);
  sqlite3_create_function(db, "cgi", 1, SQLITE_UTF8, 0, db_sql_cgi, 0, 0);
  sqlite3_create_function(db, "cgi", 2, SQLITE_UTF8, 0, db_sql_cgi, 0, 0);
  sqlite3_create_function(db, "print", -1, SQLITE_UTF8, 0,db_sql_print,0,0);
  sqlite3_create_function(
    db, "is_selected", 1, SQLITE_UTF8, 0, file_is_selected,0,0
  );
  sqlite3_create_function(
    db, "if_selected", 3, SQLITE_UTF8, 0, file_is_selected,0,0
  );








  if( g.fSqlTrace ) sqlite3_trace(db, db_sql_trace, 0);
  db_add_aux_functions(db);
  re_add_sql_func(db);  /* The REGEXP operator */
  foci_register(db);    /* The "files_of_checkin" virtual table */
  sqlite3_exec(db, "PRAGMA foreign_keys=OFF;", 0, 0, 0);
  return db;
}


/*
** Detaches the zLabel database.
................................................................................
void db_open_config(int useAttach){
  char *zDbName;
  char *zHome;
  if( g.zConfigDbName ){
    if( useAttach==g.useAttach ) return;
    db_close_config();
  }
  zHome = fossil_getenv("FOSSIL_HOME");
#if defined(_WIN32) || defined(__CYGWIN__)
  if( zHome==0 ){
    zHome = fossil_getenv("LOCALAPPDATA");
    if( zHome==0 ){
      zHome = fossil_getenv("APPDATA");
      if( zHome==0 ){
        char *zDrive = fossil_getenv("HOMEDRIVE");
        char *zPath = fossil_getenv("HOMEPATH");
        if( zDrive && zPath ) zHome = mprintf("%s%s", zDrive, zPath);
      }
    }
  }
  if( zHome==0 ){
    fossil_fatal("cannot locate home directory - please set the "
                 "FOSSIL_HOME, LOCALAPPDATA, APPDATA, or HOMEPATH "
                 "environment variables");
  }
#else
  if( zHome==0 ){
    zHome = fossil_getenv("HOME");
  }
  if( zHome==0 ){
    fossil_fatal("cannot locate home directory - please set the "
                 "FOSSIL_HOME or HOME environment variables");
  }
#endif
  if( file_isdir(zHome)!=1 ){
    fossil_fatal("invalid home directory: %s", zHome);
  }
#if defined(_WIN32) || defined(__CYGWIN__)
  /* . filenames give some window systems problems and many apps problems */
................................................................................
    }
  }
  g.zRepositoryName = mprintf("%s", zDbName);
  db_open_or_attach(g.zRepositoryName, "repository", 0);
  g.repositoryOpen = 1;
  /* Cache "allow-symlinks" option, because we'll need it on every stat call */
  g.allowSymlinks = db_get_boolean("allow-symlinks", 0);
  g.zAuxSchema = db_get("aux-schema","");

  /* Verify that the PLINK table has a new column added by the
  ** 2014-11-28 schema change.  Create it if necessary.  This code
  ** can be removed in the future, once all users have upgraded to the
  ** 2014-11-28 or later schema.
  */
  if( !db_table_has_column("repository","plink","baseid") ){
    db_multi_exec(
      "ALTER TABLE %s.plink ADD COLUMN baseid;", db_name("repository")
    );
  }

  /* Verify that the MLINK table has the newer columns added by the
  ** 2015-01-24 schema change.  Create them if necessary.  This code
  ** can be removed in the future, once all users have upgraded to the
  ** 2015-01-24 or later schema.
  */
  if( !db_table_has_column("repository","mlink","isaux") ){
    db_begin_transaction();
    db_multi_exec(
      "ALTER TABLE %s.mlink ADD COLUMN pmid INTEGER DEFAULT 0;"
      "ALTER TABLE %s.mlink ADD COLUMN isaux BOOLEAN DEFAULT 0;",
      db_name("repository"), db_name("repository")
    );
    db_end_transaction(0);
  }
}

/*
** Flags for the db_find_and_open_repository() function.
*/
#if INTERFACE
#define OPEN_OK_NOT_FOUND    0x001      /* Do not error out if not found */
................................................................................
  return zDb;
}

/*
** Return TRUE if the schema is out-of-date
*/
int db_schema_is_outofdate(void){

  return strcmp(g.zAuxSchema,AUX_SCHEMA_MIN)<0
      || strcmp(g.zAuxSchema,AUX_SCHEMA_MAX)>0;
}

/*
** Return true if the database is writeable
*/
................................................................................
  pStmt = 0;
  if( reportErrors ){
    while( (pStmt = sqlite3_next_stmt(g.db, pStmt))!=0 ){
      fossil_warning("unfinalized SQL statement: [%s]", sqlite3_sql(pStmt));
    }
  }
  db_close_config();

  /* If the localdb (the check-out database) is open and if it has
  ** a lot of unused free space, then VACUUM it as we shut down.
  */
  if( g.localOpen && strcmp(db_name("localdb"),"main")==0 ){
    int nFree = db_int(0, "PRAGMA main.freelist_count");
    int nTotal = db_int(0, "PRAGMA main.page_count");
    if( nFree>nTotal/4 ){
      db_multi_exec("VACUUM;");
    }
  }

  if( g.db ){
    sqlite3_wal_checkpoint(g.db, 0);
    sqlite3_close(g.db);
    g.db = 0;
    g.zMainDbType = 0;
  }
  g.repositoryOpen = 0;
................................................................................
  db_multi_exec(
     "UPDATE user SET cap='s', pw=lower(hex(randomblob(3)))"
     " WHERE login=%Q", zUser
  );
  if( !setupUserOnly ){
    db_multi_exec(
       "INSERT OR IGNORE INTO user(login,pw,cap,info)"
       "   VALUES('anonymous',hex(randomblob(8)),'hmnc','Anon');"
       "INSERT OR IGNORE INTO user(login,pw,cap,info)"
       "   VALUES('nobody','','gjorz','Nobody');"
       "INSERT OR IGNORE INTO user(login,pw,cap,info)"
       "   VALUES('developer','','dei','Dev');"
       "INSERT OR IGNORE INTO user(login,pw,cap,info)"
       "   VALUES('reader','','kptw','Reader');"
    );
  }
}
................................................................................
  find_option("empty", 0, 0); /* deprecated */
  /* We should be done with options.. */
  verify_all_options();

  if( g.argc!=3 ){
    usage("REPOSITORY-NAME");
  }
 
  if( -1 != file_size(g.argv[2]) ){
    fossil_fatal("file already exists: %s", g.argv[2]);
  }

  db_create_repository(g.argv[2]);
  db_open_repository(g.argv[2]);
  db_open_config(0);
  if( zTemplate ) db_attach(zTemplate, "settingSrc");
  db_begin_transaction();
  db_initial_setup(zTemplate, zDate, zDefaultUser, makeServerCodes);
  db_end_transaction(0);
................................................................................
        }else{
          db_set(ctrlSettings[i].name, g.argv[3], globalFlag);
        }
      }
    }else{
      isManifest = 0;
      while( ctrlSettings[i].name
          && strncmp(ctrlSettings[i].name, zName, n)==0
      ){
        print_setting(&ctrlSettings[i], db_open_local(0));
        i++;
      }
    }
    if( isManifest && g.localOpen ){
      manifest_to_disk(db_lget_int("checkout", 0));

Changes to src/deltacmd.c.

15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
**
*******************************************************************************
**
** This module implements the interface to the delta generator.
*/
#include "config.h"
#include "deltacmd.h"
 
/*
** Create a delta that describes the change from pOriginal to pTarget
** and put that delta in pDelta.  The pDelta blob is assumed to be
** uninitialized.
*/
int blob_delta_create(Blob *pOriginal, Blob *pTarget, Blob *pDelta){
  const char *zOrig, *zTarg;







|







15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
**
*******************************************************************************
**
** This module implements the interface to the delta generator.
*/
#include "config.h"
#include "deltacmd.h"

/*
** Create a delta that describes the change from pOriginal to pTarget
** and put that delta in pDelta.  The pDelta blob is assumed to be
** uninitialized.
*/
int blob_delta_create(Blob *pOriginal, Blob *pTarget, Blob *pDelta){
  const char *zOrig, *zTarg;

Changes to src/diff.tcl.










1
2
3
4
5
6
7









set prog {
package require Tk

array set CFG {
  TITLE      {Fossil Diff}
  LN_COL_BG  #dddddd
  LN_COL_FG  #444444
>
>
>
>
>
>
>
>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# The "diff --tk" command outputs prepends a "set fossilcmd {...}" line
# to this file, then runs this file using "tclsh" in order to display the
# graphical diff in a separate window.  A typical "set fossilcmd" line
# looks like this:
#
#     set fossilcmd {| "./fossil" diff --html -y -i -v}
#
# This header comment is stripped off by the "mkbuiltin.c" program.
#
set prog {
package require Tk

array set CFG {
  TITLE      {Fossil Diff}
  LN_COL_BG  #dddddd
  LN_COL_FG  #444444

Changes to src/doc.c.

348
349
350
351
352
353
354
355
356




































357
358
359
360
361
362
363
364



365
366
367
368




















369
370
371

372

373
374
375
376
377



378
379
380


381
382
383
384
385



386
387
388
389






390

391


392
393
394


395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415

416

417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504

505
506
507
508
509
510
511
...
513
514
515
516
517
518
519

520
521
522
523
524
525
526
527
...
534
535
536
537
538
539
540


541
542
543
544

545

546
547




548

549
550
551
552
553
554
555
*/
void mimetype_test_cmd(void){
  int i;
  for(i=2; i<g.argc; i++){
    fossil_print("%-20s -> %s\n", g.argv[i], mimetype_from_name(g.argv[i]));
  }
}

/*




































** WEBPAGE: doc
** URL: /doc?name=BASELINE/PATH
** URL: /doc/BASELINE/PATH
**
** BASELINE can be either a baseline uuid prefix or magic words "tip"
** to mean the most recently checked in baseline or "ckout" to mean the
** content of the local checkout, if any.  PATH is the relative pathname
** of some file.  This method returns the file content.



**
** If PATH matches the patterns *.wiki or *.txt then formatting content
** is added before returning the file.  For all other names, the content
** is returned straight without any interpretation or processing.




















*/
void doc_page(void){
  const char *zName;                /* Argument to the /doc page */

  const char *zMime;                /* Document MIME type */

  int vid = 0;                      /* Artifact of baseline */
  int rid = 0;                      /* Artifact of file */
  int i;                            /* Loop counter */
  Blob filebody;                    /* Content of the documentation file */
  char zBaseline[UUID_SIZE+1];      /* Baseline UUID */




  login_check_credentials();
  if( !g.perm.Read ){ login_needed(); return; }


  zName = PD("name", "tip/index.wiki");
  for(i=0; zName[i] && zName[i]!='/'; i++){}
  if( zName[i]==0 || i>UUID_SIZE ){
    zName = "index.html";
    goto doc_not_found;



  }
  g.zPath = mprintf("%s/%s", g.zPath, zName);
  memcpy(zBaseline, zName, i);
  zBaseline[i] = 0;






  zName += i;

  while( zName[0]=='/' ){ zName++; }


  if( !file_is_simple_pathname(zName, 1) ){
    int n = strlen(zName);
    if( n>0 && zName[n-1]=='/' ){


      zName = mprintf("%sindex.html", zName);
      if( !file_is_simple_pathname(zName, 1) ){
        goto doc_not_found;
      }
    }else{
      goto doc_not_found;
    }
  }
  if( fossil_strcmp(zBaseline,"ckout")==0 && db_open_local(0)==0 ){
    sqlite3_snprintf(sizeof(zBaseline), zBaseline, "tip");
  }
  if( fossil_strcmp(zBaseline,"ckout")==0 ){
    /* Read from the local checkout */
    char *zFullpath;
    db_must_be_within_tree();
    zFullpath = mprintf("%s/%s", g.zLocalRoot, zName);
    if( !file_isfile(zFullpath) ){
      goto doc_not_found;
    }
    if( blob_read_from_file(&filebody, zFullpath)<0 ){
      goto doc_not_found;

    }

  }else{
    db_begin_transaction();
    if( fossil_strcmp(zBaseline,"tip")==0 ){
      vid = db_int(0, "SELECT objid FROM event WHERE type='ci'"
                      " ORDER BY mtime DESC LIMIT 1");
    }else{
      vid = name_to_typed_rid(zBaseline, "ci");
    }

    /* Create the baseline cache if it does not already exist */
    db_multi_exec(
      "CREATE TABLE IF NOT EXISTS vcache(\n"
      "  vid INTEGER,         -- baseline ID\n"
      "  fname TEXT,          -- filename\n"
      "  rid INTEGER,         -- artifact ID\n"
      "  UNIQUE(vid,fname,rid)\n"
      ")"
    );



    /* Check to see if the documentation file artifact ID is contained
    ** in the baseline cache */
    rid = db_int(0, "SELECT rid FROM vcache"
                    " WHERE vid=%d AND fname=%Q", vid, zName);
    if( rid==0 && db_exists("SELECT 1 FROM vcache WHERE vid=%d", vid) ){
      goto doc_not_found;
    }

    if( rid==0 ){
      Stmt s;
      Manifest *pM;
      ManifestFile *pFile;

      /* Add the vid baseline to the cache */
      if( db_int(0, "SELECT count(*) FROM vcache")>10000 ){
        db_multi_exec("DELETE FROM vcache");
      }
      pM = manifest_get(vid, CFTYPE_MANIFEST, 0);
      if( pM==0 ){
        goto doc_not_found;
      }
      db_prepare(&s,
        "INSERT INTO vcache(vid,fname,rid)"
        " SELECT %d, :fname, rid FROM blob"
        "  WHERE uuid=:uuid",
        vid
      );
      manifest_file_rewind(pM);
      while( (pFile = manifest_file_next(pM,0))!=0 ){
        db_bind_text(&s, ":fname", pFile->zName);
        db_bind_text(&s, ":uuid", pFile->zUuid);
        db_step(&s);
        db_reset(&s);
      }
      db_finalize(&s);
      manifest_destroy(pM);

      /* Try again to find the file */
      rid = db_int(0, "SELECT rid FROM vcache"
                      " WHERE vid=%d AND fname=%Q", vid, zName);
    }
    if( rid==0 ){
      goto doc_not_found;
    }

    /* Get the file content */
    if( content_get(rid, &filebody)==0 ){
      goto doc_not_found;
    }
    db_end_transaction(0);
  }
  blob_to_utf8_no_bom(&filebody, 0);

  /* The file is now contained in the filebody blob.  Deliver the
  ** file to the user
  */
  zMime = P("mimetype");
  if( zMime==0 ){
    zMime = mimetype_from_name(zName);
  }
  Th_Store("doc_name", zName);
  Th_Store("doc_version", db_text(0, "SELECT '[' || substr(uuid,1,10) || ']'"
                                     "  FROM blob WHERE rid=%d", vid));
  Th_Store("doc_date", db_text(0, "SELECT datetime(mtime) FROM event"
                                  " WHERE objid=%d AND type='ci'", vid));
  if( fossil_strcmp(zMime, "text/x-fossil-wiki")==0 ){
    Blob title, tail;

    if( wiki_find_title(&filebody, &title, &tail) ){
      style_header("%s", blob_str(&title));
      wiki_convert(&tail, 0, WIKI_BUTTONS);
    }else{
      style_header("Documentation");
      wiki_convert(&filebody, 0, WIKI_BUTTONS);
    }
................................................................................
  }else if( fossil_strcmp(zMime, "text/x-markdown")==0 ){
    Blob title = BLOB_INITIALIZER;
    Blob tail = BLOB_INITIALIZER;
    markdown_to_html(&filebody, &title, &tail);
    if( blob_size(&title)>0 ){
      style_header("%s", blob_str(&title));
    }else{

      style_header("Documentation");
    }
    blob_append(cgi_output_blob(), blob_buffer(&tail), blob_size(&tail));
    style_footer();
  }else if( fossil_strcmp(zMime, "text/plain")==0 ){
    style_header("Documentation");
    @ <blockquote><pre>
    @ %h(blob_str(&filebody))
................................................................................
    Th_Render(blob_str(&filebody));
    style_footer();
#endif
  }else{
    cgi_set_content_type(zMime);
    cgi_set_content(&filebody);
  }


  return;

doc_not_found:
  /* Jump here when unable to locate the document */

  db_end_transaction(0);

  style_header("Document Not Found");
  @ <p>No such document: %h(zName)</p>




  style_footer();

  return;
}

/*
** The default logo.
*/
static const unsigned char aLogo[] = {









>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

|
|

<
<
<
<
>
>
>

<
<
<
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>



>

>
|



|
>
>
>



>
>
|
|
<
<
<
>
>
>
|
<
<
<
>
>
>
>
>
>
|
>
|
>
>
|
<
<
>
>
|
|
|
|
|
|
|
|
<
<
<
|
|
|
|
|
|
<
<
|
<
>
|
>
|
<
<
<
<
<
|
<
<
|
<
<
<
<
<
<
<
<
|
|
<
<
<
<
<
<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<





|










>







 







>
|







 







>
>


<

>

>
|
<
>
>
>
>

>







348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396




397
398
399
400



401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441



442
443
444
445



446
447
448
449
450
451
452
453
454
455
456
457


458
459
460
461
462
463
464
465
466
467



468
469
470
471
472
473


474

475
476
477
478





479


480








481
482






483













































484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
...
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
...
531
532
533
534
535
536
537
538
539
540
541

542
543
544
545
546

547
548
549
550
551
552
553
554
555
556
557
558
559
*/
void mimetype_test_cmd(void){
  int i;
  for(i=2; i<g.argc; i++){
    fossil_print("%-20s -> %s\n", g.argv[i], mimetype_from_name(g.argv[i]));
  }
}

/*
** Look for a file named zName in the checkin with RID=vid.  Load the content
** of that file into pContent and return the RID for the file.  Or return 0
** if the file is not found or could not be loaded.
*/
int doc_load_content(int vid, const char *zName, Blob *pContent){
  int rid;   /* The RID of the file being loaded */
  if( !db_table_exists("repository","vcache") ){
    db_multi_exec(
      "CREATE TABLE IF NOT EXISTS vcache(\n"
      "  vid INTEGER,         -- checkin ID\n"
      "  fname TEXT,          -- filename\n"
      "  rid INTEGER,         -- artifact ID\n"
      "  PRIMARY KEY(vid,fname)\n"
      ") WITHOUT ROWID"
    );
  }
  if( !db_exists("SELECT 1 FROM vcache WHERE vid=%d", vid) ){
    db_multi_exec(
      "DELETE FROM vcache;\n"
      "CREATE VIRTUAL TABLE IF NOT EXISTS temp.foci USING files_of_checkin;\n"
      "INSERT INTO vcache(vid,fname,rid)"
      "  SELECT checkinID, filename, blob.rid FROM foci, blob"
      "   WHERE blob.uuid=foci.uuid"
      "     AND foci.checkinID=%d;",
      vid
    );
  }
  rid = db_int(0, "SELECT rid FROM vcache"
                  " WHERE vid=%d AND fname=%Q", vid, zName);
  if( rid && content_get(rid, pContent)==0 ){
    rid = 0;
  }
  return rid;
}

/*
** WEBPAGE: doc
** URL: /doc?name=CHECKIN/FILE
** URL: /doc/CHECKIN/FILE
**




** CHECKIN can be either tag or SHA1 hash or timestamp identifying a
** particular check, or the name of a branch (meaning the most recent
** check-in on that branch) or one of various magic words:
**



**     "tip"      means the most recent check-in
**
**     "ckout"    means the current check-out, if the server is run from
**                within a check-out, otherwise it is the same as "tip"
**
** FILE is the name of a file to delivered up as a webpage.  FILE is relative
** to the root of the source tree of the repository. The FILE must
** be a part of CHECKIN, except when CHECKIN=="ckout" when FILE is read
** directly from disk and need not be a managed file.
**
** The "ckout" CHECKIN is intended for development - to provide a mechanism
** for looking at what a file will look like using the /doc webpage after
** it gets checked in.
**
** The file extension is used to decide how to render the file.
**
** If FILE ends in "/" then names "FILE/index.html", "FILE/index.wiki",
** and "FILE/index.md" are  in that order.  If none of those are found,
** then FILE is completely replaced by "404.md" and tried.  If that is
** not found, then a default 404 screen is generated.
*/
void doc_page(void){
  const char *zName;                /* Argument to the /doc page */
  const char *zOrigName = "?";      /* Original document name */
  const char *zMime;                /* Document MIME type */
  char *zCheckin = "tip";           /* The checkin holding the document */
  int vid = 0;                      /* Artifact of checkin */
  int rid = 0;                      /* Artifact of file */
  int i;                            /* Loop counter */
  Blob filebody;                    /* Content of the documentation file */
  int nMiss = (-1);                 /* Failed attempts to find the document */
  static const char *const azSuffix[] = {
     "index.html", "index.wiki", "index.md"
  };

  login_check_credentials();
  if( !g.perm.Read ){ login_needed(); return; }
  db_begin_transaction();
  while( rid==0 && (++nMiss)<=ArraySize(azSuffix) ){
    zName = PD("name", "tip/index.wiki");
    for(i=0; zName[i] && zName[i]!='/'; i++){}



    zCheckin = mprintf("%.*s", i, zName);
    if( fossil_strcmp(zCheckin,"ckout")==0 && db_open_local(0)==0 ){
      zCheckin = "tip";
    }



    if( nMiss==ArraySize(azSuffix) ){
      zName = "404.md";
    }else if( zName[i]==0 ){
      assert( nMiss>=0 && nMiss<ArraySize(azSuffix) );
      zName = azSuffix[nMiss];
    }else{
      zName += i;
    }
    while( zName[0]=='/' ){ zName++; }
    g.zPath = mprintf("%s/%s/%s", g.zPath, zCheckin, zName);
    if( nMiss==0 ) zOrigName = zName;
    if( !file_is_simple_pathname(zName, 1) ){


      if( sqlite3_strglob("*/", zName)==0 ){
        assert( nMiss>=0 && nMiss<ArraySize(azSuffix) );
        zName = mprintf("%s%s", zName, azSuffix[nMiss]);
        if( !file_is_simple_pathname(zName, 1) ){
          goto doc_not_found;
        }
      }else{
        goto doc_not_found;
      }
    }



    if( fossil_strcmp(zCheckin,"ckout")==0 ){
      /* Read from the local checkout */
      char *zFullpath;
      db_must_be_within_tree();
      zFullpath = mprintf("%s/%s", g.zLocalRoot, zName);
      if( file_isfile(zFullpath)


       && blob_read_from_file(&filebody, zFullpath)>0 ){

        rid = 1;  /* Fake RID just to get the loop to end */
      }
      fossil_free(zFullpath);
    }else{





      vid = name_to_typed_rid(zCheckin, "ci");


      rid = doc_load_content(vid, zName, &filebody);








    }
  }






  if( rid==0 ) goto doc_not_found;













































  blob_to_utf8_no_bom(&filebody, 0);

  /* The file is now contained in the filebody blob.  Deliver the
  ** file to the user
  */
  zMime = nMiss==0 ? P("mimetype") : 0;
  if( zMime==0 ){
    zMime = mimetype_from_name(zName);
  }
  Th_Store("doc_name", zName);
  Th_Store("doc_version", db_text(0, "SELECT '[' || substr(uuid,1,10) || ']'"
                                     "  FROM blob WHERE rid=%d", vid));
  Th_Store("doc_date", db_text(0, "SELECT datetime(mtime) FROM event"
                                  " WHERE objid=%d AND type='ci'", vid));
  if( fossil_strcmp(zMime, "text/x-fossil-wiki")==0 ){
    Blob title, tail;
    style_adunit_config(ADUNIT_RIGHT_OK);
    if( wiki_find_title(&filebody, &title, &tail) ){
      style_header("%s", blob_str(&title));
      wiki_convert(&tail, 0, WIKI_BUTTONS);
    }else{
      style_header("Documentation");
      wiki_convert(&filebody, 0, WIKI_BUTTONS);
    }
................................................................................
  }else if( fossil_strcmp(zMime, "text/x-markdown")==0 ){
    Blob title = BLOB_INITIALIZER;
    Blob tail = BLOB_INITIALIZER;
    markdown_to_html(&filebody, &title, &tail);
    if( blob_size(&title)>0 ){
      style_header("%s", blob_str(&title));
    }else{
      style_header("%s", nMiss>=ArraySize(azSuffix)?
                        "Not Found" : "Documentation");
    }
    blob_append(cgi_output_blob(), blob_buffer(&tail), blob_size(&tail));
    style_footer();
  }else if( fossil_strcmp(zMime, "text/plain")==0 ){
    style_header("Documentation");
    @ <blockquote><pre>
    @ %h(blob_str(&filebody))
................................................................................
    Th_Render(blob_str(&filebody));
    style_footer();
#endif
  }else{
    cgi_set_content_type(zMime);
    cgi_set_content(&filebody);
  }
  if( nMiss>=ArraySize(azSuffix) ) cgi_set_status(404, "Not Found");
  db_end_transaction(0);
  return;


  /* Jump here when unable to locate the document */
doc_not_found:
  db_end_transaction(0);
  cgi_set_status(404, "Not Found");
  style_header("Not Found");

  @ <p>Document %h(zOrigName) not found
  if( fossil_strcmp(zCheckin,"ckout")!=0 ){
    @ in %z(href("%R/tree?ci=%T",zCheckin))%h(zCheckin)</a>
  }
  style_footer();
  db_end_transaction(0);
  return;
}

/*
** The default logo.
*/
static const unsigned char aLogo[] = {

Changes to src/export.c.

102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
...
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
/*
** COMMAND: export
**
** Usage: %fossil export --git ?OPTIONS? ?REPOSITORY?
**
** Write an export of all check-ins to standard output.  The export is
** written in the git-fast-export file format assuming the --git option is
** provided.  The git-fast-export format is currently the only VCS 
** interchange format supported, though other formats may be added in
** the future.
**
** Run this command within a checkout.  Or use the -R or --repository
** option to specify a Fossil repository to be exported.
**
** Only check-ins are exported using --git.  Git does not support tickets 
** or wiki or events or attachments, so none of those are exported.
**
** If the "--import-marks FILE" option is used, it contains a list of
** rids to skip.
**
** If the "--export-marks FILE" option is used, the rid of all commits and
** blobs written on exit for use with "--import-marks" on the next run.
**
** Options:
**   --export-marks FILE          export rids of exported data to FILE
**   --import-marks FILE          read rids of data to ignore from FILE
**   --repository|-R REPOSITORY   export the given REPOSITORY
**   
** See also: import
*/
void export_cmd(void){
  Stmt q, q2, q3;
  int i;
  Bag blobs, vers;
  const char *markfile_in;
................................................................................
    }
    db_finalize(&qb);
    db_finalize(&qc);
    fclose(f);
  }

  /* Step 1:  Generate "blob" records for every artifact that is part
  ** of a check-in 
  */
  fossil_binary_mode(stdout);
  db_multi_exec("CREATE TEMP TABLE newblob(rid INTEGER KEY, srcid INTEGER)");
  db_multi_exec("CREATE INDEX newblob_src ON newblob(srcid)");
  db_multi_exec(
    "INSERT INTO newblob"
    " SELECT DISTINCT fid,"







|






|












|







 







|







102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
...
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
/*
** COMMAND: export
**
** Usage: %fossil export --git ?OPTIONS? ?REPOSITORY?
**
** Write an export of all check-ins to standard output.  The export is
** written in the git-fast-export file format assuming the --git option is
** provided.  The git-fast-export format is currently the only VCS
** interchange format supported, though other formats may be added in
** the future.
**
** Run this command within a checkout.  Or use the -R or --repository
** option to specify a Fossil repository to be exported.
**
** Only check-ins are exported using --git.  Git does not support tickets
** or wiki or events or attachments, so none of those are exported.
**
** If the "--import-marks FILE" option is used, it contains a list of
** rids to skip.
**
** If the "--export-marks FILE" option is used, the rid of all commits and
** blobs written on exit for use with "--import-marks" on the next run.
**
** Options:
**   --export-marks FILE          export rids of exported data to FILE
**   --import-marks FILE          read rids of data to ignore from FILE
**   --repository|-R REPOSITORY   export the given REPOSITORY
**
** See also: import
*/
void export_cmd(void){
  Stmt q, q2, q3;
  int i;
  Bag blobs, vers;
  const char *markfile_in;
................................................................................
    }
    db_finalize(&qb);
    db_finalize(&qc);
    fclose(f);
  }

  /* Step 1:  Generate "blob" records for every artifact that is part
  ** of a check-in
  */
  fossil_binary_mode(stdout);
  db_multi_exec("CREATE TEMP TABLE newblob(rid INTEGER KEY, srcid INTEGER)");
  db_multi_exec("CREATE INDEX newblob_src ON newblob(srcid)");
  db_multi_exec(
    "INSERT INTO newblob"
    " SELECT DISTINCT fid,"

Changes to src/file.c.

1260
1261
1262
1263
1264
1265
1266



















1267
1268
1269
1270
1271
1272
1273
  fossil_unicode_free(uName);
#else
  char *zValue = getenv(zName);
#endif
  if( zValue ) zValue = fossil_filename_to_utf8(zValue);
  return zValue;
}




















/*
** Like fopen() but always takes a UTF8 argument.
*/
FILE *fossil_fopen(const char *zName, const char *zMode){
#ifdef _WIN32
  wchar_t *uMode = fossil_utf8_to_unicode(zMode);







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
  fossil_unicode_free(uName);
#else
  char *zValue = getenv(zName);
#endif
  if( zValue ) zValue = fossil_filename_to_utf8(zValue);
  return zValue;
}

/*
** Sets the value of an environment variable as UTF8.
*/
int fossil_setenv(const char *zName, const char *zValue){
  int rc;
  char *zString = mprintf("%s=%s", zName, zValue);
#ifdef _WIN32
  wchar_t *uString = fossil_utf8_to_unicode(zString);
  rc = _wputenv(uString);
  fossil_unicode_free(uString);
  fossil_free(zString);
#else
  rc = putenv(zString);
  /* NOTE: Cannot free the string on POSIX. */
  /* fossil_free(zString); */
#endif
  return rc;
}

/*
** Like fopen() but always takes a UTF8 argument.
*/
FILE *fossil_fopen(const char *zName, const char *zMode){
#ifdef _WIN32
  wchar_t *uMode = fossil_utf8_to_unicode(zMode);

Changes to src/finfo.c.

248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
...
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299

300
301
302
303
304
305
306
307

308
309
310
311
312
313
314
315
316
317
318
319
320
321














322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357

358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374

375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399

400

401
402
403
404

405
406
407
408
409
410
411
...
420
421
422
423
424
425
426



















427
428
429
430
431
432
433
434
435
436
437
438
439
440
...
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460




461
462
463
464
465
466
467
...
471
472
473
474
475
476
477



478
479
480

481
482
483
484
485
486
487
488
489
490
491
492
493
494
495

496
497

498


499
500
501
502
503
504
505
506
507
508
509
510
511
512
void cat_cmd(void){
  int i;
  int rc;
  Blob content, fname;
  const char *zRev;
  db_find_and_open_repository(0, 0);
  zRev = find_option("r","r",1);
  
  /* We should be done with options.. */
  verify_all_options();

  for(i=2; i<g.argc; i++){
    file_tree_name(g.argv[i], &fname, 1);
    blob_zero(&content);
    rc = historical_version_of_file(zRev, blob_str(&fname), &content, 0,0,0,0);
................................................................................
**
**    a=DATE     Only show changes after DATE
**    b=DATE     Only show changes before DATE
**    n=NUM      Show the first NUM changes only
**    brbg       Background color by branch name
**    ubg        Background color by user name
**    ci=UUID    Ancestors of a particular check-in
**    fco=BOOL   Show only first occurrence of each version if true (default)
*/
void finfo_page(void){
  Stmt q;
  const char *zFilename;
  char zPrevDate[20];
  const char *zA;
  const char *zB;
  int n;
  int baseCheckin;


  Blob title;
  Blob sql;
  HQuery url;
  GraphContext *pGraph;
  int brBg = P("brbg")!=0;
  int uBg = P("ubg")!=0;
  int firstChngOnly = atoi(PD("fco","1"))!=0;
  int fDebug = atoi(PD("debug","0"));


  login_check_credentials();
  if( !g.perm.Read ){ login_needed(); return; }
  style_header("File History");
  login_anonymous_available();
  url_initialize(&url, "finfo");
  if( brBg ) url_add_parameter(&url, "brbg", 0);
  if( uBg ) url_add_parameter(&url, "ubg", 0);
  baseCheckin = name_to_rid_www("ci");
  if( baseCheckin ) firstChngOnly = 1;
  if( !firstChngOnly ) url_add_parameter(&url, "fco", "0");

  zPrevDate[0] = 0;
  zFilename = PD("name","");














  url_add_parameter(&url, "name", zFilename);
  blob_zero(&sql);
  blob_append_sql(&sql,
    "SELECT"
    " datetime(event.mtime%s),"                      /* Date of change */
    " coalesce(event.ecomment, event.comment),"      /* Check-in comment */
    " coalesce(event.euser, event.user),"            /* User who made chng */
    " mlink.pid,"                                    /* Parent file rid */
    " mlink.fid,"                                    /* File rid */
    " (SELECT uuid FROM blob WHERE rid=mlink.pid),"  /* Parent file uuid */
    " (SELECT uuid FROM blob WHERE rid=mlink.fid),"  /* Current file uuid */
    " (SELECT uuid FROM blob WHERE rid=mlink.mid),"  /* Check-in uuid */
    " event.bgcolor,"                                /* Background color */
    " (SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0"
                                " AND tagxref.rid=mlink.mid)," /* Tags */
    " mlink.mid,"                                    /* check-in ID */
    " mlink.pfnid",                                  /* Previous filename */
    timeline_utc(), TAG_BRANCH
  );
  if( firstChngOnly ){
#if 0
    blob_append_sql(&sql, ", min(event.mtime)");
#else
    blob_append_sql(&sql,
        ", min(CASE (SELECT value FROM tagxref"
                    " WHERE tagtype>0 AND tagid=%d"
                    "   AND tagxref.rid=mlink.mid)"
             " WHEN 'trunk' THEN event.mtime-10000 ELSE event.mtime END)",
    TAG_BRANCH);
#endif
  }
  blob_append_sql(&sql,
    "  FROM mlink, event"
    " WHERE mlink.fnid IN (SELECT fnid FROM filename WHERE name=%Q)"
    "   AND event.objid=mlink.mid",
    zFilename

  );
  if( baseCheckin ){
    compute_direct_ancestors(baseCheckin, 10000000);
    blob_append_sql(&sql,"  AND mlink.mid IN (SELECT rid FROM ancestor)");
  }
  if( (zA = P("a"))!=0 ){
    blob_append_sql(&sql, " AND event.mtime>=julianday('%q')", zA);
    url_add_parameter(&url, "a", zA);
  }
  if( (zB = P("b"))!=0 ){
    blob_append_sql(&sql, " AND event.mtime<=julianday('%q')", zB);
    url_add_parameter(&url, "b", zB);
  }
  if( firstChngOnly ){
    blob_append_sql(&sql, " GROUP BY mlink.fid");
  }
  blob_append_sql(&sql," ORDER BY event.mtime DESC /*sort*/");

  if( (n = atoi(PD("n","0")))>0 ){
    blob_append_sql(&sql, " LIMIT %d", n);
    url_add_parameter(&url, "n", P("n"));
  }
  if( baseCheckin==0 ){
    if( firstChngOnly ){
      style_submenu_element("Full", "Show all changes","%s",
                            url_render(&url, "fco", "0", 0, 0));
    }else{
      style_submenu_element("Simplified",
                            "Show only first use of a change","%s",
                            url_render(&url, "fco", 0, 0, 0));
    }
  }
  db_prepare(&q, "%s", blob_sql_text(&sql));
  if( P("showsql")!=0 ){
    @ <p>SQL: %h(blob_str(&sql))</p>
  }
  blob_reset(&sql);
  blob_zero(&title);
  if( baseCheckin ){
    char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", baseCheckin);
    char *zLink = href("%R/info/%s", zUuid);
    blob_appendf(&title, "Ancestors of file ");
    hyperlinked_path(zFilename, &title, zUuid, "tree", "");

    blob_appendf(&title, " from check-in %z%S</a>", zLink, zUuid);

    fossil_free(zUuid);
  }else{
    blob_appendf(&title, "History of files named ");
    hyperlinked_path(zFilename, &title, 0, "tree", "");

  }
  @ <h2>%b(&title)</h2>
  blob_reset(&title);
  pGraph = graph_init();
  @ <div id="canvas" style="position:relative;width:1px;height:1px;"
  @  onclick="clickOnGraph(event)"></div>
  @ <table id="timelineTable" class="timelineTable">
................................................................................
    const char *zCkin = db_column_text(&q,7);
    const char *zBgClr = db_column_text(&q, 8);
    const char *zBr = db_column_text(&q, 9);
    int fmid = db_column_int(&q, 10);
    int pfnid = db_column_int(&q, 11);
    int gidx;
    char zTime[10];



















    if( zBr==0 ) zBr = "trunk";
    if( uBg ){
      zBgClr = hash_color(zUser);
    }else if( brBg || zBgClr==0 || zBgClr[0]==0 ){
      zBgClr = strcmp(zBr,"trunk")==0 ? "" : hash_color(zBr);
    }
    gidx = graph_add_row(pGraph, frid, fpid>0 ? 1 : 0, &fpid, zBr, zBgClr,
                         zUuid, 0);
    if( strncmp(zDate, zPrevDate, 10) ){
      sqlite3_snprintf(sizeof(zPrevDate), zPrevDate, "%.10s", zDate);
      @ <tr><td>
      @   <div class="divider">%s(zPrevDate)</div>
      @ </td><td></td><td></td></tr>
    }
................................................................................
    @ <td class="timelineGraph"><div id="m%d(gidx)"></div></td>
    if( zBgClr && zBgClr[0] ){
      @ <td class="timelineTableCell" style="background-color: %h(zBgClr);">
    }else{
      @ <td class="timelineTableCell">
    }
    if( zUuid ){
      if( fpid==0 ){
        @ <b>Added</b>
      }else if( pfnid ){
        char *zPrevName = db_text(0, "SELECT name FROM filename WHERE fnid=%d",
                                  pfnid);
        @ <b>Renamed</b> from
        @ %z(href("%R/finfo?name=%t", zPrevName))%h(zPrevName)</a>
      }
      @ %z(href("%R/artifact/%s",zUuid))[%S(zUuid)]</a> part of check-in




    }else{
      char *zNewName;
      zNewName = db_text(0,
        "SELECT name FROM filename WHERE fnid = "
        "   (SELECT fnid FROM mlink"
        "     WHERE mid=%d"
        "       AND pfnid IN (SELECT fnid FROM filename WHERE name=%Q))",
................................................................................
        @ %z(href("%R/finfo?name=%t",zNewName))%h(zNewName)</a> by check-in
        fossil_free(zNewName);
      }else{
        @ <b>Deleted</b> by check-in
      }
    }
    hyperlink_to_uuid(zCkin);



    @ %W(zCom) (user:
    hyperlink_to_user(zUser, zDate, "");
    @ branch: %h(zBr))

    if( g.perm.Hyperlink && zUuid ){
      const char *z = zFilename;
      @ %z(href("%R/annotate?filename=%h&checkin=%s",z,zCkin))
      @ [annotate]</a>
      @ %z(href("%R/blame?filename=%h&checkin=%s",z,zCkin))
      @ [blame]</a>
      @ %z(href("%R/timeline?n=200&uf=%s",zUuid))[checkins&nbsp;using]</a>
      if( fpid ){
        @ %z(href("%R/fdiff?sbs=1&v1=%s&v2=%s",zPUuid,zUuid))[diff]</a>
      }
    }
    if( fDebug & FINFO_DEBUG_MLINK ){
      int srcid = db_int(0, "SELECT srcid FROM delta WHERE rid=%d", frid);
      int sz = db_int(0, "SELECT length(content) FROM blob WHERE rid=%d", frid);
      @ <br>fid=%d(frid) pid=%d(fpid) mid=%d(fmid) sz=%d(sz)

      if( srcid ){
        @ srcid=%d(srcid)

      }


    }
    tag_private_status(frid);
    @ </td></tr>
  }
  db_finalize(&q);
  if( pGraph ){
    graph_finish(pGraph, 0);
    if( pGraph->nErr ){
      graph_free(pGraph);
      pGraph = 0;
    }else{
      int w = (pGraph->mxRail+1)*pGraph->iRailPitch + 10;
      @ <tr><td></td><td>
      @ <div id="grbtm" style="width:%d(w)px;"></div>







|







 







<









|
>






<

>









<
<
<


>
>
>
>
>
>
>
>
>
>
>
>
>
>




|









|

|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<

|

<
>

<
<
<
<








|
|
<
|
>




<
<
<
<
<
<
<
<
<
<











>

>




>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>






|







 







|







|
>
>
>
>







 







>
>
>


<
>












|
<
|
>
|
|
>
|
>
>






|







248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
...
282
283
284
285
286
287
288

289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305

306
307
308
309
310
311
312
313
314
315
316



317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349















350
351
352

353
354




355
356
357
358
359
360
361
362
363
364

365
366
367
368
369
370










371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
...
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
...
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
...
479
480
481
482
483
484
485
486
487
488
489
490

491
492
493
494
495
496
497
498
499
500
501
502
503
504

505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
void cat_cmd(void){
  int i;
  int rc;
  Blob content, fname;
  const char *zRev;
  db_find_and_open_repository(0, 0);
  zRev = find_option("r","r",1);

  /* We should be done with options.. */
  verify_all_options();

  for(i=2; i<g.argc; i++){
    file_tree_name(g.argv[i], &fname, 1);
    blob_zero(&content);
    rc = historical_version_of_file(zRev, blob_str(&fname), &content, 0,0,0,0);
................................................................................
**
**    a=DATE     Only show changes after DATE
**    b=DATE     Only show changes before DATE
**    n=NUM      Show the first NUM changes only
**    brbg       Background color by branch name
**    ubg        Background color by user name
**    ci=UUID    Ancestors of a particular check-in

*/
void finfo_page(void){
  Stmt q;
  const char *zFilename;
  char zPrevDate[20];
  const char *zA;
  const char *zB;
  int n;
  int baseCheckin;
  int fnid;
  Bag ancestor;
  Blob title;
  Blob sql;
  HQuery url;
  GraphContext *pGraph;
  int brBg = P("brbg")!=0;
  int uBg = P("ubg")!=0;

  int fDebug = atoi(PD("debug","0"));
  int fShowId = P("showid")!=0;

  login_check_credentials();
  if( !g.perm.Read ){ login_needed(); return; }
  style_header("File History");
  login_anonymous_available();
  url_initialize(&url, "finfo");
  if( brBg ) url_add_parameter(&url, "brbg", 0);
  if( uBg ) url_add_parameter(&url, "ubg", 0);
  baseCheckin = name_to_rid_www("ci");



  zPrevDate[0] = 0;
  zFilename = PD("name","");
  fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", zFilename);
  if( fnid==0 ){
    @ No such file: %h(zFilename)
    style_footer();
    return;
  }
  if( baseCheckin ){
    int baseFid = db_int(0,
      "SELECT fid FROM mlink WHERE fnid=%d AND mid=%d",
      fnid, baseCheckin
    );
    bag_init(&ancestor);
    if( baseFid ) bag_insert(&ancestor, baseFid);
  }
  url_add_parameter(&url, "name", zFilename);
  blob_zero(&sql);
  blob_append_sql(&sql,
    "SELECT"
    " datetime(min(event.mtime)%s),"                 /* Date of change */
    " coalesce(event.ecomment, event.comment),"      /* Check-in comment */
    " coalesce(event.euser, event.user),"            /* User who made chng */
    " mlink.pid,"                                    /* Parent file rid */
    " mlink.fid,"                                    /* File rid */
    " (SELECT uuid FROM blob WHERE rid=mlink.pid),"  /* Parent file uuid */
    " (SELECT uuid FROM blob WHERE rid=mlink.fid),"  /* Current file uuid */
    " (SELECT uuid FROM blob WHERE rid=mlink.mid),"  /* Check-in uuid */
    " event.bgcolor,"                                /* Background color */
    " (SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0"
                                " AND tagxref.rid=mlink.mid)," /* Branchname */
    " mlink.mid,"                                    /* check-in ID */
    " mlink.pfnid"                                   /* Previous filename */















    "  FROM mlink, event"
    " WHERE mlink.fnid=%d"
    "   AND event.objid=mlink.mid",

    timeline_utc(), TAG_BRANCH, fnid
  );




  if( (zA = P("a"))!=0 ){
    blob_append_sql(&sql, " AND event.mtime>=julianday('%q')", zA);
    url_add_parameter(&url, "a", zA);
  }
  if( (zB = P("b"))!=0 ){
    blob_append_sql(&sql, " AND event.mtime<=julianday('%q')", zB);
    url_add_parameter(&url, "b", zB);
  }
  blob_append_sql(&sql,
    " GROUP BY mlink.fid"

    " ORDER BY event.mtime DESC /*sort*/"
  );
  if( (n = atoi(PD("n","0")))>0 ){
    blob_append_sql(&sql, " LIMIT %d", n);
    url_add_parameter(&url, "n", P("n"));
  }










  db_prepare(&q, "%s", blob_sql_text(&sql));
  if( P("showsql")!=0 ){
    @ <p>SQL: %h(blob_str(&sql))</p>
  }
  blob_reset(&sql);
  blob_zero(&title);
  if( baseCheckin ){
    char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", baseCheckin);
    char *zLink = href("%R/info/%s", zUuid);
    blob_appendf(&title, "Ancestors of file ");
    hyperlinked_path(zFilename, &title, zUuid, "tree", "");
    if( fShowId ) blob_appendf(&title, " (%d)", fnid);
    blob_appendf(&title, " from check-in %z%S</a>", zLink, zUuid);
    if( fShowId ) blob_appendf(&title, " (%d)", baseCheckin);
    fossil_free(zUuid);
  }else{
    blob_appendf(&title, "History of files named ");
    hyperlinked_path(zFilename, &title, 0, "tree", "");
    if( fShowId ) blob_appendf(&title, " (%d)", fnid);
  }
  @ <h2>%b(&title)</h2>
  blob_reset(&title);
  pGraph = graph_init();
  @ <div id="canvas" style="position:relative;width:1px;height:1px;"
  @  onclick="clickOnGraph(event)"></div>
  @ <table id="timelineTable" class="timelineTable">
................................................................................
    const char *zCkin = db_column_text(&q,7);
    const char *zBgClr = db_column_text(&q, 8);
    const char *zBr = db_column_text(&q, 9);
    int fmid = db_column_int(&q, 10);
    int pfnid = db_column_int(&q, 11);
    int gidx;
    char zTime[10];
    int nParent = 0;
    int aParent[GR_MAX_RAIL];
    static Stmt qparent;

    if( baseCheckin && frid && !bag_find(&ancestor, frid) ) continue;
    db_static_prepare(&qparent,
      "SELECT DISTINCT pid FROM mlink"
      " WHERE fid=:fid AND mid=:mid AND pid>0 AND fnid=:fnid"
      " ORDER BY isaux /*sort*/"
    );
    db_bind_int(&qparent, ":fid", frid);
    db_bind_int(&qparent, ":mid", fmid);
    db_bind_int(&qparent, ":fnid", fnid);
    while( db_step(&qparent)==SQLITE_ROW && nParent<ArraySize(aParent) ){
      aParent[nParent] = db_column_int(&qparent, 0);
      if( baseCheckin ) bag_insert(&ancestor, aParent[nParent]);
      nParent++;
    }
    db_reset(&qparent);
    if( zBr==0 ) zBr = "trunk";
    if( uBg ){
      zBgClr = hash_color(zUser);
    }else if( brBg || zBgClr==0 || zBgClr[0]==0 ){
      zBgClr = strcmp(zBr,"trunk")==0 ? "" : hash_color(zBr);
    }
    gidx = graph_add_row(pGraph, frid, nParent, aParent, zBr, zBgClr,
                         zUuid, 0);
    if( strncmp(zDate, zPrevDate, 10) ){
      sqlite3_snprintf(sizeof(zPrevDate), zPrevDate, "%.10s", zDate);
      @ <tr><td>
      @   <div class="divider">%s(zPrevDate)</div>
      @ </td><td></td><td></td></tr>
    }
................................................................................
    @ <td class="timelineGraph"><div id="m%d(gidx)"></div></td>
    if( zBgClr && zBgClr[0] ){
      @ <td class="timelineTableCell" style="background-color: %h(zBgClr);">
    }else{
      @ <td class="timelineTableCell">
    }
    if( zUuid ){
      if( nParent==0 ){
        @ <b>Added</b>
      }else if( pfnid ){
        char *zPrevName = db_text(0, "SELECT name FROM filename WHERE fnid=%d",
                                  pfnid);
        @ <b>Renamed</b> from
        @ %z(href("%R/finfo?name=%t", zPrevName))%h(zPrevName)</a>
      }
      @ %z(href("%R/artifact/%s",zUuid))[%S(zUuid)]</a>
      if( fShowId ){
        @ (%d(frid))
      }
      @ part of check-in
    }else{
      char *zNewName;
      zNewName = db_text(0,
        "SELECT name FROM filename WHERE fnid = "
        "   (SELECT fnid FROM mlink"
        "     WHERE mid=%d"
        "       AND pfnid IN (SELECT fnid FROM filename WHERE name=%Q))",
................................................................................
        @ %z(href("%R/finfo?name=%t",zNewName))%h(zNewName)</a> by check-in
        fossil_free(zNewName);
      }else{
        @ <b>Deleted</b> by check-in
      }
    }
    hyperlink_to_uuid(zCkin);
    if( fShowId ){
      @ (%d(fmid))
    }
    @ %W(zCom) (user:
    hyperlink_to_user(zUser, zDate, "");

    @ branch: %z(href("%R/timeline?t=%T&n=200",zBr))%h(zBr)</a>
    if( g.perm.Hyperlink && zUuid ){
      const char *z = zFilename;
      @ %z(href("%R/annotate?filename=%h&checkin=%s",z,zCkin))
      @ [annotate]</a>
      @ %z(href("%R/blame?filename=%h&checkin=%s",z,zCkin))
      @ [blame]</a>
      @ %z(href("%R/timeline?n=200&uf=%s",zUuid))[checkins&nbsp;using]</a>
      if( fpid ){
        @ %z(href("%R/fdiff?sbs=1&v1=%s&v2=%s",zPUuid,zUuid))[diff]</a>
      }
    }
    if( fDebug & FINFO_DEBUG_MLINK ){
      int ii;

      @ <br>fid=%d(frid) pid=%d(fpid) mid=%d(fmid)
      if( nParent>0 ){
        @ parents=%d(aParent[0])
        for(ii=1; ii<nParent; ii++){
          @ %d(aParent[ii])
        }
      }
      @ %z(href("%R/finfo?name=%T&ci=%s&debug=1",zFilename,zCkin))[ancestry]</a>
    }
    tag_private_status(frid);
    @ </td></tr>
  }
  db_finalize(&q);
  if( pGraph ){
    graph_finish(pGraph, 1);
    if( pGraph->nErr ){
      graph_free(pGraph);
      pGraph = 0;
    }else{
      int w = (pGraph->mxRail+1)*pGraph->iRailPitch + 10;
      @ <tr><td></td><td>
      @ <div id="grbtm" style="width:%d(w)px;"></div>

Changes to src/foci.c.

15
16
17
18
19
20
21




















22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
...
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
...
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
**
*******************************************************************************
**
** This routine implements an SQLite virtual table that gives all of the
** files associated with a single checkin.
**
** The filename "foci" is short for "Files Of CheckIn".




















*/
#include "config.h"
#include "foci.h"
#include <assert.h>

/*
** The schema for the virtual table:
*/
static const char zFociSchema[] = 
@ CREATE TABLE files_of_checkin(
@  checkinID    INTEGER,    -- RID for the checkin manifest
@  filename     TEXT,       -- Name of a file
@  uuid         TEXT,       -- SHA1 hash of the file
@  previousName TEXT,       -- Name of the file in previous checkin
@  prem         TEXT        -- Permissions on the file
@ );
;

#if INTERFACE
/*
** The subclasses of sqlite3_vtab  and sqlite3_vtab_cursor tables
** that implement the files_of_checkin virtual table.
................................................................................

static int fociEof(sqlite3_vtab_cursor *pCursor){
  FociCursor *pCsr = (FociCursor *)pCursor;
  return pCsr->pFile==0;
}

static int fociFilter(
  sqlite3_vtab_cursor *pCursor, 
  int idxNum, const char *idxStr,
  int argc, sqlite3_value **argv
){
  FociCursor *pCur = (FociCursor *)pCursor;
  manifest_destroy(pCur->pMan);
  if( idxNum ){
    pCur->pMan = manifest_get(sqlite3_value_int(argv[0]), CFTYPE_MANIFEST, 0);
................................................................................
    pCur->pMan = 0;
    pCur->iFile = 0;
  }
  return SQLITE_OK;
}

static int fociColumn(
  sqlite3_vtab_cursor *pCursor, 
  sqlite3_context *ctx, 
  int i
){
  FociCursor *pCsr = (FociCursor *)pCursor;
  switch( i ){
    case 0:            /* checkinID */
      sqlite3_result_int(ctx, pCsr->pMan->rid);
      break;







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>








|





|







 







|







 







|
|







15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
...
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
...
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
**
*******************************************************************************
**
** This routine implements an SQLite virtual table that gives all of the
** files associated with a single checkin.
**
** The filename "foci" is short for "Files Of CheckIn".
**
** Usage example:
**
**    CREATE VIRTUAL TABLE temp.foci USING files_of_checkin;
**                      -- ^^^^--- important!
**    SELECT * FROM foci WHERE checkinID=symbolic_name_to_rid('trunk');
**
** The symbolic_name_to_rid('trunk') function finds the BLOB.RID value 
** corresponding to the 'trunk' tag.  Then the files_of_checkin virtual table
** decodes the manifest defined by that BLOB and returns all files described
** by that manifest.  The "schema" for the temp.foci table is:
**
**     CREATE TABLE files_of_checkin(
**       checkinID    INTEGER,    -- RID for the checkin manifest
**       filename     TEXT,       -- Name of a file
**       uuid         TEXT,       -- SHA1 hash of the file
**       previousName TEXT,       -- Name of the file in previous checkin
**       perm         TEXT        -- Permissions on the file
**     );
**
*/
#include "config.h"
#include "foci.h"
#include <assert.h>

/*
** The schema for the virtual table:
*/
static const char zFociSchema[] =
@ CREATE TABLE files_of_checkin(
@  checkinID    INTEGER,    -- RID for the checkin manifest
@  filename     TEXT,       -- Name of a file
@  uuid         TEXT,       -- SHA1 hash of the file
@  previousName TEXT,       -- Name of the file in previous checkin
@  perm         TEXT        -- Permissions on the file
@ );
;

#if INTERFACE
/*
** The subclasses of sqlite3_vtab  and sqlite3_vtab_cursor tables
** that implement the files_of_checkin virtual table.
................................................................................

static int fociEof(sqlite3_vtab_cursor *pCursor){
  FociCursor *pCsr = (FociCursor *)pCursor;
  return pCsr->pFile==0;
}

static int fociFilter(
  sqlite3_vtab_cursor *pCursor,
  int idxNum, const char *idxStr,
  int argc, sqlite3_value **argv
){
  FociCursor *pCur = (FociCursor *)pCursor;
  manifest_destroy(pCur->pMan);
  if( idxNum ){
    pCur->pMan = manifest_get(sqlite3_value_int(argv[0]), CFTYPE_MANIFEST, 0);
................................................................................
    pCur->pMan = 0;
    pCur->iFile = 0;
  }
  return SQLITE_OK;
}

static int fociColumn(
  sqlite3_vtab_cursor *pCursor,
  sqlite3_context *ctx,
  int i
){
  FociCursor *pCsr = (FociCursor *)pCursor;
  switch( i ){
    case 0:            /* checkinID */
      sqlite3_result_int(ctx, pCsr->pMan->rid);
      break;

Changes to src/fusefs.c.

12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
...
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
...
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
...
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
** Author contact information:
**   drh@sqlite.org
**   http://www.hwaci.com/drh/
**
*******************************************************************************
**
** This module implements the userspace side of a Fuse Filesystem that
** contains all check-ins for a fossil repository.  
**
** This module is a mostly a no-op unless compiled with -DFOSSIL_HAVE_FUSEFS.
** The FOSSIL_HAVE_FUSEFS should be omitted on systems that lack support for
** the Fuse Filesystem, of course.
*/
#include "config.h"
#include <stdio.h>
................................................................................
  int nPrev = 0;
  char *z;
  int cnt = 0;
  n = fusefs_parse_path(zPath);
  if( n==0 ){
    filler(buf, ".", NULL, 0);
    filler(buf, "..", NULL, 0);
    filler(buf, "checkins", NULL, 0);    
    return 0;
  }
  if( strcmp(fusefs.az[0],"checkins")!=0 ) return -ENOENT;
  if( n==1 ) return -ENOENT;
  rid = fusefs_name_to_rid(fusefs.az[1]);
  if( rid<=0 ) return -ENOENT;
  fusefs_load_rid(rid, fusefs.az[1]);
................................................................................
  content_get(rid, &fusefs.content);
  if( offset>blob_size(&fusefs.content) ) return 0;
  if( offset+size>blob_size(&fusefs.content) ){
    size = blob_size(&fusefs.content) - offset;
  }
  memcpy(buf, blob_buffer(&fusefs.content)+offset, size);
  return size;
}  

static struct fuse_operations fusefs_methods = {
  .getattr = fusefs_getattr,
  .readdir = fusefs_readdir,
  .read    = fusefs_read,
};
#endif /* FOSSIL_HAVE_FUSEFS */
................................................................................
**
** Usage: %fossil fusefs [--debug] DIRECTORY
**
** This command uses the Fuse Filesystem to mount a directory at
** DIRECTORY that contains the content of all check-ins in the
** repository.  The names of files are DIRECTORY/checkins/VERSION/PATH
** where DIRECTORY is the root of the mount, VERSION is any valid
** check-in name (examples: "trunk" or "tip" or a tag or any unique 
** prefix of a SHA1 hash, etc) and PATH is the pathname of the file
** in the checkin.  If DIRECTORY does not exist, then an attempt is
** made to create it.
**
** The DIRECTORY/checkins directory is not searchable so one cannot
** do "ls DIRECTORY/checkins" to get a listing of all possible checkin
** names.  There are countless variations on checkin names and it is







|







 







|







 







|







 







|







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
...
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
...
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
...
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
** Author contact information:
**   drh@sqlite.org
**   http://www.hwaci.com/drh/
**
*******************************************************************************
**
** This module implements the userspace side of a Fuse Filesystem that
** contains all check-ins for a fossil repository.
**
** This module is a mostly a no-op unless compiled with -DFOSSIL_HAVE_FUSEFS.
** The FOSSIL_HAVE_FUSEFS should be omitted on systems that lack support for
** the Fuse Filesystem, of course.
*/
#include "config.h"
#include <stdio.h>
................................................................................
  int nPrev = 0;
  char *z;
  int cnt = 0;
  n = fusefs_parse_path(zPath);
  if( n==0 ){
    filler(buf, ".", NULL, 0);
    filler(buf, "..", NULL, 0);
    filler(buf, "checkins", NULL, 0);
    return 0;
  }
  if( strcmp(fusefs.az[0],"checkins")!=0 ) return -ENOENT;
  if( n==1 ) return -ENOENT;
  rid = fusefs_name_to_rid(fusefs.az[1]);
  if( rid<=0 ) return -ENOENT;
  fusefs_load_rid(rid, fusefs.az[1]);
................................................................................
  content_get(rid, &fusefs.content);
  if( offset>blob_size(&fusefs.content) ) return 0;
  if( offset+size>blob_size(&fusefs.content) ){
    size = blob_size(&fusefs.content) - offset;
  }
  memcpy(buf, blob_buffer(&fusefs.content)+offset, size);
  return size;
}

static struct fuse_operations fusefs_methods = {
  .getattr = fusefs_getattr,
  .readdir = fusefs_readdir,
  .read    = fusefs_read,
};
#endif /* FOSSIL_HAVE_FUSEFS */
................................................................................
**
** Usage: %fossil fusefs [--debug] DIRECTORY
**
** This command uses the Fuse Filesystem to mount a directory at
** DIRECTORY that contains the content of all check-ins in the
** repository.  The names of files are DIRECTORY/checkins/VERSION/PATH
** where DIRECTORY is the root of the mount, VERSION is any valid
** check-in name (examples: "trunk" or "tip" or a tag or any unique
** prefix of a SHA1 hash, etc) and PATH is the pathname of the file
** in the checkin.  If DIRECTORY does not exist, then an attempt is
** made to create it.
**
** The DIRECTORY/checkins directory is not searchable so one cannot
** do "ls DIRECTORY/checkins" to get a listing of all possible checkin
** names.  There are countless variations on checkin names and it is

Changes to src/glob.c.

136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
    if( z[i]==0 ) break;
    z[i] = 0;
    z += i+1;
  }
  return p;
}

/*
** Return non-zero if string z matches glob pattern zGlob and zero if the
** pattern does not match.
**
** Globbing rules:
**
**      '*'       Matches any sequence of zero or more characters.
**
**      '?'       Matches exactly one character.
**
**     [...]      Matches one character from the enclosed list of
**                characters.
**
**     [^...]     Matches one character not in the enclosed list.
*/
int strglob(const char *zGlob, const char *z){
  return sqlite3_strglob(zGlob, z)==0;
}

/*
** Return true (non-zero) if zString matches any of the patterns in
** the Glob.  The value returned is actually a 1-based index of the pattern
** that matched.  Return 0 if none of the patterns match zString.
**
** A NULL glob matches nothing.
*/







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







136
137
138
139
140
141
142



















143
144
145
146
147
148
149
    if( z[i]==0 ) break;
    z[i] = 0;
    z += i+1;
  }
  return p;
}




















/*
** Return true (non-zero) if zString matches any of the patterns in
** the Glob.  The value returned is actually a 1-based index of the pattern
** that matched.  Return 0 if none of the patterns match zString.
**
** A NULL glob matches nothing.
*/

Changes to src/graph.c.

36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
...
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
...
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
...
377
378
379
380
381
382
383

















384




385
386
387
388
389
390
391
392
...
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
  int *aParent;               /* Array of parents.  0 element is primary .*/
  char *zBranch;              /* Branch name */
  char *zBgClr;               /* Background Color */
  char zUuid[41];             /* Check-in for file ID */

  GraphRow *pNext;            /* Next row down in the list of all rows */
  GraphRow *pPrev;            /* Previous row */
  
  int idx;                    /* Row index.  First is 1.  0 used for "none" */
  int idxTop;                 /* Direct descendent highest up on the graph */
  GraphRow *pChild;           /* Child immediately above this node */
  u8 isDup;                   /* True if this is duplicate of a prior entry */
  u8 isLeaf;                  /* True if this is a leaf node */
  u8 timeWarp;                /* Child is earlier in time */
  u8 bDescender;              /* True if riser from bottom of graph to here. */
................................................................................

/*
** Return the canonical pointer for a given branch name.
** Multiple calls to this routine with equivalent strings
** will return the same pointer.
**
** The returned value is a pointer to a (readonly) string that
** has the useful property that strings can be checked for 
** equality by comparing pointers.
**
** Note: also used for background color names.
*/
static char *persistBranchName(GraphContext *p, const char *zBranch){
  int i;
  for(i=0; i<p->nBranch; i++){
................................................................................
  p->nRow++;
  pRow->idx = pRow->idxTop = p->nRow;
  return pRow->idx;
}

/*
** Return the index of a rail currently not in use for any row between
** top and bottom, inclusive.  
*/
static int findFreeRail(
  GraphContext *p,         /* The graph context */
  int top, int btm,        /* Span of rows for which the rail is needed */
  u64 inUseMask,           /* Mask or rails already in use */
  int iNearto              /* Find rail nearest to this rail */
){
................................................................................
          pRow->aParent[i] = pRow->aParent[--pRow->nParent];
          i--;
        }
      }
    }
  }























  /* Find the pChild pointer for each node. 
  **
  ** The pChild points to the node directly above on the same rail.
  ** The pChild must be in the same branch.  Leaf nodes have a NULL
  ** pChild.
  **
  ** In the case of a fork, choose the pChild that results in the
  ** longest rail.
................................................................................
        createMergeRiser(p, pDesc, pRow);
        if( p->mxRail>=GR_MAX_RAIL ) return;
      }
    }
  }

  /*
  ** Insert merge rails from primaries to duplicates. 
  */
  if( hasDup ){
    int dupRail;
    int mxRail;
    find_max_rail(p);
    mxRail = p->mxRail;
    dupRail = mxRail+1;







|







 







|







 







|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
|







 







|







36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
...
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
...
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
...
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
...
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
  int *aParent;               /* Array of parents.  0 element is primary .*/
  char *zBranch;              /* Branch name */
  char *zBgClr;               /* Background Color */
  char zUuid[41];             /* Check-in for file ID */

  GraphRow *pNext;            /* Next row down in the list of all rows */
  GraphRow *pPrev;            /* Previous row */

  int idx;                    /* Row index.  First is 1.  0 used for "none" */
  int idxTop;                 /* Direct descendent highest up on the graph */
  GraphRow *pChild;           /* Child immediately above this node */
  u8 isDup;                   /* True if this is duplicate of a prior entry */
  u8 isLeaf;                  /* True if this is a leaf node */
  u8 timeWarp;                /* Child is earlier in time */
  u8 bDescender;              /* True if riser from bottom of graph to here. */
................................................................................

/*
** Return the canonical pointer for a given branch name.
** Multiple calls to this routine with equivalent strings
** will return the same pointer.
**
** The returned value is a pointer to a (readonly) string that
** has the useful property that strings can be checked for
** equality by comparing pointers.
**
** Note: also used for background color names.
*/
static char *persistBranchName(GraphContext *p, const char *zBranch){
  int i;
  for(i=0; i<p->nBranch; i++){
................................................................................
  p->nRow++;
  pRow->idx = pRow->idxTop = p->nRow;
  return pRow->idx;
}

/*
** Return the index of a rail currently not in use for any row between
** top and bottom, inclusive.
*/
static int findFreeRail(
  GraphContext *p,         /* The graph context */
  int top, int btm,        /* Span of rows for which the rail is needed */
  u64 inUseMask,           /* Mask or rails already in use */
  int iNearto              /* Find rail nearest to this rail */
){
................................................................................
          pRow->aParent[i] = pRow->aParent[--pRow->nParent];
          i--;
        }
      }
    }
  }

  /* If the primary parent is in a different branch, but there are
  ** other parents in the same branch, reorder the parents to make
  ** the parent from the same branch the primary parent.
  */
  for(pRow=p->pFirst; pRow; pRow=pRow->pNext){
    if( pRow->isDup ) continue;
    if( pRow->nParent<2 ) continue;                    /* Not a fork */
    pParent = hashFind(p, pRow->aParent[0]);
    if( pParent==0 ) continue;                         /* Parent off-screen */
    if( pParent->zBranch==pRow->zBranch ) continue;    /* Same branch */
    for(i=1; i<pRow->nParent; i++){
      pParent = hashFind(p, pRow->aParent[i]);
      if( pParent && pParent->zBranch==pRow->zBranch ){
        int t = pRow->aParent[0];
        pRow->aParent[0] = pRow->aParent[i];
        pRow->aParent[i] = t;
        break;
      }
    }
  }


  /* Find the pChild pointer for each node.
  **
  ** The pChild points to the node directly above on the same rail.
  ** The pChild must be in the same branch.  Leaf nodes have a NULL
  ** pChild.
  **
  ** In the case of a fork, choose the pChild that results in the
  ** longest rail.
................................................................................
        createMergeRiser(p, pDesc, pRow);
        if( p->mxRail>=GR_MAX_RAIL ) return;
      }
    }
  }

  /*
  ** Insert merge rails from primaries to duplicates.
  */
  if( hasDup ){
    int dupRail;
    int mxRail;
    find_max_rail(p);
    mxRail = p->mxRail;
    dupRail = mxRail+1;

Changes to src/http.c.

153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
...
203
204
205
206
207
208
209

210
211
212
213
214
215
216
217
...
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
...
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
...
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
...
368
369
370
371
372
373
374
375




376
377
378
379
380
381
382
...
404
405
406
407
408
409
410
411
412
413
414
415
416
417
  prompt_user("Remember Basic Authorization credentials (Y/n)? ", &x);
  c = blob_str(&x)[0];
  blob_reset(&x);
  return ( c!='n' && c!='N' );
}

/*
** Get the HTTP Basic Authorization credentials from the user 
** when 401 is received.
*/
char *prompt_for_httpauth_creds(void){
  Blob x;
  char *zUser;
  char *zPw;
  char *zPrompt;
................................................................................
** in order to fill this structure appropriately.
*/
int http_exchange(Blob *pSend, Blob *pReply, int useLogin, int maxRedirect){
  Blob login;           /* The login card */
  Blob payload;         /* The complete payload including login card */
  Blob hdr;             /* The HTTP request header */
  int closeConnection;  /* True to close the connection when done */

  int iLength;          /* Length of the reply payload */
  int rc = 0;           /* Result code */
  int iHttpVersion;     /* Which version of HTTP protocol server uses */
  char *zLine;          /* A single line of the reply header */
  int i;                /* Loop counter */
  int isError = 0;      /* True if the reply is an error message */
  int isCompressed = 1; /* True if the reply is compressed */

................................................................................
  ** Send the request to the server.
  */
  transport_send(&g.url, &hdr);
  transport_send(&g.url, &payload);
  blob_reset(&hdr);
  blob_reset(&payload);
  transport_flip(&g.url);
  
  /*
  ** Read and interpret the server reply
  */
  closeConnection = 1;
  iLength = -1;
  while( (zLine = transport_receive_line(&g.url))!=0 && zLine[0]!=0 ){
    /* printf("[%s]\n", zLine); fflush(stdout); */
................................................................................
        goto write_err;
      }
      for(i=9; zLine[i] && zLine[i]==' '; i++){}
      if( zLine[i]==0 ){
        fossil_warning("malformed redirect: %s", zLine);
        goto write_err;
      }
      j = strlen(zLine) - 1; 
      while( j>4 && fossil_strcmp(&zLine[j-4],"/xfer")==0 ){
         j -= 4;
         zLine[j] = 0;
      }
      transport_close(&g.url);
      transport_global_shutdown(&g.url);
      fossil_print("redirect with status %d to %s\n", rc, &zLine[i]);
................................................................................
      fSeenHttpAuth = 0;
      if( g.zHttpAuth ) free(g.zHttpAuth);
      g.zHttpAuth = get_httpauth();
      return http_exchange(pSend, pReply, useLogin, maxRedirect);
    }else if( fossil_strnicmp(zLine, "content-type: ", 14)==0 ){
      if( fossil_strnicmp(&zLine[14], "application/x-fossil-debug", -1)==0 ){
        isCompressed = 0;
      }else if( fossil_strnicmp(&zLine[14], 
                          "application/x-fossil-uncompressed", -1)==0 ){
        isCompressed = 0;
      }else if( fossil_strnicmp(&zLine[14], "application/x-fossil", -1)!=0 ){
        isError = 1;
      }
    }
  }
................................................................................
  }

  /*
  ** Extract the reply payload that follows the header
  */
  blob_zero(pReply);
  blob_resize(pReply, iLength);
  iLength = transport_receive(&g.url, blob_buffer(pReply), iLength);




  blob_resize(pReply, iLength);
  if( isError ){
    char *z;
    int i, j;
    z = blob_str(pReply);
    for(i=j=0; z[i]; i++, j++){
      if( z[i]=='<' ){
................................................................................
  if( closeConnection ){
    transport_close(&g.url);
  }else{
    transport_rewind(&g.url);
  }
  return 0;

  /* 
  ** Jump to here if an error is seen.
  */
write_err:
  transport_close(&g.url);
  return 1;  
}







|







 







>
|







 







|







 







|







 







|







 







|
>
>
>
>







 







|




|

153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
...
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
...
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
...
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
...
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
...
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
...
409
410
411
412
413
414
415
416
417
418
419
420
421
422
  prompt_user("Remember Basic Authorization credentials (Y/n)? ", &x);
  c = blob_str(&x)[0];
  blob_reset(&x);
  return ( c!='n' && c!='N' );
}

/*
** Get the HTTP Basic Authorization credentials from the user
** when 401 is received.
*/
char *prompt_for_httpauth_creds(void){
  Blob x;
  char *zUser;
  char *zPw;
  char *zPrompt;
................................................................................
** in order to fill this structure appropriately.
*/
int http_exchange(Blob *pSend, Blob *pReply, int useLogin, int maxRedirect){
  Blob login;           /* The login card */
  Blob payload;         /* The complete payload including login card */
  Blob hdr;             /* The HTTP request header */
  int closeConnection;  /* True to close the connection when done */
  int iLength;          /* Expected length of the reply payload */
  int iRecvLen;         /* Received length of the reply payload */
  int rc = 0;           /* Result code */
  int iHttpVersion;     /* Which version of HTTP protocol server uses */
  char *zLine;          /* A single line of the reply header */
  int i;                /* Loop counter */
  int isError = 0;      /* True if the reply is an error message */
  int isCompressed = 1; /* True if the reply is compressed */

................................................................................
  ** Send the request to the server.
  */
  transport_send(&g.url, &hdr);
  transport_send(&g.url, &payload);
  blob_reset(&hdr);
  blob_reset(&payload);
  transport_flip(&g.url);

  /*
  ** Read and interpret the server reply
  */
  closeConnection = 1;
  iLength = -1;
  while( (zLine = transport_receive_line(&g.url))!=0 && zLine[0]!=0 ){
    /* printf("[%s]\n", zLine); fflush(stdout); */
................................................................................
        goto write_err;
      }
      for(i=9; zLine[i] && zLine[i]==' '; i++){}
      if( zLine[i]==0 ){
        fossil_warning("malformed redirect: %s", zLine);
        goto write_err;
      }
      j = strlen(zLine) - 1;
      while( j>4 && fossil_strcmp(&zLine[j-4],"/xfer")==0 ){
         j -= 4;
         zLine[j] = 0;
      }
      transport_close(&g.url);
      transport_global_shutdown(&g.url);
      fossil_print("redirect with status %d to %s\n", rc, &zLine[i]);
................................................................................
      fSeenHttpAuth = 0;
      if( g.zHttpAuth ) free(g.zHttpAuth);
      g.zHttpAuth = get_httpauth();
      return http_exchange(pSend, pReply, useLogin, maxRedirect);
    }else if( fossil_strnicmp(zLine, "content-type: ", 14)==0 ){
      if( fossil_strnicmp(&zLine[14], "application/x-fossil-debug", -1)==0 ){
        isCompressed = 0;
      }else if( fossil_strnicmp(&zLine[14],
                          "application/x-fossil-uncompressed", -1)==0 ){
        isCompressed = 0;
      }else if( fossil_strnicmp(&zLine[14], "application/x-fossil", -1)!=0 ){
        isError = 1;
      }
    }
  }
................................................................................
  }

  /*
  ** Extract the reply payload that follows the header
  */
  blob_zero(pReply);
  blob_resize(pReply, iLength);
  iRecvLen = transport_receive(&g.url, blob_buffer(pReply), iLength);
  if( iRecvLen != iLength ){
    fossil_warning("response truncated: got %d bytes of %d", iRecvLen, iLength);
    goto write_err;
  }
  blob_resize(pReply, iLength);
  if( isError ){
    char *z;
    int i, j;
    z = blob_str(pReply);
    for(i=j=0; z[i]; i++, j++){
      if( z[i]=='<' ){
................................................................................
  if( closeConnection ){
    transport_close(&g.url);
  }else{
    transport_rewind(&g.url);
  }
  return 0;

  /*
  ** Jump to here if an error is seen.
  */
write_err:
  transport_close(&g.url);
  return 1;
}

Changes to src/http_socket.c.

25
26
27
28
29
30
31



32
33
34
35
36
37
38
..
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
...
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
...
132
133
134
135
136
137
138
139





140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155

156
157
158






159
160





161
162
163
164
165
166

167
168
169
170
171
172
173

174
175
176
177
178
179
180
181



182
183
184
185
186
187
188
189
...
218
219
220
221
222
223
224
225
226









227
228
229
230
231


232
233
234
** Low-level sockets are abstracted out into this module because they
** are handled different on Unix and windows.
*/

#include "config.h"
#include "http_socket.h"
#if defined(_WIN32)



#  include <winsock2.h>
#  include <ws2tcpip.h>
#else
#  include <netinet/in.h>
#  include <arpa/inet.h>
#  include <sys/socket.h>
#  include <netdb.h>
................................................................................

/*
** There can only be a single socket connection open at a time.
** State information about that socket is stored in the following
** local variables:
*/
static int socketIsInit = 0;    /* True after global initialization */
static int addrIsInit = 0;      /* True once addr is initialized */
#if defined(_WIN32)
static WSADATA socketInfo;      /* Windows socket initialize data */
#endif
static int iSocket = -1;        /* The socket on which we talk to the server */
static char *socketErrMsg = 0;  /* Text of most recent socket error */


................................................................................
  if( socketIsInit ){
#if defined(_WIN32)
    WSACleanup();
#endif
    socket_clear_errmsg();
    socketIsInit = 0;
  }
  addrIsInit = 0;
}

/*
** Close the currently open socket.  If no socket is open, this routine
** is a no-op.
*/
void socket_close(void){
................................................................................
**
**    pUrlDAta->name       Name of the server.  Ex: www.fossil-scm.org
**    pUrlDAta->port       TCP/IP port to use.  Ex: 80
**
** Return the number of errors.
*/
int socket_open(UrlData *pUrlData){
  static struct sockaddr_in addr;  /* The server address */






  socket_global_init();
  if( !addrIsInit ){
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(pUrlData->port);
    *(int*)&addr.sin_addr = inet_addr(pUrlData->name);
    if( -1 == *(int*)&addr.sin_addr ){
#ifndef FOSSIL_STATIC_LINK
      struct hostent *pHost;
      pHost = gethostbyname(pUrlData->name);
      if( pHost!=0 ){
        memcpy(&addr.sin_addr,pHost->h_addr_list[0],pHost->h_length);
      }else
#endif
      {

        socket_set_errmsg("can't resolve host name: %s", pUrlData->name);
        return 1;
      }






    }
    addrIsInit = 1;






    /* Set the Global.zIpAddr variable to the server we are talking to.
    ** This is used to populate the ipaddr column of the rcvfrom table,
    ** if any files are received from the server.
    */
    g.zIpAddr = mprintf("%s", inet_ntoa(addr.sin_addr));

  }
  iSocket = socket(AF_INET,SOCK_STREAM,0);
  if( iSocket<0 ){
    socket_set_errmsg("cannot create a socket");
    return 1;
  }
  if( connect(iSocket,(struct sockaddr*)&addr,sizeof(addr))<0 ){

    socket_set_errmsg("cannot connect to host %s:%d", pUrlData->name,
                      pUrlData->port);
    socket_close();
    return 1;
  }
#if !defined(_WIN32)
  signal(SIGPIPE, SIG_IGN);
#endif



  return 0;
}

/*
** Send content out over the open socket connection.
*/
size_t socket_send(void *NotUsed, void *pContent, size_t N){
  size_t sent;
................................................................................
/*
** Attempt to resolve pUrlData->name to an IP address and setup g.zIpAddr
** so rcvfrom gets populated. For hostnames with more than one IP (or
** if overridden in ~/.ssh/config) the rcvfrom may not match the host
** to which we connect.
*/
void socket_ssh_resolve_addr(UrlData *pUrlData){
  struct hostent *pHost;        /* Used to make best effort for rcvfrom */
  struct sockaddr_in addr;










  memset(&addr, 0, sizeof(addr));
  pHost = gethostbyname(pUrlData->name);
  if( pHost!=0 ){
    memcpy(&addr.sin_addr,pHost->h_addr_list[0],pHost->h_length);


    g.zIpAddr = mprintf("%s", inet_ntoa(addr.sin_addr));
  }
}







>
>
>







 







<







 







<







 







|
>
>
>
>
>


<
<
<
<
<
|
|
|
|
|
|
|
|
<
>
|
<
|
>
>
>
>
>
>

<
>
>
>
>
>
|
<
<
<
<
|
>

<
<
<
<
<
<
>


<
<




>
>
>
|







 







|
|
>
>
>
>
>
>
>
>
>
|
<
<
<
<
>
>
|


25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
..
46
47
48
49
50
51
52

53
54
55
56
57
58
59
...
106
107
108
109
110
111
112

113
114
115
116
117
118
119
...
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147





148
149
150
151
152
153
154
155

156
157

158
159
160
161
162
163
164
165

166
167
168
169
170
171




172
173
174






175
176
177


178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
...
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239




240
241
242
243
244
** Low-level sockets are abstracted out into this module because they
** are handled different on Unix and windows.
*/

#include "config.h"
#include "http_socket.h"
#if defined(_WIN32)
#  if !defined(_WIN32_WINNT)
#    define _WIN32_WINNT 0x0501
#  endif
#  include <winsock2.h>
#  include <ws2tcpip.h>
#else
#  include <netinet/in.h>
#  include <arpa/inet.h>
#  include <sys/socket.h>
#  include <netdb.h>
................................................................................

/*
** There can only be a single socket connection open at a time.
** State information about that socket is stored in the following
** local variables:
*/
static int socketIsInit = 0;    /* True after global initialization */

#if defined(_WIN32)
static WSADATA socketInfo;      /* Windows socket initialize data */
#endif
static int iSocket = -1;        /* The socket on which we talk to the server */
static char *socketErrMsg = 0;  /* Text of most recent socket error */


................................................................................
  if( socketIsInit ){
#if defined(_WIN32)
    WSACleanup();
#endif
    socket_clear_errmsg();
    socketIsInit = 0;
  }

}

/*
** Close the currently open socket.  If no socket is open, this routine
** is a no-op.
*/
void socket_close(void){
................................................................................
**
**    pUrlDAta->name       Name of the server.  Ex: www.fossil-scm.org
**    pUrlDAta->port       TCP/IP port to use.  Ex: 80
**
** Return the number of errors.
*/
int socket_open(UrlData *pUrlData){
  int rc = 0;
  struct addrinfo *ai = 0;
  struct addrinfo *p;
  struct addrinfo hints;
  char zPort[30];
  char zRemote[NI_MAXHOST];

  socket_global_init();





  memset(&hints, 0, sizeof(struct addrinfo));
  assert( iSocket<0 );
  hints.ai_family = g.fIPv4 ? AF_INET : AF_UNSPEC;
  hints.ai_socktype = SOCK_STREAM;
  hints.ai_protocol = IPPROTO_TCP;
  sqlite3_snprintf(sizeof(zPort),zPort,"%d", pUrlData->port);
  rc = getaddrinfo(pUrlData->name, zPort, &hints, &ai);
  if( rc ){

    socket_set_errmsg("getaddrinfo() fails: %s", gai_strerror(rc));
    goto end_socket_open;

  }
  for(p=ai; p; p=p->ai_next){
    iSocket = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
    if( iSocket<0 ) continue;
    if( connect(iSocket,p->ai_addr,p->ai_addrlen)<0 ){
      socket_close();
      continue;
    }

    rc = getnameinfo(p->ai_addr, p->ai_addrlen, zRemote, sizeof(zRemote),
                     0, 0, NI_NUMERICHOST);
    if( rc ){
      socket_set_errmsg("getnameinfo() failed: %s", gai_strerror(rc));
      goto end_socket_open;
    }




    g.zIpAddr = mprintf("%s", zRemote);
    break;
  }






  if( p==0 ){
    socket_set_errmsg("cannot connect to host %s:%d", pUrlData->name,
                      pUrlData->port);


  }
#if !defined(_WIN32)
  signal(SIGPIPE, SIG_IGN);
#endif
end_socket_open:
  if( rc && iSocket>=0 ) socket_close();
  if( ai ) freeaddrinfo(ai);
  return rc;
}

/*
** Send content out over the open socket connection.
*/
size_t socket_send(void *NotUsed, void *pContent, size_t N){
  size_t sent;
................................................................................
/*
** Attempt to resolve pUrlData->name to an IP address and setup g.zIpAddr
** so rcvfrom gets populated. For hostnames with more than one IP (or
** if overridden in ~/.ssh/config) the rcvfrom may not match the host
** to which we connect.
*/
void socket_ssh_resolve_addr(UrlData *pUrlData){
  struct addrinfo *ai = 0;
  struct addrinfo hints;
  char zRemote[NI_MAXHOST];
  hints.ai_family = AF_UNSPEC;
  hints.ai_socktype = SOCK_STREAM;
  hints.ai_protocol = IPPROTO_TCP;
  if( getaddrinfo(pUrlData->name, NULL, &hints, &ai)==0
   && ai!=0
   && getnameinfo(ai->ai_addr, ai->ai_addrlen, zRemote,
                  sizeof(zRemote), 0, 0, NI_NUMERICHOST)==0 ){
    g.zIpAddr = mprintf("%s (%s)", zRemote, pUrlData->name);
  }




  if( ai ) freeaddrinfo(ai);
  if( g.zIpAddr==0 ){
    g.zIpAddr = mprintf("%s", pUrlData->name);
  }
}

Changes to src/http_transport.c.

85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
static char zDefaultSshCmd[] = "ssh -e none -T";
#endif

/*
** SSH initialization of the transport layer
*/
int transport_ssh_open(UrlData *pUrlData){
  /* For SSH we need to create and run SSH fossil http 
  ** to talk to the remote machine.
  */
  const char *zSsh;  /* The base SSH command */
  Blob zCmd;         /* The SSH command */
  char *zHost;       /* The host name to contact */
  int n;             /* Size of prefix string */








|







85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
static char zDefaultSshCmd[] = "ssh -e none -T";
#endif

/*
** SSH initialization of the transport layer
*/
int transport_ssh_open(UrlData *pUrlData){
  /* For SSH we need to create and run SSH fossil http
  ** to talk to the remote machine.
  */
  const char *zSsh;  /* The base SSH command */
  Blob zCmd;         /* The SSH command */
  char *zHost;       /* The host name to contact */
  int n;             /* Size of prefix string */

Changes to src/info.c.

196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215

216
217
218
219
220
221
222
...
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
void info_cmd(void){
  i64 fsize;
  int verboseFlag = find_option("verbose","v",0)!=0;
  if( !verboseFlag ){
    verboseFlag = find_option("detail","l",0)!=0; /* deprecated */
  }

  /* We should be done with options.. */
  verify_all_options();

  if( g.argc==3 && (fsize = file_size(g.argv[2]))>0 && (fsize&0x1ff)==0 ){
    db_open_config(0);
    db_open_repository(g.argv[2]);
    db_record_repository_filename(g.argv[2]);
    fossil_print("project-name: %s\n", db_get("project-name", "<unnamed>"));
    fossil_print("project-code: %s\n", db_get("project-code", "<none>"));
    extraRepoInfo();
    return;
  }
  db_find_and_open_repository(0,0);

  if( g.argc==2 ){
    int vid;
         /* 012345678901234 */
    db_record_repository_filename(0);
    fossil_print("project-name: %s\n", db_get("project-name", "<unnamed>"));
    if( g.localOpen ){
      fossil_print("repository:   %s\n", db_repository_filename());
................................................................................
  db_prepare(&q3,
    "SELECT name,"
    "       mperm,"
    "       (SELECT uuid FROM blob WHERE rid=mlink.pid),"
    "       (SELECT uuid FROM blob WHERE rid=mlink.fid),"
    "       (SELECT name FROM filename WHERE filename.fnid=mlink.pfnid)"
    "  FROM mlink JOIN filename ON filename.fnid=mlink.fnid"
    " WHERE mlink.mid=%d"
    "   AND (mlink.fid>0"
           " OR mlink.fnid NOT IN (SELECT pfnid FROM mlink WHERE mid=%d))"
    " ORDER BY name /*sort*/",
    rid, rid
  );
  while( db_step(&q3)==SQLITE_ROW ){
    const char *zName = db_column_text(&q3,0);







<
<
<










>







 







|







196
197
198
199
200
201
202



203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
...
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
void info_cmd(void){
  i64 fsize;
  int verboseFlag = find_option("verbose","v",0)!=0;
  if( !verboseFlag ){
    verboseFlag = find_option("detail","l",0)!=0; /* deprecated */
  }




  if( g.argc==3 && (fsize = file_size(g.argv[2]))>0 && (fsize&0x1ff)==0 ){
    db_open_config(0);
    db_open_repository(g.argv[2]);
    db_record_repository_filename(g.argv[2]);
    fossil_print("project-name: %s\n", db_get("project-name", "<unnamed>"));
    fossil_print("project-code: %s\n", db_get("project-code", "<none>"));
    extraRepoInfo();
    return;
  }
  db_find_and_open_repository(0,0);
  verify_all_options();
  if( g.argc==2 ){
    int vid;
         /* 012345678901234 */
    db_record_repository_filename(0);
    fossil_print("project-name: %s\n", db_get("project-name", "<unnamed>"));
    if( g.localOpen ){
      fossil_print("repository:   %s\n", db_repository_filename());
................................................................................
  db_prepare(&q3,
    "SELECT name,"
    "       mperm,"
    "       (SELECT uuid FROM blob WHERE rid=mlink.pid),"
    "       (SELECT uuid FROM blob WHERE rid=mlink.fid),"
    "       (SELECT name FROM filename WHERE filename.fnid=mlink.pfnid)"
    "  FROM mlink JOIN filename ON filename.fnid=mlink.fnid"
    " WHERE mlink.mid=%d AND NOT mlink.isaux"
    "   AND (mlink.fid>0"
           " OR mlink.fnid NOT IN (SELECT pfnid FROM mlink WHERE mid=%d))"
    " ORDER BY name /*sort*/",
    rid, rid
  );
  while( db_step(&q3)==SQLITE_ROW ){
    const char *zName = db_column_text(&q3,0);

Changes to src/json_branch.c.

64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
...
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
...
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
*/
static cson_value * json_branch_list(){
  cson_value * payV;
  cson_object * pay;
  cson_value * listV;
  cson_array * list;
  char const * range = NULL;
  int which = 0;
  char * sawConversionError = NULL;
  Stmt q;
  if( !g.perm.Read ){
    json_set_err(FSL_JSON_E_DENIED,
                 "Requires 'o' permissions.");
    return NULL;
  }
................................................................................
  if(!range || !*range){
    range = "o";
  }
  /* Normalize range values... */
  switch(*range){
    case 'c':
      range = "closed";
      which = -1;
      break;
    case 'a':
      range = "all";
      which = 1;
      break;
    default:
      range = "open";
      which = 0;
      break;
  };
  cson_object_set(pay,"range",json_new_string(range));

  if( g.localOpen ){ /* add "current" property (branch name). */
    int vid = db_lget_int("checkout", 0);
    char const * zCurrent = vid
................................................................................
      : 0;
    if(zCurrent){
      cson_object_set(pay,"current",json_new_string(zCurrent));
    }
  }

  
  branch_prepare_list_query(&q, which);
  cson_object_set(pay,"branches",listV);
  while((SQLITE_ROW==db_step(&q))){
    cson_value * v = cson_sqlite3_column_to_value(q.pStmt,0);
    if(v){
      cson_array_append(list,v);
    }else if(!sawConversionError){
      sawConversionError = mprintf("Column-to-json failed @ %s:%d",







|







 







|



|



|







 







|







64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
...
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
...
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
*/
static cson_value * json_branch_list(){
  cson_value * payV;
  cson_object * pay;
  cson_value * listV;
  cson_array * list;
  char const * range = NULL;
  int branchListFlags = BRL_OPEN_ONLY;
  char * sawConversionError = NULL;
  Stmt q;
  if( !g.perm.Read ){
    json_set_err(FSL_JSON_E_DENIED,
                 "Requires 'o' permissions.");
    return NULL;
  }
................................................................................
  if(!range || !*range){
    range = "o";
  }
  /* Normalize range values... */
  switch(*range){
    case 'c':
      range = "closed";
      branchListFlags = BRL_CLOSED_ONLY;
      break;
    case 'a':
      range = "all";
      branchListFlags = BRL_BOTH;
      break;
    default:
      range = "open";
      branchListFlags = BRL_OPEN_ONLY;
      break;
  };
  cson_object_set(pay,"range",json_new_string(range));

  if( g.localOpen ){ /* add "current" property (branch name). */
    int vid = db_lget_int("checkout", 0);
    char const * zCurrent = vid
................................................................................
      : 0;
    if(zCurrent){
      cson_object_set(pay,"current",json_new_string(zCurrent));
    }
  }

  
  branch_prepare_list_query(&q, branchListFlags);
  cson_object_set(pay,"branches",listV);
  while((SQLITE_ROW==db_step(&q))){
    cson_value * v = cson_sqlite3_column_to_value(q.pStmt,0);
    if(v){
      cson_array_append(list,v);
    }else if(!sawConversionError){
      sawConversionError = mprintf("Column-to-json failed @ %s:%d",

Changes to src/leaf.c.

25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
..
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
..
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
...
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
#include "leaf.h"
#include <assert.h>


/*
** Return true if the check-in with RID=rid is a leaf.
**
** A leaf has no children in the same branch. 
*/
int is_a_leaf(int rid){
  int rc;
  static const char zSql[] = 
    @ SELECT 1 FROM plink
    @  WHERE pid=%d
    @    AND coalesce((SELECT value FROM tagxref
    @                   WHERE tagid=%d AND rid=plink.pid), 'trunk')
    @       =coalesce((SELECT value FROM tagxref
    @                   WHERE tagid=%d AND rid=plink.cid), 'trunk')
  ;
................................................................................
** kind.  This routine counts only primary children.
**
** A non-branch child is one which is on the same branch as the parent.
*/
int count_nonbranch_children(int pid){
  int nNonBranch = 0;
  static Stmt q;
  static const char zSql[] = 
    @ SELECT count(*) FROM plink
    @  WHERE pid=:pid AND isprim
    @    AND coalesce((SELECT value FROM tagxref
    @                   WHERE tagid=%d AND rid=plink.pid), 'trunk')
    @       =coalesce((SELECT value FROM tagxref
    @                   WHERE tagid=%d AND rid=plink.cid), 'trunk')
  ;
................................................................................
  }
  db_reset(&q);
  return nNonBranch;
}


/*
** Recompute the entire LEAF table.  
**
** This can be expensive (5 seconds or so) for a really large repository.
** So it is only done for things like a rebuild.
*/
void leaf_rebuild(void){
  db_multi_exec(
    "DELETE FROM leaf;"
................................................................................

/*
** Schedule a leaf check for "rid" and its parents.
*/
void leaf_eventually_check(int rid){
  static Stmt parentsOf;

  db_static_prepare(&parentsOf, 
     "SELECT pid FROM plink WHERE cid=:rid AND pid>0"
  );
  db_bind_int(&parentsOf, ":rid", rid);
  bag_insert(&needToCheck, rid);
  while( db_step(&parentsOf)==SQLITE_ROW ){
    bag_insert(&needToCheck, db_column_int(&parentsOf, 0));
  }







|



|







 







|







 







|







 







|







25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
..
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
..
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
...
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
#include "leaf.h"
#include <assert.h>


/*
** Return true if the check-in with RID=rid is a leaf.
**
** A leaf has no children in the same branch.
*/
int is_a_leaf(int rid){
  int rc;
  static const char zSql[] =
    @ SELECT 1 FROM plink
    @  WHERE pid=%d
    @    AND coalesce((SELECT value FROM tagxref
    @                   WHERE tagid=%d AND rid=plink.pid), 'trunk')
    @       =coalesce((SELECT value FROM tagxref
    @                   WHERE tagid=%d AND rid=plink.cid), 'trunk')
  ;
................................................................................
** kind.  This routine counts only primary children.
**
** A non-branch child is one which is on the same branch as the parent.
*/
int count_nonbranch_children(int pid){
  int nNonBranch = 0;
  static Stmt q;
  static const char zSql[] =
    @ SELECT count(*) FROM plink
    @  WHERE pid=:pid AND isprim
    @    AND coalesce((SELECT value FROM tagxref
    @                   WHERE tagid=%d AND rid=plink.pid), 'trunk')
    @       =coalesce((SELECT value FROM tagxref
    @                   WHERE tagid=%d AND rid=plink.cid), 'trunk')
  ;
................................................................................
  }
  db_reset(&q);
  return nNonBranch;
}


/*
** Recompute the entire LEAF table.
**
** This can be expensive (5 seconds or so) for a really large repository.
** So it is only done for things like a rebuild.
*/
void leaf_rebuild(void){
  db_multi_exec(
    "DELETE FROM leaf;"
................................................................................

/*
** Schedule a leaf check for "rid" and its parents.
*/
void leaf_eventually_check(int rid){
  static Stmt parentsOf;

  db_static_prepare(&parentsOf,
     "SELECT pid FROM plink WHERE cid=:rid AND pid>0"
  );
  db_bind_int(&parentsOf, ":rid", rid);
  bag_insert(&needToCheck, rid);
  while( db_step(&parentsOf)==SQLITE_ROW ){
    bag_insert(&needToCheck, db_column_int(&parentsOf, 0));
  }

Changes to src/login.c.

481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
...
573
574
575
576
577
578
579

580
581
582
583
584
585
586
    const char *zQS = P("QUERY_STRING");
    if( zQS==0 ){
      zQS = "";
    }else if( zQS[0]!=0 ){
      zQS = mprintf("?%s", zQS);
    }
    cgi_redirectf("%s%s%s", g.zHttpsURL, P("PATH_INFO"), zQS);
    return;    
  }
  sqlite3_create_function(g.db, "constant_time_cmp", 2, SQLITE_UTF8, 0,
                  constant_time_cmp_function, 0, 0);
  zUsername = P("u");
  zPasswd = P("p");
  anonFlag = P("anon")!=0;
  if( P("out")!=0 ){
................................................................................
      ** code prefix, and LOGIN is the user name.
      */
      login_set_user_cookie(zUsername, uid, NULL);
      redirect_to_g();
    }
  }
  style_header("Login/Logout");

  @ %s(zErrMsg)
  if( zGoto && P("anon")==0 ){
    @ <p>A login is required for <a href="%h(zGoto)">%h(zGoto)</a>.</p>
  }
  form_begin(0, "%R/login");
  if( zGoto ){
    @ <input type="hidden" name="g" value="%h(zGoto)" />







|







 







>







481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
...
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
    const char *zQS = P("QUERY_STRING");
    if( zQS==0 ){
      zQS = "";
    }else if( zQS[0]!=0 ){
      zQS = mprintf("?%s", zQS);
    }
    cgi_redirectf("%s%s%s", g.zHttpsURL, P("PATH_INFO"), zQS);
    return;
  }
  sqlite3_create_function(g.db, "constant_time_cmp", 2, SQLITE_UTF8, 0,
                  constant_time_cmp_function, 0, 0);
  zUsername = P("u");
  zPasswd = P("p");
  anonFlag = P("anon")!=0;
  if( P("out")!=0 ){
................................................................................
      ** code prefix, and LOGIN is the user name.
      */
      login_set_user_cookie(zUsername, uid, NULL);
      redirect_to_g();
    }
  }
  style_header("Login/Logout");
  style_adunit_config(ADUNIT_OFF);
  @ %s(zErrMsg)
  if( zGoto && P("anon")==0 ){
    @ <p>A login is required for <a href="%h(zGoto)">%h(zGoto)</a>.</p>
  }
  form_begin(0, "%R/login");
  if( zGoto ){
    @ <input type="hidden" name="g" value="%h(zGoto)" />

Changes to src/main.c.

141
142
143
144
145
146
147

148
149
150
151
152
153

154
155
156
157
158
159
160
...
655
656
657
658
659
660
661
662
663
664
665
666

667
668
669
670
671
672
673
....
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806






1807
1808
1809
1810
1811
1812






1813
1814
1815
1816
1817
1818





1819
1820
1821
1822
1823





1824
1825
1826
1827
1828


1829
1830
1831
1832
1833
1834
1835
1836
1837










1838










































1839
1840
1841
1842
1843
1844
1845
  char *zLocalRoot;       /* The directory holding the  local database */
  int minPrefix;          /* Number of digits needed for a distinct UUID */
  int fSqlTrace;          /* True if --sqltrace flag is present */
  int fSqlStats;          /* True if --sqltrace or --sqlstats are present */
  int fSqlPrint;          /* True if -sqlprint flag is present */
  int fQuiet;             /* True if -quiet flag is present */
  int fHttpTrace;         /* Trace outbound HTTP requests */

  char *zHttpAuth;        /* HTTP Authorization user:pass information */
  int fSystemTrace;       /* Trace calls to fossil_system(), --systemtrace */
  int fSshTrace;          /* Trace the SSH setup traffic */
  int fSshClient;         /* HTTP client flags for SSH client */
  char *zSshCmd;          /* SSH command string */
  int fNoSync;            /* Do not do an autosync ever.  --nosync */

  char *zPath;            /* Name of webpage being served */
  char *zExtra;           /* Extra path information past the webpage name */
  char *zBaseURL;         /* Full text of the URL being served */
  char *zHttpsURL;        /* zBaseURL translated to https: */
  char *zTop;             /* Parent directory of zPath */
  const char *zContentType;  /* The content type of the input HTTP request */
  int iErrPriority;       /* Priority of current error message */
................................................................................
    g.fSqlTrace = find_option("sqltrace", 0, 0)!=0;
    g.fSqlStats = find_option("sqlstats", 0, 0)!=0;
    g.fSystemTrace = find_option("systemtrace", 0, 0)!=0;
    g.fSshTrace = find_option("sshtrace", 0, 0)!=0;
    g.fSshClient = 0;
    g.zSshCmd = 0;
    if( g.fSqlTrace ) g.fSqlStats = 1;
    g.fSqlPrint = find_option("sqlprint", 0, 0)!=0;
    g.fHttpTrace = find_option("httptrace", 0, 0)!=0;
#ifdef FOSSIL_ENABLE_TH1_HOOKS
    g.fNoThHook = find_option("no-th-hook", 0, 0)!=0;
#endif

    g.zHttpAuth = 0;
    g.zLogin = find_option("user", "U", 1);
    g.zSSLIdentity = find_option("ssl-identity", 0, 1);
    g.zErrlog = find_option("errorlog", 0, 1);
    fossil_init_flags_from_options();
    if( find_option("utc",0,0) ) g.fTimeFormat = 1;
    if( find_option("localtime",0,0) ) g.fTimeFormat = 2;
................................................................................
  fossil_binary_mode(g.httpOut);
  fossil_binary_mode(g.httpIn);
  g.cgiOutput = 1;
  blob_read_from_file(&config, zFile);
  while( blob_line(&config, &line) ){
    if( !blob_token(&line, &key) ) continue;
    if( blob_buffer(&key)[0]=='#' ) continue;
    if( blob_eq(&key, "debug:") && blob_token(&line, &value) ){
      g.fDebug = fossil_fopen(blob_str(&value), "ab");
      blob_reset(&value);
      continue;
    }
    if( blob_eq(&key, "errorlog:") && blob_token(&line, &value) ){
      g.zErrlog = mprintf("%s", blob_str(&value));
      continue;
    }
    if( blob_eq(&key, "HOME:") && blob_token(&line, &value) ){
      cgi_setenv("HOME", blob_str(&value));
      blob_reset(&value);
      continue;
    }
    if( blob_eq(&key, "repository:") && blob_tail(&line, &value) ){






      blob_trim(&value);
      db_open_repository(blob_str(&value));
      blob_reset(&value);
      continue;
    }
    if( blob_eq(&key, "directory:") && blob_token(&line, &value) ){






      db_close(1);
      g.zRepositoryName = mprintf("%s", blob_str(&value));
      blob_reset(&value);
      continue;
    }
    if( blob_eq(&key, "notfound:") && blob_token(&line, &value) ){





      zNotFound = mprintf("%s", blob_str(&value));
      blob_reset(&value);
      continue;
    }
    if( blob_eq(&key, "localauth") ){





      g.useLocalauth = 1;
      continue;
    }
    if( blob_eq(&key, "redirect:") && blob_token(&line, &value)
            && blob_token(&line, &value2) ){


      nRedirect++;
      azRedirect = fossil_realloc(azRedirect, 2*nRedirect*sizeof(char*));
      azRedirect[nRedirect*2-2] = mprintf("%s", blob_str(&value));
      azRedirect[nRedirect*2-1] = mprintf("%s", blob_str(&value2));
      blob_reset(&value);
      blob_reset(&value2);
      continue;
    }
    if( blob_eq(&key, "files:") && blob_token(&line, &value) ){










      pFileGlob = glob_create(blob_str(&value));










































      continue;
    }
  }
  blob_reset(&config);
  if( g.db==0 && g.zRepositoryName==0 && nRedirect==0 ){
    cgi_panic("Unable to find or open the project repository");
  }







>






>







 







<




>







 







<
<
<
<
<
<
<
<
<
<
<
<
<
<

>
>
>
>
>
>






>
>
>
>
>
>






>
>
>
>
>





>
>
>
>
>





>
>









>
>
>
>
>
>
>
>
>
>

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
...
657
658
659
660
661
662
663

664
665
666
667
668
669
670
671
672
673
674
675
....
1787
1788
1789
1790
1791
1792
1793














1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
  char *zLocalRoot;       /* The directory holding the  local database */
  int minPrefix;          /* Number of digits needed for a distinct UUID */
  int fSqlTrace;          /* True if --sqltrace flag is present */
  int fSqlStats;          /* True if --sqltrace or --sqlstats are present */
  int fSqlPrint;          /* True if -sqlprint flag is present */
  int fQuiet;             /* True if -quiet flag is present */
  int fHttpTrace;         /* Trace outbound HTTP requests */
  int fAnyTrace;          /* Any kind of tracing */
  char *zHttpAuth;        /* HTTP Authorization user:pass information */
  int fSystemTrace;       /* Trace calls to fossil_system(), --systemtrace */
  int fSshTrace;          /* Trace the SSH setup traffic */
  int fSshClient;         /* HTTP client flags for SSH client */
  char *zSshCmd;          /* SSH command string */
  int fNoSync;            /* Do not do an autosync ever.  --nosync */
  int fIPv4;              /* Use only IPv4, not IPv6. --ipv4 */
  char *zPath;            /* Name of webpage being served */
  char *zExtra;           /* Extra path information past the webpage name */
  char *zBaseURL;         /* Full text of the URL being served */
  char *zHttpsURL;        /* zBaseURL translated to https: */
  char *zTop;             /* Parent directory of zPath */
  const char *zContentType;  /* The content type of the input HTTP request */
  int iErrPriority;       /* Priority of current error message */
................................................................................
    g.fSqlTrace = find_option("sqltrace", 0, 0)!=0;
    g.fSqlStats = find_option("sqlstats", 0, 0)!=0;
    g.fSystemTrace = find_option("systemtrace", 0, 0)!=0;
    g.fSshTrace = find_option("sshtrace", 0, 0)!=0;
    g.fSshClient = 0;
    g.zSshCmd = 0;
    if( g.fSqlTrace ) g.fSqlStats = 1;

    g.fHttpTrace = find_option("httptrace", 0, 0)!=0;
#ifdef FOSSIL_ENABLE_TH1_HOOKS
    g.fNoThHook = find_option("no-th-hook", 0, 0)!=0;
#endif
    g.fAnyTrace = g.fSqlTrace|g.fSystemTrace|g.fSshTrace|g.fHttpTrace;
    g.zHttpAuth = 0;
    g.zLogin = find_option("user", "U", 1);
    g.zSSLIdentity = find_option("ssl-identity", 0, 1);
    g.zErrlog = find_option("errorlog", 0, 1);
    fossil_init_flags_from_options();
    if( find_option("utc",0,0) ) g.fTimeFormat = 1;
    if( find_option("localtime",0,0) ) g.fTimeFormat = 2;
................................................................................
  fossil_binary_mode(g.httpOut);
  fossil_binary_mode(g.httpIn);
  g.cgiOutput = 1;
  blob_read_from_file(&config, zFile);
  while( blob_line(&config, &line) ){
    if( !blob_token(&line, &key) ) continue;
    if( blob_buffer(&key)[0]=='#' ) continue;














    if( blob_eq(&key, "repository:") && blob_tail(&line, &value) ){
      /* repository: FILENAME
      **
      ** The name of the Fossil repository to be served via CGI.  Most
      ** fossil CGI scripts have a single non-comment line that contains
      ** this one entry.
      */
      blob_trim(&value);
      db_open_repository(blob_str(&value));
      blob_reset(&value);
      continue;
    }
    if( blob_eq(&key, "directory:") && blob_token(&line, &value) ){
      /* directory: DIRECTORY
      **
      ** If repository: is omitted, then terms of the PATH_INFO cgi parameter
      ** are appended to DIRECTORY looking for a repository (whose name ends
      ** in ".fossil") or a file in "files:".
      */
      db_close(1);
      g.zRepositoryName = mprintf("%s", blob_str(&value));
      blob_reset(&value);
      continue;
    }
    if( blob_eq(&key, "notfound:") && blob_token(&line, &value) ){
      /* notfound: URL
      **
      ** If using directory: and no suitable repository or file is found,
      ** then redirect to URL.
      */
      zNotFound = mprintf("%s", blob_str(&value));
      blob_reset(&value);
      continue;
    }
    if( blob_eq(&key, "localauth") ){
      /* localauth
      **
      ** Grant "administrator" privileges to users connecting with HTTP
      ** from IP address 127.0.0.1.  Do not bother checking credentials.
      */
      g.useLocalauth = 1;
      continue;
    }
    if( blob_eq(&key, "redirect:") && blob_token(&line, &value)
            && blob_token(&line, &value2) ){
      /* See the header comment on the redirect_web_page() function
      ** above for details. */
      nRedirect++;
      azRedirect = fossil_realloc(azRedirect, 2*nRedirect*sizeof(char*));
      azRedirect[nRedirect*2-2] = mprintf("%s", blob_str(&value));
      azRedirect[nRedirect*2-1] = mprintf("%s", blob_str(&value2));
      blob_reset(&value);
      blob_reset(&value2);
      continue;
    }
    if( blob_eq(&key, "files:") && blob_token(&line, &value) ){
      /* files: GLOBLIST
      **
      ** GLOBLIST is a comma-separated list of filename globs.  For
      ** example:  *.html,*.css,*.js
      **
      ** If the repository: line is omitted and then PATH_INFO is searched
      ** for files that match any of these GLOBs and if any such file is
      ** found it is returned verbatim.  This feature allows "fossil server"
      ** to function as a primitive web-server delivering arbitrary content.
      */
      pFileGlob = glob_create(blob_str(&value));
      blob_reset(&value);
      continue;
    }
    if( blob_eq(&key, "setenv:") && blob_token(&line, &value)
            && blob_token(&line, &value2) ){
      /* setenv: NAME VALUE
      **
      ** Sets environment variable NAME to VALUE
      */
      fossil_setenv(blob_str(&value), blob_str(&value2));
      blob_reset(&value);
      blob_reset(&value2);
      continue;
    }
    if( blob_eq(&key, "debug:") && blob_token(&line, &value) ){
      /* debug: FILENAME
      **
      ** Causes output from cgi_debug() and CGIDEBUG(()) calls to go
      ** into FILENAME.
      */
      g.fDebug = fossil_fopen(blob_str(&value), "ab");
      blob_reset(&value);
      continue;
    }
    if( blob_eq(&key, "errorlog:") && blob_token(&line, &value) ){
      /* errorlog: FILENAME
      **
      ** Causes messages from warnings, errors, and panics to be appended
      ** to FILENAME.
      */
      g.zErrlog = mprintf("%s", blob_str(&value));
      blob_reset(&value);
      continue;
    }
    if( blob_eq(&key, "HOME:") && blob_token(&line, &value) ){
      /* HOME: VALUE
      **
      ** Set CGI parameter "HOME" to VALUE.  This is legacy.  Use
      ** setenv: instead.
      */
      cgi_setenv("HOME", blob_str(&value));
      blob_reset(&value);
      continue;
    }
  }
  blob_reset(&config);
  if( g.db==0 && g.zRepositoryName==0 && nRedirect==0 ){
    cgi_panic("Unable to find or open the project repository");
  }

Changes to src/main.mk.

102
103
104
105
106
107
108

109
110
111
112
113
114
115
...
129
130
131
132
133
134
135
























136

137
138
139
140
141
142
143
...
224
225
226
227
228
229
230

231
232
233
234
235
236
237
...
343
344
345
346
347
348
349

350
351
352
353
354
355
356
...
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
...
571
572
573
574
575
576
577

578
579
580
581
582
583
584
....
1338
1339
1340
1341
1342
1343
1344








1345
1346
1347
1348
1349
1350
1351
  $(SRCDIR)/sha1.c \
  $(SRCDIR)/shun.c \
  $(SRCDIR)/sitemap.c \
  $(SRCDIR)/skins.c \
  $(SRCDIR)/sqlcmd.c \
  $(SRCDIR)/stash.c \
  $(SRCDIR)/stat.c \

  $(SRCDIR)/style.c \
  $(SRCDIR)/sync.c \
  $(SRCDIR)/tag.c \
  $(SRCDIR)/tar.c \
  $(SRCDIR)/th_main.c \
  $(SRCDIR)/timeline.c \
  $(SRCDIR)/tkt.c \
................................................................................
  $(SRCDIR)/winhttp.c \
  $(SRCDIR)/wysiwyg.c \
  $(SRCDIR)/xfer.c \
  $(SRCDIR)/xfersetup.c \
  $(SRCDIR)/zip.c

EXTRA_FILES = \
























  $(SRCDIR)/diff.tcl


TRANS_SRC = \
  $(OBJDIR)/add_.c \
  $(OBJDIR)/allrepo_.c \
  $(OBJDIR)/attach_.c \
  $(OBJDIR)/bag_.c \
  $(OBJDIR)/bisect_.c \
................................................................................
  $(OBJDIR)/sha1_.c \
  $(OBJDIR)/shun_.c \
  $(OBJDIR)/sitemap_.c \
  $(OBJDIR)/skins_.c \
  $(OBJDIR)/sqlcmd_.c \
  $(OBJDIR)/stash_.c \
  $(OBJDIR)/stat_.c \

  $(OBJDIR)/style_.c \
  $(OBJDIR)/sync_.c \
  $(OBJDIR)/tag_.c \
  $(OBJDIR)/tar_.c \
  $(OBJDIR)/th_main_.c \
  $(OBJDIR)/timeline_.c \
  $(OBJDIR)/tkt_.c \
................................................................................
 $(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 \
................................................................................
	rm -rf $(OBJDIR)/* $(APPNAME)


$(OBJDIR)/page_index.h: $(TRANS_SRC) $(OBJDIR)/mkindex
	$(OBJDIR)/mkindex $(TRANS_SRC) >$@

$(OBJDIR)/builtin_data.h: $(OBJDIR)/mkbuiltin $(EXTRA_FILES)
	$(OBJDIR)/mkbuiltin $(EXTRA_FILES) >$@

$(OBJDIR)/headers:	$(OBJDIR)/page_index.h $(OBJDIR)/builtin_data.h $(OBJDIR)/makeheaders $(OBJDIR)/VERSION.h
	$(OBJDIR)/makeheaders $(OBJDIR)/add_.c:$(OBJDIR)/add.h \
	$(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h \
	$(OBJDIR)/attach_.c:$(OBJDIR)/attach.h \
	$(OBJDIR)/bag_.c:$(OBJDIR)/bag.h \
	$(OBJDIR)/bisect_.c:$(OBJDIR)/bisect.h \
................................................................................
	$(OBJDIR)/sha1_.c:$(OBJDIR)/sha1.h \
	$(OBJDIR)/shun_.c:$(OBJDIR)/shun.h \
	$(OBJDIR)/sitemap_.c:$(OBJDIR)/sitemap.h \
	$(OBJDIR)/skins_.c:$(OBJDIR)/skins.h \
	$(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h \
	$(OBJDIR)/stash_.c:$(OBJDIR)/stash.h \
	$(OBJDIR)/stat_.c:$(OBJDIR)/stat.h \

	$(OBJDIR)/style_.c:$(OBJDIR)/style.h \
	$(OBJDIR)/sync_.c:$(OBJDIR)/sync.h \
	$(OBJDIR)/tag_.c:$(OBJDIR)/tag.h \
	$(OBJDIR)/tar_.c:$(OBJDIR)/tar.h \
	$(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h \
	$(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h \
	$(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h \
................................................................................
$(OBJDIR)/stat_.c:	$(SRCDIR)/stat.c $(OBJDIR)/translate
	$(OBJDIR)/translate $(SRCDIR)/stat.c >$@

$(OBJDIR)/stat.o:	$(OBJDIR)/stat_.c $(OBJDIR)/stat.h $(SRCDIR)/config.h
	$(XTCC) -o $(OBJDIR)/stat.o -c $(OBJDIR)/stat_.c

$(OBJDIR)/stat.h:	$(OBJDIR)/headers









$(OBJDIR)/style_.c:	$(SRCDIR)/style.c $(OBJDIR)/translate
	$(OBJDIR)/translate $(SRCDIR)/style.c >$@

$(OBJDIR)/style.o:	$(OBJDIR)/style_.c $(OBJDIR)/style.h $(SRCDIR)/config.h
	$(XTCC) -o $(OBJDIR)/style.o -c $(OBJDIR)/style_.c








>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>







 







>







 







>







 







|







 







>







 







>
>
>
>
>
>
>
>







102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
...
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
...
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
...
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
...
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
...
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
....
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
  $(SRCDIR)/sha1.c \
  $(SRCDIR)/shun.c \
  $(SRCDIR)/sitemap.c \
  $(SRCDIR)/skins.c \
  $(SRCDIR)/sqlcmd.c \
  $(SRCDIR)/stash.c \
  $(SRCDIR)/stat.c \
  $(SRCDIR)/statrep.c \
  $(SRCDIR)/style.c \
  $(SRCDIR)/sync.c \
  $(SRCDIR)/tag.c \
  $(SRCDIR)/tar.c \
  $(SRCDIR)/th_main.c \
  $(SRCDIR)/timeline.c \
  $(SRCDIR)/tkt.c \
................................................................................
  $(SRCDIR)/winhttp.c \
  $(SRCDIR)/wysiwyg.c \
  $(SRCDIR)/xfer.c \
  $(SRCDIR)/xfersetup.c \
  $(SRCDIR)/zip.c

EXTRA_FILES = \
  $(SRCDIR)/../skins/black_and_white/css.txt \
  $(SRCDIR)/../skins/black_and_white/footer.txt \
  $(SRCDIR)/../skins/black_and_white/header.txt \
  $(SRCDIR)/../skins/default/css.txt \
  $(SRCDIR)/../skins/default/footer.txt \
  $(SRCDIR)/../skins/default/header.txt \
  $(SRCDIR)/../skins/eagle/css.txt \
  $(SRCDIR)/../skins/eagle/footer.txt \
  $(SRCDIR)/../skins/eagle/header.txt \
  $(SRCDIR)/../skins/enhanced1/css.txt \
  $(SRCDIR)/../skins/enhanced1/footer.txt \
  $(SRCDIR)/../skins/enhanced1/header.txt \
  $(SRCDIR)/../skins/etienne1/css.txt \
  $(SRCDIR)/../skins/etienne1/footer.txt \
  $(SRCDIR)/../skins/etienne1/header.txt \
  $(SRCDIR)/../skins/khaki/css.txt \
  $(SRCDIR)/../skins/khaki/footer.txt \
  $(SRCDIR)/../skins/khaki/header.txt \
  $(SRCDIR)/../skins/plain_gray/css.txt \
  $(SRCDIR)/../skins/plain_gray/footer.txt \
  $(SRCDIR)/../skins/plain_gray/header.txt \
  $(SRCDIR)/../skins/rounded1/css.txt \
  $(SRCDIR)/../skins/rounded1/footer.txt \
  $(SRCDIR)/../skins/rounded1/header.txt \
  $(SRCDIR)/diff.tcl \
  $(SRCDIR)/markdown.md

TRANS_SRC = \
  $(OBJDIR)/add_.c \
  $(OBJDIR)/allrepo_.c \
  $(OBJDIR)/attach_.c \
  $(OBJDIR)/bag_.c \
  $(OBJDIR)/bisect_.c \
................................................................................
  $(OBJDIR)/sha1_.c \
  $(OBJDIR)/shun_.c \
  $(OBJDIR)/sitemap_.c \
  $(OBJDIR)/skins_.c \
  $(OBJDIR)/sqlcmd_.c \
  $(OBJDIR)/stash_.c \
  $(OBJDIR)/stat_.c \
  $(OBJDIR)/statrep_.c \
  $(OBJDIR)/style_.c \
  $(OBJDIR)/sync_.c \
  $(OBJDIR)/tag_.c \
  $(OBJDIR)/tar_.c \
  $(OBJDIR)/th_main_.c \
  $(OBJDIR)/timeline_.c \
  $(OBJDIR)/tkt_.c \
................................................................................
 $(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 \
................................................................................
	rm -rf $(OBJDIR)/* $(APPNAME)


$(OBJDIR)/page_index.h: $(TRANS_SRC) $(OBJDIR)/mkindex
	$(OBJDIR)/mkindex $(TRANS_SRC) >$@

$(OBJDIR)/builtin_data.h: $(OBJDIR)/mkbuiltin $(EXTRA_FILES)
	$(OBJDIR)/mkbuiltin --prefix $(SRCDIR)/ $(EXTRA_FILES) >$@

$(OBJDIR)/headers:	$(OBJDIR)/page_index.h $(OBJDIR)/builtin_data.h $(OBJDIR)/makeheaders $(OBJDIR)/VERSION.h
	$(OBJDIR)/makeheaders $(OBJDIR)/add_.c:$(OBJDIR)/add.h \
	$(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h \
	$(OBJDIR)/attach_.c:$(OBJDIR)/attach.h \
	$(OBJDIR)/bag_.c:$(OBJDIR)/bag.h \
	$(OBJDIR)/bisect_.c:$(OBJDIR)/bisect.h \
................................................................................
	$(OBJDIR)/sha1_.c:$(OBJDIR)/sha1.h \
	$(OBJDIR)/shun_.c:$(OBJDIR)/shun.h \
	$(OBJDIR)/sitemap_.c:$(OBJDIR)/sitemap.h \
	$(OBJDIR)/skins_.c:$(OBJDIR)/skins.h \
	$(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h \
	$(OBJDIR)/stash_.c:$(OBJDIR)/stash.h \
	$(OBJDIR)/stat_.c:$(OBJDIR)/stat.h \
	$(OBJDIR)/statrep_.c:$(OBJDIR)/statrep.h \
	$(OBJDIR)/style_.c:$(OBJDIR)/style.h \
	$(OBJDIR)/sync_.c:$(OBJDIR)/sync.h \
	$(OBJDIR)/tag_.c:$(OBJDIR)/tag.h \
	$(OBJDIR)/tar_.c:$(OBJDIR)/tar.h \
	$(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h \
	$(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h \
	$(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h \
................................................................................
$(OBJDIR)/stat_.c:	$(SRCDIR)/stat.c $(OBJDIR)/translate
	$(OBJDIR)/translate $(SRCDIR)/stat.c >$@

$(OBJDIR)/stat.o:	$(OBJDIR)/stat_.c $(OBJDIR)/stat.h $(SRCDIR)/config.h
	$(XTCC) -o $(OBJDIR)/stat.o -c $(OBJDIR)/stat_.c

$(OBJDIR)/stat.h:	$(OBJDIR)/headers

$(OBJDIR)/statrep_.c:	$(SRCDIR)/statrep.c $(OBJDIR)/translate
	$(OBJDIR)/translate $(SRCDIR)/statrep.c >$@

$(OBJDIR)/statrep.o:	$(OBJDIR)/statrep_.c $(OBJDIR)/statrep.h $(SRCDIR)/config.h
	$(XTCC) -o $(OBJDIR)/statrep.o -c $(OBJDIR)/statrep_.c

$(OBJDIR)/statrep.h:	$(OBJDIR)/headers

$(OBJDIR)/style_.c:	$(SRCDIR)/style.c $(OBJDIR)/translate
	$(OBJDIR)/translate $(SRCDIR)/style.c >$@

$(OBJDIR)/style.o:	$(OBJDIR)/style_.c $(OBJDIR)/style.h $(SRCDIR)/config.h
	$(XTCC) -o $(OBJDIR)/style.o -c $(OBJDIR)/style_.c

Changes to src/makeheaders.c.

110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
...
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
...
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
...
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
...
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
...
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
...
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
...
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
...
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
...
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
....
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
....
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
....
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
....
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
....
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
....
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
....
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
....
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
....
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
....
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
....
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
....
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
....
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
....
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
....
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
....
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
....
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
....
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
....
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
....
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
....
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
....
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
....
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
....
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
....
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
....
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
....
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
....
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
** doesn't tell about the objects structure.  A typical forward declaration
** is:
**
**          struct Xyzzy;
**
** Not every object has a forward declaration.  If it does, thought, the
** forward declaration will be contained in the zFwd field for C and
** the zFwdCpp for C++.  The zDecl field contains the complete 
** declaration text.  
*/
typedef struct Decl Decl;
struct Decl {
  char *zName;       /* Name of the object being declared.  The appearance
                     ** of this name is a source file triggers the declaration
                     ** to be added to the header for that file. */
  char *zFile;       /* File from which extracted.  */
  char *zIf;         /* Surround the declaration with this #if */
  char *zFwd;        /* A forward declaration.  NULL if there is none. */
  char *zFwdCpp;     /* Use this forward declaration for C++. */
  char *zDecl;       /* A full declaration of this object */
  char *zExtra;      /* Extra declaration text inserted into class objects */
  int extraType;     /* Last public:, protected: or private: in zExtraDecl */
  struct Include *pInclude;   /* #includes that come before this declaration */
................................................................................
**                        a library, then the object is not visible to users
**                        of the library.  (i.e. the object does not appear
**                        in the output when using the -H option.)
**
**    EXPORT scope        The object is visible and usable everywhere.
**
** The DP_Flag is a temporary use flag that is used during processing to
** prevent an infinite loop.  It's use is localized.  
**
** The DP_Cplusplus, DP_ExternCReqd and DP_ExternReqd flags are permanent
** and are used to specify what type of declaration the object requires.
*/
#define DP_Forward      0x001   /* Has a forward declaration in this file */
#define DP_Declared     0x002   /* Has a full declaration in this file */
#define DP_Export       0x004   /* Export this declaration */
................................................................................
** the same "flags" field.
**
** Be careful not to confuse PS_Export with DP_Export or
** PS_Local with DP_Local.  Their names are similar, but the meanings
** of these flags are very different.
*/
#define PS_Extern        0x000800    /* "extern" has been seen */
#define PS_Export        0x001000    /* If between "#if EXPORT_INTERFACE" 
                                     ** and "#endif" */
#define PS_Export2       0x002000    /* If "EXPORT" seen */
#define PS_Typedef       0x004000    /* If "typedef" has been seen */
#define PS_Static        0x008000    /* If "static" has been seen */
#define PS_Interface     0x010000    /* If within #if INTERFACE..#endif */
#define PS_Method        0x020000    /* If "::" token has been seen */
#define PS_Local         0x040000    /* If within #if LOCAL_INTERFACE..#endif */
................................................................................
#define TY_Variable      0x01000000
#define TY_Structure     0x02000000
#define TY_Union         0x04000000
#define TY_Enumeration   0x08000000
#define TY_Defunct       0x10000000  /* Used to erase a declaration */

/*
** Each nested #if (or #ifdef or #ifndef) is stored in a stack of 
** instances of the following structure.
*/
typedef struct Ifmacro Ifmacro;
struct Ifmacro {
  int nLine;         /* Line number where this macro occurs */
  char *zCondition;  /* Text of the condition for this macro */
  Ifmacro *pNext;    /* Next down in the stack */
................................................................................
  char *zHdr;              /* Name of the generated .h file for this input.
                           ** Will be NULL if input is to be scanned only */
  int flags;               /* One or more DP_, PS_ and/or TY_ flags */
  InFile *pNext;           /* Next input file in the list of them all */
  IdentTable idTable;      /* All identifiers in this input file */
};

/* 
** An unbounded string is able to grow without limit.  We use these
** to construct large in-memory strings from lots of smaller components.
*/
typedef struct String String;
struct String {
  int nAlloc;      /* Number of bytes allocated */
  int nUsed;       /* Number of bytes used (not counting null terminator) */
................................................................................
** The following text line appears at the top of every file generated
** by this program.  By recognizing this line, the program can be sure
** never to read a file that it generated itself.
**
** The "#undef INTERFACE" part is a hack to work around a name collision
** in MSVC 2008.
*/
const char zTopLine[] = 
  "/* \aThis file was automatically generated.  Do not edit! */\n"
  "#undef INTERFACE\n";
#define nTopLine (sizeof(zTopLine)-1)

/*
** The name of the file currently being parsed.
*/
static char *zFilename;

/*
** The stack of #if macros for the file currently being parsed.
*/
static Ifmacro *ifStack = 0;

/*
................................................................................
*/
static char *ReadFile(const char *zFilename){
  struct stat sStat;
  FILE *pIn;
  char *zBuf;
  int n;

  if( stat(zFilename,&sStat)!=0 
#ifndef WIN32
    || !S_ISREG(sStat.st_mode)
#endif
  ){
    return 0;
  }
  pIn = fopen(zFilename,"r");
................................................................................
              }else{
                 isBlockComment = 0;
              }
            }
          }
          i++;
        }
        if( z[i] ){ 
          i += 2; 
        }else{
          isBlockComment = 0;
          fprintf(stderr,"%s:%d: Unterminated comment\n",
            zFilename, startLine);
          nErr++;
        }
        pToken->eType = isBlockComment==2 ? TT_BlockComment : TT_Comment;
................................................................................
      }else{
        /* A divide operator */
        pToken->eType = TT_Other;
        pToken->nText = 1 + (z[i+1]=='+');
      }
      break;

    case '0': 
      if( z[i+1]=='x' || z[i+1]=='X' ){
        /* A hex constant */
        i += 2;
        while( isxdigit(z[i]) ){ i++; }
      }else{
        /* An octal constant */
        while( isdigit(z[i]) ){ i++; }
................................................................................
    case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W':
    case 'X': case 'Y': case 'Z': case '_':
      while( isalnum(z[i]) || z[i]=='_' ){ i++; };
      pToken->eType = TT_Id;
      pToken->nText = i - pIn->i;
      break;

    case ':': 
      pToken->eType = TT_Other;
      pToken->nText = 1 + (z[i+1]==':');
      break;

    case '=':
    case '<':
    case '>':
    case '+':
    case '-':
    case '*':
    case '%':
    case '^':
    case '&':
    case '|': 
      pToken->eType = TT_Other;
      pToken->nText = 1 + (z[i+1]=='=');
      break;

    default:
      pToken->eType = TT_Other;
      pToken->nText = 1;
................................................................................
        }
        break;
    }
  }
  /* NOT REACHED */
}

/* 
** This routine looks for identifiers (strings of contiguous alphanumeric
** characters) within a preprocessor directive and adds every such string
** found to the given identifier table
*/
static void FindIdentifiersInMacro(Token *pToken, IdentTable *pTable){
  Token sToken;
  InStream sIn;
................................................................................
        return nErr;

      case TT_Id:
        if( pTable ){
          IdentTableInsert(pTable,pToken->zText,pToken->nText);
        }
        break;
  
      case TT_Preprocessor:
        if( pTable!=0 ){
          FindIdentifiersInMacro(pToken,pTable);
        }
        break;

      case TT_Other:
................................................................................
  if( zFile==0 ){
    fprintf(stderr,"Can't read file \"%s\"\n",argv[1]);
    exit(1);
  }
  pList = TokenizeFile(zFile,&sTable);
  for(p=pList; p; p=p->pNext){
    int j;
    switch( p->eType ){ 
      case TT_Space:
        printf("%4d: Space\n",p->nLine);
        break;
      case TT_Id:
        printf("%4d: Id           %.*s\n",p->nLine,p->nText,p->zText);
        break;
      case TT_Preprocessor:
................................................................................
      case TT_Number:
        printf("%s%.*s", needSpace ? " " : "", pFirst->nText, pFirst->zText);
        needSpace = 1;
        break;

      default:
        c = pFirst->zText[0];
        printf("%s%.*s", 
          (needSpace && (c=='*' || c=='{')) ? " " : "",
          pFirst->nText, pFirst->zText);
        needSpace = pFirst->zText[0]==',';
        break;
    }
    pFirst = pFirst->pNext;
  }
................................................................................
  int iSkip = 0;
  int skipOne = 0;

  StringInit(&str);
  pLast = pLast->pNext;
  while( pFirst!=pLast ){
    if( pFirst==pSkip ){ iSkip = nSkip; }
    if( iSkip>0 ){ 
      iSkip--;
      pFirst=pFirst->pNext; 
      continue;
    }
    switch( pFirst->eType ){
      case TT_Preprocessor:
        StringAppend(&str,"\n",1);
        StringAppend(&str,pFirst->zText,pFirst->nText);
        StringAppend(&str,"\n",1);
        needSpace = 0;
        break;

      case TT_Id: 
        switch( pFirst->zText[0] ){
          case 'E':        
            if( pFirst->nText==6 && strncmp(pFirst->zText,"EXPORT",6)==0 ){
              skipOne = 1;
            }
            break;
          case 'P':
            switch( pFirst->nText ){
              case 6:  skipOne = !strncmp(pFirst->zText,"PUBLIC", 6);    break;
................................................................................
    return 0;
  }
  pLast = pLast->pNext;
  for(p=pFirst; p && p!=pLast; p=p->pNext){
    if( p->eType==TT_Id ){
      static IdentTable sReserved;
      static int isInit = 0;
      static char *aWords[] = { "char", "class", 
       "const", "double", "enum", "extern", "EXPORT", "ET_PROC", 
       "float", "int", "long",
       "PRIVATE", "PROTECTED", "PUBLIC",
       "register", "static", "struct", "sizeof", "signed", "typedef", 
       "union", "volatile", "virtual", "void", };
  
      if( !isInit ){
        int i;
        for(i=0; i<sizeof(aWords)/sizeof(aWords[0]); i++){
          IdentTableInsert(&sReserved,aWords[i],0);
        }
        isInit = 1;
      }
................................................................................
    return 0;
  }
  pCode = pLast;
  while( pLast && pLast!=pFirst && pLast->zText[0]!=')' ){
    pLast = pLast->pPrev;
  }
  if( pLast==0 || pLast==pFirst || pFirst->pNext==pLast ){
    fprintf(stderr,"%s:%d: Unrecognized syntax.\n", 
      zFilename, pFirst->nLine);
    return 1;
  }
  if( flags & (PS_Interface|PS_Export|PS_Local) ){
    fprintf(stderr,"%s:%d: Missing \"inline\" on function or procedure.\n",
      zFilename, pFirst->nLine);
    return 1;
................................................................................
    fprintf(stderr,"%s:%d: malformed inline procedure definition\n",
      zFilename, pFirst->nLine);
    return 1;
  }

#ifdef DEBUG
  if( debugMask & PARSER ){
    printf("**** Found inline routine: %.*s on line %d...\n", 
       pName->nText, pName->zText, pFirst->nLine);
    PrintTokens(pFirst,pEnd);
    printf("\n");
  }
#endif
  pDecl = CreateDecl(pName->zText,pName->nText);
  pDecl->pComment = pFirst->pComment;
................................................................................
**
** If pEnd is ';', then the determination is more difficult.  We have
** to search for an occurrence of an ID followed immediately by '('.
** If found, we have a prototype.  Otherwise we are dealing with a
** variable definition.
*/
static int isVariableDef(Token *pFirst, Token *pEnd){
  if( pEnd && pEnd->zText[0]=='=' && 
    (pEnd->pPrev->nText!=8 || strncmp(pEnd->pPrev->zText,"operator",8)!=0)
  ){
    return 1;
  }
  while( pFirst && pFirst!=pEnd && pFirst->pNext && pFirst->pNext!=pEnd ){
    if( pFirst->eType==TT_Id && pFirst->pNext->zText[0]=='(' ){
      return 0;
................................................................................
      ** option was specified or the "LOCAL" keyword is used. */
      return nErr;
    }
    while( pFirst!=0 && pFirst->pNext!=pEnd &&
       ((pFirst->nText==6 && strncmp(pFirst->zText,"static",6)==0)
        || (pFirst->nText==5 && strncmp(pFirst->zText,"LOCAL",6)==0))
    ){
      /* Lose the initial "static" or local from local variables. 
      ** We'll prepend "extern" later. */
      pFirst = pFirst->pNext;
      isLocal = 1;
    }
    if( pFirst==0 || !isLocal ){
      return nErr;
    }
  }else if( flags & PS_Method ){
    /* Methods are declared by their class.  Don't declare separately. */
    return nErr;
  }
  isVar =  (flags & (PS_Typedef|PS_Method))==0 && isVariableDef(pFirst,pEnd);
  if( isVar && (flags & (PS_Interface|PS_Export|PS_Local))!=0 
  && (flags & PS_Extern)==0 ){
    fprintf(stderr,"%s:%d: Can't define a variable in this context\n",
      zFilename, pFirst->nLine);
    nErr++;
  }
  pName = FindDeclName(pFirst,pEnd->pPrev);
  if( pName==0 ){
................................................................................
  nCmd = 1;
  while( isalpha(zCmd[nCmd]) ){
    nCmd++;
  }

  if( nCmd==5 && strncmp(zCmd,"endif",5)==0 ){
    /*
    ** Pop the if stack 
    */
    pIf = ifStack;
    if( pIf==0 ){
      fprintf(stderr,"%s:%d: extra '#endif'.\n",zFilename,pToken->nLine);
      return 1;
    }
    ifStack = pIf->pNext;
    SafeFree(pIf);
  }else if( nCmd==6 && strncmp(zCmd,"define",6)==0 ){
    /*
    ** Record a #define if we are in PS_Interface or PS_Export 
    */
    Decl *pDecl;
    if( !(flags & (PS_Local|PS_Interface|PS_Export)) ){ return 0; }
    zArg = &zCmd[6];
    while( *zArg && isspace(*zArg) && *zArg!='\n' ){
      zArg++;
    }
................................................................................
    if( flags & PS_Export ){
      DeclSetProperty(pDecl,DP_Export);
    }else if( flags & PS_Local ){
      DeclSetProperty(pDecl,DP_Local);
    }
  }else if( nCmd==7 && strncmp(zCmd,"include",7)==0 ){
    /*
    ** Record an #include if we are in PS_Interface or PS_Export 
    */
    Include *pInclude;
    char *zIf;

    if( !(flags & (PS_Interface|PS_Export)) ){ return 0; }
    zArg = &zCmd[7];
    while( *zArg && isspace(*zArg) ){ zArg++; }
................................................................................
      PushIfMacro(0,0,0,pToken->nLine,PS_Export);
    }else if( nArg==15 && strncmp(zArg,"LOCAL_INTERFACE",15)==0 ){
      PushIfMacro(0,0,0,pToken->nLine,PS_Local);
    }else{
      PushIfMacro(0,zArg,nArg,pToken->nLine,0);
    }
  }else if( nCmd==5 && strncmp(zCmd,"ifdef",5)==0 ){
    /* 
    ** Push an #ifdef.
    */
    zArg = &zCmd[5];
    while( *zArg && isspace(*zArg) && *zArg!='\n' ){
      zArg++;
    }
    if( *zArg==0 || *zArg=='\n' ){ return 0; }
................................................................................
      zArg++;
    }
    if( *zArg==0 || *zArg=='\n' ){ return 0; }
    nArg = pToken->nText + (int)(pToken->zText - zArg);
    PushIfMacro("!defined",zArg,nArg,pToken->nLine,0);
  }else if( nCmd==4 && strncmp(zCmd,"else",4)==0 ){
    /*
    ** Invert the #if on the top of the stack 
    */
    if( ifStack==0 ){
      fprintf(stderr,"%s:%d: '#else' without an '#if'\n",zFilename,
         pToken->nLine);
      return 1;
    }
    pIf = ifStack;
................................................................................
      PushIfMacro("!",pIf->zCondition,strlen(pIf->zCondition),pIf->nLine,0);
      SafeFree(pIf);
    }else{
      pIf->flags = 0;
    }
  }else{
    /*
    ** This directive can be safely ignored 
    */
    return 0;
  }

  /* 
  ** Recompute the preset flags 
  */
  *pPresetFlags = 0;
  for(pIf = ifStack; pIf; pIf=pIf->pNext){
    *pPresetFlags |= pIf->flags;
  }
    
  return nErr;
}

/*
** Parse an entire file.  Return the number of errors.
**
** pList is a list of tokens in the file.  Whitespace tokens have been
** eliminated, and text with {...} has been collapsed into a
** single TT_Brace token.
** 
** initFlags are a set of parse flags that should always be set for this
** file.  For .c files this is normally 0.  For .h files it is PS_Interface.
*/
static int ParseFile(Token *pList, int initFlags){
  int nErr = 0;
  Token *pStart = 0;
  int flags = initFlags;
................................................................................
      case ';':
        nErr += ProcessDecl(pStart,pList,flags);
        pStart = 0;
        flags = presetFlags;
        break;

      case '=':
        if( pList->pPrev->nText==8 
            && strncmp(pList->pPrev->zText,"operator",8)==0 ){
          break;
        }
        nErr += ProcessDecl(pStart,pList,flags);
        pStart = 0;
        while( pList && pList->zText[0]!=';' ){
          pList = pList->pNext;
................................................................................
  pDecl->zDecl = StrDup(StringGet(&str), 0);
  StringReset(&str);
  pDecl->zExtra = 0;
}

/*
** Reset the DP_Forward and DP_Declared flags on all Decl structures.
** Set both flags for anything that is tagged as local and isn't 
** in the file zFilename so that it won't be printing in other files.
*/
static void ResetDeclFlags(char *zFilename){
  Decl *pDecl;

  for(pDecl = pDeclFirst; pDecl; pDecl = pDecl->pNext){
    DeclClearProperty(pDecl,DP_Forward|DP_Declared);
................................................................................
){
  Decl *p;               /* The object to be declared */
  int flag;
  int isCpp;             /* True if generating C++ */
  int doneTypedef = 0;   /* True if a typedef has been done for this object */

  /* printf("BEGIN %s of %s\n",needFullDecl?"FULL":"PROTOTYPE",pDecl->zName);*/
  /* 
  ** For any object that has a forward declaration, go ahead and do the
  ** forward declaration first.
  */
  isCpp = (pState->flags & DP_Cplusplus) != 0;
  for(p=pDecl; p; p=p->pSameName){
    if( p->zFwd ){
      if( !DeclHasProperty(p,DP_Forward) ){
................................................................................
  ** with the DP_Flag bit.  We are only able to use DP_Flag in this
  ** way because we know we'll never execute this far into this
  ** function on a recursive call with the same pDecl.  Hence, recursive
  ** calls to this function (through ScanText()) can never change the
  ** value of DP_Flag out from under us.
  */
  for(p=pDecl; p; p=p->pSameName){
    if( !DeclHasProperty(p,DP_Declared) 
     && (p->zFwd==0 || needFullDecl) 
     && p->zDecl!=0
    ){
      DeclSetProperty(p,DP_Forward|DP_Declared|DP_Flag);
    }else{
      DeclClearProperty(p,DP_Flag);
    }
  }
................................................................................
      /*
      ** See if there is a declaration in the database with the name given
      ** by sToken.
      */
      pDecl = FindDecl(sToken.zText,sToken.nText);
      if( pDecl==0 ) continue;

      /* 
      ** If we get this far, we've found an identifier that has a 
      ** declaration in the database.  Now see if we the full declaration
      ** or just a forward declaration.
      */
      GetNonspaceToken(&sIn,&sNext);
      if( sNext.zText[0]=='*' ){
        needFullDecl = 0;
      }else{
................................................................................
static void CompleteForwardDeclarations(GenState *pState){
  Decl *pDecl;
  int progress;

  do{
    progress = 0;
    for(pDecl=pDeclFirst; pDecl; pDecl=pDecl->pNext){
      if( DeclHasProperty(pDecl,DP_Forward) 
       && !DeclHasProperty(pDecl,DP_Declared) 
      ){
        DeclareObject(pDecl,pState,1);
        progress = 1;
        assert( DeclHasProperty(pDecl,DP_Declared) );
      }
    }
  }while( progress );
................................................................................
    if( WriteFile(pFile->zHdr,zNewVersion) ){
      fprintf(stderr,"%s: Can't write to file\n",pFile->zHdr);
      nErr++;
    }
  }else if( report ){
    fprintf(report,"unchanged\n");
  }
  SafeFree(zOldVersion); 
  IdentTableReset(&includeTable);
  StringReset(&outStr);
  return nErr;
}

/*
** Generate a global header file -- a header file that contains all
................................................................................
      DeclareObject(pDecl,&sState,1);
    }
  }
  ChangeIfContext(0,&sState);
  printf("%s",StringGet(&outStr));
  IdentTableReset(&includeTable);
  StringReset(&outStr);
  return 0;  
}

#ifdef DEBUG
/*
** Return the number of characters in the given string prior to the
** first newline.
*/
................................................................................
*/
static InFile *CreateInFile(char *zArg, int *pnErr){
  int nSrc;
  char *zSrc;
  InFile *pFile;
  int i;

  /* 
  ** Get the name of the input file to be scanned.  The input file is
  ** everything before the first ':' or the whole file if no ':' is seen.
  **
  ** Except, on windows, ignore any ':' that occurs as the second character
  ** since it might be part of the drive specifier.  So really, the ":' has
  ** to be the 3rd or later character in the name.  This precludes 1-character
  ** file names, which really should not be a problem.
................................................................................
      SafeFree(pFile->zHdr);
      pFile->zHdr = 0;
    }
  }

  /*
  ** If pFile->zSrc contains no 'c' or 'C' in its extension, it
  ** must be a header file.   In that case, we need to set the 
  ** PS_Interface flag.
  */
  pFile->flags |= PS_Interface;
  for(i=nSrc-1; i>0 && zSrc[i]!='.'; i--){
    if( zSrc[i]=='c' || zSrc[i]=='C' ){
      pFile->flags &= ~PS_Interface;
      break;
    }
  }

  /* Done! 
  */
  return pFile;
}

/* MS-Windows and MS-DOS both have the following serious OS bug:  the
** length of a command line is severely restricted.  But this program
** occasionally requires long command lines.  Hence the following
................................................................................
  }
  c = ' ';
  while( c!=EOF ){
    while( c!=EOF && isspace(c) ){
      if( c=='\n' ){
        startOfLine = 1;
      }
      c = getc(in); 
      if( startOfLine && c=='#' ){
        while( c!=EOF && c!='\n' ){
          c = getc(in);
        }
      }
    }
    n = 0;
................................................................................
      nNew++;
      if( nNew + argc > nAlloc ){
        if( nAlloc==0 ){
          nAlloc = 100 + argc;
          zNew = malloc( sizeof(char*) * nAlloc );
        }else{
          nAlloc *= 2;
          zNew = realloc( zNew, sizeof(char*) * nAlloc );  
        }
      }
      if( zNew ){
        int j = nNew + index;
        zNew[j] = malloc( n + 1 );
        if( zNew[j] ){
          strcpy( zNew[j], zBuf );
................................................................................
  );
}

/*
** The following text contains a few simple #defines that we want
** to be available to every file.
*/
static char zInit[] = 
  "#define INTERFACE 0\n"
  "#define EXPORT_INTERFACE 0\n"
  "#define LOCAL_INTERFACE 0\n"
  "#define EXPORT\n"
  "#define LOCAL static\n"
  "#define PUBLIC\n"
  "#define PRIVATE\n"







|
|






|







 







|







 







|







 







|







 







|







 







|







|







 







|







 







|
|







 







|







 







|













|







 







|







 







|







 







|







 







|







 







|

|










|

|







 







|
|


|

|







 







|







 







|







 







|







 







|












|







 







|










|







 







|







 







|







 







|







 







|




|
|





|









|







 







|







 







|







 







|







 







|
|







 







|
|







 







|
|







 







|







 







|







 







|







 







|










|







 







|







 







|







 







|







110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
...
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
...
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
...
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
...
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
...
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
...
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
...
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
...
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
...
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
....
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
....
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
....
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
....
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
....
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
....
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
....
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
....
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
....
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
....
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
....
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
....
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
....
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
....
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
....
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
....
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
....
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
....
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
....
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
....
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
....
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
....
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
....
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
....
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
....
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
....
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
....
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
....
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
** doesn't tell about the objects structure.  A typical forward declaration
** is:
**
**          struct Xyzzy;
**
** Not every object has a forward declaration.  If it does, thought, the
** forward declaration will be contained in the zFwd field for C and
** the zFwdCpp for C++.  The zDecl field contains the complete
** declaration text.
*/
typedef struct Decl Decl;
struct Decl {
  char *zName;       /* Name of the object being declared.  The appearance
                     ** of this name is a source file triggers the declaration
                     ** to be added to the header for that file. */
  const char *zFile; /* File from which extracted.  */
  char *zIf;         /* Surround the declaration with this #if */
  char *zFwd;        /* A forward declaration.  NULL if there is none. */
  char *zFwdCpp;     /* Use this forward declaration for C++. */
  char *zDecl;       /* A full declaration of this object */
  char *zExtra;      /* Extra declaration text inserted into class objects */
  int extraType;     /* Last public:, protected: or private: in zExtraDecl */
  struct Include *pInclude;   /* #includes that come before this declaration */
................................................................................
**                        a library, then the object is not visible to users
**                        of the library.  (i.e. the object does not appear
**                        in the output when using the -H option.)
**
**    EXPORT scope        The object is visible and usable everywhere.
**
** The DP_Flag is a temporary use flag that is used during processing to
** prevent an infinite loop.  It's use is localized.
**
** The DP_Cplusplus, DP_ExternCReqd and DP_ExternReqd flags are permanent
** and are used to specify what type of declaration the object requires.
*/
#define DP_Forward      0x001   /* Has a forward declaration in this file */
#define DP_Declared     0x002   /* Has a full declaration in this file */
#define DP_Export       0x004   /* Export this declaration */
................................................................................
** the same "flags" field.
**
** Be careful not to confuse PS_Export with DP_Export or
** PS_Local with DP_Local.  Their names are similar, but the meanings
** of these flags are very different.
*/
#define PS_Extern        0x000800    /* "extern" has been seen */
#define PS_Export        0x001000    /* If between "#if EXPORT_INTERFACE"
                                     ** and "#endif" */
#define PS_Export2       0x002000    /* If "EXPORT" seen */
#define PS_Typedef       0x004000    /* If "typedef" has been seen */
#define PS_Static        0x008000    /* If "static" has been seen */
#define PS_Interface     0x010000    /* If within #if INTERFACE..#endif */
#define PS_Method        0x020000    /* If "::" token has been seen */
#define PS_Local         0x040000    /* If within #if LOCAL_INTERFACE..#endif */
................................................................................
#define TY_Variable      0x01000000
#define TY_Structure     0x02000000
#define TY_Union         0x04000000
#define TY_Enumeration   0x08000000
#define TY_Defunct       0x10000000  /* Used to erase a declaration */

/*
** Each nested #if (or #ifdef or #ifndef) is stored in a stack of
** instances of the following structure.
*/
typedef struct Ifmacro Ifmacro;
struct Ifmacro {
  int nLine;         /* Line number where this macro occurs */
  char *zCondition;  /* Text of the condition for this macro */
  Ifmacro *pNext;    /* Next down in the stack */
................................................................................
  char *zHdr;              /* Name of the generated .h file for this input.
                           ** Will be NULL if input is to be scanned only */
  int flags;               /* One or more DP_, PS_ and/or TY_ flags */
  InFile *pNext;           /* Next input file in the list of them all */
  IdentTable idTable;      /* All identifiers in this input file */
};

/*
** An unbounded string is able to grow without limit.  We use these
** to construct large in-memory strings from lots of smaller components.
*/
typedef struct String String;
struct String {
  int nAlloc;      /* Number of bytes allocated */
  int nUsed;       /* Number of bytes used (not counting null terminator) */
................................................................................
** The following text line appears at the top of every file generated
** by this program.  By recognizing this line, the program can be sure
** never to read a file that it generated itself.
**
** The "#undef INTERFACE" part is a hack to work around a name collision
** in MSVC 2008.
*/
const char zTopLine[] =
  "/* \aThis file was automatically generated.  Do not edit! */\n"
  "#undef INTERFACE\n";
#define nTopLine (sizeof(zTopLine)-1)

/*
** The name of the file currently being parsed.
*/
static const char *zFilename;

/*
** The stack of #if macros for the file currently being parsed.
*/
static Ifmacro *ifStack = 0;

/*
................................................................................
*/
static char *ReadFile(const char *zFilename){
  struct stat sStat;
  FILE *pIn;
  char *zBuf;
  int n;

  if( stat(zFilename,&sStat)!=0
#ifndef WIN32
    || !S_ISREG(sStat.st_mode)
#endif
  ){
    return 0;
  }
  pIn = fopen(zFilename,"r");
................................................................................
              }else{
                 isBlockComment = 0;
              }
            }
          }
          i++;
        }
        if( z[i] ){
          i += 2;
        }else{
          isBlockComment = 0;
          fprintf(stderr,"%s:%d: Unterminated comment\n",
            zFilename, startLine);
          nErr++;
        }
        pToken->eType = isBlockComment==2 ? TT_BlockComment : TT_Comment;
................................................................................
      }else{
        /* A divide operator */
        pToken->eType = TT_Other;
        pToken->nText = 1 + (z[i+1]=='+');
      }
      break;

    case '0':
      if( z[i+1]=='x' || z[i+1]=='X' ){
        /* A hex constant */
        i += 2;
        while( isxdigit(z[i]) ){ i++; }
      }else{
        /* An octal constant */
        while( isdigit(z[i]) ){ i++; }
................................................................................
    case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W':
    case 'X': case 'Y': case 'Z': case '_':
      while( isalnum(z[i]) || z[i]=='_' ){ i++; };
      pToken->eType = TT_Id;
      pToken->nText = i - pIn->i;
      break;

    case ':':
      pToken->eType = TT_Other;
      pToken->nText = 1 + (z[i+1]==':');
      break;

    case '=':
    case '<':
    case '>':
    case '+':
    case '-':
    case '*':
    case '%':
    case '^':
    case '&':
    case '|':
      pToken->eType = TT_Other;
      pToken->nText = 1 + (z[i+1]=='=');
      break;

    default:
      pToken->eType = TT_Other;
      pToken->nText = 1;
................................................................................
        }
        break;
    }
  }
  /* NOT REACHED */
}

/*
** This routine looks for identifiers (strings of contiguous alphanumeric
** characters) within a preprocessor directive and adds every such string
** found to the given identifier table
*/
static void FindIdentifiersInMacro(Token *pToken, IdentTable *pTable){
  Token sToken;
  InStream sIn;
................................................................................
        return nErr;

      case TT_Id:
        if( pTable ){
          IdentTableInsert(pTable,pToken->zText,pToken->nText);
        }
        break;

      case TT_Preprocessor:
        if( pTable!=0 ){
          FindIdentifiersInMacro(pToken,pTable);
        }
        break;

      case TT_Other:
................................................................................
  if( zFile==0 ){
    fprintf(stderr,"Can't read file \"%s\"\n",argv[1]);
    exit(1);
  }
  pList = TokenizeFile(zFile,&sTable);
  for(p=pList; p; p=p->pNext){
    int j;
    switch( p->eType ){
      case TT_Space:
        printf("%4d: Space\n",p->nLine);
        break;
      case TT_Id:
        printf("%4d: Id           %.*s\n",p->nLine,p->nText,p->zText);
        break;
      case TT_Preprocessor:
................................................................................
      case TT_Number:
        printf("%s%.*s", needSpace ? " " : "", pFirst->nText, pFirst->zText);
        needSpace = 1;
        break;

      default:
        c = pFirst->zText[0];
        printf("%s%.*s",
          (needSpace && (c=='*' || c=='{')) ? " " : "",
          pFirst->nText, pFirst->zText);
        needSpace = pFirst->zText[0]==',';
        break;
    }
    pFirst = pFirst->pNext;
  }
................................................................................
  int iSkip = 0;
  int skipOne = 0;

  StringInit(&str);
  pLast = pLast->pNext;
  while( pFirst!=pLast ){
    if( pFirst==pSkip ){ iSkip = nSkip; }
    if( iSkip>0 ){
      iSkip--;
      pFirst=pFirst->pNext;
      continue;
    }
    switch( pFirst->eType ){
      case TT_Preprocessor:
        StringAppend(&str,"\n",1);
        StringAppend(&str,pFirst->zText,pFirst->nText);
        StringAppend(&str,"\n",1);
        needSpace = 0;
        break;

      case TT_Id:
        switch( pFirst->zText[0] ){
          case 'E':
            if( pFirst->nText==6 && strncmp(pFirst->zText,"EXPORT",6)==0 ){
              skipOne = 1;
            }
            break;
          case 'P':
            switch( pFirst->nText ){
              case 6:  skipOne = !strncmp(pFirst->zText,"PUBLIC", 6);    break;
................................................................................
    return 0;
  }
  pLast = pLast->pNext;
  for(p=pFirst; p && p!=pLast; p=p->pNext){
    if( p->eType==TT_Id ){
      static IdentTable sReserved;
      static int isInit = 0;
      static const char *aWords[] = { "char", "class",
       "const", "double", "enum", "extern", "EXPORT", "ET_PROC",
       "float", "int", "long",
       "PRIVATE", "PROTECTED", "PUBLIC",
       "register", "static", "struct", "sizeof", "signed", "typedef",
       "union", "volatile", "virtual", "void", };

      if( !isInit ){
        int i;
        for(i=0; i<sizeof(aWords)/sizeof(aWords[0]); i++){
          IdentTableInsert(&sReserved,aWords[i],0);
        }
        isInit = 1;
      }
................................................................................
    return 0;
  }
  pCode = pLast;
  while( pLast && pLast!=pFirst && pLast->zText[0]!=')' ){
    pLast = pLast->pPrev;
  }
  if( pLast==0 || pLast==pFirst || pFirst->pNext==pLast ){
    fprintf(stderr,"%s:%d: Unrecognized syntax.\n",
      zFilename, pFirst->nLine);
    return 1;
  }
  if( flags & (PS_Interface|PS_Export|PS_Local) ){
    fprintf(stderr,"%s:%d: Missing \"inline\" on function or procedure.\n",
      zFilename, pFirst->nLine);
    return 1;
................................................................................
    fprintf(stderr,"%s:%d: malformed inline procedure definition\n",
      zFilename, pFirst->nLine);
    return 1;
  }

#ifdef DEBUG
  if( debugMask & PARSER ){
    printf("**** Found inline routine: %.*s on line %d...\n",
       pName->nText, pName->zText, pFirst->nLine);
    PrintTokens(pFirst,pEnd);
    printf("\n");
  }
#endif
  pDecl = CreateDecl(pName->zText,pName->nText);
  pDecl->pComment = pFirst->pComment;
................................................................................
**
** If pEnd is ';', then the determination is more difficult.  We have
** to search for an occurrence of an ID followed immediately by '('.
** If found, we have a prototype.  Otherwise we are dealing with a
** variable definition.
*/
static int isVariableDef(Token *pFirst, Token *pEnd){
  if( pEnd && pEnd->zText[0]=='=' &&
    (pEnd->pPrev->nText!=8 || strncmp(pEnd->pPrev->zText,"operator",8)!=0)
  ){
    return 1;
  }
  while( pFirst && pFirst!=pEnd && pFirst->pNext && pFirst->pNext!=pEnd ){
    if( pFirst->eType==TT_Id && pFirst->pNext->zText[0]=='(' ){
      return 0;
................................................................................
      ** option was specified or the "LOCAL" keyword is used. */
      return nErr;
    }
    while( pFirst!=0 && pFirst->pNext!=pEnd &&
       ((pFirst->nText==6 && strncmp(pFirst->zText,"static",6)==0)
        || (pFirst->nText==5 && strncmp(pFirst->zText,"LOCAL",6)==0))
    ){
      /* Lose the initial "static" or local from local variables.
      ** We'll prepend "extern" later. */
      pFirst = pFirst->pNext;
      isLocal = 1;
    }
    if( pFirst==0 || !isLocal ){
      return nErr;
    }
  }else if( flags & PS_Method ){
    /* Methods are declared by their class.  Don't declare separately. */
    return nErr;
  }
  isVar =  (flags & (PS_Typedef|PS_Method))==0 && isVariableDef(pFirst,pEnd);
  if( isVar && (flags & (PS_Interface|PS_Export|PS_Local))!=0
  && (flags & PS_Extern)==0 ){
    fprintf(stderr,"%s:%d: Can't define a variable in this context\n",
      zFilename, pFirst->nLine);
    nErr++;
  }
  pName = FindDeclName(pFirst,pEnd->pPrev);
  if( pName==0 ){
................................................................................
  nCmd = 1;
  while( isalpha(zCmd[nCmd]) ){
    nCmd++;
  }

  if( nCmd==5 && strncmp(zCmd,"endif",5)==0 ){
    /*
    ** Pop the if stack
    */
    pIf = ifStack;
    if( pIf==0 ){
      fprintf(stderr,"%s:%d: extra '#endif'.\n",zFilename,pToken->nLine);
      return 1;
    }
    ifStack = pIf->pNext;
    SafeFree(pIf);
  }else if( nCmd==6 && strncmp(zCmd,"define",6)==0 ){
    /*
    ** Record a #define if we are in PS_Interface or PS_Export
    */
    Decl *pDecl;
    if( !(flags & (PS_Local|PS_Interface|PS_Export)) ){ return 0; }
    zArg = &zCmd[6];
    while( *zArg && isspace(*zArg) && *zArg!='\n' ){
      zArg++;
    }
................................................................................
    if( flags & PS_Export ){
      DeclSetProperty(pDecl,DP_Export);
    }else if( flags & PS_Local ){
      DeclSetProperty(pDecl,DP_Local);
    }
  }else if( nCmd==7 && strncmp(zCmd,"include",7)==0 ){
    /*
    ** Record an #include if we are in PS_Interface or PS_Export
    */
    Include *pInclude;
    char *zIf;

    if( !(flags & (PS_Interface|PS_Export)) ){ return 0; }
    zArg = &zCmd[7];
    while( *zArg && isspace(*zArg) ){ zArg++; }
................................................................................
      PushIfMacro(0,0,0,pToken->nLine,PS_Export);
    }else if( nArg==15 && strncmp(zArg,"LOCAL_INTERFACE",15)==0 ){
      PushIfMacro(0,0,0,pToken->nLine,PS_Local);
    }else{
      PushIfMacro(0,zArg,nArg,pToken->nLine,0);
    }
  }else if( nCmd==5 && strncmp(zCmd,"ifdef",5)==0 ){
    /*
    ** Push an #ifdef.
    */
    zArg = &zCmd[5];
    while( *zArg && isspace(*zArg) && *zArg!='\n' ){
      zArg++;
    }
    if( *zArg==0 || *zArg=='\n' ){ return 0; }
................................................................................
      zArg++;
    }
    if( *zArg==0 || *zArg=='\n' ){ return 0; }
    nArg = pToken->nText + (int)(pToken->zText - zArg);
    PushIfMacro("!defined",zArg,nArg,pToken->nLine,0);
  }else if( nCmd==4 && strncmp(zCmd,"else",4)==0 ){
    /*
    ** Invert the #if on the top of the stack
    */
    if( ifStack==0 ){
      fprintf(stderr,"%s:%d: '#else' without an '#if'\n",zFilename,
         pToken->nLine);
      return 1;
    }
    pIf = ifStack;
................................................................................
      PushIfMacro("!",pIf->zCondition,strlen(pIf->zCondition),pIf->nLine,0);
      SafeFree(pIf);
    }else{
      pIf->flags = 0;
    }
  }else{
    /*
    ** This directive can be safely ignored
    */
    return 0;
  }

  /*
  ** Recompute the preset flags
  */
  *pPresetFlags = 0;
  for(pIf = ifStack; pIf; pIf=pIf->pNext){
    *pPresetFlags |= pIf->flags;
  }

  return nErr;
}

/*
** Parse an entire file.  Return the number of errors.
**
** pList is a list of tokens in the file.  Whitespace tokens have been
** eliminated, and text with {...} has been collapsed into a
** single TT_Brace token.
**
** initFlags are a set of parse flags that should always be set for this
** file.  For .c files this is normally 0.  For .h files it is PS_Interface.
*/
static int ParseFile(Token *pList, int initFlags){
  int nErr = 0;
  Token *pStart = 0;
  int flags = initFlags;
................................................................................
      case ';':
        nErr += ProcessDecl(pStart,pList,flags);
        pStart = 0;
        flags = presetFlags;
        break;

      case '=':
        if( pList->pPrev->nText==8
            && strncmp(pList->pPrev->zText,"operator",8)==0 ){
          break;
        }
        nErr += ProcessDecl(pStart,pList,flags);
        pStart = 0;
        while( pList && pList->zText[0]!=';' ){
          pList = pList->pNext;
................................................................................
  pDecl->zDecl = StrDup(StringGet(&str), 0);
  StringReset(&str);
  pDecl->zExtra = 0;
}

/*
** Reset the DP_Forward and DP_Declared flags on all Decl structures.
** Set both flags for anything that is tagged as local and isn't
** in the file zFilename so that it won't be printing in other files.
*/
static void ResetDeclFlags(char *zFilename){
  Decl *pDecl;

  for(pDecl = pDeclFirst; pDecl; pDecl = pDecl->pNext){
    DeclClearProperty(pDecl,DP_Forward|DP_Declared);
................................................................................
){
  Decl *p;               /* The object to be declared */
  int flag;
  int isCpp;             /* True if generating C++ */
  int doneTypedef = 0;   /* True if a typedef has been done for this object */

  /* printf("BEGIN %s of %s\n",needFullDecl?"FULL":"PROTOTYPE",pDecl->zName);*/
  /*
  ** For any object that has a forward declaration, go ahead and do the
  ** forward declaration first.
  */
  isCpp = (pState->flags & DP_Cplusplus) != 0;
  for(p=pDecl; p; p=p->pSameName){
    if( p->zFwd ){
      if( !DeclHasProperty(p,DP_Forward) ){
................................................................................
  ** with the DP_Flag bit.  We are only able to use DP_Flag in this
  ** way because we know we'll never execute this far into this
  ** function on a recursive call with the same pDecl.  Hence, recursive
  ** calls to this function (through ScanText()) can never change the
  ** value of DP_Flag out from under us.
  */
  for(p=pDecl; p; p=p->pSameName){
    if( !DeclHasProperty(p,DP_Declared)
     && (p->zFwd==0 || needFullDecl)
     && p->zDecl!=0
    ){
      DeclSetProperty(p,DP_Forward|DP_Declared|DP_Flag);
    }else{
      DeclClearProperty(p,DP_Flag);
    }
  }
................................................................................
      /*
      ** See if there is a declaration in the database with the name given
      ** by sToken.
      */
      pDecl = FindDecl(sToken.zText,sToken.nText);
      if( pDecl==0 ) continue;

      /*
      ** If we get this far, we've found an identifier that has a
      ** declaration in the database.  Now see if we the full declaration
      ** or just a forward declaration.
      */
      GetNonspaceToken(&sIn,&sNext);
      if( sNext.zText[0]=='*' ){
        needFullDecl = 0;
      }else{
................................................................................
static void CompleteForwardDeclarations(GenState *pState){
  Decl *pDecl;
  int progress;

  do{
    progress = 0;
    for(pDecl=pDeclFirst; pDecl; pDecl=pDecl->pNext){
      if( DeclHasProperty(pDecl,DP_Forward)
       && !DeclHasProperty(pDecl,DP_Declared)
      ){
        DeclareObject(pDecl,pState,1);
        progress = 1;
        assert( DeclHasProperty(pDecl,DP_Declared) );
      }
    }
  }while( progress );
................................................................................
    if( WriteFile(pFile->zHdr,zNewVersion) ){
      fprintf(stderr,"%s: Can't write to file\n",pFile->zHdr);
      nErr++;
    }
  }else if( report ){
    fprintf(report,"unchanged\n");
  }
  SafeFree(zOldVersion);
  IdentTableReset(&includeTable);
  StringReset(&outStr);
  return nErr;
}

/*
** Generate a global header file -- a header file that contains all
................................................................................
      DeclareObject(pDecl,&sState,1);
    }
  }
  ChangeIfContext(0,&sState);
  printf("%s",StringGet(&outStr));
  IdentTableReset(&includeTable);
  StringReset(&outStr);
  return 0;
}

#ifdef DEBUG
/*
** Return the number of characters in the given string prior to the
** first newline.
*/
................................................................................
*/
static InFile *CreateInFile(char *zArg, int *pnErr){
  int nSrc;
  char *zSrc;
  InFile *pFile;
  int i;

  /*
  ** Get the name of the input file to be scanned.  The input file is
  ** everything before the first ':' or the whole file if no ':' is seen.
  **
  ** Except, on windows, ignore any ':' that occurs as the second character
  ** since it might be part of the drive specifier.  So really, the ":' has
  ** to be the 3rd or later character in the name.  This precludes 1-character
  ** file names, which really should not be a problem.
................................................................................
      SafeFree(pFile->zHdr);
      pFile->zHdr = 0;
    }
  }

  /*
  ** If pFile->zSrc contains no 'c' or 'C' in its extension, it
  ** must be a header file.   In that case, we need to set the
  ** PS_Interface flag.
  */
  pFile->flags |= PS_Interface;
  for(i=nSrc-1; i>0 && zSrc[i]!='.'; i--){
    if( zSrc[i]=='c' || zSrc[i]=='C' ){
      pFile->flags &= ~PS_Interface;
      break;
    }
  }

  /* Done!
  */
  return pFile;
}

/* MS-Windows and MS-DOS both have the following serious OS bug:  the
** length of a command line is severely restricted.  But this program
** occasionally requires long command lines.  Hence the following
................................................................................
  }
  c = ' ';
  while( c!=EOF ){
    while( c!=EOF && isspace(c) ){
      if( c=='\n' ){
        startOfLine = 1;
      }
      c = getc(in);
      if( startOfLine && c=='#' ){
        while( c!=EOF && c!='\n' ){
          c = getc(in);
        }
      }
    }
    n = 0;
................................................................................
      nNew++;
      if( nNew + argc > nAlloc ){
        if( nAlloc==0 ){
          nAlloc = 100 + argc;
          zNew = malloc( sizeof(char*) * nAlloc );
        }else{
          nAlloc *= 2;
          zNew = realloc( zNew, sizeof(char*) * nAlloc );
        }
      }
      if( zNew ){
        int j = nNew + index;
        zNew[j] = malloc( n + 1 );
        if( zNew[j] ){
          strcpy( zNew[j], zBuf );
................................................................................
  );
}

/*
** The following text contains a few simple #defines that we want
** to be available to every file.
*/
static const char zInit[] =
  "#define INTERFACE 0\n"
  "#define EXPORT_INTERFACE 0\n"
  "#define LOCAL_INTERFACE 0\n"
  "#define EXPORT\n"
  "#define LOCAL static\n"
  "#define PUBLIC\n"
  "#define PRIVATE\n"

Changes to src/makemake.tcl.

1
2
3
4
5
6
7
8
9
10
...
108
109
110
111
112
113
114

115
116
117
118
119
120
121
...
140
141
142
143
144
145
146


147
148
149
150
151
152
153
...
201
202
203
204
205
206
207









208
209
210
211
212
213
214
...
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
...
571
572
573
574
575
576
577
578

579
580
581
582
583
584
585
586
....
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
....
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
....
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
....
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
....
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
#!/usr/bin/tclsh
#
# Run this TCL script to generate the various makefiles for a variety
# of platforms.  Files generated include:
#
#     src/main.mk           # makefile for all unix systems
#     win/Makefile.mingw    # makefile for mingw on windows
#     win/Makefile.*        # makefiles for other windows compilers
#
# Run this script while in the "src" subdirectory.  Like this:
................................................................................
  sha1
  shun
  sitemap
  skins
  sqlcmd
  stash
  stat

  style
  sync
  tag
  tar
  th_main
  timeline
  tkt
................................................................................
  http_ssl
}

# Additional resource files that get built into the executable.
#
set extra_files {
  diff.tcl


}

# Options used to compile the included SQLite library.
#
set SQLITE_OPTIONS {
  -DNDEBUG=1
  -DSQLITE_OMIT_LOAD_EXTENSION=1
................................................................................
    puts $output_file [lindex $args 0]
  }
}

# STOP HERE.
# Unless the build procedures changes, you should not have to edit anything
# below this line.










##############################################################################
##############################################################################
##############################################################################
# Start by generating the "main.mk" makefile used for all unix systems.
#
puts "building main.mk"
................................................................................
#append mhargs "\$(SRCDIR)/cson_amalgamation.h <<<NEXT_LINE>>>"
append mhargs "\$(OBJDIR)/VERSION.h"
set mhargs [string map [list <<<NEXT_LINE>>> \\\n\t] $mhargs]
writeln "\$(OBJDIR)/page_index.h: \$(TRANS_SRC) \$(OBJDIR)/mkindex"
writeln "\t\$(OBJDIR)/mkindex \$(TRANS_SRC) >\$@\n"

writeln "\$(OBJDIR)/builtin_data.h: \$(OBJDIR)/mkbuiltin \$(EXTRA_FILES)"
writeln "\t\$(OBJDIR)/mkbuiltin \$(EXTRA_FILES) >\$@\n"

writeln "\$(OBJDIR)/headers:\t\$(OBJDIR)/page_index.h \$(OBJDIR)/builtin_data.h \$(OBJDIR)/makeheaders \$(OBJDIR)/VERSION.h"
writeln "\t\$(OBJDIR)/makeheaders $mhargs"
writeln "\ttouch \$(OBJDIR)/headers"
writeln "\$(OBJDIR)/headers: Makefile"
writeln "\$(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 : \$(SRCDIR)/json_detail.h"
writeln "Makefile:"
................................................................................
endif

#### The directories where the OpenSSL include and library files are located.
#    The recommended usage here is to use the Sysinternals junction tool
#    to create a hard link between an "openssl-1.x" sub-directory of the
#    Fossil source code directory and the target OpenSSL source directory.
#
OPENSSLINCDIR = $(SRCDIR)/../compat/openssl-1.0.1j/include

OPENSSLLIBDIR = $(SRCDIR)/../compat/openssl-1.0.1j

#### Either the directory where the Tcl library is installed or the Tcl
#    source code directory resides (depending on the value of the macro
#    FOSSIL_TCL_SOURCE).  If this points to the Tcl install directory,
#    this directory must have "include" and "lib" sub-directories.  If
#    this points to the Tcl source code directory, this directory must
#    have "generic" and "win" sub-directories.  The recommended usage
................................................................................
append mhargs " \\\n\t\t\$(SRCDIR)/sqlite3.h"
append mhargs " \\\n\t\t\$(SRCDIR)/th.h"
append mhargs " \\\n\t\t\$(OBJDIR)/VERSION.h"
writeln "\$(OBJDIR)/page_index.h: \$(TRANS_SRC) \$(MKINDEX)"
writeln "\t\$(MKINDEX) \$(TRANS_SRC) >\$@\n"

writeln "\$(OBJDIR)/builtin_data.h:\t\$(MKBUILTIN) \$(EXTRA_FILES)"
writeln "\t\$(MKBUILTIN) \$(EXTRA_FILES) >\$@\n"

writeln "\$(OBJDIR)/headers:\t\$(OBJDIR)/page_index.h \$(OBJDIR)/builtin_data.h \$(MAKEHEADERS) \$(OBJDIR)/VERSION.h"
writeln "\t\$(MAKEHEADERS) $mhargs"
writeln "\techo Done >\$(OBJDIR)/headers\n"
writeln "\$(OBJDIR)/headers: Makefile\n"
writeln "Makefile:\n"
set extra_h(main) " \$(OBJDIR)/page_index.h "
................................................................................
VERSION.h : mkversion$E $B\manifest.uuid $B\manifest $B\VERSION
	+$** > $@

page_index.h: mkindex$E $(SRC)
	+$** > $@

builtin_data.h:	mkbuiltin$E $(EXTRA_FILES)
	+$** > $@

clean:
	-del $(OBJDIR)\*.obj
	-del *.obj *_.c *.h *.map

realclean:
	-del $(APPNAME) translate$E mkindex$E makeheaders$E mkversion$E codecheck1$E mkbuiltin$E
................................................................................
# Uncomment to enable TH1 hooks
# FOSSIL_ENABLE_TH1_HOOKS = 1

# Uncomment to enable Tcl support
# FOSSIL_ENABLE_TCL = 1

!ifdef FOSSIL_ENABLE_SSL
SSLDIR    = $(B)\compat\openssl-1.0.1j
SSLINCDIR = $(SSLDIR)\inc32
SSLLIBDIR = $(SSLDIR)\out32
SSLLFLAGS = /nologo /opt:ref /debug
SSLLIB    = ssleay32.lib libeay32.lib user32.lib gdi32.lib
!if "$(PLATFORM)"=="amd64" || "$(PLATFORM)"=="x64"
!message Using 'x64' platform for OpenSSL...
# BUGBUG (OpenSSL): Apparently, using "no-ssl*" here breaks the build.
................................................................................
$(OX)\cson_amalgamation$O : $(SRCDIR)\cson_amalgamation.c
	$(TCC) /Fo$@ /c $**

page_index.h: mkindex$E $(SRC)
	$** > $@

builtin_data.h:	mkbuiltin$E $(EXTRA_FILES)
	$** > $@

clean:
	-del $(OX)\*.obj
	-del *.obj
	-del *_.c
	-del *.h
	-del *.ilk
................................................................................
	translate.exe $< >$@

# generate the index source, containing all web references,..
page_index.h:	$(TRANSLATEDSRC) mkindex.exe
	mkindex.exe $(TRANSLATEDSRC) >$@

builtin_data.h:	$(EXTRA_FILES) mkbuiltin.exe
	mkbuiltin.exe $(EXTRA_FILES) >$@

# extracting version info from manifest
VERSION.h:	version.exe ..\manifest.uuid ..\manifest ..\VERSION
	version.exe ..\manifest.uuid ..\manifest ..\VERSION  >$@

# generate the simplified headers
headers: makeheaders.exe page_index.h builtin_data.h VERSION.h ../src/sqlite3.h ../src/th.h VERSION.h


|







 







>







 







>
>







 







>
>
>
>
>
>
>
>
>







 







|







 







|
>
|







 







|







 







|







 







|







 







|







 







|







1
2
3
4
5
6
7
8
9
10
...
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
...
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
...
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
...
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
...
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
....
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
....
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
....
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
....
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
....
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
#!/usr/bin/tclsh
#
# Run this Tcl script to generate the various makefiles for a variety
# of platforms.  Files generated include:
#
#     src/main.mk           # makefile for all unix systems
#     win/Makefile.mingw    # makefile for mingw on windows
#     win/Makefile.*        # makefiles for other windows compilers
#
# Run this script while in the "src" subdirectory.  Like this:
................................................................................
  sha1
  shun
  sitemap
  skins
  sqlcmd
  stash
  stat
  statrep
  style
  sync
  tag
  tar
  th_main
  timeline
  tkt
................................................................................
  http_ssl
}

# Additional resource files that get built into the executable.
#
set extra_files {
  diff.tcl
  markdown.md
  ../skins/*/*.txt
}

# Options used to compile the included SQLite library.
#
set SQLITE_OPTIONS {
  -DNDEBUG=1
  -DSQLITE_OMIT_LOAD_EXTENSION=1
................................................................................
    puts $output_file [lindex $args 0]
  }
}

# STOP HERE.
# Unless the build procedures changes, you should not have to edit anything
# below this line.

# Expand any wildcards in "extra_files"
set new_extra_files {}
foreach file $extra_files {
  foreach x [glob -nocomplain $file] {
    lappend new_extra_files $x
  }
}
set extra_files $new_extra_files

##############################################################################
##############################################################################
##############################################################################
# Start by generating the "main.mk" makefile used for all unix systems.
#
puts "building main.mk"
................................................................................
#append mhargs "\$(SRCDIR)/cson_amalgamation.h <<<NEXT_LINE>>>"
append mhargs "\$(OBJDIR)/VERSION.h"
set mhargs [string map [list <<<NEXT_LINE>>> \\\n\t] $mhargs]
writeln "\$(OBJDIR)/page_index.h: \$(TRANS_SRC) \$(OBJDIR)/mkindex"
writeln "\t\$(OBJDIR)/mkindex \$(TRANS_SRC) >\$@\n"

writeln "\$(OBJDIR)/builtin_data.h: \$(OBJDIR)/mkbuiltin \$(EXTRA_FILES)"
writeln "\t\$(OBJDIR)/mkbuiltin --prefix \$(SRCDIR)/ \$(EXTRA_FILES) >\$@\n"

writeln "\$(OBJDIR)/headers:\t\$(OBJDIR)/page_index.h \$(OBJDIR)/builtin_data.h \$(OBJDIR)/makeheaders \$(OBJDIR)/VERSION.h"
writeln "\t\$(OBJDIR)/makeheaders $mhargs"
writeln "\ttouch \$(OBJDIR)/headers"
writeln "\$(OBJDIR)/headers: Makefile"
writeln "\$(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 : \$(SRCDIR)/json_detail.h"
writeln "Makefile:"
................................................................................
endif

#### The directories where the OpenSSL include and library files are located.
#    The recommended usage here is to use the Sysinternals junction tool
#    to create a hard link between an "openssl-1.x" sub-directory of the
#    Fossil source code directory and the target OpenSSL source directory.
#
OPENSSLDIR = $(SRCDIR)/../compat/openssl-1.0.2
OPENSSLINCDIR = $(OPENSSLDIR)/include
OPENSSLLIBDIR = $(OPENSSLDIR)

#### Either the directory where the Tcl library is installed or the Tcl
#    source code directory resides (depending on the value of the macro
#    FOSSIL_TCL_SOURCE).  If this points to the Tcl install directory,
#    this directory must have "include" and "lib" sub-directories.  If
#    this points to the Tcl source code directory, this directory must
#    have "generic" and "win" sub-directories.  The recommended usage
................................................................................
append mhargs " \\\n\t\t\$(SRCDIR)/sqlite3.h"
append mhargs " \\\n\t\t\$(SRCDIR)/th.h"
append mhargs " \\\n\t\t\$(OBJDIR)/VERSION.h"
writeln "\$(OBJDIR)/page_index.h: \$(TRANS_SRC) \$(MKINDEX)"
writeln "\t\$(MKINDEX) \$(TRANS_SRC) >\$@\n"

writeln "\$(OBJDIR)/builtin_data.h:\t\$(MKBUILTIN) \$(EXTRA_FILES)"
writeln "\t\$(MKBUILTIN) --prefix \$(SRCDIR)/ \$(EXTRA_FILES) >\$@\n"

writeln "\$(OBJDIR)/headers:\t\$(OBJDIR)/page_index.h \$(OBJDIR)/builtin_data.h \$(MAKEHEADERS) \$(OBJDIR)/VERSION.h"
writeln "\t\$(MAKEHEADERS) $mhargs"
writeln "\techo Done >\$(OBJDIR)/headers\n"
writeln "\$(OBJDIR)/headers: Makefile\n"
writeln "Makefile:\n"
set extra_h(main) " \$(OBJDIR)/page_index.h "
................................................................................
VERSION.h : mkversion$E $B\manifest.uuid $B\manifest $B\VERSION
	+$** > $@

page_index.h: mkindex$E $(SRC)
	+$** > $@

builtin_data.h:	mkbuiltin$E $(EXTRA_FILES)
	mkbuiltin$E --prefix $(SRCDIR)/ $(EXTRA_FILES) > $@

clean:
	-del $(OBJDIR)\*.obj
	-del *.obj *_.c *.h *.map

realclean:
	-del $(APPNAME) translate$E mkindex$E makeheaders$E mkversion$E codecheck1$E mkbuiltin$E
................................................................................
# Uncomment to enable TH1 hooks
# FOSSIL_ENABLE_TH1_HOOKS = 1

# Uncomment to enable Tcl support
# FOSSIL_ENABLE_TCL = 1

!ifdef FOSSIL_ENABLE_SSL
SSLDIR    = $(B)\compat\openssl-1.0.2
SSLINCDIR = $(SSLDIR)\inc32
SSLLIBDIR = $(SSLDIR)\out32
SSLLFLAGS = /nologo /opt:ref /debug
SSLLIB    = ssleay32.lib libeay32.lib user32.lib gdi32.lib
!if "$(PLATFORM)"=="amd64" || "$(PLATFORM)"=="x64"
!message Using 'x64' platform for OpenSSL...
# BUGBUG (OpenSSL): Apparently, using "no-ssl*" here breaks the build.
................................................................................
$(OX)\cson_amalgamation$O : $(SRCDIR)\cson_amalgamation.c
	$(TCC) /Fo$@ /c $**

page_index.h: mkindex$E $(SRC)
	$** > $@

builtin_data.h:	mkbuiltin$E $(EXTRA_FILES)
	mkbuiltin$E --prefix $(SRCDIR)/ $(EXTRA_FILES) > $@

clean:
	-del $(OX)\*.obj
	-del *.obj
	-del *_.c
	-del *.h
	-del *.ilk
................................................................................
	translate.exe $< >$@

# generate the index source, containing all web references,..
page_index.h:	$(TRANSLATEDSRC) mkindex.exe
	mkindex.exe $(TRANSLATEDSRC) >$@

builtin_data.h:	$(EXTRA_FILES) mkbuiltin.exe
	mkbuiltin.exe --prefix $(SRCDIR)/ $(EXTRA_FILES) >$@

# extracting version info from manifest
VERSION.h:	version.exe ..\manifest.uuid ..\manifest ..\VERSION
	version.exe ..\manifest.uuid ..\manifest ..\VERSION  >$@

# generate the simplified headers
headers: makeheaders.exe page_index.h builtin_data.h VERSION.h ../src/sqlite3.h ../src/th.h VERSION.h

Changes to src/manifest.c.

1185
1186
1187
1188
1189
1190
1191


1192
1193
1194
1195
1196
1197

1198
1199
1200
1201
1202
1203
1204
....
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224

1225
1226
1227
1228
1229

1230
1231
1232
1233
1234
1235
1236
....
1340
1341
1342
1343
1344
1345
1346
1347




1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360

1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
....
1412
1413
1414
1415
1416
1417
1418
1419
1420

1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
....
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
....
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806












1807
1808
1809
1810

1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
}

/*
** Add a single entry to the mlink table.  Also add the filename to
** the filename table if it is not there already.
*/
static void add_one_mlink(


  int mid,                  /* The record ID of the manifest */
  const char *zFromUuid,    /* UUID for the mlink.pid. "" to add file */
  const char *zToUuid,      /* UUID for the mlink.fid. "" to delete */
  const char *zFilename,    /* Filename */
  const char *zPrior,       /* Previous filename. NULL if unchanged */
  int isPublic,             /* True if mid is not a private manifest */

  int mperm                 /* 1: exec, 2: symlink */
){
  int fnid, pfnid, pid, fid;
  static Stmt s1;

  fnid = filename_to_fnid(zFilename);
  if( zPrior==0 ){
................................................................................
  if( zToUuid==0 || zToUuid[0]==0 ){
    fid = 0;
  }else{
    fid = uuid_to_rid(zToUuid, 1);
    if( isPublic ) content_make_public(fid);
  }
  db_static_prepare(&s1,
    "INSERT INTO mlink(mid,pid,fid,fnid,pfnid,mperm)"
    "VALUES(:m,:p,:f,:n,:pfn,:mp)"
  );
  db_bind_int(&s1, ":m", mid);

  db_bind_int(&s1, ":p", pid);
  db_bind_int(&s1, ":f", fid);
  db_bind_int(&s1, ":n", fnid);
  db_bind_int(&s1, ":pfn", pfnid);
  db_bind_int(&s1, ":mp", mperm);

  db_exec(&s1);
  if( pid && fid ){
    content_deltify(pid, fid, 0);
  }
}

/*
................................................................................
** A single mlink entry is added for every file that changed content,
** name, and/or permissions going from pid to cid.
**
** Deleted files have mlink.fid=0.
** Added files have mlink.pid=0.
** Edited files have both mlink.pid!=0 and mlink.fid!=0
*/
static void add_mlink(int pid, Manifest *pParent, int cid, Manifest *pChild){




  Blob otherContent;
  int otherRid;
  int i, rc;
  ManifestFile *pChildFile, *pParentFile;
  Manifest **ppOther;
  static Stmt eq;
  int isPublic;                /* True if pChild is non-private */

  /* If mlink table entires are already set for cid, then abort early
  ** doing no work.
  */
  db_static_prepare(&eq, "SELECT 1 FROM mlink WHERE mid=:mid");
  db_bind_int(&eq, ":mid", cid);

  rc = db_step(&eq);
  db_reset(&eq);
  if( rc==SQLITE_ROW ) return;

  /* Compute the value of the missing pParent or pChild parameter.
  ** Fetch the baseline checkins for both.
  */
  assert( pParent==0 || pChild==0 );
  if( pParent==0 ){
    ppOther = &pParent;
    otherRid = pid;
  }else{
    ppOther = &pChild;
    otherRid = cid;
  }
  if( (*ppOther = manifest_cache_find(otherRid))==0 ){
    content_get(otherRid, &otherContent);
    if( blob_size(&otherContent)==0 ) return;
    *ppOther = manifest_parse(&otherContent, otherRid, 0);
    if( *ppOther==0 ) return;
  }
  if( fetch_baseline(pParent, 0) || fetch_baseline(pChild, 0) ){
    manifest_destroy(*ppOther);
    return;
  }
  isPublic = !content_is_private(cid);

  /* Try to make the parent manifest a delta from the child, if that
  ** is an appropriate thing to do.  For a new baseline, make the
  ** previous baseline a delta from the current baseline.
  */
  if( (pParent->zBaseline==0)==(pChild->zBaseline==0) ){
    content_deltify(pid, cid, 0);
  }else if( pChild->zBaseline==0 && pParent->zBaseline!=0 ){
    content_deltify(pParent->pBaseline->rid, cid, 0);
  }

  /* Remember all children less than a few seconds younger than their parent,
  ** as we might want to fudge the times for those children.
  */
  if( pChild->rDate<pParent->rDate+AGE_FUDGE_WINDOW
      && manifest_crosslink_busy
................................................................................
  */
  for(i=0, pChildFile=pChild->aFile; i<pChild->nFile; i++, pChildFile++){
    int mperm = manifest_file_mperm(pChildFile);
    if( pChildFile->zPrior ){
       pParentFile = manifest_file_seek(pParent, pChildFile->zPrior, 0);
       if( pParentFile ){
         /* File with name change */
         add_one_mlink(cid, pParentFile->zUuid, pChildFile->zUuid,
                       pChildFile->zName, pChildFile->zPrior, isPublic, mperm);

       }else{
         /* File name changed, but the old name is not found in the parent!
         ** Treat this like a new file. */
         add_one_mlink(cid, 0, pChildFile->zUuid, pChildFile->zName, 0,
                       isPublic, mperm);
       }
    }else{
       pParentFile = manifest_file_seek(pParent, pChildFile->zName, 0);
       if( pParentFile==0 ){
         if( pChildFile->zUuid ){
           /* A new file */
           add_one_mlink(cid, 0, pChildFile->zUuid, pChildFile->zName, 0,
                         isPublic, mperm);
         }
       }else if( fossil_strcmp(pChildFile->zUuid, pParentFile->zUuid)!=0
              || manifest_file_mperm(pParentFile)!=mperm ){
         /* Changes in file content or permissions */
         add_one_mlink(cid, pParentFile->zUuid, pChildFile->zUuid,
                       pChildFile->zName, 0, isPublic, mperm);
       }
    }
  }
  if( pParent->zBaseline && pChild->zBaseline ){
    /* Both parent and child are delta manifests.  Look for files that
    ** are deleted or modified in the parent but which reappear or revert
    ** to baseline in the child and show such files as being added or changed
................................................................................
    for(i=0, pParentFile=pParent->aFile; i<pParent->nFile; i++, pParentFile++){
      if( pParentFile->zUuid ){
        pChildFile = manifest_file_seek_base(pChild, pParentFile->zName, 0);
        if( pChildFile==0 ){
          /* The child file reverts to baseline.  Show this as a change */
          pChildFile = manifest_file_seek(pChild, pParentFile->zName, 0);
          if( pChildFile ){
            add_one_mlink(cid, pParentFile->zUuid, pChildFile->zUuid,
                          pChildFile->zName, 0, isPublic,
                          manifest_file_mperm(pChildFile));
          }
        }
      }else{
        pChildFile = manifest_file_seek(pChild, pParentFile->zName, 0);
        if( pChildFile ){
          /* File resurrected in the child after having been deleted in
          ** the parent.  Show this as an added file. */
          add_one_mlink(cid, 0, pChildFile->zUuid, pChildFile->zName, 0,
                        isPublic, manifest_file_mperm(pChildFile));
        }
      }
    }
  }else if( pChild->zBaseline==0 ){
    /* pChild is a baseline.  Look for files that are present in pParent
    ** but are missing from pChild and mark them as having been deleted. */
    manifest_file_rewind(pParent);
    while( (pParentFile = manifest_file_next(pParent,0))!=0 ){
      pChildFile = manifest_file_seek(pChild, pParentFile->zName, 0);
      if( pChildFile==0 && pParentFile->zUuid!=0 ){
        add_one_mlink(cid, pParentFile->zUuid, 0, pParentFile->zName, 0,
                      isPublic, 0);
      }
    }
  }
  manifest_cache_insert(*ppOther);
}

/*
................................................................................
      char zBaseId[30];
      if( p->zBaseline ){
        sqlite3_snprintf(sizeof(zBaseId), zBaseId, "%d",
                         uuid_to_rid(p->zBaseline,1));
      }else{
        sqlite3_snprintf(sizeof(zBaseId), zBaseId, "NULL");
      }
      (void)db_schema_is_outofdate(); /* Make sure g.zAuxSchema is initialized */
      for(i=0; i<p->nParent; i++){
        int pid = uuid_to_rid(p->azParent[i], 1);
        if( strcmp(g.zAuxSchema,"2014-11-24 20:35")>=0 ){
          /* Support for PLINK.BASEID added on 2014-11-24 */
          db_multi_exec(
             "INSERT OR IGNORE INTO plink(pid, cid, isprim, mtime, baseid)"
             "VALUES(%d, %d, %d, %.17g, %s)",
             pid, rid, i==0, p->rDate, zBaseId/*safe-for-%s*/);
        }else{
          /* Continue to work with older schema to avoid an unnecessary
          ** rebuild */
          db_multi_exec(
             "INSERT OR IGNORE INTO plink(pid, cid, isprim, mtime)"
             "VALUES(%d, %d, %d, %.17g)",
             pid, rid, i==0, p->rDate);
        }
        if( i==0 ){
          add_mlink(pid, 0, rid, p);
          parentid = pid;
        }












      }
      db_prepare(&q, "SELECT cid FROM plink WHERE pid=%d AND isprim", rid);
      while( db_step(&q)==SQLITE_ROW ){
        int cid = db_column_int(&q, 0);

        add_mlink(rid, p, cid, 0);
      }
      db_finalize(&q);
      if( p->nParent==0 ){
        /* For root files (files without parents) add mlink entries
        ** showing all content as new. */
        int isPublic = !content_is_private(rid);
        for(i=0; i<p->nFile; i++){
          add_one_mlink(rid, 0, p->aFile[i].zUuid, p->aFile[i].zName, 0,
                        isPublic, manifest_file_mperm(&p->aFile[i]));
        }
      }
      db_multi_exec(
        "REPLACE INTO event(type,mtime,objid,user,comment,"
                           "bgcolor,euser,ecomment,omtime)"
        "VALUES('ci',"
        "  coalesce("







>
>

<
|



>







 







|
|


>
|
|



>







 







|
>
>
>
>








|
|

|
|
>










|


|











|






|

|







 







|
|
>



|
|






|
|




|
|







 







|
|








|
|










|
|







 







<


<
<
|
|
|
|
<
<
<
<
<
<
<
<
<
|
|
|
>
>
>
>
>
>
>
>
>
>
>
>

|


>
|







|
|







1185
1186
1187
1188
1189
1190
1191
1192
1193
1194

1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
....
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
....
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
....
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
....
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
....
1789
1790
1791
1792
1793
1794
1795

1796
1797


1798
1799
1800
1801









1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
}

/*
** Add a single entry to the mlink table.  Also add the filename to
** the filename table if it is not there already.
*/
static void add_one_mlink(
  int pmid,                 /* The parent manifest */
  const char *zFromUuid,    /* UUID for content in parent */
  int mid,                  /* The record ID of the manifest */

  const char *zToUuid,      /* UUID for content in child */
  const char *zFilename,    /* Filename */
  const char *zPrior,       /* Previous filename. NULL if unchanged */
  int isPublic,             /* True if mid is not a private manifest */
  int isPrimary,            /* pmid is the primary parent of mid */
  int mperm                 /* 1: exec, 2: symlink */
){
  int fnid, pfnid, pid, fid;
  static Stmt s1;

  fnid = filename_to_fnid(zFilename);
  if( zPrior==0 ){
................................................................................
  if( zToUuid==0 || zToUuid[0]==0 ){
    fid = 0;
  }else{
    fid = uuid_to_rid(zToUuid, 1);
    if( isPublic ) content_make_public(fid);
  }
  db_static_prepare(&s1,
    "INSERT INTO mlink(mid,fid,pmid,pid,fnid,pfnid,mperm,isaux)"
    "VALUES(:m,:f,:pm,:p,:n,:pfn,:mp,:isaux)"
  );
  db_bind_int(&s1, ":m", mid);
  db_bind_int(&s1, ":f", fid);
  db_bind_int(&s1, ":pm", pmid);
  db_bind_int(&s1, ":p", pid);
  db_bind_int(&s1, ":n", fnid);
  db_bind_int(&s1, ":pfn", pfnid);
  db_bind_int(&s1, ":mp", mperm);
  db_bind_int(&s1, ":isaux", isPrimary==0);
  db_exec(&s1);
  if( pid && fid ){
    content_deltify(pid, fid, 0);
  }
}

/*
................................................................................
** A single mlink entry is added for every file that changed content,
** name, and/or permissions going from pid to cid.
**
** Deleted files have mlink.fid=0.
** Added files have mlink.pid=0.
** Edited files have both mlink.pid!=0 and mlink.fid!=0
*/
static void add_mlink(
  int pmid, Manifest *pParent,    /* Parent check-in */
  int mid,  Manifest *pChild,     /* The child check-in */
  int isPrim                      /* TRUE if pmid is the primary parent of mid */
){
  Blob otherContent;
  int otherRid;
  int i, rc;
  ManifestFile *pChildFile, *pParentFile;
  Manifest **ppOther;
  static Stmt eq;
  int isPublic;                /* True if pChild is non-private */

  /* If mlink table entires are already exist for the pmid-to-mid transition,
  ** then abort early doing no work.
  */
  db_static_prepare(&eq, "SELECT 1 FROM mlink WHERE mid=:mid AND pmid=:pmid");
  db_bind_int(&eq, ":mid", mid);
  db_bind_int(&eq, ":pmid", pmid);
  rc = db_step(&eq);
  db_reset(&eq);
  if( rc==SQLITE_ROW ) return;

  /* Compute the value of the missing pParent or pChild parameter.
  ** Fetch the baseline checkins for both.
  */
  assert( pParent==0 || pChild==0 );
  if( pParent==0 ){
    ppOther = &pParent;
    otherRid = pmid;
  }else{
    ppOther = &pChild;
    otherRid = mid;
  }
  if( (*ppOther = manifest_cache_find(otherRid))==0 ){
    content_get(otherRid, &otherContent);
    if( blob_size(&otherContent)==0 ) return;
    *ppOther = manifest_parse(&otherContent, otherRid, 0);
    if( *ppOther==0 ) return;
  }
  if( fetch_baseline(pParent, 0) || fetch_baseline(pChild, 0) ){
    manifest_destroy(*ppOther);
    return;
  }
  isPublic = !content_is_private(mid);

  /* Try to make the parent manifest a delta from the child, if that
  ** is an appropriate thing to do.  For a new baseline, make the
  ** previous baseline a delta from the current baseline.
  */
  if( (pParent->zBaseline==0)==(pChild->zBaseline==0) ){
    content_deltify(pmid, mid, 0);
  }else if( pChild->zBaseline==0 && pParent->zBaseline!=0 ){
    content_deltify(pParent->pBaseline->rid, mid, 0);
  }

  /* Remember all children less than a few seconds younger than their parent,
  ** as we might want to fudge the times for those children.
  */
  if( pChild->rDate<pParent->rDate+AGE_FUDGE_WINDOW
      && manifest_crosslink_busy
................................................................................
  */
  for(i=0, pChildFile=pChild->aFile; i<pChild->nFile; i++, pChildFile++){
    int mperm = manifest_file_mperm(pChildFile);
    if( pChildFile->zPrior ){
       pParentFile = manifest_file_seek(pParent, pChildFile->zPrior, 0);
       if( pParentFile ){
         /* File with name change */
         add_one_mlink(pmid, pParentFile->zUuid, mid, pChildFile->zUuid,
                       pChildFile->zName, pChildFile->zPrior,
                       isPublic, isPrim, mperm);
       }else{
         /* File name changed, but the old name is not found in the parent!
         ** Treat this like a new file. */
         add_one_mlink(pmid, 0, mid, pChildFile->zUuid, pChildFile->zName, 0,
                       isPublic, isPrim, mperm);
       }
    }else{
       pParentFile = manifest_file_seek(pParent, pChildFile->zName, 0);
       if( pParentFile==0 ){
         if( pChildFile->zUuid ){
           /* A new file */
           add_one_mlink(pmid, 0, mid, pChildFile->zUuid, pChildFile->zName, 0,
                         isPublic, isPrim, mperm);
         }
       }else if( fossil_strcmp(pChildFile->zUuid, pParentFile->zUuid)!=0
              || manifest_file_mperm(pParentFile)!=mperm ){
         /* Changes in file content or permissions */
         add_one_mlink(pmid, pParentFile->zUuid, mid, pChildFile->zUuid,
                       pChildFile->zName, 0, isPublic, isPrim, mperm);
       }
    }
  }
  if( pParent->zBaseline && pChild->zBaseline ){
    /* Both parent and child are delta manifests.  Look for files that
    ** are deleted or modified in the parent but which reappear or revert
    ** to baseline in the child and show such files as being added or changed
................................................................................
    for(i=0, pParentFile=pParent->aFile; i<pParent->nFile; i++, pParentFile++){
      if( pParentFile->zUuid ){
        pChildFile = manifest_file_seek_base(pChild, pParentFile->zName, 0);
        if( pChildFile==0 ){
          /* The child file reverts to baseline.  Show this as a change */
          pChildFile = manifest_file_seek(pChild, pParentFile->zName, 0);
          if( pChildFile ){
            add_one_mlink(pmid, pParentFile->zUuid, mid, pChildFile->zUuid,
                          pChildFile->zName, 0, isPublic, isPrim,
                          manifest_file_mperm(pChildFile));
          }
        }
      }else{
        pChildFile = manifest_file_seek(pChild, pParentFile->zName, 0);
        if( pChildFile ){
          /* File resurrected in the child after having been deleted in
          ** the parent.  Show this as an added file. */
          add_one_mlink(pmid, 0, mid, pChildFile->zUuid, pChildFile->zName, 0,
                        isPublic, isPrim, manifest_file_mperm(pChildFile));
        }
      }
    }
  }else if( pChild->zBaseline==0 ){
    /* pChild is a baseline.  Look for files that are present in pParent
    ** but are missing from pChild and mark them as having been deleted. */
    manifest_file_rewind(pParent);
    while( (pParentFile = manifest_file_next(pParent,0))!=0 ){
      pChildFile = manifest_file_seek(pChild, pParentFile->zName, 0);
      if( pChildFile==0 && pParentFile->zUuid!=0 ){
        add_one_mlink(pmid, pParentFile->zUuid, mid, 0, pParentFile->zName, 0,
                      isPublic, isPrim, 0);
      }
    }
  }
  manifest_cache_insert(*ppOther);
}

/*
................................................................................
      char zBaseId[30];
      if( p->zBaseline ){
        sqlite3_snprintf(sizeof(zBaseId), zBaseId, "%d",
                         uuid_to_rid(p->zBaseline,1));
      }else{
        sqlite3_snprintf(sizeof(zBaseId), zBaseId, "NULL");
      }

      for(i=0; i<p->nParent; i++){
        int pid = uuid_to_rid(p->azParent[i], 1);


        db_multi_exec(
           "INSERT OR IGNORE INTO plink(pid, cid, isprim, mtime, baseid)"
           "VALUES(%d, %d, %d, %.17g, %s)",
           pid, rid, i==0, p->rDate, zBaseId/*safe-for-%s*/);









        add_mlink(pid, 0, rid, p, i==0);
        if( i==0 ) parentid = pid;
      }
      if( p->nParent>1 ){
        /* Remove incorrect MLINK create-file entries that arise when a
        ** file is added by merge. */
        db_multi_exec(
           "DELETE FROM mlink"
           " WHERE mid=%d"
           "   AND pid=0"
           "   AND fnid IN "
           "  (SELECT fnid FROM mlink WHERE mid=%d GROUP BY fnid"
           "    HAVING count(*)<%d)",
           rid, rid, p->nParent
        );
      }
      db_prepare(&q, "SELECT cid, isprim FROM plink WHERE pid=%d", rid);
      while( db_step(&q)==SQLITE_ROW ){
        int cid = db_column_int(&q, 0);
        int isprim = db_column_int(&q, 1);
        add_mlink(rid, p, cid, 0, isprim);
      }
      db_finalize(&q);
      if( p->nParent==0 ){
        /* For root files (files without parents) add mlink entries
        ** showing all content as new. */
        int isPublic = !content_is_private(rid);
        for(i=0; i<p->nFile; i++){
          add_one_mlink(0, 0, rid, p->aFile[i].zUuid, p->aFile[i].zName, 0,
                        isPublic, 1, manifest_file_mperm(&p->aFile[i]));
        }
      }
      db_multi_exec(
        "REPLACE INTO event(type,mtime,objid,user,comment,"
                           "bgcolor,euser,ecomment,omtime)"
        "VALUES('ci',"
        "  coalesce("

Added src/markdown.md.



































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# Markdown formatting rules

In addition to its native Wiki formatting syntax, Fossil supports Markdown syntax as specified by 
[John Gruber's original Markdown implementation](http://daringfireball.net/projects/markdown/). 
For lots of examples - not repeated here - please refer to its 
[syntax description](http://daringfireball.net/projects/markdown/syntax), of which the page you
are reading is an extract.

This page itself uses Markdown formatting.

## Summary

  - Block elements

      * A **paragraph** is a group of consecutive lines. Paragraphs are separated by blank lines.

      * A **Header** is a line of text underlined with equal signs or hyphens, or prefixed by a 
        number of hash marks.

      * **Block quotes** are blocks of text prefixed by '>'.

      * **Ordered list** items are prefixed by a number and a period. **Unordered list** items
        are prefixed by a hyphen, asterisk or plus sign. Prefix and item text are separated by
        whitespace. 

      * **Code blocks** are formed by lines of text (possibly including empty lines) prefixed by
        at least 4 spaces or a tab.

      * A **horizontal rule** is a line consisting of 3 or more asterisks, hyphens or underscores,
        with optional whitespace between them.

  - Span elements

      * 3 types of **links** exist:

        - **automatic links** are URLs or email addresses enclosed in angle brackets
          ('<' and '>'), and are displayed as such.

        - **inline links** consist of the displayed link text in square brackets ('[' and ']'), 
          followed by the link target in parentheses. 

        - **reference links** separate _link instance_ from _link definition_. A link instance 
          consists of the displayed link text in square brackets, followed by a link definition name 
          in square brackets. 
          The corresponding link definition can occur anywhere on the page, and consists
          of the link definition name in square brackets followed by a colon, whitespace and the 
          link target.

      * **Emphasis** can be given by wrapping text in one or two asterisks or underscores - use
        one for HTML `<em>`, and two for `<strong>` emphasis.

      * A **code span** is text wrapped in backticks ('`').

      * **Images** use a syntax much like inline or reference links, but with alt attribute text 
        ('img alt=...') instead of link text, and the first pair of square
        brackets in an image instance prefixed by an exclamation mark.

  - **Inline HTML** is mostly interpreted automatically.

  - **Escaping** Markdown punctuation characters is done by prefixing them by a backslash ('\\').

## Details

### Paragraphs

To cause an explicit line break within a paragraph, use 2 or more spaces at the end of a line.

Any line containing only whitespace (space or tab characters) is considered a blank line.

### Headers

#### 'Setext' style headers (underlined)

The number of underlining equal signs or hyphens used has no impact on the resulting header.

Underlining using equal sign(s) creates a top level header (corresponding to HTML `<h1>`),
while hyphen(s) create a second level header (HTML `<h2>`). Thus, only 2 levels of headers
can be made this way.

#### 'Atx' style headers (hash prefixed)

1 to 6 hash characters can be used to indicate header levels 1 (HTML `<h1>`) to 6 (`<h6>`).

Headers may optionally be 'closed' for cosmetic reasons, by appending a whitespace and hash
characters to the header. The number of trailing hash characters has no impact on the header
level.

### Block quotes

Not every line in a paragraph needs to be prefixed by '>' in order to make it a block quote,
only the first line.

Block quoted paragraphs can be nested by using multiple '>' characters as prefix. 

Within a block quote, Markdown formatting (e.g. lists, emphasis) still works as normal.

### Lists

A list item prefix need not occur first on its line; up to 3 leading spaces are allowed
(4 spaces would make a code block out of the following text).

For unordered lists, asterisks, hyphens and plus signs can be used interchangeably.

For ordered lists, arbitrary numbers can be used as part of an item prefix; the items will be 
renumbered during rendering. However, future implementations may demand that the number used 
for the first item in a list indicates an offset to be used for subsequent items.

For list items spanning multiple lines, subsequent lines can be indented using an arbitrary amount
of whitespace.

List items will be wrapped in HTML `<p>` tags if they are separated by blank lines.

A list item may span multiple paragraphs. At least the first line of each such paragraph must 
be indented using at least 4 spaces or a tab character.

Block quotes within list items must have their '>' delimiters indented using 4 up to 7 spaces.

Code blocks within list items need to be indented _twice_, that is, using 8 spaces or 2 tab
characters.

### Code blocks

Lines within a code block are rendered verbatim using HTML `<pre>` and `<code>` tags, except that
HTML punctuation characters like '<' and '&' are automatically converted to HTML entities. Thus,
there is no need to explicitly escape HTML syntax within a code block.

A code block runs until the first non blank line with indent less than 4 spaces or 1 tab character.


Regular Markdown syntax is not processed within code blocks.

### Links

#### Automatic links

When rendering automatic links to email addresses, HTML encoding obfuscation is used to 
prevent some spambots from harvesting.

#### Inline links

Links to resources on the same server can use relative paths (i.e. can start with a '/').

An optional title for the link (e.g. to have mouseover text in the browser) may be given behind 
the link target but within the parentheses, in single and double quotes, and separated from the 
link target by whitespace. 

#### Reference links

> Each reference link consists of 
>
>   - one or more _link instances_ at appropriate locations in the page text
>   - a single _link definition_ at an arbitrary location on the page
> 
> During rendering, each link instance is resolved, and the corresponding definition is
> filled in. No separate link definition clauses occur in the rendered output.
> 
> There are 3 fields involved in link instances and definitions:
>
>   - link text (i.e. the text that is displayed at the resulting link)
>   - link definition name (i.e. an unique ID binding link instances to link definition)
>   - link target (a target URL for the link)

Multiple link instances may reference the same link definition using its link definition
name.

Link definition names are case insensitive, and may contain letters, numbers, spaces and
punctuation.

##### Link instance

A space may be inserted between the bracket pairs for link text and link definition name.

A link instance can use an _implicit link definition name_ shortcut, in which case the link
text is used as the link definition name. The second set of brackets then remains empty, e.g.
'[Google][]' ('Google' being used as both link text and link definition name).

##### Link definition

The first bracket pair containing the link definition name may be indented using up to 3 spaces.

The link target may optionally be surrounded by angle brackets ('<' and '>').

A link target may be followed by an optional title (e.g. to have mouseover text in the browser).
This title may be enclosed in parentheses, single or double quotes.

Link definitions may be split into 2 lines, with the title on the second line, arbitrarily
indented. This may be more visually pleasing when using long link targets.

### Emphasis

The same character(s) used for starting the emphasis must be used to end it; don't mix
asterisks and underscores.

Emphasis can be used in the middle of a word. That is, there need not be whitespace on either
side of emphasis start or end punctuation characters.

### Code spans

To include a literal backtick character in a code span, use multiple backticks as opening and
closing delimiters.

Whitespace may exist immediately after the opening delimiter and before the closing delimiter 
of a code span, to allow for code fragments starting or ending with a backtick.

Within a code span - like within a code block - angle brackets and ampersands are automatically encoded to make including
HTML fragments easier.

### Images

If necessary, HTML must be used to specify image dimensions. Markdown has no provision for this.

### Inline HTML

Start and end tags of 
a HTML block level construct (`<div>`, `<table>` etc) must be separated from surrounding
context using blank lines, and must both occur at the start of a line.

No extra unwanted `<p>` HTML tags are added around HTML block level tags.

Markdown formatting within HTML block level tags is not processed; however, formatting within 
span level tags (e.g. `<mark>`) is processed normally.

### Escaping Markdown punctuation

The following punctuation characters can be escaped using backslash:

  - \\   backslash
  - `   backtick
  - *   asterisk
  - _   underscore
  - {}  curly braces
  - []  square brackets
  - ()  parentheses
  - #   hash mark
  - +   plus sign
  - -   minus sign (hyphen)
  - .   dot
  - !   exclamation mark

To render a literal backslash, use 2 backslashes ('\\\\').

Changes to src/md5.c.

175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
...
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
...
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
...
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
...
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
        ctx->bits[1] = 0;
}

/*
 * Update context to reflect the concatenation of another buffer full
 * of bytes.
 */
static 
void MD5Update(MD5Context *pCtx, const unsigned char *buf, unsigned int len){
        struct Context *ctx = (struct Context *)pCtx;
        uint32 t;

        /* Update bitcount */

        t = ctx->bits[0];
................................................................................

        /* Handle any remaining bytes of data. */

        memcpy(ctx->in, buf, len);
}

/*
 * Final wrapup - pad to 64-byte boundary with the bit pattern 
 * 1 0* (64-bit count of bits processed, MSB-first)
 */
static void MD5Final(unsigned char digest[16], MD5Context *pCtx){
        struct Context *ctx = (struct Context *)pCtx;
        unsigned count;
        unsigned char *p;

................................................................................
/*
** Convert a digest into base-16.  digest should be declared as
** "unsigned char digest[16]" in the calling function.  The MD5
** digest is stored in the first 16 bytes.  zBuf should
** be "char zBuf[33]".
*/
static void DigestToBase16(unsigned char *digest, char *zBuf){
  static char const zEncode[] = "0123456789abcdef";
  int i, j;

  for(j=i=0; i<16; i++){
    int a = digest[i];
    zBuf[j++] = zEncode[(a>>4)&0xf];
    zBuf[j++] = zEncode[a & 0xf];
  }
................................................................................
  }
  sqlite3_snprintf(sizeof(zResult), zResult, "%08x", cksum);
  return zResult;
}

/*
** Finish the incremental MD5 checksum.  Store the result in blob pOut
** if pOut!=0.  Also return a pointer to the result.  
**
** This resets the incremental checksum preparing for the next round
** of computation.  The return pointer points to a static buffer that
** is overwritten by subsequent calls to this function.
*/
char *md5sum_finish(Blob *pOut){
  unsigned char zResult[16];
................................................................................
** Compute an MD5 checksum of all files named on the command-line.
** If a file is named "-" then content is read from standard input.
*/
void md5sum_test(void){
  int i;
  Blob in;
  Blob cksum;
  
  for(i=2; i<g.argc; i++){
    blob_init(&cksum, "********** not found ***********", -1);
    if( g.argv[i][0]=='-' && g.argv[i][1]==0 ){
      blob_read_from_channel(&in, stdin, -1);
      md5sum_blob(&in, &cksum);
    }else{
      md5sum_file(g.argv[i], &cksum);
    }
    fossil_print("%s  %s\n", blob_str(&cksum), g.argv[i]);
    blob_reset(&cksum);
  }
}







|







 







|







 







|







 







|







 







|












175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
...
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
...
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
...
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
...
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
        ctx->bits[1] = 0;
}

/*
 * Update context to reflect the concatenation of another buffer full
 * of bytes.
 */
static
void MD5Update(MD5Context *pCtx, const unsigned char *buf, unsigned int len){
        struct Context *ctx = (struct Context *)pCtx;
        uint32 t;

        /* Update bitcount */

        t = ctx->bits[0];
................................................................................

        /* Handle any remaining bytes of data. */

        memcpy(ctx->in, buf, len);
}

/*
 * Final wrapup - pad to 64-byte boundary with the bit pattern
 * 1 0* (64-bit count of bits processed, MSB-first)
 */
static void MD5Final(unsigned char digest[16], MD5Context *pCtx){
        struct Context *ctx = (struct Context *)pCtx;
        unsigned count;
        unsigned char *p;

................................................................................
/*
** Convert a digest into base-16.  digest should be declared as
** "unsigned char digest[16]" in the calling function.  The MD5
** digest is stored in the first 16 bytes.  zBuf should
** be "char zBuf[33]".
*/
static void DigestToBase16(unsigned char *digest, char *zBuf){
  static const char zEncode[] = "0123456789abcdef";
  int i, j;

  for(j=i=0; i<16; i++){
    int a = digest[i];
    zBuf[j++] = zEncode[(a>>4)&0xf];
    zBuf[j++] = zEncode[a & 0xf];
  }
................................................................................
  }
  sqlite3_snprintf(sizeof(zResult), zResult, "%08x", cksum);
  return zResult;
}

/*
** Finish the incremental MD5 checksum.  Store the result in blob pOut
** if pOut!=0.  Also return a pointer to the result.
**
** This resets the incremental checksum preparing for the next round
** of computation.  The return pointer points to a static buffer that
** is overwritten by subsequent calls to this function.
*/
char *md5sum_finish(Blob *pOut){
  unsigned char zResult[16];
................................................................................
** Compute an MD5 checksum of all files named on the command-line.
** If a file is named "-" then content is read from standard input.
*/
void md5sum_test(void){
  int i;
  Blob in;
  Blob cksum;

  for(i=2; i<g.argc; i++){
    blob_init(&cksum, "********** not found ***********", -1);
    if( g.argv[i][0]=='-' && g.argv[i][1]==0 ){
      blob_read_from_channel(&in, stdin, -1);
      md5sum_blob(&in, &cksum);
    }else{
      md5sum_file(g.argv[i], &cksum);
    }
    fossil_print("%s  %s\n", blob_str(&cksum), g.argv[i]);
    blob_reset(&cksum);
  }
}

Changes to src/merge.c.

39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
...
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
...
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
...
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
    const char *zTagList = db_column_text(&q, 4);
    char *zCom;
    if( zTagList && zTagList[0] ){
      zCom = mprintf("%s (%s)", db_column_text(&q, 2), zTagList);
    }else{
      zCom = mprintf("%s", db_column_text(&q,2));
    }
    fossil_print("%-*s [%S] by %s on %s\n%*s", 
       indent-1, zLabel,
       db_column_text(&q, 3),
       db_column_text(&q, 1),
       db_column_text(&q, 0),
       indent, "");
    comment_print(zCom, db_column_text(&q,2), indent, -1, g.comFmtFlags);
    fossil_free(zCom);
................................................................................
      fossil_fatal("not a version: %s", g.argv[2]);
    }
  }else if( g.argc==2 ){
    /* No version specified on the command-line so pick the most recent
    ** leaf that is (1) not the version currently checked out and (2)
    ** has not already been merged into the current checkout and (3)
    ** the leaf is not closed and (4) the leaf is in the same branch
    ** as the current checkout. 
    */
    Stmt q;
    if( pickFlag || backoutFlag || integrateFlag){
      fossil_fatal("cannot use --backout, --cherrypick or --integrate with a fork merge");
    }
    mid = db_int(0,
      "SELECT leaf.rid"
................................................................................
    fossil_free(zFullName);
    if( !dryRunFlag ){
      undo_save(zName);
      vfile_to_disk(0, idm, 0, 0);
    }
  }
  db_finalize(&q);
  
  /*
  ** Find files that have changed from P->M but not P->V. 
  ** Copy the M content over into V.
  */
  db_prepare(&q,
    "SELECT idv, ridm, fn, islinkm FROM fv"
    " WHERE idp>0 AND idv>0 AND idm>0"
    "   AND ridm!=ridp AND ridv=ridp AND NOT chnged"
  );
................................................................................
    int islinkv = db_column_int(&q, 7);
    int islinkm = db_column_int(&q, 8);
    int rc;
    char *zFullPath;
    Blob m, p, r;
    /* Do a 3-way merge of idp->idm into idp->idv.  The results go into idv. */
    if( verboseFlag ){
      fossil_print("MERGE %s  (pivot=%d v1=%d v2=%d)\n", 
                   zName, ridp, ridm, ridv);
    }else{
      fossil_print("MERGE %s\n", zName);
    }
    if( islinkv || islinkm /* || file_wd_islink(zFullPath) */ ){
      fossil_print("***** Cannot merge symlink %s\n", zName);
      nConflict++;        
    }else{
      undo_save(zName);
      zFullPath = mprintf("%s/%s", g.zLocalRoot, zName);
      content_get(ridp, &p);
      content_get(ridm, &m);
      if( isBinary ){
        rc = -1;







|







 







|







 







|

|







 







|






|







39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
...
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
...
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
...
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
    const char *zTagList = db_column_text(&q, 4);
    char *zCom;
    if( zTagList && zTagList[0] ){
      zCom = mprintf("%s (%s)", db_column_text(&q, 2), zTagList);
    }else{
      zCom = mprintf("%s", db_column_text(&q,2));
    }
    fossil_print("%-*s [%S] by %s on %s\n%*s",
       indent-1, zLabel,
       db_column_text(&q, 3),
       db_column_text(&q, 1),
       db_column_text(&q, 0),
       indent, "");
    comment_print(zCom, db_column_text(&q,2), indent, -1, g.comFmtFlags);
    fossil_free(zCom);
................................................................................
      fossil_fatal("not a version: %s", g.argv[2]);
    }
  }else if( g.argc==2 ){
    /* No version specified on the command-line so pick the most recent
    ** leaf that is (1) not the version currently checked out and (2)
    ** has not already been merged into the current checkout and (3)
    ** the leaf is not closed and (4) the leaf is in the same branch
    ** as the current checkout.
    */
    Stmt q;
    if( pickFlag || backoutFlag || integrateFlag){
      fossil_fatal("cannot use --backout, --cherrypick or --integrate with a fork merge");
    }
    mid = db_int(0,
      "SELECT leaf.rid"
................................................................................
    fossil_free(zFullName);
    if( !dryRunFlag ){
      undo_save(zName);
      vfile_to_disk(0, idm, 0, 0);
    }
  }
  db_finalize(&q);

  /*
  ** Find files that have changed from P->M but not P->V.
  ** Copy the M content over into V.
  */
  db_prepare(&q,
    "SELECT idv, ridm, fn, islinkm FROM fv"
    " WHERE idp>0 AND idv>0 AND idm>0"
    "   AND ridm!=ridp AND ridv=ridp AND NOT chnged"
  );
................................................................................
    int islinkv = db_column_int(&q, 7);
    int islinkm = db_column_int(&q, 8);
    int rc;
    char *zFullPath;
    Blob m, p, r;
    /* Do a 3-way merge of idp->idm into idp->idv.  The results go into idv. */
    if( verboseFlag ){
      fossil_print("MERGE %s  (pivot=%d v1=%d v2=%d)\n",
                   zName, ridp, ridm, ridv);
    }else{
      fossil_print("MERGE %s\n", zName);
    }
    if( islinkv || islinkm /* || file_wd_islink(zFullPath) */ ){
      fossil_print("***** Cannot merge symlink %s\n", zName);
      nConflict++;
    }else{
      undo_save(zName);
      zFullPath = mprintf("%s/%s", g.zLocalRoot, zName);
      content_get(ridp, &p);
      content_get(ridm, &m);
      if( isBinary ){
        rc = -1;

Changes to src/mkbuiltin.c.

27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
..
60
61
62
63
64
65
66

67
68
69
70
71
72
73
..
77
78
79
80
81
82
83
84
85
86


87






88
89
90
91
92
93
94
...
101
102
103
104
105
106
107








108

109
110
111
112
113
114
115
116
117
118
119
...
127
128
129
130
131
132
133
134
135

136
137
138
139
140


141

142
143
144
145
#include <stdio.h>
#include <stdlib.h>
#include <string.h>


/*
** Read the entire content of the file named zFilename into memory obtained
** from malloc() and retur a pointer to that memory.  Write the size of the
** file into *pnByte.
*/
static unsigned char *read_file(const char *zFilename, int *pnByte){
  FILE *in;
  unsigned char *z;
  int nByte;
  int got;
................................................................................
/*
** There is an instance of the following for each file translated.
*/
typedef struct Resource Resource;
struct Resource {
  const char *zName;
  int nByte;

};

/*
** Compare two Resource objects for sorting purposes.  They sort
** in zName order so that Fossil can search for resources using
** a binary search.
*/
................................................................................
  return strcmp(pA->zName, pB->zName);
}

int main(int argc, char **argv){
  int i, sz;
  int j, n;
  Resource *aRes;
  int nRes = argc-1;
  unsigned char *pData;
  int nErr = 0;


  






  aRes = malloc( nRes*sizeof(aRes[0]) );
  if( aRes==0 ){
    fprintf(stderr, "malloc failed\n");
    return 1;
  }
  for(i=0; i<argc-1; i++){
    aRes[i].zName = argv[i+1];
................................................................................
  for(i=0; i<nRes; i++){
    pData = read_file(aRes[i].zName, &sz);
    if( pData==0 ){
      fprintf(stderr, "Cannot open file [%s]\n", aRes[i].zName);
      nErr++;
      continue;
    }








    aRes[i].nByte = sz;

    printf("/* Content of file %s */\n", aRes[i].zName);
    printf("static const unsigned char bidata%d[%d] = {\n  ",
           i, sz+1);
    for(j=n=0; j<=sz; j++){
      printf("%3d", pData[j]);
      if( j==sz ){
        printf(" };\n");
      }else if( n==14 ){
        printf(",\n  ");
        n = 0;
      }else{
................................................................................
  printf("struct BuiltinFileTable {\n");
  printf("  const char *zName;\n");
  printf("  const unsigned char *pData;\n");
  printf("  int nByte;\n");
  printf("};\n");
  printf("static const BuiltinFileTable aBuiltinFiles[] = {\n");
  for(i=0; i<nRes; i++){
    const char *zTail;
    const char *z = aRes[i].zName;

    zTail = z;
    while( z && z[0] ){
      if( z[0]=='/' || z[0]=='\\' ) zTail = &z[1];
      z++;
    }


    printf("  { \"%s\", bidata%d, %d },\n", zTail, i, aRes[i].nByte);

  }
  printf("};\n");
  return nErr;
}







|







 







>







 







|


>
>
|
>
>
>
>
>
>







 







>
>
>
>
>
>
>
>
|
>


|
|







 







<

>
|
|
<
<
|
>
>
|
>




27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
..
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
..
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
...
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
...
145
146
147
148
149
150
151

152
153
154
155


156
157
158
159
160
161
162
163
164
#include <stdio.h>
#include <stdlib.h>
#include <string.h>


/*
** Read the entire content of the file named zFilename into memory obtained
** from malloc() and return a pointer to that memory.  Write the size of the
** file into *pnByte.
*/
static unsigned char *read_file(const char *zFilename, int *pnByte){
  FILE *in;
  unsigned char *z;
  int nByte;
  int got;
................................................................................
/*
** There is an instance of the following for each file translated.
*/
typedef struct Resource Resource;
struct Resource {
  const char *zName;
  int nByte;
  int idx;
};

/*
** Compare two Resource objects for sorting purposes.  They sort
** in zName order so that Fossil can search for resources using
** a binary search.
*/
................................................................................
  return strcmp(pA->zName, pB->zName);
}

int main(int argc, char **argv){
  int i, sz;
  int j, n;
  Resource *aRes;
  int nRes;
  unsigned char *pData;
  int nErr = 0;
  int nSkip;
  int nPrefix = 0;

  if( argc>3 && strcmp(argv[1],"--prefix")==0 ){
    nPrefix = (int)strlen(argv[2]);
    argc -= 2;
    argv += 2;
  }
  nRes = argc - 1;
  aRes = malloc( nRes*sizeof(aRes[0]) );
  if( aRes==0 ){
    fprintf(stderr, "malloc failed\n");
    return 1;
  }
  for(i=0; i<argc-1; i++){
    aRes[i].zName = argv[i+1];
................................................................................
  for(i=0; i<nRes; i++){
    pData = read_file(aRes[i].zName, &sz);
    if( pData==0 ){
      fprintf(stderr, "Cannot open file [%s]\n", aRes[i].zName);
      nErr++;
      continue;
    }

    /* Skip initial lines beginning with # */
    nSkip = 0;
    while( pData[nSkip]=='#' ){
      while( pData[nSkip]!=0 && pData[nSkip]!='\n' ){ nSkip++; }
      if( pData[nSkip]=='\n' ) nSkip++;
    }

    aRes[i].nByte = sz - nSkip;
    aRes[i].idx = i;
    printf("/* Content of file %s */\n", aRes[i].zName);
    printf("static const unsigned char bidata%d[%d] = {\n  ",
           i, sz+1-nSkip);
    for(j=nSkip, n=0; j<=sz; j++){
      printf("%3d", pData[j]);
      if( j==sz ){
        printf(" };\n");
      }else if( n==14 ){
        printf(",\n  ");
        n = 0;
      }else{
................................................................................
  printf("struct BuiltinFileTable {\n");
  printf("  const char *zName;\n");
  printf("  const unsigned char *pData;\n");
  printf("  int nByte;\n");
  printf("};\n");
  printf("static const BuiltinFileTable aBuiltinFiles[] = {\n");
  for(i=0; i<nRes; i++){

    const char *z = aRes[i].zName;
    if( strlen(z)>=nPrefix ) z += nPrefix;
    while( z[0]=='.' || z[0]=='/' ){ z++; }
    aRes[i].zName = z;


  }
  qsort(aRes, nRes, sizeof(aRes[0]), compareResource);
  for(i=0; i<nRes; i++){
    printf("  { \"%s\", bidata%d, %d },\n",
           aRes[i].zName, aRes[i].idx, aRes[i].nByte);
  }
  printf("};\n");
  return nErr;
}

Changes to src/mkindex.c.

215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
...
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
...
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
  i+=j;
  while( isspace(zLine[i]) ){ i++; }
  if( zLine[i]!='(' ) goto page_skip;
  nFixed = nUsed;
  nHelp = 0;
  return;

page_skip:   
   for(i=nFixed; i<nUsed; i++){
      fprintf(stderr,"%s:%d: skipping page \"%s\"\n",
         zFile, nLine, aEntry[i].zPath);
   }
   nUsed = nFixed;
}

................................................................................
      printf("\";\n");
      if( aEntry[i].zIf ) printf("#endif\n");
      aEntry[i].zHelp[0] = 0;
    }
  }
  puts("struct CmdHelp {"
       "int eType; "
       "char const * zText;"
       "};");
  puts("static struct CmdHelp aCmdHelp[] = {");
  for(i=0; i<nFixed; i++){
    if( aEntry[i].zIf ) printf("%s", aEntry[i].zIf);
    if( aEntry[i].zHelp==0 ){
      printf("{%d, 0},\n", aEntry[i].eType);
    }else{
................................................................................
    nLine++;
    scan_for_if(zLine);
    scan_for_label("WEBPAGE:",zLine,0);
    scan_for_label("COMMAND:",zLine,1);
    scan_for_func(zLine);
  }
  fclose(in);
  nUsed = nFixed; 
}

int main(int argc, char **argv){
  int i;
  for(i=1; i<argc; i++){
    zFile = argv[i];
    process_file();
  }
  build_table();
  return 0;
}







|







 







|







 







|











215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
...
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
...
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
  i+=j;
  while( isspace(zLine[i]) ){ i++; }
  if( zLine[i]!='(' ) goto page_skip;
  nFixed = nUsed;
  nHelp = 0;
  return;

page_skip:
   for(i=nFixed; i<nUsed; i++){
      fprintf(stderr,"%s:%d: skipping page \"%s\"\n",
         zFile, nLine, aEntry[i].zPath);
   }
   nUsed = nFixed;
}

................................................................................
      printf("\";\n");
      if( aEntry[i].zIf ) printf("#endif\n");
      aEntry[i].zHelp[0] = 0;
    }
  }
  puts("struct CmdHelp {"
       "int eType; "
       "const char *zText;"
       "};");
  puts("static struct CmdHelp aCmdHelp[] = {");
  for(i=0; i<nFixed; i++){
    if( aEntry[i].zIf ) printf("%s", aEntry[i].zIf);
    if( aEntry[i].zHelp==0 ){
      printf("{%d, 0},\n", aEntry[i].eType);
    }else{
................................................................................
    nLine++;
    scan_for_if(zLine);
    scan_for_label("WEBPAGE:",zLine,0);
    scan_for_label("COMMAND:",zLine,1);
    scan_for_func(zLine);
  }
  fclose(in);
  nUsed = nFixed;
}

int main(int argc, char **argv){
  int i;
  for(i=1; i<argc; i++){
    zFile = argv[i];
    process_file();
  }
  build_table();
  return 0;
}

Changes to src/mkversion.c.

41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
    if( fgets(b, sizeof(b)-1,v)==0 ){
      fprintf(stderr, "malformed VERSION file: %s\n", argv[3]);
      exit(1);
    }
    fclose(v);
    for(z=b; z[0] && z[0]!='\r' && z[0]!='\n'; z++){}
    *z = 0;
    printf("#define RELEASE_VERSION \"%s\"\n", b);   
    x=0;
    i=0;
    z=b;
    while(1){
      if( z[0]>='0' && z[0]<='9' ){
        x = x*10 + z[0] - '0';
      }else{







|







41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
    if( fgets(b, sizeof(b)-1,v)==0 ){
      fprintf(stderr, "malformed VERSION file: %s\n", argv[3]);
      exit(1);
    }
    fclose(v);
    for(z=b; z[0] && z[0]!='\r' && z[0]!='\n'; z++){}
    *z = 0;
    printf("#define RELEASE_VERSION \"%s\"\n", b);
    x=0;
    i=0;
    z=b;
    while(1){
      if( z[0]>='0' && z[0]<='9' ){
        x = x*10 + z[0] - '0';
      }else{

Changes to src/publish.c.

56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
**
** Usage: %fossil publish ?--only? TAGS...
**
** Cause artifacts identified by TAGS... to be published (made non-private).
** This can be used (for example) to convert a private branch into a public
** branch, or to publish a bundle that was imported privately.
**
** If any of TAGS names a branch, then all checkins on that most recent
** instance of that branch are included, not just the most recent checkin.
**
** If any of TAGS name checkins then all files and tags associated with
** those checkins are also published automatically.  Except if the --only
** option is used, then only the specific artifacts identified by TAGS
** are published.
**







|







56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
**
** Usage: %fossil publish ?--only? TAGS...
**
** Cause artifacts identified by TAGS... to be published (made non-private).
** This can be used (for example) to convert a private branch into a public
** branch, or to publish a bundle that was imported privately.
**
** If any of TAGS names a branch, then all checkins on the most recent
** instance of that branch are included, not just the most recent checkin.
**
** If any of TAGS name checkins then all files and tags associated with
** those checkins are also published automatically.  Except if the --only
** option is used, then only the specific artifacts identified by TAGS
** are published.
**

Changes to src/regexp.c.

125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
...
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
...
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
...
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
...
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
...
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
...
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
  unsigned i;
  for(i=0; i<pSet->nState; i++) if( pSet->aState[i]==newState ) return;
  pSet->aState[pSet->nState++] = newState;
}

/* Extract the next unicode character from *pzIn and return it.  Advance
** *pzIn to the first byte past the end of the character returned.  To
** be clear:  this routine converts utf8 to unicode.  This routine is 
** optimized for the common case where the next character is a single byte.
*/
static unsigned re_next_char(ReInput *p){
  unsigned c;
  if( p->i>=p->mx ) return 0;
  c = p->z[p->i++];
  if( c>=0x80 ){
................................................................................
  int c = RE_EOF+1;
  int cPrev = 0;
  int rc = 0;
  ReInput in;

  in.z = zIn;
  in.i = 0;
  in.mx = nIn>=0 ? nIn : strlen((char const*)zIn);

  /* Look for the initial prefix match, if there is one. */
  if( pRe->nInit ){
    unsigned char x = pRe->zInit[0];
    while( in.i+pRe->nInit<=in.mx 
     && (zIn[in.i]!=x ||
         strncmp((const char*)zIn+in.i, (const char*)pRe->zInit, pRe->nInit)!=0)
    ){
      in.i++;
    }
    if( in.i+pRe->nInit>in.mx ) return 0;
  }
................................................................................
              }else{
                j++;
              }
            }
          }
          if( pRe->aOp[x]==RE_OP_CC_EXC ) hit = !hit;
          if( hit ) re_add_state(pNext, x+n);
          break;            
        }
      }
    }
  }
  for(i=0; i<pNext->nState; i++){
    if( pRe->aOp[pNext->aState[i]]==RE_OP_ACCEPT ){ rc = 1; break; }
  }
................................................................................
  int iStart;
  unsigned c;
  const char *zErr;
  while( (c = p->xNextChar(&p->sIn))!=0 ){
    iStart = p->nState;
    switch( c ){
      case '|':
      case '$': 
      case ')': {
        p->sIn.i--;
        return 0;
      }
      case '(': {
        zErr = re_subcompile_re(p);
        if( zErr ) return zErr;
................................................................................
        p->sIn.i++;
        break;
      }
      case '.': {
        if( rePeek(p)=='*' ){
          re_append(p, RE_OP_ANYSTAR, 0);
          p->sIn.i++;
        }else{ 
          re_append(p, RE_OP_ANY, 0);
        }
        break;
      }
      case '*': {
        if( iPrev<0 ) return "'*' without operand";
        re_insert(p, iPrev, RE_OP_GOTO, p->nState - iPrev + 1);
................................................................................
    re_free(pRe);
    return "unrecognized character";
  }

  /* The following is a performance optimization.  If the regex begins with
  ** ".*" (if the input regex lacks an initial "^") and afterwards there are
  ** one or more matching characters, enter those matching characters into
  ** zInit[].  The re_match() routine can then search ahead in the input 
  ** string looking for the initial match without having to run the whole
  ** regex engine over the string.  Do not worry able trying to match
  ** unicode characters beyond plane 0 - those are very rare and this is
  ** just an optimization. */
  if( pRe->aOp[0]==RE_OP_ANYSTAR ){
    for(j=0, i=1; j<sizeof(pRe->zInit)-2 && pRe->aOp[i]==RE_OP_MATCH; i++){
      unsigned x = pRe->aArg[i];
................................................................................
** pattern and the second argument is the string.  So, the SQL statements:
**
**       A REGEXP B
**
** is implemented as regexp(B,A).
*/
static void re_sql_func(
  sqlite3_context *context, 
  int argc, 
  sqlite3_value **argv
){
  ReCompiled *pRe;          /* Compiled regular expression */
  const char *zPattern;     /* The regular expression */
  const unsigned char *zStr;/* String being searched */
  const char *zErr;         /* Compile error message */








|







 







|




|







 







|







 







|







 







|







 







|







 







|
|







125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
...
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
...
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
...
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
...
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
...
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
...
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
  unsigned i;
  for(i=0; i<pSet->nState; i++) if( pSet->aState[i]==newState ) return;
  pSet->aState[pSet->nState++] = newState;
}

/* Extract the next unicode character from *pzIn and return it.  Advance
** *pzIn to the first byte past the end of the character returned.  To
** be clear:  this routine converts utf8 to unicode.  This routine is
** optimized for the common case where the next character is a single byte.
*/
static unsigned re_next_char(ReInput *p){
  unsigned c;
  if( p->i>=p->mx ) return 0;
  c = p->z[p->i++];
  if( c>=0x80 ){
................................................................................
  int c = RE_EOF+1;
  int cPrev = 0;
  int rc = 0;
  ReInput in;

  in.z = zIn;
  in.i = 0;
  in.mx = nIn>=0 ? nIn : strlen((const char*)zIn);

  /* Look for the initial prefix match, if there is one. */
  if( pRe->nInit ){
    unsigned char x = pRe->zInit[0];
    while( in.i+pRe->nInit<=in.mx
     && (zIn[in.i]!=x ||
         strncmp((const char*)zIn+in.i, (const char*)pRe->zInit, pRe->nInit)!=0)
    ){
      in.i++;
    }
    if( in.i+pRe->nInit>in.mx ) return 0;
  }
................................................................................
              }else{
                j++;
              }
            }
          }
          if( pRe->aOp[x]==RE_OP_CC_EXC ) hit = !hit;
          if( hit ) re_add_state(pNext, x+n);
          break;
        }
      }
    }
  }
  for(i=0; i<pNext->nState; i++){
    if( pRe->aOp[pNext->aState[i]]==RE_OP_ACCEPT ){ rc = 1; break; }
  }
................................................................................
  int iStart;
  unsigned c;
  const char *zErr;
  while( (c = p->xNextChar(&p->sIn))!=0 ){
    iStart = p->nState;
    switch( c ){
      case '|':
      case '$':
      case ')': {
        p->sIn.i--;
        return 0;
      }
      case '(': {
        zErr = re_subcompile_re(p);
        if( zErr ) return zErr;
................................................................................
        p->sIn.i++;
        break;
      }
      case '.': {
        if( rePeek(p)=='*' ){
          re_append(p, RE_OP_ANYSTAR, 0);
          p->sIn.i++;
        }else{
          re_append(p, RE_OP_ANY, 0);
        }
        break;
      }
      case '*': {
        if( iPrev<0 ) return "'*' without operand";
        re_insert(p, iPrev, RE_OP_GOTO, p->nState - iPrev + 1);
................................................................................
    re_free(pRe);
    return "unrecognized character";
  }

  /* The following is a performance optimization.  If the regex begins with
  ** ".*" (if the input regex lacks an initial "^") and afterwards there are
  ** one or more matching characters, enter those matching characters into
  ** zInit[].  The re_match() routine can then search ahead in the input
  ** string looking for the initial match without having to run the whole
  ** regex engine over the string.  Do not worry able trying to match
  ** unicode characters beyond plane 0 - those are very rare and this is
  ** just an optimization. */
  if( pRe->aOp[0]==RE_OP_ANYSTAR ){
    for(j=0, i=1; j<sizeof(pRe->zInit)-2 && pRe->aOp[i]==RE_OP_MATCH; i++){
      unsigned x = pRe->aArg[i];
................................................................................
** pattern and the second argument is the string.  So, the SQL statements:
**
**       A REGEXP B
**
** is implemented as regexp(B,A).
*/
static void re_sql_func(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  ReCompiled *pRe;          /* Compiled regular expression */
  const char *zPattern;     /* The regular expression */
  const unsigned char *zStr;/* String being searched */
  const char *zErr;         /* Compile error message */

Changes to src/report.c.

169
170
171
172
173
174
175

176
177
178
179
180
181
182
...
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
...
238
239
240
241
242
243
244
245

246
247
248

249
250
251
252
253
254
255
256
...
920
921
922
923
924
925
926
927
928
929


930
931
932
933






934
935







936
937




938
939
940

941
942
943







944
945
946
947
948




949
950


951
952
953
954
955
956
957
958


















959
960
961
962
963
964
965
966
967
968
969
970
971
972
973

974
975
976








977
978
979
980
981
982
983
984
985


986


987

988
989
990
991
992
993

994
995
996
997
998
999
1000
1001
1002
....
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
  int rc = SQLITE_OK;
  if( *(char**)pError ){
    /* We've already seen an error.  No need to continue. */
    return SQLITE_OK;
  }
  switch( code ){
    case SQLITE_SELECT:

    case SQLITE_FUNCTION: {
      break;
    }
    case SQLITE_READ: {
      static const char *const azAllowed[] = {
         "ticket",
         "ticketchng",
................................................................................
        *(char**)pError = mprintf("access to table \"%s\" is restricted",zArg1);
        rc = SQLITE_DENY;
      }else if( !g.perm.RdAddr && strncmp(zArg2, "private_", 8)==0 ){
        rc = SQLITE_IGNORE;
      }
      break;
    }
    case SQLITE_RECURSIVE: {
      *(char**)pError = mprintf("recursive queries are not allowed");
      rc = SQLITE_DENY;
      break;
    }
    default: {
      *(char**)pError = mprintf("only SELECT statements are allowed");
      rc = SQLITE_DENY;
      break;
    }
  }
  return rc;
................................................................................
  int i;
  char *zErr = 0;
  const char *zTail;
  sqlite3_stmt *pStmt;
  int rc;

  /* First make sure the SQL is a single query command by verifying that
  ** the first token is "SELECT" and that there are no unquoted semicolons.

  */
  for(i=0; fossil_isspace(zSql[i]); i++){}
  if( fossil_strnicmp(&zSql[i],"select",6)!=0 ){

    return mprintf("The SQL must be a SELECT statement");
  }
  for(i=0; zSql[i]; i++){
    if( zSql[i]==';' ){
      int bad;
      int c = zSql[i+1];
      zSql[i+1] = 0;
      bad = sqlite3_complete(zSql);
................................................................................
  return rc;
}

/*
** Output Javascript code that will enables sorting of the table with
** the id zTableId by clicking.
**
** The javascript is derived from:
**
**     http://www.webtoolkit.info/sortable-html-table.html


**
** This variation allows column types to be expressed using the second
** argument.  Each character of the second argument represent a column.
** "t" means sort as text.  "n" means sort numerically.  "x" means do not






** sort on this column.  If there are fewer characters in zColumnTypes[] than
** their are columns, the all extra columns assume type "t" (text).







*/
void output_table_sorting_javascript(const char *zTableId, const char *zColumnTypes){




  @ <script>
  @ function SortableTable(tableEl,columnTypes){
  @   this.tbody = tableEl.getElementsByTagName('tbody');

  @   this.sort = function (cell) {
  @     var column = cell.cellIndex;
  @     var sortFn = cell.sortType=="n" ? this.sortNumeric : this.sortText;







  @     this.sortIndex = column;
  @     var newRows = new Array();
  @     for (j = 0; j < this.tbody[0].rows.length; j++) {
  @        newRows[j] = this.tbody[0].rows[j];
  @     }




  @     newRows.sort(sortFn);
  @     if (cell.getAttribute("sortdir") == 'down') {


  @        newRows.reverse();
  @        cell.setAttribute('sortdir','up');
  @     } else {
  @        cell.setAttribute('sortdir','down');
  @     }
  @     for (i=0;i<newRows.length;i++) {
  @       this.tbody[0].appendChild(newRows[i]);
  @     }


















  @   }
  @   this.sortText = function(a,b) {
  @     var i = thisObject.sortIndex;
  @     aa = a.cells[i].textContent.replace(/^\W+/,'').toLowerCase();
  @     bb = b.cells[i].textContent.replace(/^\W+/,'').toLowerCase();
  @     if(aa==bb) return 0;
  @     if(aa<bb) return -1;
  @     return 1;
  @   }
  @   this.sortNumeric = function(a,b) {
  @     var i = thisObject.sortIndex;
  @     aa = parseFloat(a.cells[i].textContent);
  @     if (isNaN(aa)) aa = 0;
  @     bb = parseFloat(b.cells[i].textContent);
  @     if (isNaN(bb)) bb = 0;

  @     return aa-bb;
  @   }
  @   var thisObject = this;








  @   var x = tableEl.getElementsByTagName('thead');
  @   if(!(this.tbody && this.tbody[0].rows && this.tbody[0].rows.length>0)){
  @     return;
  @   }
  @   if(x && x[0].rows && x[0].rows.length > 0) {
  @     var sortRow = x[0].rows[0];
  @   } else {
  @     return;
  @   }


  @   for (var i=0; i<sortRow.cells.length; i++) {


  @     sortRow.cells[i].sTable = this;

  @     sortRow.cells[i].sortType = columnTypes[i] || 't';
  @     sortRow.cells[i].onclick = function () {
  @       this.sTable.sort(this);
  @       return false;
  @     }
  @   }

  @ }
  @ var t = new SortableTable(gebi("%s(zTableId)"),"%s(zColumnTypes)");
  @ </script>
}


/*
** WEBPAGE: /rptview
**
................................................................................
    report_unrestrict_sql();
    @ </tbody></table>
    if( zErr1 ){
      @ <p class="reportError">Error: %h(zErr1)</p>
    }else if( zErr2 ){
      @ <p class="reportError">Error: %h(zErr2)</p>
    }
    output_table_sorting_javascript("reportTable","");
    style_footer();
  }else{
    report_restrict_sql(&zErr1);
    db_exec_readonly(g.db, zSql, output_tab_separated, &count, &zErr2);
    report_unrestrict_sql();
    cgi_set_content_type("text/plain");
  }







>







 







<
<
<
<
<







 







|
>


|
>
|







 







|


>
>



|
>
>
>
>
>
>
|
|
>
>
>
>
>
>
>

|
>
>
>
>

|

>


<
>
>
>
>
>
>
>





>
>
>
>
|
<
>
>
|
<
|
<




>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>





|









>


<
>
>
>
>
>
>
>
>





|



>
>
|
>
>
|
>
|
|




>

|







 







|







169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
...
200
201
202
203
204
205
206





207
208
209
210
211
212
213
...
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
...
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960

961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977

978
979
980

981

982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021

1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
....
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
  int rc = SQLITE_OK;
  if( *(char**)pError ){
    /* We've already seen an error.  No need to continue. */
    return SQLITE_OK;
  }
  switch( code ){
    case SQLITE_SELECT:
    case SQLITE_RECURSIVE:
    case SQLITE_FUNCTION: {
      break;
    }
    case SQLITE_READ: {
      static const char *const azAllowed[] = {
         "ticket",
         "ticketchng",
................................................................................
        *(char**)pError = mprintf("access to table \"%s\" is restricted",zArg1);
        rc = SQLITE_DENY;
      }else if( !g.perm.RdAddr && strncmp(zArg2, "private_", 8)==0 ){
        rc = SQLITE_IGNORE;
      }
      break;
    }





    default: {
      *(char**)pError = mprintf("only SELECT statements are allowed");
      rc = SQLITE_DENY;
      break;
    }
  }
  return rc;
................................................................................
  int i;
  char *zErr = 0;
  const char *zTail;
  sqlite3_stmt *pStmt;
  int rc;

  /* First make sure the SQL is a single query command by verifying that
  ** the first token is "SELECT" or "WITH" and that there are no unquoted
  ** semicolons.
  */
  for(i=0; fossil_isspace(zSql[i]); i++){}
  if( fossil_strnicmp(&zSql[i], "select", 6)!=0
      && fossil_strnicmp(&zSql[i], "with", 4)!=0 ){
    return mprintf("The SQL must be a SELECT or WITH statement");
  }
  for(i=0; zSql[i]; i++){
    if( zSql[i]==';' ){
      int bad;
      int c = zSql[i+1];
      zSql[i+1] = 0;
      bad = sqlite3_complete(zSql);
................................................................................
  return rc;
}

/*
** Output Javascript code that will enables sorting of the table with
** the id zTableId by clicking.
**
** The javascript was originally derived from:
**
**     http://www.webtoolkit.info/sortable-html-table.html
**
** But there have been extensive modifications.
**
** This variation allows column types to be expressed using the second
** argument.  Each character of the second argument represent a column.
**
**       t      Sort by text
**       n      Sort numerically
**       k      Sort by the data-sortkey property
**       x      This column is not sortable
**
** Capital letters mean sort in reverse order.
** If there are fewer characters in zColumnTypes[] than their are columns,
** the all extra columns assume type "t" (text).
**
** The third parameter is the column that was initially sorted (using 1-based
** column numbers, like SQL).  Make this value 0 if none of the columns are
** initially sorted.  Make the value negative if the column is initially sorted
** in reverse order.
**
** Clicking on the same column header twice in a row inverts the sort.
*/
void output_table_sorting_javascript(
  const char *zTableId,      /* ID of table to sort */
  const char *zColumnTypes,  /* String for column types */
  int iInitSort              /* Initially sorted column. Leftmost is 1. 0 for NONE */
){
  @ <script>
  @ function SortableTable(tableEl,columnTypes,initSort){
  @   this.tbody = tableEl.getElementsByTagName('tbody');
  @   this.columnTypes = columnTypes;
  @   this.sort = function (cell) {
  @     var column = cell.cellIndex;

  @     var sortFn;
  @     switch( cell.sortType ){
  @       case "N": case "n":  sortFn = this.sortNumeric;  break;
  @       case "T": case "t":  sortFn = this.sortText;     break;
  @       case "K": case "k":  sortFn = this.sortKey;      break;
  @       default:  return;
  @     }
  @     this.sortIndex = column;
  @     var newRows = new Array();
  @     for (j = 0; j < this.tbody[0].rows.length; j++) {
  @        newRows[j] = this.tbody[0].rows[j];
  @     }
  @     if( this.sortIndex==Math.abs(this.prevColumn)-1 ){
  @       newRows.reverse();
  @       this.prevColumn = -this.prevColumn;
  @     }else{
  @       newRows.sort(sortFn);

  @       this.prevColumn = this.sortIndex+1;
  @       if( cell.sortType>="A" && cell.sortType<="Z" ){
  @         newRows.reverse();

  @       }

  @     }
  @     for (i=0;i<newRows.length;i++) {
  @       this.tbody[0].appendChild(newRows[i]);
  @     }
  @     this.setHdrIcons();
  @   }
  @   this.setHdrIcons = function() {
  @     for (var i=0; i<this.hdrRow.cells.length; i++) {
  @       if( this.columnTypes[i]=='x' ) continue;
  @       var sortType;
  @       if( this.prevColumn==i+1 ){
  @         sortType = 'asc';
  @       }else if( this.prevColumn==(-1-i) ){
  @         sortType = 'desc'
  @       }else{
  @         sortType = 'none';
  @       }
  @       var hdrCell = this.hdrRow.cells[i];
  @       var clsName = hdrCell.className.replace(/\s*\bsort\s*\w+/, '');
  @       clsName += ' sort ' + sortType;
  @       hdrCell.className = clsName;
  @     }
  @   }
  @   this.sortText = function(a,b) {
  @     var i = thisObject.sortIndex;
  @     aa = a.cells[i].textContent.replace(/^\W+/,'').toLowerCase();
  @     bb = b.cells[i].textContent.replace(/^\W+/,'').toLowerCase();
  @     if(aa==bb) return a.rowIndex-b.rowIndex;
  @     if(aa<bb) return -1;
  @     return 1;
  @   }
  @   this.sortNumeric = function(a,b) {
  @     var i = thisObject.sortIndex;
  @     aa = parseFloat(a.cells[i].textContent);
  @     if (isNaN(aa)) aa = 0;
  @     bb = parseFloat(b.cells[i].textContent);
  @     if (isNaN(bb)) bb = 0;
  @     if(aa==bb) return a.rowIndex-b.rowIndex;
  @     return aa-bb;
  @   }

  @   this.sortKey = function(a,b) {
  @     var i = thisObject.sortIndex;
  @     aa = a.cells[i].getAttribute("data-sortkey");
  @     bb = b.cells[i].getAttribute("data-sortkey");
  @     if(aa==bb) return a.rowIndex-b.rowIndex;
  @     if(aa<bb) return -1;
  @     return 1;
  @   }
  @   var x = tableEl.getElementsByTagName('thead');
  @   if(!(this.tbody && this.tbody[0].rows && this.tbody[0].rows.length>0)){
  @     return;
  @   }
  @   if(x && x[0].rows && x[0].rows.length > 0) {
  @     this.hdrRow = x[0].rows[0];
  @   } else {
  @     return;
  @   }
  @   var thisObject = this;
  @   this.prevColumn = initSort;
  @   for (var i=0; i<this.hdrRow.cells.length; i++) {
  @     if( columnTypes[i]=='x' ) continue;
  @     var hdrcell = this.hdrRow.cells[i];
  @     hdrcell.sTable = this;
  @     hdrcell.style.cursor = "pointer";
  @     hdrcell.sortType = columnTypes[i] || 't';
  @     hdrcell.onclick = function () {
  @       this.sTable.sort(this);
  @       return false;
  @     }
  @   }
  @   this.setHdrIcons()
  @ }
  @ var t = new SortableTable(gebi("%s(zTableId)"),"%s(zColumnTypes)",%d(iInitSort));
  @ </script>
}


/*
** WEBPAGE: /rptview
**
................................................................................
    report_unrestrict_sql();
    @ </tbody></table>
    if( zErr1 ){
      @ <p class="reportError">Error: %h(zErr1)</p>
    }else if( zErr2 ){
      @ <p class="reportError">Error: %h(zErr2)</p>
    }
    output_table_sorting_javascript("reportTable","",0);
    style_footer();
  }else{
    report_restrict_sql(&zErr1);
    db_exec_readonly(g.db, zSql, output_tab_separated, &count, &zErr2);
    report_unrestrict_sql();
    cgi_set_content_type("text/plain");
  }

Changes to src/schema.c.

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
..
43
44
45
46
47
48
49
50



51
52
53
54
55
56
57
..
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
...
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
...
225
226
227
228
229
230
231


















232
233
234
235
236
237
238

239
240
241
242

243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
...
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
** merchantability or fitness for a particular purpose.
**
** Author contact information:
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*******************************************************************************
** 
** This file contains string constants that implement the database schema.
*/
#include "config.h"
#include "schema.h"

/*
** The database schema for the ~/.fossil configuration database.
................................................................................
** changes.  The aux tables have an arbitrary version number (typically
** a date) which can change frequently.  When the content schema changes,
** we have to execute special procedures to update the schema.  When
** the aux schema changes, all we need to do is rebuild the database.
*/
#define CONTENT_SCHEMA  "2"
#define AUX_SCHEMA_MIN  "2011-04-25 19:50"
#define AUX_SCHEMA_MAX  "2014-11-24 20:35"




#endif /* INTERFACE */


/*
** The schema for a repository database.
**
................................................................................
@   rcvid INTEGER,                  -- Origin of this record
@   size INTEGER,                   -- Size of content. -1 for a phantom.
@   uuid TEXT UNIQUE NOT NULL,      -- SHA1 hash of the content
@   content BLOB,                   -- Compressed content of this record
@   CHECK( length(uuid)==40 AND rid>0 )
@ );
@ CREATE TABLE delta(
@   rid INTEGER PRIMARY KEY,                 -- BLOB that is delta-compressed 
@   srcid INTEGER NOT NULL REFERENCES blob   -- Baseline for delta-compression
@ );
@ CREATE INDEX delta_i1 ON delta(srcid);
@
@ -------------------------------------------------------------------------
@ -- The BLOB and DELTA tables above hold the "global state" of a Fossil
@ -- project; the stuff that is normally exchanged during "sync".  The
................................................................................
@   ipaddr TEXT,                    -- IP address for which cookie is valid
@   cexpire DATETIME,               -- Time when cookie expires
@   info TEXT,                      -- contact information
@   mtime DATE,                     -- last change.  seconds since 1970
@   photo BLOB                      -- JPEG image of this user
@ );
@
@ -- The VAR table holds miscellanous information about the repository.
@ -- in the form of name-value pairs.
@ --
@ CREATE TABLE config(
@   name TEXT PRIMARY KEY NOT NULL,  -- Primary name of the entry
@   value CLOB,                      -- Content of the named parameter
@   mtime DATE,                      -- last modified.  seconds since 1970
@   CHECK( typeof(name)='text' AND length(name)>=1 )
................................................................................
@ CREATE TABLE filename(
@   fnid INTEGER PRIMARY KEY,    -- Filename ID
@   name TEXT UNIQUE             -- Name of file page
@ );
@
@ -- Linkages between checkins, files created by each checkin, and
@ -- the names of those files.


















@ --
@ -- pid==0 if the file is added by checkin mid.
@ -- fid==0 if the file is removed by checkin mid.
@ --
@ CREATE TABLE mlink(
@   mid INTEGER REFERENCES blob,        -- Manifest ID where change occurs
@   pid INTEGER REFERENCES blob,        -- File ID in parent manifest

@   fid INTEGER REFERENCES blob,        -- Changed file ID in this manifest
@   fnid INTEGER REFERENCES filename,   -- Name of the file
@   pfnid INTEGER REFERENCES filename,  -- Previous name. 0 if unchanged
@   mperm INTEGER                       -- File permissions.  1==exec

@ );
@ CREATE INDEX mlink_i1 ON mlink(mid);
@ CREATE INDEX mlink_i2 ON mlink(fnid);
@ CREATE INDEX mlink_i3 ON mlink(fid);
@ CREATE INDEX mlink_i4 ON mlink(pid);
@
@ -- Parent/child linkages between checkins
@ --
@ CREATE TABLE plink(
@   pid INTEGER REFERENCES blob,    -- Parent manifest
@   cid INTEGER REFERENCES blob,    -- Child manifest
@   isprim BOOLEAN,                 -- pid is the primary parent of cid
@   mtime DATETIME,                 -- the date/time stamp on cid.  Julian day.
@   baseid INTEGER REFERENCES blob, -- Baseline if child is a delta manifest
@   UNIQUE(pid, cid)
@ );
@ CREATE INDEX plink_i2 ON plink(cid,pid);
@
@ -- A "leaf" checkin is a checkin that has no children in the same
@ -- branch.  The set of all leaves is easily computed with a join,
@ -- between the plink and tagxref tables, but it is a slower join for
................................................................................
@ -- added but not yet committed.
@ --
@ -- Vfile.chnged is 0 for unmodified files, 1 for files that have
@ -- been edited or which have been subjected to a 3-way merge.
@ -- Vfile.chnged is 2 if the file has been replaced from a different
@ -- version by the merge and 3 if the file has been added by a merge.
@ -- Vfile.chnged is 4|5 is the same as 2|3, but the operation has been
@ -- done by an --integrate merge.  The difference between vfile.chnged==2|4
@ -- and a regular add is that with vfile.chnged==2|4 we know that the
@ -- current version of the file is already in the repository.
@ --
@ CREATE TABLE vfile(
@   id INTEGER PRIMARY KEY,           -- ID of the checked out file
@   vid INTEGER REFERENCES blob,      -- The baseline this file is part of.
@   chnged INT DEFAULT 0,             -- 0:unchnged 1:edited 2:m-chng 3:m-add 4:i-chng 5:i-add
@   deleted BOOLEAN DEFAULT 0,        -- True if deleted
@   isexe BOOLEAN,                    -- True if file should be executable
@   islink BOOLEAN,                   -- True if file should be symlink
@   rid INTEGER,                      -- Originally from this repository record
@   mrid INTEGER,                     -- Based on this record due to a merge
@   mtime INTEGER,                    -- Mtime of file on disk. sec since 1970
@   pathname TEXT,                    -- Full pathname relative to root







|







 







|
>
>
>







 







|







 







|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>





|
|
>
|


|
>













|







 







|
|





|







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
..
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
..
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
...
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
...
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
...
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
** merchantability or fitness for a particular purpose.
**
** Author contact information:
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*******************************************************************************
**
** This file contains string constants that implement the database schema.
*/
#include "config.h"
#include "schema.h"

/*
** The database schema for the ~/.fossil configuration database.
................................................................................
** changes.  The aux tables have an arbitrary version number (typically
** a date) which can change frequently.  When the content schema changes,
** we have to execute special procedures to update the schema.  When
** the aux schema changes, all we need to do is rebuild the database.
*/
#define CONTENT_SCHEMA  "2"
#define AUX_SCHEMA_MIN  "2011-04-25 19:50"
#define AUX_SCHEMA_MAX  "2015-01-24"
/* NB:  Some features require the latest schema.  Warning or error messages
** will appear if an older schema is used.  However, the older schemas are
** adequate for many common functions. */

#endif /* INTERFACE */


/*
** The schema for a repository database.
**
................................................................................
@   rcvid INTEGER,                  -- Origin of this record
@   size INTEGER,                   -- Size of content. -1 for a phantom.
@   uuid TEXT UNIQUE NOT NULL,      -- SHA1 hash of the content
@   content BLOB,                   -- Compressed content of this record
@   CHECK( length(uuid)==40 AND rid>0 )
@ );
@ CREATE TABLE delta(
@   rid INTEGER PRIMARY KEY,                 -- BLOB that is delta-compressed
@   srcid INTEGER NOT NULL REFERENCES blob   -- Baseline for delta-compression
@ );
@ CREATE INDEX delta_i1 ON delta(srcid);
@
@ -------------------------------------------------------------------------
@ -- The BLOB and DELTA tables above hold the "global state" of a Fossil
@ -- project; the stuff that is normally exchanged during "sync".  The
................................................................................
@   ipaddr TEXT,                    -- IP address for which cookie is valid
@   cexpire DATETIME,               -- Time when cookie expires
@   info TEXT,                      -- contact information
@   mtime DATE,                     -- last change.  seconds since 1970
@   photo BLOB                      -- JPEG image of this user
@ );
@
@ -- The config table holds miscellanous information about the repository.
@ -- in the form of name-value pairs.
@ --
@ CREATE TABLE config(
@   name TEXT PRIMARY KEY NOT NULL,  -- Primary name of the entry
@   value CLOB,                      -- Content of the named parameter
@   mtime DATE,                      -- last modified.  seconds since 1970
@   CHECK( typeof(name)='text' AND length(name)>=1 )
................................................................................
@ CREATE TABLE filename(
@   fnid INTEGER PRIMARY KEY,    -- Filename ID
@   name TEXT UNIQUE             -- Name of file page
@ );
@
@ -- Linkages between checkins, files created by each checkin, and
@ -- the names of those files.
@ -- 
@ -- Each entry represents a file that changed content from pid to fid
@ -- due to the check-in that goes from pmid to mid.  fnid is the name
@ -- of the file in the mid check-in.  If the file was renamed as part
@ -- of the mid check-in, then pfnid is the previous filename.
@
@ -- There can be multiple entries for (mid,fid) if the mid checkin was
@ -- a merge.  Entries with isaux==0 are from the primary parent.  Merge
@ -- parents have isaux set to true.
@ --
@ -- Field name mnemonics:
@ --    mid = Manifest ID.  (Each check-in is stored as a "Manifest")
@ --    fid = File ID.
@ --    pmid = Parent Manifest ID.
@ --    pid = Parent file ID.
@ --    fnid = File Name ID.
@ --    pfnid = Parent File Name ID.
@ --    isaux = pmid IS AUXiliary parent, not primary parent
@ --
@ -- pid==0 if the file is added by checkin mid.
@ -- fid==0 if the file is removed by checkin mid.
@ --
@ CREATE TABLE mlink(
@   mid INTEGER REFERENCES plink(cid),  -- Checkin that contains fid
@   fid INTEGER REFERENCES blob,        -- New file content. 0 if deleted
@   pmid INTEGER REFERENCES plink(cid), -- Checkin that contains pid
@   pid INTEGER REFERENCES blob,        -- Prev file content. 0 if new
@   fnid INTEGER REFERENCES filename,   -- Name of the file
@   pfnid INTEGER REFERENCES filename,  -- Previous name. 0 if unchanged
@   mperm INTEGER,                      -- File permissions.  1==exec
@   isaux BOOLEAN DEFAULT 0             -- TRUE if pmid is the primary
@ );
@ CREATE INDEX mlink_i1 ON mlink(mid);
@ CREATE INDEX mlink_i2 ON mlink(fnid);
@ CREATE INDEX mlink_i3 ON mlink(fid);
@ CREATE INDEX mlink_i4 ON mlink(pid);
@
@ -- Parent/child linkages between checkins
@ --
@ CREATE TABLE plink(
@   pid INTEGER REFERENCES blob,    -- Parent manifest
@   cid INTEGER REFERENCES blob,    -- Child manifest
@   isprim BOOLEAN,                 -- pid is the primary parent of cid
@   mtime DATETIME,                 -- the date/time stamp on cid.  Julian day.
@   baseid INTEGER REFERENCES blob, -- Baseline if cid is a delta manifest.
@   UNIQUE(pid, cid)
@ );
@ CREATE INDEX plink_i2 ON plink(cid,pid);
@
@ -- A "leaf" checkin is a checkin that has no children in the same
@ -- branch.  The set of all leaves is easily computed with a join,
@ -- between the plink and tagxref tables, but it is a slower join for
................................................................................
@ -- added but not yet committed.
@ --
@ -- Vfile.chnged is 0 for unmodified files, 1 for files that have
@ -- been edited or which have been subjected to a 3-way merge.
@ -- Vfile.chnged is 2 if the file has been replaced from a different
@ -- version by the merge and 3 if the file has been added by a merge.
@ -- Vfile.chnged is 4|5 is the same as 2|3, but the operation has been
@ -- done by an --integrate merge.  The difference between vfile.chnged==3|5
@ -- and a regular add is that with vfile.chnged==3|5 we know that the
@ -- current version of the file is already in the repository.
@ --
@ CREATE TABLE vfile(
@   id INTEGER PRIMARY KEY,           -- ID of the checked out file
@   vid INTEGER REFERENCES blob,      -- The baseline this file is part of.
@   chnged INT DEFAULT 0,  -- 0:unchng 1:edit 2:m-chng 3:m-add 4:i-chng 5:i-add
@   deleted BOOLEAN DEFAULT 0,        -- True if deleted
@   isexe BOOLEAN,                    -- True if file should be executable
@   islink BOOLEAN,                   -- True if file should be symlink
@   rid INTEGER,                      -- Originally from this repository record
@   mrid INTEGER,                     -- Based on this record due to a merge
@   mtime INTEGER,                    -- Mtime of file on disk. sec since 1970
@   pathname TEXT,                    -- Full pathname relative to root

Changes to src/search.c.

24
25
26
27
28
29
30




31
32
33
34
35
36
37
38
39






40





41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
..
90
91
92
93
94
95
96

97

98







































































99


100
101
102
103
104

105
106
107
108
109
110
111
112













113
114







115
116
117


118
119

120
121
122


123
124
125
126
127
128




129






130
131
132
133
134
135
136
137
138
139
140
141

142
143
144

145

























































146


























147
148
149










150























151
152


153




































154
155

156
157
158
159
160
161
162
163
164
165

166

167
168
169
170





171































172
173
174
175
176
177
178
179
180
181








182
183
184
185
186
187
188
...
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
...
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
...
253
254
255
256
257
258
259


































































































































































































































































** full functionality of FTS4.
*/
#include "config.h"
#include "search.h"
#include <assert.h>

#if INTERFACE




/*
** A compiled search pattern
*/
struct Search {
  int nTerm;            /* Number of search terms */
  struct srchTerm {     /* For each search term */
    char *z;               /* Text */
    int n;                 /* length */
  } a[8];               






};





#endif

/*
** Compile a search pattern
*/
Search *search_init(const char *zPattern){
  int nPattern = strlen(zPattern);
  Search *p;
  char *z;
  int i;

  p = fossil_malloc( nPattern + sizeof(*p) + 1);
  z = (char*)&p[1];
  memcpy(z, zPattern, nPattern+1);
  memset(p, 0, sizeof(*p));
  while( *z && p->nTerm<sizeof(p->a)/sizeof(p->a[0]) ){
    while( !fossil_isalnum(*z) && *z ){ z++; }
    if( *z==0 ) break;
    p->a[p->nTerm].z = z;
    for(i=1; fossil_isalnum(z[i]) || z[i]=='_'; i++){}
    p->a[p->nTerm].n = i;
    z += i;
    p->nTerm++;
  }
  return p;
}


/*
** Destroy a search context.
*/
void search_end(Search *p){
  free(p);
}

/*
** Theses characters constitute a word boundary
*/
static const char isBoundary[] = {
  1, 1, 1, 1, 1, 1, 1, 1,     1, 1, 1, 1, 1, 1, 1, 1,
  1, 1, 1, 1, 1, 1, 1, 1,     1, 1, 1, 1, 1, 1, 1, 1,
................................................................................
  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
};



/*







































































** Compare a search pattern against an input string and return a score.


**
** Scoring:
**   *  All terms must match at least once or the score is zero
**   *  10 bonus points if the first occurrence is an exact match
**   *  1 additional point for each subsequent match of the same word

**   *  Extra points of two consecutive words of the pattern are consecutive
**      in the document
*/
int search_score(Search *p, int nDoc, const char **azDoc){
  int iPrev = 999;
  int score = 10;
  int iBonus = 0;
  int i, j, k;













  const char *zDoc;
  unsigned char seen[8];








  memset(seen, 0, sizeof(seen));
  for(k=0; k<nDoc; k++){


    zDoc = azDoc[k];
    if( zDoc==0 ) continue;

    for(i=0; zDoc[i]; i++){
      char c = zDoc[i];
      if( isBoundary[c&0xff] ) continue;


      for(j=0; j<p->nTerm; j++){
        int n = p->a[j].n;
        if( sqlite3_strnicmp(p->a[j].z, &zDoc[i], n)==0 ){
          score += 1;
          if( !seen[j] ){
            if( isBoundary[zDoc[i+n]&0xff] ) score += 10;




            seen[j] = 1;






          }
          if( j==iPrev+1 ){
            score += iBonus;
          }
          i += n-1;
          iPrev = j;
          iBonus = 50;
          break;
        }
      }
      iBonus /= 2;
      while( !isBoundary[zDoc[i]&0xff] ){ i++; }

    }
  }
  

  /* Every term must be seen or else the score is zero */

























































  for(j=0; j<p->nTerm; j++){


























    if( !seen[j] ) return 0;
  }











  return score;























}



/*




































** This is an SQLite function that scores its input using
** a pre-computed pattern.

*/
static void search_score_sqlfunc(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  Search *p = (Search*)sqlite3_user_data(context);
  const char **azDoc;
  int score;
  int i;



  azDoc = fossil_malloc( sizeof(const char*)*(argc+1) );
  for(i=0; i<argc; i++) azDoc[i] = (const char*)sqlite3_value_text(argv[i]);
  score = search_score(p, argc, azDoc);
  fossil_free(azDoc);





  sqlite3_result_int(context, score);































}

/*
** Register the "score()" SQL function to score its input text
** using the given Search object.  Once this function is registered,
** do not delete the Search object.
*/
void search_sql_setup(Search *p){
  sqlite3_create_function(g.db, "score", -1, SQLITE_UTF8, p,
     search_score_sqlfunc, 0, 0);








}

/*
** Testing the search function.
**
** COMMAND: search*
** %fossil search [-all|-a] [-limit|-n #] [-width|-W #] pattern...
................................................................................
** all matches, regardless of their search score.
** The -limit option can be used to limit the number
** of entries returned.  The -width option can be
** used to set the output width used when printing
** matches.
*/
void search_cmd(void){
  Search *p;
  Blob pattern;
  int i;
  Blob sql = empty_blob;
  Stmt q;
  int iBest;
  char fAll = NULL != find_option("all", "a", 0); /* If set, do not lop
                                                     off the end of the
................................................................................

  db_must_be_within_tree();
  if( g.argc<2 ) return;
  blob_init(&pattern, g.argv[2], -1);
  for(i=3; i<g.argc; i++){
    blob_appendf(&pattern, " %s", g.argv[i]);
  }
  p = search_init(blob_str(&pattern));
  blob_reset(&pattern);
  search_sql_setup(p);

  db_multi_exec(
     "CREATE TEMP TABLE srch(rid,uuid,date,comment,x);"
     "CREATE INDEX srch_idx1 ON srch(x);"
     "INSERT INTO srch(rid,uuid,date,comment,x)"
     "   SELECT blob.rid, uuid, datetime(event.mtime%s),"
     "          coalesce(ecomment,comment),"
................................................................................
  }
  blob_append(&sql, "ORDER BY x DESC, date DESC ", -1);
  db_prepare(&q, "%s", blob_sql_text(&sql));
  blob_reset(&sql);
  print_timeline(&q, nLimit, width, 0);
  db_finalize(&q);
}









































































































































































































































































>
>
>
>








|
>
>
>
>
>
>

>
>
>
>
>



|

<
<
|
<
<

<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







 







>

>

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>



<
<
>
|


|
<
<
<
<
>
>
>
>
>
>
>
>
>
>
>
>
>
|
<
>
>
>
>
>
>
>

|
<
>
>
|

>

<
<
>
>


|
<
<
<
>
>
>
>
|
>
>
>
>
>
>
|
<
<

<
<
<



<
<
>


|
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|

>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
>
>

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

<
>






|



>

>


|
|
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







|
|

>
>
>
>
>
>
>
>







 







<







 







|

|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60


61


62























63
64
65
66
67
68
69
..
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165


166
167
168
169
170




171
172
173
174
175
176
177
178
179
180
181
182
183
184

185
186
187
188
189
190
191
192
193

194
195
196
197
198
199


200
201
202
203
204



205
206
207
208
209
210
211
212
213
214
215
216


217



218
219
220


221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389

390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
...
477
478
479
480
481
482
483

484
485
486
487
488
489
490
...
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
...
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
** full functionality of FTS4.
*/
#include "config.h"
#include "search.h"
#include <assert.h>

#if INTERFACE

/* Maximum number of search terms */
#define SEARCH_MAX_TERM   8

/*
** A compiled search pattern
*/
struct Search {
  int nTerm;            /* Number of search terms */
  struct srchTerm {     /* For each search term */
    char *z;               /* Text */
    int n;                 /* length */
  } a[SEARCH_MAX_TERM];
  /* Snippet controls */
  char *zPattern;       /* The search pattern */
  char *zMarkBegin;     /* Start of a match */   
  char *zMarkEnd;       /* End of a match */
  char *zMarkGap;       /* A gap between two matches */
  unsigned fSrchFlg;    /* Flags */
};

#define SRCHFLG_HTML    0x01   /* Escape snippet text for HTML */
#define SRCHFLG_SCORE   0x02   /* Prepend the score to each snippet */
#define SRCHFLG_STATIC  0x04   /* The static gSearch object */

#endif

/*
** There is a single global Search object:
*/


static Search gSearch;



























/*
** Theses characters constitute a word boundary
*/
static const char isBoundary[] = {
  1, 1, 1, 1, 1, 1, 1, 1,     1, 1, 1, 1, 1, 1, 1, 1,
  1, 1, 1, 1, 1, 1, 1, 1,     1, 1, 1, 1, 1, 1, 1, 1,
................................................................................
  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0,     0, 0, 0, 0, 0, 0, 0, 0,
};
#define ISALNUM(x)  (!isBoundary[(x)&0xff])


/*
** Destroy a search context.
*/
void search_end(Search *p){
  if( p ){
    fossil_free(p->zPattern);
    fossil_free(p->zMarkBegin);
    fossil_free(p->zMarkEnd);
    fossil_free(p->zMarkGap);
    memset(p, 0, sizeof(*p));
    if( p!=&gSearch ) fossil_free(p);
  }
}

/*
** Compile a search pattern
*/
Search *search_init(
  const char *zPattern,       /* The search pattern */
  const char *zMarkBegin,     /* Start of a match */   
  const char *zMarkEnd,       /* End of a match */
  const char *zMarkGap,       /* A gap between two matches */
  unsigned fSrchFlg           /* Flags */
){
  Search *p;
  char *z;
  int i;

  if( fSrchFlg & SRCHFLG_STATIC ){
    p = &gSearch;
    search_end(p);
  }else{
    p = fossil_malloc(sizeof(*p));
    memset(p, 0, sizeof(*p));
  }
  p->zPattern = z = mprintf("%s", zPattern);
  p->zMarkBegin = mprintf("%s", zMarkBegin);
  p->zMarkEnd = mprintf("%s", zMarkEnd);
  p->zMarkGap = mprintf("%s", zMarkGap);
  p->fSrchFlg = fSrchFlg;
  while( *z && p->nTerm<SEARCH_MAX_TERM ){
    while( *z && !ISALNUM(*z) ){ z++; }
    if( *z==0 ) break;
    p->a[p->nTerm].z = z;
    for(i=1; ISALNUM(z[i]); i++){}
    p->a[p->nTerm].n = i;
    z += i;
    p->nTerm++;
  }
  return p;
}


/*
** Append n bytes of text to snippet zTxt.  Encode the text appropriately.
*/
static void snippet_text_append(
  Search *p,             /* The search context */
  Blob *pSnip,           /* Append to this snippet */
  const char *zTxt,      /* Text to append */
  int n                  /* How many bytes to append */
){
  if( n>0 ){
    if( p->fSrchFlg & SRCHFLG_HTML ){
      blob_appendf(pSnip, "%#h", n, zTxt);
    }else{
      blob_append(pSnip, zTxt, n);
    }
  }
}

/*
** Compare a search pattern against one or more input strings which
** collectively comprise a document.  Return a match score.  Optionally
** also return a "snippet".
**
** Scoring:
**   *  All terms must match at least once or the score is zero


**   *  One point for each matching term
**   *  Extra points if consecutive words of the pattern are consecutive
**      in the document
*/
static int search_score(




  Search *p,              /* Search pattern and flags */
  int nDoc,               /* Number of strings in this document */
  const char **azDoc,     /* Text of each string */
  Blob *pSnip             /* If not NULL: Write a snippet here */
){
  int score;                         /* Final score */
  int i;                             /* Offset into current document */
  int ii;                            /* Loop counter */
  int j;                             /* Loop over search terms */
  int k;                             /* Loop over prior terms */
  int iWord = 0;                     /* Current word number */
  int iDoc;                          /* Current document number */
  int wantGap = 0;                   /* True if a zMarkGap is wanted */
  const char *zDoc;                  /* Current document text */

  const int CTX = 50;                /* Amount of snippet context */
  int anMatch[SEARCH_MAX_TERM];      /* Number of terms in best match */
  int aiBestDoc[SEARCH_MAX_TERM];    /* Document containing best match */
  int aiBestOfst[SEARCH_MAX_TERM];   /* Byte offset to start of best match */
  int aiLastDoc[SEARCH_MAX_TERM];    /* Document containing most recent match */
  int aiLastOfst[SEARCH_MAX_TERM];   /* Byte offset to the most recent match */
  int aiWordIdx[SEARCH_MAX_TERM];    /* Word index of most recent match */

  memset(anMatch, 0, sizeof(anMatch));

  memset(aiWordIdx, 0xff, sizeof(aiWordIdx));
  for(iDoc=0; iDoc<nDoc; iDoc++){
    zDoc = azDoc[iDoc];
    if( zDoc==0 ) continue;
    iWord++;
    for(i=0; zDoc[i]; i++){


      if( !ISALNUM(zDoc[i]) ) continue;
      iWord++;
      for(j=0; j<p->nTerm; j++){
        int n = p->a[j].n;
        if( sqlite3_strnicmp(p->a[j].z, &zDoc[i], n)==0



         && (!ISALNUM(zDoc[i+n]) || p->a[j].z[n]=='*')
        ){
          aiWordIdx[j] = iWord;
          aiLastDoc[j] = iDoc;
          aiLastOfst[j] = i;
          for(k=1; j-k>=0 && anMatch[j-k] && aiWordIdx[j-k]==iWord-k; k++){}
          for(ii=0; ii<k; ii++){
            if( anMatch[j-ii]<k ){
              anMatch[j-ii] = k;
              aiBestDoc[j-ii] = aiLastDoc[j-ii];
              aiBestOfst[j-ii] = aiLastOfst[j-ii];
            }


          }



          break;
        }
      }


      while( ISALNUM(zDoc[i]) ){ i++; }
    }
  }

  /* Finished search all documents.
  ** Every term must be seen or else the score is zero 
  */
  score = 1;
  for(j=0; j<p->nTerm; j++) score *= anMatch[j];
  if( score==0 || pSnip==0 ) return score;


  /* Prepare a snippet that describes the matching text.
  */
  blob_init(pSnip, 0, 0);
  if( p->fSrchFlg & SRCHFLG_SCORE ) blob_appendf(pSnip, "%08x", score);

  while(1){
    int iOfst;
    int iTail;
    int iBest;
    for(ii=0; ii<p->nTerm && anMatch[ii]==0; ii++){}
    if( ii>=p->nTerm ) break;  /* This is where the loop exits */
    iBest = ii;
    iDoc = aiBestDoc[ii];
    iOfst = aiBestOfst[ii];
    for(; ii<p->nTerm; ii++){
      if( anMatch[ii]==0 ) continue;
      if( aiBestDoc[ii]>iDoc ) continue;
      if( aiBestOfst[ii]>iOfst ) continue;
      iDoc = aiBestDoc[ii];
      iOfst = aiBestOfst[ii];
      iBest = ii;
    }
    iTail = iOfst + p->a[iBest].n;
    anMatch[iBest] = 0;
    for(ii=0; ii<p->nTerm; ii++){
      if( anMatch[ii]==0 ) continue;
      if( aiBestDoc[ii]!=iDoc ) continue;
      if( aiBestOfst[ii]<=iTail+CTX*2 ){
        if( iTail<aiBestOfst[ii]+p->a[ii].n ){
          iTail = aiBestOfst[ii]+p->a[ii].n;
        }
        anMatch[ii] = 0;
        ii = -1;
        continue;
      }
    }
    zDoc = azDoc[iDoc];
    iOfst -= CTX;
    if( iOfst<0 ) iOfst = 0;
    while( iOfst>0 && ISALNUM(zDoc[iOfst-1]) ) iOfst--;
    while( zDoc[iOfst] && !ISALNUM(zDoc[iOfst]) ) iOfst++;
    for(ii=0; ii<CTX && zDoc[iTail]; ii++, iTail++){}
    while( ISALNUM(zDoc[iTail]) ) iTail++;
    if( iOfst>0 || wantGap ) blob_append(pSnip, p->zMarkGap, -1);
    wantGap = zDoc[iTail]!=0;
    zDoc += iOfst;
    iTail -= iOfst;

    /* Add a snippet segment using characters iOfst..iOfst+iTail from zDoc */
    for(i=0; i<iTail; i++){
      if( !ISALNUM(zDoc[i]) ) continue;
      for(j=0; j<p->nTerm; j++){
        int n = p->a[j].n;
        if( sqlite3_strnicmp(p->a[j].z, &zDoc[i], n)==0
         && (!ISALNUM(zDoc[i+n]) || p->a[j].z[n]=='*')
        ){
          snippet_text_append(p, pSnip, zDoc, i);
          zDoc += i;
          iTail -= i;
          blob_append(pSnip, p->zMarkBegin, -1);
          if( p->a[j].z[n]=='*' ){
            while( ISALNUM(zDoc[n]) ) n++;
          }
          snippet_text_append(p, pSnip, zDoc, n);
          zDoc += n;
          iTail -= n;
          blob_append(pSnip, p->zMarkEnd, -1);
          i = -1;
          break;
        } /* end-if */
      } /* end for(j) */
      if( j<p->nTerm ){
        while( ISALNUM(zDoc[i]) && i<iTail ){ i++; }
      }
    } /* end for(i) */
    snippet_text_append(p, pSnip, zDoc, iTail);
  }
  if( wantGap ) blob_append(pSnip, p->zMarkGap, -1);
  return score;
}

/*
** COMMAND: test-snippet
**
** Usage: fossil test-snippet SEARCHSTRING FILE1 FILE2 ... 
*/
void test_snippet_cmd(void){
  Search *p;
  int i;
  Blob x;
  Blob snip;
  int score;
  char *zDoc;
  int flg = 0;
  char *zBegin = (char*)find_option("begin",0,1);
  char *zEnd = (char*)find_option("end",0,1);
  char *zGap = (char*)find_option("gap",0,1);
  if( find_option("html",0,0)!=0 ) flg |= SRCHFLG_HTML;
  if( find_option("score",0,0)!=0 ) flg |= SRCHFLG_SCORE;
  if( find_option("static",0,0)!=0 ) flg |= SRCHFLG_STATIC;
  verify_all_options();
  if( g.argc<4 ) usage("SEARCHSTRING FILE1...");
  if( zBegin==0 ) zBegin = "[[";
  if( zEnd==0 ) zEnd = "]]";
  if( zGap==0 ) zGap = " ... ";
  p = search_init(g.argv[2], zBegin, zEnd, zGap, flg);
  for(i=3; i<g.argc; i++){
    blob_read_from_file(&x, g.argv[i]);
    zDoc = blob_str(&x);
    score = search_score(p, 1, (const char**)&zDoc, &snip);
    fossil_print("%s: %d\n", g.argv[i], score);
    blob_reset(&x);
    if( score ){
      fossil_print("%.78c\n%s\n%.78c\n\n", '=', blob_str(&snip), '=');
      blob_reset(&snip);
    }
  }
}

/*
** An SQL function to initialize the global search pattern:
**
**     search_init(PATTERN,BEGIN,END,GAP,FLAGS)
**
** All arguments are optional.
*/
static void search_init_sqlfunc(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  const char *zPattern = 0;
  const char *zBegin = "<b>";
  const char *zEnd = "</b>";
  const char *zGap = " ... ";
  unsigned int flg = SRCHFLG_HTML;
  switch( argc ){
    default:
      flg = (unsigned int)sqlite3_value_int(argv[4]);
    case 4:
      zGap = (const char*)sqlite3_value_text(argv[3]);
    case 3:
      zEnd = (const char*)sqlite3_value_text(argv[2]);
    case 2:
      zBegin = (const char*)sqlite3_value_text(argv[1]);
    case 1:
      zPattern = (const char*)sqlite3_value_text(argv[0]);
  }
  if( zPattern && zPattern[0] ){
    search_init(zPattern, zBegin, zEnd, zGap, flg | SRCHFLG_STATIC);
  }else{
    search_end(&gSearch);
  }
}

/*
** This is an SQLite function that scores its input using

** the pattern from the previous call to search_init().
*/
static void search_score_sqlfunc(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  int isSnippet = sqlite3_user_data(context)!=0;
  const char **azDoc;
  int score;
  int i;
  Blob snip;

  if( gSearch.nTerm==0 ) return;
  azDoc = fossil_malloc( sizeof(const char*)*(argc+1) );
  for(i=0; i<argc; i++) azDoc[i] = (const char*)sqlite3_value_text(argv[i]);
  score = search_score(&gSearch, argc, azDoc, isSnippet ? &snip : 0);
  fossil_free((void *)azDoc);
  if( isSnippet ){
    if( score ){
      sqlite3_result_text(context, blob_materialize(&snip), -1, fossil_free);
    }
  }else{
    sqlite3_result_int(context, score);
  }
}

/*
** This is an SQLite function that computes the searchable text.
** It is a wrapper around the search_stext() routine.  See the 
** search_stext() routine for further detail.
*/
static void search_stext_sqlfunc(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  Blob txt;
  const char *zType = (const char*)sqlite3_value_text(argv[0]);
  const char *zArg1 = (const char*)sqlite3_value_text(argv[1]);
  const char *zArg2 = (const char*)sqlite3_value_text(argv[2]);
  search_stext(zType[0], zArg1, zArg2, &txt);
  sqlite3_result_text(context, blob_materialize(&txt), -1, fossil_free);
}

/*
** Encode a string for use as a query parameter in a URL
*/
static void search_urlencode_sqlfunc(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  char *z = mprintf("%T",sqlite3_value_text(argv[0]));
  sqlite3_result_text(context, z, -1, fossil_free);
}

/*
** Register the "score()" SQL function to score its input text
** using the given Search object.  Once this function is registered,
** do not delete the Search object.
*/
void search_sql_setup(sqlite3 *db){
  sqlite3_create_function(db, "score", -1, SQLITE_UTF8, 0,
     search_score_sqlfunc, 0, 0);
  sqlite3_create_function(db, "snippet", -1, SQLITE_UTF8, &gSearch,
     search_score_sqlfunc, 0, 0);
  sqlite3_create_function(db, "search_init", -1, SQLITE_UTF8, 0,
     search_init_sqlfunc, 0, 0);
  sqlite3_create_function(db, "stext", 3, SQLITE_UTF8, 0,
     search_stext_sqlfunc, 0, 0);
  sqlite3_create_function(db, "urlencode", 1, SQLITE_UTF8, 0,
     search_urlencode_sqlfunc, 0, 0);
}

/*
** Testing the search function.
**
** COMMAND: search*
** %fossil search [-all|-a] [-limit|-n #] [-width|-W #] pattern...
................................................................................
** all matches, regardless of their search score.
** The -limit option can be used to limit the number
** of entries returned.  The -width option can be
** used to set the output width used when printing
** matches.
*/
void search_cmd(void){

  Blob pattern;
  int i;
  Blob sql = empty_blob;
  Stmt q;
  int iBest;
  char fAll = NULL != find_option("all", "a", 0); /* If set, do not lop
                                                     off the end of the
................................................................................

  db_must_be_within_tree();
  if( g.argc<2 ) return;
  blob_init(&pattern, g.argv[2], -1);
  for(i=3; i<g.argc; i++){
    blob_appendf(&pattern, " %s", g.argv[i]);
  }
  (void)search_init(blob_str(&pattern),"*","*","...",SRCHFLG_STATIC);
  blob_reset(&pattern);
  search_sql_setup(g.db);

  db_multi_exec(
     "CREATE TEMP TABLE srch(rid,uuid,date,comment,x);"
     "CREATE INDEX srch_idx1 ON srch(x);"
     "INSERT INTO srch(rid,uuid,date,comment,x)"
     "   SELECT blob.rid, uuid, datetime(event.mtime%s),"
     "          coalesce(ecomment,comment),"
................................................................................
  }
  blob_append(&sql, "ORDER BY x DESC, date DESC ", -1);
  db_prepare(&q, "%s", blob_sql_text(&sql));
  blob_reset(&sql);
  print_timeline(&q, nLimit, width, 0);
  db_finalize(&q);
}

/*
** WEBPAGE: /search
**
** This is an EXPERIMENTAL page for doing search across a repository.
**
** The current implementation does a full text search over embedded
** documentation files on the tip of the "trunk" branch.  Only files
** ending in ".wiki", ".md", ".html", and ".txt" are searched.
**
** The entire text is scanned.  There is no full-text index.  This is
** experimental.  We may change to using a full-text index depending
** on performance.
**
** Other pending enhancements:
**    *   Search tickets
**    *   Search wiki
*/
void search_page(void){
  const char *zPattern = PD("s","");
  Stmt q;
  const char *zSrchEnable = "dwc";

  login_check_credentials();
  if( !g.perm.Read ){ login_needed(); return; }
  style_header("Search");
  @ <form method="GET" action="search"><center>
  @ <input type="text" name="s" size="40" value="%h(zPattern)">
  @ <input type="submit" value="Search">
  @ </center></form>
  while( fossil_isspace(zPattern[0]) ) zPattern++;
  if( zPattern[0] ){
    search_sql_setup(g.db);
    add_content_sql_commands(g.db);
    search_init(zPattern, "<b>", "</b>", " ... ",
            SRCHFLG_STATIC|SRCHFLG_HTML|SRCHFLG_SCORE);
    db_multi_exec(
      "CREATE VIRTUAL TABLE IF NOT EXISTS temp.foci USING files_of_checkin;"
      "CREATE TEMP TABLE x(label TEXT,url TEXT,date TEXT,snip TEXT);"
    );
    if( strchr(zSrchEnable, 'd') ){
      db_multi_exec(
        "INSERT INTO x(label,url,date,snip)"
        "  SELECT printf('Document: %%s',foci.filename),"
        "         printf('%R/doc/trunk/%%s',foci.filename),"
        "         (SELECT datetime(event.mtime) FROM event"
        "            WHERE objid=symbolic_name_to_rid('trunk')),"
        "         snippet(stext('d',blob.rid,foci.filename))"
        "    FROM foci CROSS JOIN blob"
        "   WHERE checkinID=symbolic_name_to_rid('trunk')"
        "     AND blob.uuid=foci.uuid"
        "     AND (filename GLOB '*.wiki' OR"
        "          filename GLOB '*.md' OR"
        "          filename GLOB '*.txt' OR"
        "          filename GLOB '*.html');"
      );
    }
    if( strchr(zSrchEnable, 'w') ){
      db_multi_exec(
        "WITH wiki(name,rid,mtime) AS ("
        "  SELECT substr(tagname,6), tagxref.rid, max(tagxref.mtime)"
        "    FROM tag, tagxref"
        "   WHERE tag.tagname GLOB 'wiki-*'"
        "     AND tagxref.tagid=tag.tagid"
        "   GROUP BY 1"
        ")"
        "INSERT INTO x(label,url,date,snip)"
        "  SELECT printf('Wiki: %%s',name),"
        "         printf('%R/wiki?name=%%s',urlencode(name)),"
        "         datetime(mtime),"
        "         snippet(stext('w',rid,name))"
        "    FROM wiki;"
      );
    }
    if( strchr(zSrchEnable, 'c') ){
      db_multi_exec(
        "WITH ckin(uuid,rid,mtime) AS ("
        "  SELECT blob.uuid, event.objid, event.mtime"
        "    FROM event, blob"
        "   WHERE event.type='ci'"
        "     AND blob.rid=event.objid"
        ")"
        "INSERT INTO x(label,url,date,snip)"
        "  SELECT printf('Check-in [%%.10s] on %%s',uuid,datetime(mtime)),"
        "         printf('%R/timeline?c=%%s&n=8&y=ci',uuid),"
        "         datetime(mtime),"
        "         snippet(stext('c',rid,NULL))"
        "    FROM ckin;"
      );
    }
    db_prepare(&q, "SELECT url, substr(snip,9), label"
                   "   FROM x WHERE snip IS NOT NULL"
                   " ORDER BY substr(snip,1,9) DESC, date DESC;");
    @ <ol>
    while( db_step(&q)==SQLITE_ROW ){
      const char *zUrl = db_column_text(&q, 0);
      const char *zSnippet = db_column_text(&q, 1);
      const char *zLabel = db_column_text(&q, 2);
      @ <li><p>%s(href("%s",zUrl))%h(zLabel)</a><br>%s(zSnippet)</li>
    }
    db_finalize(&q);
    @ </ol>
  }
  style_footer();
}


/*
** This is a helper function for search_stext().  Writing into pOut
** the search text obtained from pIn according to zMimetype.
*/
static void get_stext_by_mimetype(
  Blob *pIn,
  const char *zMimetype,
  Blob *pOut
){
  Blob html, title;
  blob_init(&html, 0, 0);
  blob_init(&title, 0, 0);
  if( zMimetype==0 ) zMimetype = "text/plain";
  if( fossil_strcmp(zMimetype,"text/x-fossil-wiki")==0 ){
    wiki_convert(pIn, &html, 0);
    html_to_plaintext(blob_str(&html), pOut);
  }else if( fossil_strcmp(zMimetype,"text/x-markdown")==0 ){
    markdown_to_html(pIn, &title, &html);
    html_to_plaintext(blob_str(&html), pOut);
  }else if( fossil_strcmp(zMimetype,"text/html")==0 ){
    html_to_plaintext(blob_str(pIn), pOut);
  }else{
    *pOut = *pIn;
    blob_init(pIn, 0, 0);
  }
  blob_reset(&html);
  blob_reset(&title);
}

/*
** Return "search text" - a reduced version of a document appropriate for
** full text search and/or for constructing a search result snippet.
**
**    cType:            d      Embedded documentation
**                      s      Source code listing
**                      w      Wiki page
**                      c      Check-in comment
**                      t      Ticket text
**                      e      Event/Blog text
**                      k      Diff of a wiki
**                      f      Diff of a checkin
**
**   zArg1, zArg2:      Description of the document, depending on cType.
*/
void search_stext(
  char cType,            /* Type of document */
  const char *zArg1,     /* First parameter */
  const char *zArg2,     /* Second parameter */
  Blob *pOut             /* OUT: Initialize to the search text */
){
  blob_init(pOut, 0, 0);
  switch( cType ){
    case 'd':     /* Doc.     zArg1: RID of the file.  zArg2: Filename */
    case 's': {   /* Source.  zArg1: RID of the file.  zArg2: Filename */
      int rid = atoi(zArg1);
      Blob doc;
      content_get(rid, &doc);
      blob_to_utf8_no_bom(&doc, 0);
      get_stext_by_mimetype(&doc, mimetype_from_name(zArg2), pOut);
      blob_reset(&doc);
      break;
    }
    case 'w': {   /* Wiki.    zArg1: RID of the page.  zArg2: Page name */
      int rid = atoi(zArg1);
      Manifest *pWiki = manifest_get(rid, CFTYPE_WIKI,0);
      Blob wiki;
      if( pWiki==0 ) break;
      blob_init(&wiki, pWiki->zWiki, -1);
      get_stext_by_mimetype(&wiki, wiki_filter_mimetypes(pWiki->zMimetype),
                            pOut);
      blob_reset(&wiki);
      manifest_destroy(pWiki);
      break;
    }
    case 'c': {   /* Ckeckin:  zArg1: RID of the checkin.  zArg2: Not used */
      int rid = atoi(zArg1);
      static Stmt q;
      db_static_prepare(&q,
         "SELECT coalesce(ecomment,comment)"
         "  ||' (user: '||coalesce(euser,user,'?')"
         "  ||', tags: '||"
         "  (SELECT group_concat(substr(tag.tagname,5),',')"
         "     FROM tag, tagxref"
         "    WHERE tagname GLOB 'sym-*' AND tag.tagid=tagxref.tagid"
         "      AND tagxref.rid=event.objid AND tagxref.tagtype>0)"
         "  ||')'"
         "  FROM event WHERE objid=:x AND type='ci'");
      db_bind_int(&q, ":x", rid);
      if( db_step(&q)==SQLITE_ROW ){
        db_column_blob(&q, 0, pOut);
        blob_append(pOut, "\n", 1);
      }
      db_reset(&q);
      break;
    }
  }
}

/*
** The arguments cType,zArg1,zArg2 define an object that can be searched
** for.  Return a URL (relative to the root of the Fossil project) that
** will jump to that document.  
**
** Space to hold the returned string is obtained from mprintf() and should
** be freed by the caller using fossil_free() or the equivalent.
*/
char *search_url(
  char cType,            /* Type of document */
  const char *zArg1,     /* First parameter */
  const char *zArg2      /* Second parameter */
){
  char *zUrl = 0;
  switch( cType ){
    case 'd': {   /* Doc.     zArg1: RID of the file.  zArg2: Filename */
    case 's':     /* Source.  zArg1: RID of the file.  zArg2: Filename */
      zUrl = db_text(0,
         "SELECT printf('/doc/%%s%%s', substr(blob.uuid,20), %Q)"
         "  FROM mlink, blob"
         " WHERE mlink.fid=%d AND mlink.mid=blob.rid",
         zArg2, atoi(zArg1));
      break;
    }
    case 'w': {   /* Wiki.    zArg1: RID of the page.  zArg2: Page name */
      char *zId = db_text(0, "SELECT uuid FROM blob WHERE rid=%d",atoi(zArg1));
      zUrl = mprintf("/wiki?id=%z&name=%t", zId, zArg2);
      break;
    }     
    case 'c': {   /* Ckeckin:  zArg1: RID of the checkin.  zArg2: Not used */
      char *zId = db_text(0, "SELECT uuid FROM blob WHERE rid=%d",atoi(zArg1));
      zUrl = mprintf("/info/%z", zId);
      break;
    }
  }
  return zUrl;
}	

/*
** COMMAND: test-search-stext
**
** Usage: fossil test-search-stext TYPE ARG1 ARG2
*/
void test_search_stext(void){
  Blob out;
  char *zUrl;
  db_find_and_open_repository(0,0);
  if( g.argc!=5 ) usage("TYPE ARG1 ARG2");
  search_stext(g.argv[2][0], g.argv[3], g.argv[4], &out);
  zUrl = search_url(g.argv[2][0], g.argv[3], g.argv[4]);
  fossil_print("%s\n%z\n",blob_str(&out),zUrl);
  blob_reset(&out);
}

Changes to src/setup.c.

149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
...
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
...
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
....
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535

1536
1537
1538
1539
1540
1541
1542
1543

1544
1545
1546
1547
1548
1549
1550
....
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575

1576
1577

1578
1579
1580
1581
1582
1583
1584
....
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606

1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
....
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642

1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
....
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722



1723
1724
1725
1726
1727
1728
1729
1730
1731
1732































1733
1734
1735
1736
1737
1738
1739
....
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
  prevLevel = 0;
  db_prepare(&s,
     "SELECT uid, login, cap, info, 1 FROM user"
     " WHERE login IN ('anonymous','nobody','developer','reader') "
     " UNION ALL "
     "SELECT uid, login, cap, info, 2 FROM user"
     " WHERE login NOT IN ('anonymous','nobody','developer','reader') "
     "ORDER BY 5, 2"
  );
  while( db_step(&s)==SQLITE_ROW ){
    int iLevel = db_column_int(&s, 4);
    const char *zCap = db_column_text(&s, 2);
    const char *zLogin = db_column_text(&s, 1);
    if( iLevel>prevLevel ){
      if( prevLevel>0 ){
................................................................................
  @ <h2>Special Logins</h2>
  @
  @ <ul>
  @ <li><p>
  @ No login is required for user <span class="usertype">nobody</span>. The
  @ capabilities of the <span class="usertype">nobody</span> user are
  @ inherited by all users, regardless of whether or not they are logged in.
  @ To disable universal access to the repository, make sure no user named
  @ <span class="usertype">nobody</span> exists or that the
  @ <span class="usertype">nobody</span> user has no capabilities
  @ enabled. The password for <span class="usertype">nobody</span> is ignored.
  @ To avoid problems with spiders overloading the server, it is recommended
  @ that the <span class="capability">h</span> (Hyperlinks) capability be
  @ turned off for the <span class="usertype">nobody</span> user.
  @ </p></li>
  @
  @ <li><p>
  @ Login is required for user <span class="usertype">anonymous</span> but the
  @ password is displayed on the login screen beside the password entry box
  @ so anybody who can read should be able to login as anonymous.
  @ On the other hand, spiders and web-crawlers will typically not
................................................................................
  db_begin_transaction();
  @ <form action="%s(g.zTop)/setup_access" method="post"><div>
  login_insert_csrf_secret();
  @ <hr />
  onoff_attribute("Redirect to HTTPS on the Login page",
     "redirect-to-https", "redirhttps", 0, 0);
  @ <p>When selected, force the use of HTTPS for the Login page.
  @ <p>Details:  When enabled, this option causes the $secureurl TH1 
  @ variable is set to an "https:" variant of $baseurl.  Otherwise,
  @ $secureurl is just an alias for $baseurl.  Also when enabled, the
  @ Login page redirects to https if accessed via http.
  @ <hr />
  onoff_attribute("Require password for local access",
     "localauth", "localauth", 0, 0);
  @ <p>When enabled, the password sign-in is always required for
................................................................................
  login_check_credentials();
  if( !g.perm.Setup ){
    login_needed();
  }
  db_begin_transaction();
  if( P("clear")!=0 ){
    db_multi_exec("DELETE FROM config WHERE name='css'");
    cgi_replace_parameter("css", zDefaultCSS);
    db_end_transaction(0);
    cgi_redirect("setup_editcss");
  }
  if( P("submit")!=0 ){
    textarea_attribute(0, 0, 0, "css", "css", zDefaultCSS, 0);

    db_end_transaction(0);
    cgi_redirect("setup_editcss");
  }
  style_header("Edit CSS");
  @ <form action="%s(g.zTop)/setup_editcss" method="post"><div>
  login_insert_csrf_secret();
  @ Edit the CSS below:<br />
  textarea_attribute("", 35, 80, "css", "css", zDefaultCSS, 0);

  @ <br />
  @ <input type="submit" name="submit" value="Apply Changes" />
  @ <input type="submit" name="clear" value="Revert To Default" />
  @ </div></form>
  @ <p><span class="note">Note:</span> Press your browser Reload button after
  @ modifying the CSS in order to pull in the modified CSS file.</p>
  @ <hr />
................................................................................
  login_check_credentials();
  if( !g.perm.Setup ){
    login_needed();
  }
  db_begin_transaction();
  if( P("clear")!=0 ){
    db_multi_exec("DELETE FROM config WHERE name='header'");
    cgi_replace_parameter("header", zDefaultHeader);
  }else if( P("submit")!=0 ){
    textarea_attribute(0, 0, 0, "header", "header", zDefaultHeader, 0);

  }else if( P("fixbase")!=0 ){
    const char *z = db_get("header", (char*)zDefaultHeader);

    char *zHead = strstr(z, "<head>");
    if( strstr(z, "<base href=")==0 && zHead!=0 ){
      char *zNew;
      char *zTail = &zHead[6];
      while( fossil_isspace(zTail[0]) ) zTail++;
      zNew = mprintf("%.*s\n<base href=\"$secureurl/$current_page\" />\n%s",
                     zHead+6-z, z, zTail);
................................................................................
    @ <p class="generalError">Please add
    @ <tt>&lt;base href="$secureurl/$current_page"&gt;</tt> after
    @ <tt>&lt;head&gt;</tt> in the header!
    @ <input type="submit" name="fixbase" value="Add &lt;base&gt; Now"></p>
  }

  login_insert_csrf_secret();
  @ <p>Edit HTML text with embedded TH1 (a TCL dialect) that will be used to
  @ generate the beginning of every page through start of the main
  @ menu.</p>
  textarea_attribute("", 35, 80, "header", "header", zDefaultHeader, 0);

  @ <br />
  @ <input type="submit" name="submit" value="Apply Changes" />
  @ <input type="submit" name="clear" value="Revert To Default" />
  @ </div></form>
  @ <hr />
  @ The default header is shown below for reference.  Other examples
  @ of headers can be seen on the <a href="setup_skin">skins page</a>.
  @ See also the <a href="setup_editcss">CSS</a> and
  @ <a href="setup_footer">footer</a> editing screens.
  @ <blockquote><pre>
  @ %h(zDefaultHeader)
  @ </pre></blockquote>
  style_footer();
  db_end_transaction(0);
}

/*
** WEBPAGE: setup_footer
................................................................................
  login_check_credentials();
  if( !g.perm.Setup ){
    login_needed();
  }
  db_begin_transaction();
  if( P("clear")!=0 ){
    db_multi_exec("DELETE FROM config WHERE name='footer'");
    cgi_replace_parameter("footer", zDefaultFooter);
  }

  style_header("Edit Page Footer");
  @ <form action="%s(g.zTop)/setup_footer" method="post"><div>
  login_insert_csrf_secret();
  @ <p>Edit HTML text with embedded TH1 (a TCL dialect) that will be used to
  @ generate the end of every page.</p>
  textarea_attribute("", 20, 80, "footer", "footer", zDefaultFooter, 0);

  @ <br />
  @ <input type="submit" name="submit" value="Apply Changes" />
  @ <input type="submit" name="clear" value="Revert To Default" />
  @ </div></form>
  @ <hr />
  @ The default footer is shown below for reference.  Other examples
  @ of footers can be seen on the <a href="setup_skin">skins page</a>.
  @ See also the <a href="setup_editcss">CSS</a> and
  @ <a href="setup_header">header</a> editing screens.
  @ <blockquote><pre>
  @ %h(zDefaultFooter)
  @ </pre></blockquote>
  style_footer();
  db_end_transaction(0);
}

/*
** WEBPAGE: setup_modreq
................................................................................
    db_multi_exec("DELETE FROM config WHERE name GLOB 'adunit*'");
    cgi_replace_parameter("adunit","");
  }

  style_header("Edit Ad Unit");
  @ <form action="%s(g.zTop)/setup_adunit" method="post"><div>
  login_insert_csrf_secret();
  @ <p>Edit HTML text for an ad unit that will be inserted after the
  @ menu bar and above the content of every page.</p>
  textarea_attribute("", 20, 80, "adunit", "adunit", "", 0);



  @ <br />
  onoff_attribute("Omit ads to administrator",
     "adunit-omit-if-admin", "oia", 0, 0);
  @ <br />
  onoff_attribute("Omit ads to logged-in users",
     "adunit-omit-if-user", "oiu", 0, 0);
  @ <br />
  @ <input type="submit" name="submit" value="Apply Changes" />
  @ <input type="submit" name="clear" value="Delete Ad-Unit" />
  @ </div></form>































  style_footer();
  db_end_transaction(0);
}

/*
** WEBPAGE: setup_logo
*/
................................................................................
  @ <thead>
  @ <th>Time</th>
  @ <th>User</th>
  @ <th>Page</th>
  @ <th width="60%%">Message</th>
  @ </thead><tbody>
  while( SQLITE_ROW == db_step(&stLog) ){
    char const * zTime = db_column_text(&stLog, 0);
    char const * zUser = db_column_text(&stLog, 1);
    char const * zPage = db_column_text(&stLog, 2);
    char const * zMessage = db_column_text(&stLog, 3);
    @ <tr class="row%d(counter++%2)">
    @ <td class="adminTime">%s(zTime)</td>
    @ <td>%s(zUser)</td>
    @ <td>%s(zPage)</td>
    @ <td>%h(zMessage)</td>
    @ </tr>
  }
  @ </tbody></table>
  if(limit>0 && counter<limit){
    @ <div>%d(counter) entries shown.</div>
  }
  style_footer();
}







|







 







|
<


<
<
<







 







|







 







|




|
>







|
>







 







|

|
>

|
>







 







|


|
>










|







 







|





|

|
>










|







 







|
<
|
>
>
>










>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







|
|
|
|













149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
...
811
812
813
814
815
816
817
818

819
820



821
822
823
824
825
826
827
...
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
....
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
....
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
....
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
....
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
....
1715
1716
1717
1718
1719
1720
1721
1722

1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
....
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
  prevLevel = 0;
  db_prepare(&s,
     "SELECT uid, login, cap, info, 1 FROM user"
     " WHERE login IN ('anonymous','nobody','developer','reader') "
     " UNION ALL "
     "SELECT uid, login, cap, info, 2 FROM user"
     " WHERE login NOT IN ('anonymous','nobody','developer','reader') "
     "ORDER BY 5, 2 COLLATE nocase"
  );
  while( db_step(&s)==SQLITE_ROW ){
    int iLevel = db_column_int(&s, 4);
    const char *zCap = db_column_text(&s, 2);
    const char *zLogin = db_column_text(&s, 1);
    if( iLevel>prevLevel ){
      if( prevLevel>0 ){
................................................................................
  @ <h2>Special Logins</h2>
  @
  @ <ul>
  @ <li><p>
  @ No login is required for user <span class="usertype">nobody</span>. The
  @ capabilities of the <span class="usertype">nobody</span> user are
  @ inherited by all users, regardless of whether or not they are logged in.
  @ To disable universal access to the repository, make sure that the

  @ <span class="usertype">nobody</span> user has no capabilities
  @ enabled. The password for <span class="usertype">nobody</span> is ignored.



  @ </p></li>
  @
  @ <li><p>
  @ Login is required for user <span class="usertype">anonymous</span> but the
  @ password is displayed on the login screen beside the password entry box
  @ so anybody who can read should be able to login as anonymous.
  @ On the other hand, spiders and web-crawlers will typically not
................................................................................
  db_begin_transaction();
  @ <form action="%s(g.zTop)/setup_access" method="post"><div>
  login_insert_csrf_secret();
  @ <hr />
  onoff_attribute("Redirect to HTTPS on the Login page",
     "redirect-to-https", "redirhttps", 0, 0);
  @ <p>When selected, force the use of HTTPS for the Login page.
  @ <p>Details:  When enabled, this option causes the $secureurl TH1
  @ variable is set to an "https:" variant of $baseurl.  Otherwise,
  @ $secureurl is just an alias for $baseurl.  Also when enabled, the
  @ Login page redirects to https if accessed via http.
  @ <hr />
  onoff_attribute("Require password for local access",
     "localauth", "localauth", 0, 0);
  @ <p>When enabled, the password sign-in is always required for
................................................................................
  login_check_credentials();
  if( !g.perm.Setup ){
    login_needed();
  }
  db_begin_transaction();
  if( P("clear")!=0 ){
    db_multi_exec("DELETE FROM config WHERE name='css'");
    cgi_replace_parameter("css", builtin_text("skins/default/css.txt"));
    db_end_transaction(0);
    cgi_redirect("setup_editcss");
  }
  if( P("submit")!=0 ){
    textarea_attribute(0, 0, 0, "css", "css",
                       builtin_text("skins/default/css.txt"), 0);
    db_end_transaction(0);
    cgi_redirect("setup_editcss");
  }
  style_header("Edit CSS");
  @ <form action="%s(g.zTop)/setup_editcss" method="post"><div>
  login_insert_csrf_secret();
  @ Edit the CSS below:<br />
  textarea_attribute("", 35, 80, "css", "css",
                     builtin_text("skins/default/css.txt"), 0);
  @ <br />
  @ <input type="submit" name="submit" value="Apply Changes" />
  @ <input type="submit" name="clear" value="Revert To Default" />
  @ </div></form>
  @ <p><span class="note">Note:</span> Press your browser Reload button after
  @ modifying the CSS in order to pull in the modified CSS file.</p>
  @ <hr />
................................................................................
  login_check_credentials();
  if( !g.perm.Setup ){
    login_needed();
  }
  db_begin_transaction();
  if( P("clear")!=0 ){
    db_multi_exec("DELETE FROM config WHERE name='header'");
    cgi_replace_parameter("header", builtin_text("skins/default/header.txt"));
  }else if( P("submit")!=0 ){
    textarea_attribute(0, 0, 0, "header", "header",
                       builtin_text("skins/default/header.txt"), 0);
  }else if( P("fixbase")!=0 ){
    const char *z = db_get("header",
                           (char*)builtin_text("skins/default/header.txt"));
    char *zHead = strstr(z, "<head>");
    if( strstr(z, "<base href=")==0 && zHead!=0 ){
      char *zNew;
      char *zTail = &zHead[6];
      while( fossil_isspace(zTail[0]) ) zTail++;
      zNew = mprintf("%.*s\n<base href=\"$secureurl/$current_page\" />\n%s",
                     zHead+6-z, z, zTail);
................................................................................
    @ <p class="generalError">Please add
    @ <tt>&lt;base href="$secureurl/$current_page"&gt;</tt> after
    @ <tt>&lt;head&gt;</tt> in the header!
    @ <input type="submit" name="fixbase" value="Add &lt;base&gt; Now"></p>
  }

  login_insert_csrf_secret();
  @ <p>Edit HTML text with embedded TH1 (a Tcl dialect) that will be used to
  @ generate the beginning of every page through start of the main
  @ menu.</p>
  textarea_attribute("", 35, 80, "header", "header",
                     builtin_text("skins/default/header.txt"), 0);
  @ <br />
  @ <input type="submit" name="submit" value="Apply Changes" />
  @ <input type="submit" name="clear" value="Revert To Default" />
  @ </div></form>
  @ <hr />
  @ The default header is shown below for reference.  Other examples
  @ of headers can be seen on the <a href="setup_skin">skins page</a>.
  @ See also the <a href="setup_editcss">CSS</a> and
  @ <a href="setup_footer">footer</a> editing screens.
  @ <blockquote><pre>
  @ %h(builtin_text("skins/default/header.txt"))
  @ </pre></blockquote>
  style_footer();
  db_end_transaction(0);
}

/*
** WEBPAGE: setup_footer
................................................................................
  login_check_credentials();
  if( !g.perm.Setup ){
    login_needed();
  }
  db_begin_transaction();
  if( P("clear")!=0 ){
    db_multi_exec("DELETE FROM config WHERE name='footer'");
    cgi_replace_parameter("footer", builtin_text("skins/default/footer.txt"));
  }

  style_header("Edit Page Footer");
  @ <form action="%s(g.zTop)/setup_footer" method="post"><div>
  login_insert_csrf_secret();
  @ <p>Edit HTML text with embedded TH1 (a Tcl dialect) that will be used to
  @ generate the end of every page.</p>
  textarea_attribute("", 20, 80, "footer", "footer",
                     builtin_text("skins/default/footer.txt"), 0);
  @ <br />
  @ <input type="submit" name="submit" value="Apply Changes" />
  @ <input type="submit" name="clear" value="Revert To Default" />
  @ </div></form>
  @ <hr />
  @ The default footer is shown below for reference.  Other examples
  @ of footers can be seen on the <a href="setup_skin">skins page</a>.
  @ See also the <a href="setup_editcss">CSS</a> and
  @ <a href="setup_header">header</a> editing screens.
  @ <blockquote><pre>
  @ %h(builtin_text("skins/default/footer.txt"))
  @ </pre></blockquote>
  style_footer();
  db_end_transaction(0);
}

/*
** WEBPAGE: setup_modreq
................................................................................
    db_multi_exec("DELETE FROM config WHERE name GLOB 'adunit*'");
    cgi_replace_parameter("adunit","");
  }

  style_header("Edit Ad Unit");
  @ <form action="%s(g.zTop)/setup_adunit" method="post"><div>
  login_insert_csrf_secret();
  @ <b>Banner Ad-Unit:</b><br />

 textarea_attribute("", 6, 80, "adunit", "adunit", "", 0);
  @ <br />
  @ <b>Right-Column Ad-Unit:</b><br />
  textarea_attribute("", 6, 80, "adunit-right", "adright", "", 0);
  @ <br />
  onoff_attribute("Omit ads to administrator",
     "adunit-omit-if-admin", "oia", 0, 0);
  @ <br />
  onoff_attribute("Omit ads to logged-in users",
     "adunit-omit-if-user", "oiu", 0, 0);
  @ <br />
  @ <input type="submit" name="submit" value="Apply Changes" />
  @ <input type="submit" name="clear" value="Delete Ad-Unit" />
  @ </div></form>
  @ <hr />
  @ <b>Ad-Unit Notes:</b><ul>
  @ <li>Leave both Ad-Units blank to disable all advertising.
  @ <li>The "Banner Ad-Unit" is used for wide pages.
  @ <li>The "Right-Column Ad-Unit" is used on pages with tall, narrow content.
  @ <li>If the "Right-Column Ad-Unit" is blank, the "Banner Ad-Unit" is used on all pages.
  @ <li>Suggested <a href="setup_editcss">CSS</a> changes:
  @ <blockquote><pre>
  @ div.adunit_banner {
  @   margin: auto;
  @   width: 100%;
  @ }
  @ div.adunit_right {
  @   float: right;
  @ }
  @ div.adunit_right_container {
  @   min-height: <i>height-of-right-column-ad-unit</i>;
  @ }
  @ </pre></blockquote>
  @ <li>For a place-holder Ad-Unit for testing, Copy/Paste the following
  @ with appropriate adjustments to "width:" and "height:".
  @ <blockquote><pre>
  @ &lt;div style='
  @   margin: 0 auto;
  @   width: 600px;
  @   height: 90px;
  @   border: 1px solid #f11;
  @   background-color: #fcc;
  @ '&gt;Demo Ad&lt;/div&gt;
  @ </pre></blockquote>
  @ </li>
  style_footer();
  db_end_transaction(0);
}

/*
** WEBPAGE: setup_logo
*/
................................................................................
  @ <thead>
  @ <th>Time</th>
  @ <th>User</th>
  @ <th>Page</th>
  @ <th width="60%%">Message</th>
  @ </thead><tbody>
  while( SQLITE_ROW == db_step(&stLog) ){
    const char *zTime = db_column_text(&stLog, 0);
    const char *zUser = db_column_text(&stLog, 1);
    const char *zPage = db_column_text(&stLog, 2);
    const char *zMessage = db_column_text(&stLog, 3);
    @ <tr class="row%d(counter++%2)">
    @ <td class="adminTime">%s(zTime)</td>
    @ <td>%s(zUser)</td>
    @ <td>%s(zPage)</td>
    @ <td>%h(zMessage)</td>
    @ </tr>
  }
  @ </tbody></table>
  if(limit>0 && counter<limit){
    @ <div>%d(counter) entries shown.</div>
  }
  style_footer();
}

Changes to src/sha1.c.

62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
...
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
...
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
...
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
...
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
...
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
#define blk0be(i) block[i]
#define blk(i) (block[i&15] = rol(block[(i+13)&15]^block[(i+8)&15] \
    ^block[(i+2)&15]^block[i&15],1))

/*
 * (R0+R1), R2, R3, R4 are the different operations (rounds) used in SHA1
 *
 * Rl0() for little-endian and Rb0() for big-endian.  Endianness is 
 * determined at run-time.
 */
#define Rl0(v,w,x,y,z,i) \
    z+=((w&(x^y))^y)+blk0le(i)+0x5A827999+rol(v,5);w=ror(w,2);
#define Rb0(v,w,x,y,z,i) \
    z+=((w&(x^y))^y)+blk0be(i)+0x5A827999+rol(v,5);w=ror(w,2);
#define R1(v,w,x,y,z,i) \
................................................................................
/*
** Convert a digest into base-16.  digest should be declared as
** "unsigned char digest[20]" in the calling function.  The SHA1
** digest is stored in the first 20 bytes.  zBuf should
** be "char zBuf[41]".
*/
static void DigestToBase16(unsigned char *digest, char *zBuf){
  static char const zEncode[] = "0123456789abcdef";
  int ix;

  for(ix=0; ix<20; ix++){
    *zBuf++ = zEncode[(*digest>>4)&0xf];
    *zBuf++ = zEncode[*digest++ & 0xf];
  }
  *zBuf = '\0';
................................................................................
*/
void sha1sum_step_blob(Blob *p){
  sha1sum_step_text(blob_buffer(p), blob_size(p));
}

/*
** Finish the incremental SHA1 checksum.  Store the result in blob pOut
** if pOut!=0.  Also return a pointer to the result.  
**
** This resets the incremental checksum preparing for the next round
** of computation.  The return pointer points to a static buffer that
** is overwritten by subsequent calls to this function.
*/
char *sha1sum_finish(Blob *pOut){
  unsigned char zResult[20];
................................................................................
  unsigned char zResult[20];
  char zBuf[10240];

  if( file_wd_islink(zFilename) ){
    /* Instead of file content, return sha1 of link destination path */
    Blob destinationPath;
    int rc;
    
    blob_read_link(&destinationPath, zFilename);
    rc = sha1sum_blob(&destinationPath, pCksum);
    blob_reset(&destinationPath);
    return rc;
  }

  in = fossil_fopen(zFilename,"rb");
................................................................................
  SHA1Final(&ctx, zResult);
  DigestToBase16(zResult, zDigest);
  return mprintf("%s", zDigest);
}

/*
** Convert a cleartext password for a specific user into a SHA1 hash.
** 
** The algorithm here is:
**
**       SHA1( project-code + "/" + login + "/" + password )
**
** In words: The users login name and password are appended to the
** project ID code and the SHA1 hash of the result is computed.
**
** The result of this function is the shared secret used by a client
** to authenticate to a server for the sync protocol.  It is also the
** value stored in the USER.PW field of the database.  By mixing in the
** login name and the project id with the hash, different shared secrets
** are obtained even if two users select the same password, or if a 
** single user selects the same password for multiple projects.
*/
char *sha1_shared_secret(
  const char *zPw,        /* The password to encrypt */
  const char *zLogin,     /* Username */
  const char *zProjCode   /* Project-code.  Use built-in project code if NULL */
){
................................................................................
** Compute an SHA1 checksum of all files named on the command-line.
** If an file is named "-" then take its content from standard input.
*/
void sha1sum_test(void){
  int i;
  Blob in;
  Blob cksum;
  
  for(i=2; i<g.argc; i++){
    blob_init(&cksum, "************** not found ***************", -1);
    if( g.argv[i][0]=='-' && g.argv[i][1]==0 ){
      blob_read_from_channel(&in, stdin, -1);
      sha1sum_blob(&in, &cksum);
    }else{
      sha1sum_file(g.argv[i], &cksum);
    }
    fossil_print("%s  %s\n", blob_str(&cksum), g.argv[i]);
    blob_reset(&cksum);
  }
}







|







 







|







 







|







 







|







 







|











|







 







|












62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
...
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
...
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
...
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
...
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
...
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
#define blk0be(i) block[i]
#define blk(i) (block[i&15] = rol(block[(i+13)&15]^block[(i+8)&15] \
    ^block[(i+2)&15]^block[i&15],1))

/*
 * (R0+R1), R2, R3, R4 are the different operations (rounds) used in SHA1
 *
 * Rl0() for little-endian and Rb0() for big-endian.  Endianness is
 * determined at run-time.
 */
#define Rl0(v,w,x,y,z,i) \
    z+=((w&(x^y))^y)+blk0le(i)+0x5A827999+rol(v,5);w=ror(w,2);
#define Rb0(v,w,x,y,z,i) \
    z+=((w&(x^y))^y)+blk0be(i)+0x5A827999+rol(v,5);w=ror(w,2);
#define R1(v,w,x,y,z,i) \
................................................................................
/*
** Convert a digest into base-16.  digest should be declared as
** "unsigned char digest[20]" in the calling function.  The SHA1
** digest is stored in the first 20 bytes.  zBuf should
** be "char zBuf[41]".
*/
static void DigestToBase16(unsigned char *digest, char *zBuf){
  static const char zEncode[] = "0123456789abcdef";
  int ix;

  for(ix=0; ix<20; ix++){
    *zBuf++ = zEncode[(*digest>>4)&0xf];
    *zBuf++ = zEncode[*digest++ & 0xf];
  }
  *zBuf = '\0';
................................................................................
*/
void sha1sum_step_blob(Blob *p){
  sha1sum_step_text(blob_buffer(p), blob_size(p));
}

/*
** Finish the incremental SHA1 checksum.  Store the result in blob pOut
** if pOut!=0.  Also return a pointer to the result.
**
** This resets the incremental checksum preparing for the next round
** of computation.  The return pointer points to a static buffer that
** is overwritten by subsequent calls to this function.
*/
char *sha1sum_finish(Blob *pOut){
  unsigned char zResult[20];
................................................................................
  unsigned char zResult[20];
  char zBuf[10240];

  if( file_wd_islink(zFilename) ){
    /* Instead of file content, return sha1 of link destination path */
    Blob destinationPath;
    int rc;

    blob_read_link(&destinationPath, zFilename);
    rc = sha1sum_blob(&destinationPath, pCksum);
    blob_reset(&destinationPath);
    return rc;
  }

  in = fossil_fopen(zFilename,"rb");
................................................................................
  SHA1Final(&ctx, zResult);
  DigestToBase16(zResult, zDigest);
  return mprintf("%s", zDigest);
}

/*
** Convert a cleartext password for a specific user into a SHA1 hash.
**
** The algorithm here is:
**
**       SHA1( project-code + "/" + login + "/" + password )
**
** In words: The users login name and password are appended to the
** project ID code and the SHA1 hash of the result is computed.
**
** The result of this function is the shared secret used by a client
** to authenticate to a server for the sync protocol.  It is also the
** value stored in the USER.PW field of the database.  By mixing in the
** login name and the project id with the hash, different shared secrets
** are obtained even if two users select the same password, or if a
** single user selects the same password for multiple projects.
*/
char *sha1_shared_secret(
  const char *zPw,        /* The password to encrypt */
  const char *zLogin,     /* Username */
  const char *zProjCode   /* Project-code.  Use built-in project code if NULL */
){
................................................................................
** Compute an SHA1 checksum of all files named on the command-line.
** If an file is named "-" then take its content from standard input.
*/
void sha1sum_test(void){
  int i;
  Blob in;
  Blob cksum;

  for(i=2; i<g.argc; i++){
    blob_init(&cksum, "************** not found ***************", -1);
    if( g.argv[i][0]=='-' && g.argv[i][1]==0 ){
      blob_read_from_channel(&in, stdin, -1);
      sha1sum_blob(&in, &cksum);
    }else{
      sha1sum_file(g.argv[i], &cksum);
    }
    fossil_print("%s  %s\n", blob_str(&cksum), g.argv[i]);
    blob_reset(&cksum);
  }
}

Changes to src/shell.c.

13
14
15
16
17
18
19







20
21
22
23
24
25
26
..
44
45
46
47
48
49
50
51
52
53
54

55
56
57
58
59
60
61
62
63
64
65
66
67
68
..
95
96
97
98
99
100
101




















102
103
104
105
106
107
108
...
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
...
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
...
504
505
506
507
508
509
510

511
512
513
514
515
516
517
518
519
520
521

522
523













524
525
526
527
528
529
530
...
559
560
561
562
563
564
565

566
567
568
569
570
571
572
...
581
582
583
584
585
586
587

588
589
590
591
592
593
594
...
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
...
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
...
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
...
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778

779
780

781
782
783
784
785
786
787
...
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
...
811
812
813
814
815
816
817
818

819
820
821

822
823
824
825
826
827
828
829
830

831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
...
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
...
928
929
930
931
932
933
934
















935
936
937
938
939
940
941
....
1426
1427
1428
1429
1430
1431
1432











1433
1434
1435
1436
1437
1438
1439
....
1694
1695
1696
1697
1698
1699
1700

1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
....
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
....
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016

2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
....
2031
2032
2033
2034
2035
2036
2037
2038

2039
2040
2041
2042
2043
2044
2045
2046

2047
2048
2049
2050
2051
2052
2053

2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102


































2103
2104
2105
2106
2107
2108
2109
....
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660

2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677


















2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691





2692
2693
2694
2695
2696

2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
....
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771




2772






2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
....
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930




2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
....
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
....
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230

3231
3232
3233

3234
3235
3236
3237
3238
3239
3240
....
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276

3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
....
3392
3393
3394
3395
3396
3397
3398

3399
3400
3401
3402
3403
3404
3405
....
3458
3459
3460
3461
3462
3463
3464
3465

3466
3467
3468
3469
3470
3471
3472
....
3934
3935
3936
3937
3938
3939
3940

3941
3942
3943
3944
3945
3946
3947
....
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
....
3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
4000
4001
....
4048
4049
4050
4051
4052
4053
4054


4055
4056
4057
4058
4059
4060
4061
....
4226
4227
4228
4229
4230
4231
4232
4233






4234
4235
4236
4237
4238
4239
4240
4241
4242
4243
4244
4245
4246
4247
4248
....
4354
4355
4356
4357
4358
4359
4360
4361
4362
4363
4364
4365
4366
4367
4368
** utility for accessing SQLite databases.
*/
#if (defined(_WIN32) || defined(WIN32)) && !defined(_CRT_SECURE_NO_WARNINGS)
/* This needs to come before any includes for MSVC compiler */
#define _CRT_SECURE_NO_WARNINGS
#endif








/*
** Enable large-file support for fopen() and friends on unix.
*/
#ifndef SQLITE_DISABLE_LFS
# define _LARGE_FILE       1
# ifndef _FILE_OFFSET_BITS
#   define _FILE_OFFSET_BITS 64
................................................................................
# if !defined(__RTP__) && !defined(_WRS_KERNEL)
#  include <pwd.h>
# endif
# include <unistd.h>
# include <sys/types.h>
#endif

#if defined(HAVE_READLINE) && HAVE_READLINE!=0
# include <readline/readline.h>
# include <readline/history.h>
#else

# undef HAVE_READLINE
#endif
#if defined(HAVE_EDITLINE) && !defined(HAVE_READLINE)
# define HAVE_READLINE 1
# include <editline/readline.h>
#endif
#if !defined(HAVE_READLINE)
# define add_history(X)
# define read_history(X)
# define write_history(X)
# define stifle_history(X)
#endif

#if defined(_WIN32) || defined(WIN32)
................................................................................
#define isatty(x) 1
#endif

/* ctype macros that work with signed characters */
#define IsSpace(X)  isspace((unsigned char)X)
#define IsDigit(X)  isdigit((unsigned char)X)
#define ToLower(X)  (char)tolower((unsigned char)X)






















/* True if the timer is enabled */
static int enableTimer = 0;

/* Return the current wall-clock time */
static sqlite3_int64 timeOfDay(void){
................................................................................
static char *one_input_line(FILE *in, char *zPrior, int isContinuation){
  char *zPrompt;
  char *zResult;
  if( in!=0 ){
    zResult = local_getline(zPrior, in);
  }else{
    zPrompt = isContinuation ? continuePrompt : mainPrompt;
#if defined(HAVE_READLINE)
    free(zPrior);
    zResult = readline(zPrompt);
    if( zResult && *zResult ) add_history(zResult);
#else
    printf("%s", zPrompt);
    fflush(stdout);
    zResult = local_getline(zPrior, stdin);
................................................................................
  FILE *traceOut;        /* Output for sqlite3_trace() */
  int nErr;              /* Number of errors seen */
  int mode;              /* An output mode setting */
  int writableSchema;    /* True if PRAGMA writable_schema=ON */
  int showHeader;        /* True to show column names in List or Column mode */
  unsigned shellFlgs;    /* Various flags */
  char *zDestTable;      /* Name of destination table when MODE_Insert */
  char separator[20];    /* Separator character for MODE_List */
  char newline[20];      /* Record separator in MODE_Csv */
  int colWidth[100];     /* Requested width of each column when in column mode*/
  int actualWidth[100];  /* Actual width of each column */
  char nullvalue[20];    /* The text to print when a NULL comes back from
                         ** the database */
  SavedModeInfo normalMode;/* Holds the mode just before .explain ON */
  char outfile[FILENAME_MAX]; /* Filename for *out */
  const char *zDbFilename;    /* name of the database file */
  char *zFreeOnClose;         /* Filename to free when closing */
  const char *zVfs;           /* Name of VFS to use */
  sqlite3_stmt *pStmt;   /* Current statement if any. */
................................................................................
#define MODE_List     2  /* One record per line with a separator */
#define MODE_Semi     3  /* Same as MODE_List but append ";" to each line */
#define MODE_Html     4  /* Generate an XHTML table */
#define MODE_Insert   5  /* Generate SQL "insert" statements */
#define MODE_Tcl      6  /* Generate ANSI-C or TCL quoted elements */
#define MODE_Csv      7  /* Quote strings, numbers are plain */
#define MODE_Explain  8  /* Like MODE_Column, but do not truncate data */


static const char *modeDescr[] = {
  "line",
  "column",
  "list",
  "semi",
  "html",
  "insert",
  "tcl",
  "csv",
  "explain",

};














/*
** Number of elements in an array
*/
#define ArraySize(X)  (int)(sizeof(X)/sizeof(X[0]))

/*
** Compute a string length that is limited to what can be stored in
................................................................................

/*
** Output the given string as a quoted string using SQL quoting conventions.
*/
static void output_quoted_string(FILE *out, const char *z){
  int i;
  int nSingle = 0;

  for(i=0; z[i]; i++){
    if( z[i]=='\'' ) nSingle++;
  }
  if( nSingle==0 ){
    fprintf(out,"'%s'",z);
  }else{
    fprintf(out,"'");
................................................................................
      }else{
        fprintf(out,"%s",z);
        break;
      }
    }
    fprintf(out,"'");
  }

}

/*
** Output the given string as a quoted according to C or TCL quoting rules.
*/
static void output_c_string(FILE *out, const char *z){
  unsigned int c;
................................................................................
  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
};

/*
** Output a single term of CSV.  Actually, p->separator is used for
** the separator, which may or may not be a comma.  p->nullvalue is
** the null value.  Strings are quoted if necessary.  The separator
** is only issued if bSep is true.
*/
static void output_csv(ShellState *p, const char *z, int bSep){
  FILE *out = p->out;
  if( z==0 ){
    fprintf(out,"%s",p->nullvalue);
  }else{
    int i;
    int nSep = strlen30(p->separator);
    for(i=0; z[i]; i++){
      if( needCsvQuote[((unsigned char*)z)[i]] 
         || (z[i]==p->separator[0] && 
             (nSep==1 || memcmp(z, p->separator, nSep)==0)) ){
        i = 0;
        break;
      }
    }
    if( i==0 ){
      putc('"', out);
      for(i=0; z[i]; i++){
................................................................................
      }
      putc('"', out);
    }else{
      fprintf(out, "%s", z);
    }
  }
  if( bSep ){
    fprintf(p->out, "%s", p->separator);
  }
}

#ifdef SIGINT
/*
** This routine runs when the user presses Ctrl-C
*/
................................................................................
    case MODE_Line: {
      int w = 5;
      if( azArg==0 ) break;
      for(i=0; i<nArg; i++){
        int len = strlen30(azCol[i] ? azCol[i] : "");
        if( len>w ) w = len;
      }
      if( p->cnt++>0 ) fprintf(p->out,"\n");
      for(i=0; i<nArg; i++){
        fprintf(p->out,"%*s = %s\n", w, azCol[i],
                azArg[i] ? azArg[i] : p->nullvalue);
      }
      break;
    }
    case MODE_Explain:
    case MODE_Column: {
      if( p->cnt++==0 ){
        for(i=0; i<nArg; i++){
................................................................................
            w = p->colWidth[i];
          }else{
            w = 0;
          }
          if( w==0 ){
            w = strlen30(azCol[i] ? azCol[i] : "");
            if( w<10 ) w = 10;
            n = strlen30(azArg && azArg[i] ? azArg[i] : p->nullvalue);
            if( w<n ) w = n;
          }
          if( i<ArraySize(p->actualWidth) ){
            p->actualWidth[i] = w;
          }
          if( p->showHeader ){
            if( w<0 ){
              fprintf(p->out,"%*.*s%s",-w,-w,azCol[i], i==nArg-1 ? "\n": "  ");

            }else{
              fprintf(p->out,"%-*.*s%s",w,w,azCol[i], i==nArg-1 ? "\n": "  ");

            }
          }
        }
        if( p->showHeader ){
          for(i=0; i<nArg; i++){
            int w;
            if( i<ArraySize(p->actualWidth) ){
................................................................................
               w = p->actualWidth[i];
               if( w<0 ) w = -w;
            }else{
               w = 10;
            }
            fprintf(p->out,"%-*.*s%s",w,w,"-----------------------------------"
                   "----------------------------------------------------------",
                    i==nArg-1 ? "\n": "  ");
          }
        }
      }
      if( azArg==0 ) break;
      for(i=0; i<nArg; i++){
        int w;
        if( i<ArraySize(p->actualWidth) ){
................................................................................
          if( p->iIndent<p->nIndent ){
            fprintf(p->out, "%*.s", p->aiIndent[p->iIndent], "");
          }
          p->iIndent++;
        }
        if( w<0 ){
          fprintf(p->out,"%*.*s%s",-w,-w,
              azArg[i] ? azArg[i] : p->nullvalue, i==nArg-1 ? "\n": "  ");

        }else{
          fprintf(p->out,"%-*.*s%s",w,w,
              azArg[i] ? azArg[i] : p->nullvalue, i==nArg-1 ? "\n": "  ");

        }
      }
      break;
    }
    case MODE_Semi:
    case MODE_List: {
      if( p->cnt++==0 && p->showHeader ){
        for(i=0; i<nArg; i++){
          fprintf(p->out,"%s%s",azCol[i], i==nArg-1 ? "\n" : p->separator);

        }
      }
      if( azArg==0 ) break;
      for(i=0; i<nArg; i++){
        char *z = azArg[i];
        if( z==0 ) z = p->nullvalue;
        fprintf(p->out, "%s", z);
        if( i<nArg-1 ){
          fprintf(p->out, "%s", p->separator);
        }else if( p->mode==MODE_Semi ){
          fprintf(p->out, ";\n");
        }else{
          fprintf(p->out, "\n");
        }
      }
      break;
    }
    case MODE_Html: {
      if( p->cnt++==0 && p->showHeader ){
        fprintf(p->out,"<TR>");
................................................................................
        }
        fprintf(p->out,"</TR>\n");
      }
      if( azArg==0 ) break;
      fprintf(p->out,"<TR>");
      for(i=0; i<nArg; i++){
        fprintf(p->out,"<TD>");
        output_html_string(p->out, azArg[i] ? azArg[i] : p->nullvalue);
        fprintf(p->out,"</TD>\n");
      }
      fprintf(p->out,"</TR>\n");
      break;
    }
    case MODE_Tcl: {
      if( p->cnt++==0 && p->showHeader ){
        for(i=0; i<nArg; i++){
          output_c_string(p->out,azCol[i] ? azCol[i] : "");
          if(i<nArg-1) fprintf(p->out, "%s", p->separator);
        }
        fprintf(p->out,"\n");
      }
      if( azArg==0 ) break;
      for(i=0; i<nArg; i++){
        output_c_string(p->out, azArg[i] ? azArg[i] : p->nullvalue);
        if(i<nArg-1) fprintf(p->out, "%s", p->separator);
      }
      fprintf(p->out,"\n");
      break;
    }
    case MODE_Csv: {
#if defined(WIN32) || defined(_WIN32)
      fflush(p->out);
      _setmode(_fileno(p->out), _O_BINARY);
#endif
      if( p->cnt++==0 && p->showHeader ){
        for(i=0; i<nArg; i++){
          output_csv(p, azCol[i] ? azCol[i] : "", i<nArg-1);
        }
        fprintf(p->out,"%s",p->newline);
      }
      if( nArg>0 ){
        for(i=0; i<nArg; i++){
          output_csv(p, azArg[i], i<nArg-1);
        }
        fprintf(p->out,"%s",p->newline);
      }
#if defined(WIN32) || defined(_WIN32)
      fflush(p->out);
      _setmode(_fileno(p->out), _O_TEXT);
#endif
      break;
    }
    case MODE_Insert: {
      p->cnt++;
      if( azArg==0 ) break;
      fprintf(p->out,"INSERT INTO %s VALUES(",p->zDestTable);
      for(i=0; i<nArg; i++){
................................................................................
        }else{
          if( zSep[0] ) fprintf(p->out,"%s",zSep);
          output_quoted_string(p->out, azArg[i]);
        }
      }
      fprintf(p->out,");\n");
      break;
















    }
  }
  return 0;
}

/*
** This is the callback routine that the SQLite library
................................................................................
            fprintf(pArg->out,"%d,", sqlite3_column_int(pExplain, 2));
            fprintf(pArg->out,"%s\n", sqlite3_column_text(pExplain, 3));
          }
        }
        sqlite3_finalize(pExplain);
        sqlite3_free(zEQP);
      }












      /* If the shell is currently in ".explain" mode, gather the extra
      ** data required to add indents to the output.*/
      if( pArg && pArg->mode==MODE_Explain ){
        explain_data_prepare(pArg, pStmt);
      }

................................................................................
  ".iotrace FILE          Enable I/O diagnostic logging to FILE\n"
#endif
#ifndef SQLITE_OMIT_LOAD_EXTENSION
  ".load FILE ?ENTRY?     Load an extension library\n"
#endif
  ".log FILE|off          Turn logging on or off.  FILE can be stderr/stdout\n"
  ".mode MODE ?TABLE?     Set output mode where MODE is one of:\n"

  "                         csv      Comma-separated values\n"
  "                         column   Left-aligned columns.  (See .width)\n"
  "                         html     HTML <table> code\n"
  "                         insert   SQL insert statements for TABLE\n"
  "                         line     One value per line\n"
  "                         list     Values delimited by .separator string\n"
  "                         tabs     Tab-separated values\n"
  "                         tcl      TCL list elements\n"
  ".nullvalue STRING      Use STRING in place of NULL values\n"
  ".once FILENAME         Output for the next SQL command only to FILENAME\n"
  ".open ?FILENAME?       Close existing database and reopen FILENAME\n"
  ".output ?FILENAME?     Send output to FILENAME or stdout\n"
  ".print STRING...       Print literal STRING\n"
................................................................................
  ".read FILENAME         Execute SQL in FILENAME\n"
  ".restore ?DB? FILE     Restore content of DB (default \"main\") from FILE\n"
  ".save FILE             Write in-memory database into FILE\n"
  ".scanstats on|off      Turn sqlite3_stmt_scanstatus() metrics on or off\n"
  ".schema ?TABLE?        Show the CREATE statements\n"
  "                         If TABLE specified, only show tables matching\n"
  "                         LIKE pattern TABLE.\n"
  ".separator STRING ?NL? Change separator used by output mode and .import\n"
  "                         NL is the end-of-line mark for CSV\n"
  ".shell CMD ARGS...     Run CMD ARGS... in a system shell\n"
  ".show                  Show the current values for various settings\n"
  ".stats on|off          Turn stats on or off\n"
  ".system CMD ARGS...    Run CMD ARGS... in a system shell\n"
  ".tables ?TABLE?        List names of tables\n"
  "                         If TABLE specified, only list tables matching\n"
  "                         LIKE pattern TABLE.\n"
................................................................................
*/
static void test_breakpoint(void){
  static int nCall = 0;
  nCall++;
}

/*
** An object used to read a CSV file
*/
typedef struct CSVReader CSVReader;
struct CSVReader {
  const char *zFile;  /* Name of the input file */
  FILE *in;           /* Read the CSV text from this input stream */
  char *z;            /* Accumulated text for a field */
  int n;              /* Number of bytes in z */
  int nAlloc;         /* Space allocated for z[] */
  int nLine;          /* Current line number */
  int cTerm;          /* Character that terminated the most recent field */
  int cSeparator;     /* The separator character.  (Usually ",") */

};

/* Append a single byte to z[] */
static void csv_append_char(CSVReader *p, int c){
  if( p->n+1>=p->nAlloc ){
    p->nAlloc += p->nAlloc + 100;
    p->z = sqlite3_realloc(p->z, p->nAlloc);
    if( p->z==0 ){
      fprintf(stderr, "out of memory\n");
      exit(1);
    }
................................................................................

/* Read a single field of CSV text.  Compatible with rfc4180 and extended
** with the option of having a separator other than ",".
**
**   +  Input comes from p->in.
**   +  Store results in p->z of length p->n.  Space to hold p->z comes
**      from sqlite3_malloc().
**   +  Use p->cSep as the separator.  The default is ",".

**   +  Keep track of the line number in p->nLine.
**   +  Store the character that terminates the field in p->cTerm.  Store
**      EOF on end-of-file.
**   +  Report syntax errors on stderr
*/
static char *csv_read_one_field(CSVReader *p){
  int c, pc, ppc;
  int cSep = p->cSeparator;

  p->n = 0;
  c = fgetc(p->in);
  if( c==EOF || seenInterrupt ){
    p->cTerm = EOF;
    return 0;
  }
  if( c=='"' ){

    int startLine = p->nLine;
    int cQuote = c;
    pc = ppc = 0;
    while( 1 ){
      c = fgetc(p->in);
      if( c=='\n' ) p->nLine++;
      if( c==cQuote ){
        if( pc==cQuote ){
          pc = 0;
          continue;
        }
      }
      if( (c==cSep && pc==cQuote)
       || (c=='\n' && pc==cQuote)
       || (c=='\n' && pc=='\r' && ppc==cQuote)
       || (c==EOF && pc==cQuote)
      ){
        do{ p->n--; }while( p->z[p->n]!=cQuote );
        p->cTerm = c;
        break;
      }
      if( pc==cQuote && c!='\r' ){
        fprintf(stderr, "%s:%d: unescaped %c character\n",
                p->zFile, p->nLine, cQuote);
      }
      if( c==EOF ){
        fprintf(stderr, "%s:%d: unterminated %c-quoted field\n",
                p->zFile, startLine, cQuote);
        p->cTerm = EOF;
        break;
      }
      csv_append_char(p, c);
      ppc = pc;
      pc = c;
    }
  }else{
    while( c!=EOF && c!=cSep && c!='\n' ){
      csv_append_char(p, c);
      c = fgetc(p->in);
    }
    if( c=='\n' ){
      p->nLine++;
      if( p->n>0 && p->z[p->n-1]=='\r' ) p->n--;
    }
    p->cTerm = c;
  }
  if( p->z ) p->z[p->n] = 0;
  return p->z;
}



































/*
** Try to transfer data for table zTable.  If an error is seen while
** moving forward, try to go backwards.  The backwards movement won't
** work for WITHOUT ROWID tables.
*/
static void tryToCloneData(
................................................................................
    char *zTable;               /* Insert data into this table */
    char *zFile;                /* Name of file to extra content from */
    sqlite3_stmt *pStmt = NULL; /* A statement */
    int nCol;                   /* Number of columns in the table */
    int nByte;                  /* Number of bytes in an SQL string */
    int i, j;                   /* Loop counters */
    int needCommit;             /* True to COMMIT or ROLLBACK at end */
    int nSep;                   /* Number of bytes in p->separator[] */
    char *zSql;                 /* An SQL statement */
    CSVReader sCsv;             /* Reader context */

    int (*xCloser)(FILE*);      /* Procedure to close th3 connection */

    if( nArg!=3 ){
      fprintf(stderr, "Usage: .import FILE TABLE\n");
      goto meta_command_exit;
    }
    zFile = azArg[1];
    zTable = azArg[2];
    seenInterrupt = 0;
    memset(&sCsv, 0, sizeof(sCsv));
    open_db(p, 0);
    nSep = strlen30(p->separator);
    if( nSep==0 ){
      fprintf(stderr, "Error: non-null separator required for import\n");
      return 1;
    }
    if( nSep>1 ){


















      fprintf(stderr, "Error: multi-character separators not allowed"
                      " for import\n");
      return 1;
    }
    sCsv.zFile = zFile;
    sCsv.nLine = 1;
    if( sCsv.zFile[0]=='|' ){
      sCsv.in = popen(sCsv.zFile+1, "r");
      sCsv.zFile = "<pipe>";
      xCloser = pclose;
    }else{
      sCsv.in = fopen(sCsv.zFile, "rb");
      xCloser = fclose;
    }





    if( sCsv.in==0 ){
      fprintf(stderr, "Error: cannot open \"%s\"\n", zFile);
      return 1;
    }
    sCsv.cSeparator = p->separator[0];

    zSql = sqlite3_mprintf("SELECT * FROM %s", zTable);
    if( zSql==0 ){
      fprintf(stderr, "Error: out of memory\n");
      xCloser(sCsv.in);
      return 1;
    }
    nByte = strlen30(zSql);
    rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
    csv_append_char(&sCsv, 0);    /* To ensure sCsv.z is allocated */
    if( rc && sqlite3_strglob("no such table: *", sqlite3_errmsg(db))==0 ){
      char *zCreate = sqlite3_mprintf("CREATE TABLE %s", zTable);
      char cSep = '(';
      while( csv_read_one_field(&sCsv) ){
        zCreate = sqlite3_mprintf("%z%c\n  \"%s\" TEXT", zCreate, cSep, sCsv.z);
        cSep = ',';
        if( sCsv.cTerm!=sCsv.cSeparator ) break;
      }
      if( cSep=='(' ){
        sqlite3_free(zCreate);
        sqlite3_free(sCsv.z);
        xCloser(sCsv.in);
        fprintf(stderr,"%s: empty file\n", sCsv.zFile);
        return 1;
      }
      zCreate = sqlite3_mprintf("%z\n)", zCreate);
      rc = sqlite3_exec(p->db, zCreate, 0, 0, 0);
      sqlite3_free(zCreate);
      if( rc ){
        fprintf(stderr, "CREATE TABLE %s(...) failed: %s\n", zTable,
                sqlite3_errmsg(db));
        sqlite3_free(sCsv.z);
        xCloser(sCsv.in);
        return 1;
      }
      rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
    }
    sqlite3_free(zSql);
    if( rc ){
      if (pStmt) sqlite3_finalize(pStmt);
      fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db));
      xCloser(sCsv.in);
      return 1;
    }
    nCol = sqlite3_column_count(pStmt);
    sqlite3_finalize(pStmt);
    pStmt = 0;
    if( nCol==0 ) return 0; /* no columns, no error */
    zSql = sqlite3_malloc( nByte*2 + 20 + nCol*2 );
    if( zSql==0 ){
      fprintf(stderr, "Error: out of memory\n");
      xCloser(sCsv.in);
      return 1;
    }
    sqlite3_snprintf(nByte+20, zSql, "INSERT INTO \"%w\" VALUES(?", zTable);
    j = strlen30(zSql);
    for(i=1; i<nCol; i++){
      zSql[j++] = ',';
      zSql[j++] = '?';
................................................................................
    zSql[j++] = ')';
    zSql[j] = 0;
    rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
    sqlite3_free(zSql);
    if( rc ){
      fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db));
      if (pStmt) sqlite3_finalize(pStmt);
      xCloser(sCsv.in);
      return 1;
    }
    needCommit = sqlite3_get_autocommit(db);
    if( needCommit ) sqlite3_exec(db, "BEGIN", 0, 0, 0);
    do{
      int startLine = sCsv.nLine;
      for(i=0; i<nCol; i++){
        char *z = csv_read_one_field(&sCsv);




        if( z==0 && i==0 ) break;






        sqlite3_bind_text(pStmt, i+1, z, -1, SQLITE_TRANSIENT);
        if( i<nCol-1 && sCsv.cTerm!=sCsv.cSeparator ){
          fprintf(stderr, "%s:%d: expected %d columns but found %d - "
                          "filling the rest with NULL\n",
                          sCsv.zFile, startLine, nCol, i+1);
          i++;
          while( i<=nCol ){ sqlite3_bind_null(pStmt, i); i++; }
        }
      }
      if( sCsv.cTerm==sCsv.cSeparator ){
        do{
          csv_read_one_field(&sCsv);
          i++;
        }while( sCsv.cTerm==sCsv.cSeparator );
        fprintf(stderr, "%s:%d: expected %d columns but found %d - "
                        "extras ignored\n",
                        sCsv.zFile, startLine, nCol, i);
      }
      if( i>=nCol ){
        sqlite3_step(pStmt);
        rc = sqlite3_reset(pStmt);
        if( rc!=SQLITE_OK ){
          fprintf(stderr, "%s:%d: INSERT failed: %s\n", sCsv.zFile, startLine,
                  sqlite3_errmsg(db));
        }
      }
    }while( sCsv.cTerm!=EOF );

    xCloser(sCsv.in);
    sqlite3_free(sCsv.z);
    sqlite3_finalize(pStmt);
    if( needCommit ) sqlite3_exec(db, "COMMIT", 0, 0, 0);
  }else

  if( c=='i' && strncmp(azArg[0], "indices", n)==0 ){
    ShellState data;
    char *zErrMsg = 0;
................................................................................
      p->mode = MODE_Column;
    }else if( c2=='l' && n2>2 && strncmp(azArg[1],"list",n2)==0 ){
      p->mode = MODE_List;
    }else if( c2=='h' && strncmp(azArg[1],"html",n2)==0 ){
      p->mode = MODE_Html;
    }else if( c2=='t' && strncmp(azArg[1],"tcl",n2)==0 ){
      p->mode = MODE_Tcl;
      sqlite3_snprintf(sizeof(p->separator), p->separator, " ");
    }else if( c2=='c' && strncmp(azArg[1],"csv",n2)==0 ){
      p->mode = MODE_Csv;
      sqlite3_snprintf(sizeof(p->separator), p->separator, ",");
      sqlite3_snprintf(sizeof(p->newline), p->newline, "\r\n");
    }else if( c2=='t' && strncmp(azArg[1],"tabs",n2)==0 ){
      p->mode = MODE_List;
      sqlite3_snprintf(sizeof(p->separator), p->separator, "\t");
    }else if( c2=='i' && strncmp(azArg[1],"insert",n2)==0 ){
      p->mode = MODE_Insert;
      set_table_name(p, nArg>=3 ? azArg[2] : "table");




    }else {
      fprintf(stderr,"Error: mode should be one of: "
         "column csv html insert line list tabs tcl\n");
      rc = 1;
    }
  }else

  if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 ){
    if( nArg==2 ){
      sqlite3_snprintf(sizeof(p->nullvalue), p->nullvalue,
                       "%.*s", (int)ArraySize(p->nullvalue)-1, azArg[1]);
    }else{
      fprintf(stderr, "Usage: .nullvalue STRING\n");
      rc = 1;
    }
  }else

  if( c=='o' && strncmp(azArg[0], "open", n)==0 && n>=2 ){
................................................................................
    }
  }else


#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
  if( c=='s' && n==11 && strncmp(azArg[0], "selecttrace", n)==0 ){
    extern int sqlite3SelectTrace;
    sqlite3SelectTrace = nArg>=2 ? booleanValue(azArg[1]) : 0xff;
  }else
#endif


#ifdef SQLITE_DEBUG
  /* Undocumented commands for internal testing.  Subject to change
  ** without notice. */
................................................................................
      }
    }
  }else
#endif

  if( c=='s' && strncmp(azArg[0], "separator", n)==0 ){
    if( nArg<2 || nArg>3 ){
      fprintf(stderr, "Usage: .separator SEPARATOR ?NEWLINE?\n");
      rc = 1;
    }
    if( nArg>=2 ){
      sqlite3_snprintf(sizeof(p->separator), p->separator, azArg[1]);

    }
    if( nArg>=3 ){
      sqlite3_snprintf(sizeof(p->newline), p->newline, azArg[2]);

    }
  }else

  if( c=='s'
   && (strncmp(azArg[0], "shell", n)==0 || strncmp(azArg[0],"system",n)==0)
  ){
    char *zCmd;
................................................................................
  if( c=='s' && strncmp(azArg[0], "show", n)==0 ){
    int i;
    if( nArg!=1 ){
      fprintf(stderr, "Usage: .show\n");
      rc = 1;
      goto meta_command_exit;
    }
    fprintf(p->out,"%9.9s: %s\n","echo", p->echoOn ? "on" : "off");
    fprintf(p->out,"%9.9s: %s\n","eqp", p->autoEQP ? "on" : "off");
    fprintf(p->out,"%9.9s: %s\n","explain", p->normalMode.valid ? "on" :"off");
    fprintf(p->out,"%9.9s: %s\n","headers", p->showHeader ? "on" : "off");
    fprintf(p->out,"%9.9s: %s\n","mode", modeDescr[p->mode]);
    fprintf(p->out,"%9.9s: ", "nullvalue");
      output_c_string(p->out, p->nullvalue);
      fprintf(p->out, "\n");
    fprintf(p->out,"%9.9s: %s\n","output",
            strlen30(p->outfile) ? p->outfile : "stdout");
    fprintf(p->out,"%9.9s: ", "separator");
      output_c_string(p->out, p->separator);
      fprintf(p->out," ");

      output_c_string(p->out, p->newline);
      fprintf(p->out, "\n");
    fprintf(p->out,"%9.9s: %s\n","stats", p->statsOn ? "on" : "off");
    fprintf(p->out,"%9.9s: ","width");
    for (i=0;i<(int)ArraySize(p->colWidth) && p->colWidth[i] != 0;i++) {
      fprintf(p->out,"%d ",p->colWidth[i]);
    }
    fprintf(p->out,"\n");
  }else

  if( c=='s' && strncmp(azArg[0], "stats", n)==0 ){
................................................................................
      { "assert",                SQLITE_TESTCTRL_ASSERT                 },
      { "always",                SQLITE_TESTCTRL_ALWAYS                 },
      { "reserve",               SQLITE_TESTCTRL_RESERVE                },
      { "optimizations",         SQLITE_TESTCTRL_OPTIMIZATIONS          },
      { "iskeyword",             SQLITE_TESTCTRL_ISKEYWORD              },
      { "scratchmalloc",         SQLITE_TESTCTRL_SCRATCHMALLOC          },
      { "byteorder",             SQLITE_TESTCTRL_BYTEORDER              },

    };
    int testctrl = -1;
    int rc = 0;
    int i, n;
    open_db(p, 0);

    /* convert testctrl text option to value. allow any unique prefix
................................................................................
            fprintf(stderr,"Error: testctrl %s takes a single unsigned"
                           " int option\n", azArg[1]);
          }
          break;
          
        /* sqlite3_test_control(int, int) */
        case SQLITE_TESTCTRL_ASSERT:              
        case SQLITE_TESTCTRL_ALWAYS:              

          if( nArg==3 ){
            int opt = booleanValue(azArg[2]);        
            rc = sqlite3_test_control(testctrl, opt);
            fprintf(p->out, "%d (0x%08x)\n", rc, rc);
          } else {
            fprintf(stderr,"Error: testctrl %s takes a single int option\n",
                            azArg[1]);
................................................................................
  return rc;
}

/*
** Show available command line options
*/
static const char zOptions[] = 

  "   -bail                stop after hitting an error\n"
  "   -batch               force batch I/O\n"
  "   -column              set output mode to 'column'\n"
  "   -cmd COMMAND         run \"COMMAND\" before reading stdin\n"
  "   -csv                 set output mode to 'csv'\n"
  "   -echo                print commands before execution\n"
  "   -init FILENAME       read/process named file\n"
................................................................................
  "   -line                set output mode to 'line'\n"
  "   -list                set output mode to 'list'\n"
  "   -lookaside SIZE N    use N entries of SZ bytes for lookaside memory\n"
  "   -mmap N              default mmap size set to N\n"
#ifdef SQLITE_ENABLE_MULTIPLEX
  "   -multiplex           enable the multiplexor VFS\n"
#endif
  "   -newline SEP         set newline character(s) for CSV\n"
  "   -nullvalue TEXT      set text string for NULL values. Default ''\n"
  "   -pagecache SIZE N    use N slots of SZ bytes each for page cache memory\n"
  "   -scratch SIZE N      use N slots of SZ bytes each for scratch memory\n"
  "   -separator SEP       set output field separator. Default: '|'\n"
  "   -stats               print memory stats before each finalize\n"
  "   -version             show SQLite version\n"
  "   -vfs NAME            use NAME as the default VFS\n"
#ifdef SQLITE_ENABLE_VFSTRACE
  "   -vfstrace            enable tracing of all VFS calls\n"
#endif
;
................................................................................

/*
** Initialize the state information in data
*/
static void main_init(ShellState *data) {
  memset(data, 0, sizeof(*data));
  data->mode = MODE_List;
  memcpy(data->separator,"|", 2);
  memcpy(data->newline,"\r\n", 3);
  data->showHeader = 0;
  data->shellFlgs = SHFLG_Lookaside;
  sqlite3_config(SQLITE_CONFIG_URI, 1);
  sqlite3_config(SQLITE_CONFIG_LOG, shellLog, data);
  sqlite3_config(SQLITE_CONFIG_MULTITHREAD);
  sqlite3_snprintf(sizeof(mainPrompt), mainPrompt,"sqlite> ");
  sqlite3_snprintf(sizeof(continuePrompt), continuePrompt,"   ...> ");
................................................................................
#if USE_SYSTEM_SQLITE+0!=1
  if( strcmp(sqlite3_sourceid(),SQLITE_SOURCE_ID)!=0 ){
    fprintf(stderr, "SQLite header and source version mismatch\n%s\n%s\n",
            sqlite3_sourceid(), SQLITE_SOURCE_ID);
    exit(1);
  }
#endif


  Argv0 = argv[0];
  main_init(&data);
  stdin_is_interactive = isatty(0);

  /* Make sure we have a valid signal handler early, before anything
  ** else is done.
  */
................................................................................
      data.mode = MODE_List;
    }else if( strcmp(z,"-line")==0 ){
      data.mode = MODE_Line;
    }else if( strcmp(z,"-column")==0 ){
      data.mode = MODE_Column;
    }else if( strcmp(z,"-csv")==0 ){
      data.mode = MODE_Csv;
      memcpy(data.separator,",",2);






    }else if( strcmp(z,"-separator")==0 ){
      sqlite3_snprintf(sizeof(data.separator), data.separator,
                       "%s",cmdline_option_value(argc,argv,++i));
    }else if( strcmp(z,"-newline")==0 ){
      sqlite3_snprintf(sizeof(data.newline), data.newline,
                       "%s",cmdline_option_value(argc,argv,++i));
    }else if( strcmp(z,"-nullvalue")==0 ){
      sqlite3_snprintf(sizeof(data.nullvalue), data.nullvalue,
                       "%s",cmdline_option_value(argc,argv,++i));
    }else if( strcmp(z,"-header")==0 ){
      data.showHeader = 1;
    }else if( strcmp(z,"-noheader")==0 ){
      data.showHeader = 0;
    }else if( strcmp(z,"-echo")==0 ){
      data.echoOn = 1;
................................................................................
      zHome = find_home_dir();
      if( zHome ){
        nHistory = strlen30(zHome) + 20;
        if( (zHistory = malloc(nHistory))!=0 ){
          sqlite3_snprintf(nHistory, zHistory,"%s/.sqlite_history", zHome);
        }
      }
#if defined(HAVE_READLINE)
      if( zHistory ) read_history(zHistory);
#endif
      rc = process_input(&data, 0);
      if( zHistory ){
        stifle_history(100);
        write_history(zHistory);
        free(zHistory);







>
>
>
>
>
>
>







 







|


|
>

<
<



|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







|







 







|
|


|







 







>











>


>
>
>
>
>
>
>
>
>
>
>
>
>







 







>







 







>







 







|
|






|


|


|
|







 







|







 







|

|
|







 







|







|
>

|
>







 







|







 







|
>


|
>








|
>





|


|

|

|







 







|









|

|



|
|

|



<
|
<
<




|





|

<
|
<
<







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>
>
>
>
>
>
>
>
>
>







 







>





|







 







|
|







 







|

|
|







|
>



|







 







|
>





|
|
|
>







>





|







|
|













|


|




|
|


|








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







|

|
>









|

|

|



>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|



|
|
|
|
|


|


>
>
>
>
>
|



|
>



|




|



|
|

|



|
|
|








|
|








|









|







 







|





|

|
>
>
>
>

>
>
>
>
>
>

|


|




|

|

|


|





|



|

|
|







 







|


|
|


|



>
>
>
>


|






|
|







 







|







 







|



|
>


|
>







 







|
|

|
|
|
|

|

|
|
|
>
|

|
|







 







>







 







|
>







 







>







 







|



|







 







|
|







 







>
>







 







|
>
>
>
>
>
>

|


|


|







 







|







13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
..
51
52
53
54
55
56
57
58
59
60
61
62
63


64
65
66
67
68
69
70
71
72
73
74
...
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
...
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
...
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
...
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
...
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
...
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
...
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
...
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
...
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
...
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
...
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
...
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
...
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932

933


934
935
936
937
938
939
940
941
942
943
944
945

946


947
948
949
950
951
952
953
...
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
....
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
....
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
....
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
....
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
....
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
....
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
....
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
....
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
....
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
....
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
....
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
....
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
....
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
....
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095
4096
4097
4098
4099
4100
....
4108
4109
4110
4111
4112
4113
4114
4115
4116
4117
4118
4119
4120
4121
4122
4123
4124
4125
4126
....
4139
4140
4141
4142
4143
4144
4145
4146
4147
4148
4149
4150
4151
4152
4153
4154
....
4201
4202
4203
4204
4205
4206
4207
4208
4209
4210
4211
4212
4213
4214
4215
4216
....
4381
4382
4383
4384
4385
4386
4387
4388
4389
4390
4391
4392
4393
4394
4395
4396
4397
4398
4399
4400
4401
4402
4403
4404
4405
4406
4407
4408
4409
....
4515
4516
4517
4518
4519
4520
4521
4522
4523
4524
4525
4526
4527
4528
4529
** utility for accessing SQLite databases.
*/
#if (defined(_WIN32) || defined(WIN32)) && !defined(_CRT_SECURE_NO_WARNINGS)
/* This needs to come before any includes for MSVC compiler */
#define _CRT_SECURE_NO_WARNINGS
#endif

/*
** If requested, include the SQLite compiler options file for MSVC.
*/
#if defined(INCLUDE_MSVC_H)
#include "msvc.h"
#endif

/*
** Enable large-file support for fopen() and friends on unix.
*/
#ifndef SQLITE_DISABLE_LFS
# define _LARGE_FILE       1
# ifndef _FILE_OFFSET_BITS
#   define _FILE_OFFSET_BITS 64
................................................................................
# if !defined(__RTP__) && !defined(_WRS_KERNEL)
#  include <pwd.h>
# endif
# include <unistd.h>
# include <sys/types.h>
#endif

#if HAVE_READLINE
# include <readline/readline.h>
# include <readline/history.h>
#endif
#if HAVE_EDITLINE
# undef HAVE_READLINE


# define HAVE_READLINE 1
# include <editline/readline.h>
#endif
#if !HAVE_READLINE
# define add_history(X)
# define read_history(X)
# define write_history(X)
# define stifle_history(X)
#endif

#if defined(_WIN32) || defined(WIN32)
................................................................................
#define isatty(x) 1
#endif

/* ctype macros that work with signed characters */
#define IsSpace(X)  isspace((unsigned char)X)
#define IsDigit(X)  isdigit((unsigned char)X)
#define ToLower(X)  (char)tolower((unsigned char)X)

/* On Windows, we normally run with output mode of TEXT so that \n characters
** are automatically translated into \r\n.  However, this behavior needs
** to be disabled in some cases (ex: when generating CSV output and when
** rendering quoted strings that contain \n characters).  The following
** routines take care of that.
*/
#if defined(_WIN32) || defined(WIN32)
static void setBinaryMode(FILE *out){
  fflush(out);
  _setmode(_fileno(out), _O_BINARY);
}
static void setTextMode(FILE *out){
  fflush(out);
  _setmode(_fileno(out), _O_TEXT);
}
#else
# define setBinaryMode(X)
# define setTextMode(X)
#endif


/* True if the timer is enabled */
static int enableTimer = 0;

/* Return the current wall-clock time */
static sqlite3_int64 timeOfDay(void){
................................................................................
static char *one_input_line(FILE *in, char *zPrior, int isContinuation){
  char *zPrompt;
  char *zResult;
  if( in!=0 ){
    zResult = local_getline(zPrior, in);
  }else{
    zPrompt = isContinuation ? continuePrompt : mainPrompt;
#if HAVE_READLINE
    free(zPrior);
    zResult = readline(zPrompt);
    if( zResult && *zResult ) add_history(zResult);
#else
    printf("%s", zPrompt);
    fflush(stdout);
    zResult = local_getline(zPrior, stdin);
................................................................................
  FILE *traceOut;        /* Output for sqlite3_trace() */
  int nErr;              /* Number of errors seen */
  int mode;              /* An output mode setting */
  int writableSchema;    /* True if PRAGMA writable_schema=ON */
  int showHeader;        /* True to show column names in List or Column mode */
  unsigned shellFlgs;    /* Various flags */
  char *zDestTable;      /* Name of destination table when MODE_Insert */
  char colSeparator[20]; /* Column separator character for several modes */
  char rowSeparator[20]; /* Row separator character for MODE_Ascii */
  int colWidth[100];     /* Requested width of each column when in column mode*/
  int actualWidth[100];  /* Actual width of each column */
  char nullValue[20];    /* The text to print when a NULL comes back from
                         ** the database */
  SavedModeInfo normalMode;/* Holds the mode just before .explain ON */
  char outfile[FILENAME_MAX]; /* Filename for *out */
  const char *zDbFilename;    /* name of the database file */
  char *zFreeOnClose;         /* Filename to free when closing */
  const char *zVfs;           /* Name of VFS to use */
  sqlite3_stmt *pStmt;   /* Current statement if any. */
................................................................................
#define MODE_List     2  /* One record per line with a separator */
#define MODE_Semi     3  /* Same as MODE_List but append ";" to each line */
#define MODE_Html     4  /* Generate an XHTML table */
#define MODE_Insert   5  /* Generate SQL "insert" statements */
#define MODE_Tcl      6  /* Generate ANSI-C or TCL quoted elements */
#define MODE_Csv      7  /* Quote strings, numbers are plain */
#define MODE_Explain  8  /* Like MODE_Column, but do not truncate data */
#define MODE_Ascii    9  /* Use ASCII unit and record separators (0x1F/0x1E) */

static const char *modeDescr[] = {
  "line",
  "column",
  "list",
  "semi",
  "html",
  "insert",
  "tcl",
  "csv",
  "explain",
  "ascii",
};

/*
** These are the column/row/line separators used by the various
** import/export modes.
*/
#define SEP_Column    "|"
#define SEP_Row       "\n"
#define SEP_Tab       "\t"
#define SEP_Space     " "
#define SEP_Comma     ","
#define SEP_CrLf      "\r\n"
#define SEP_Unit      "\x1F"
#define SEP_Record    "\x1E"

/*
** Number of elements in an array
*/
#define ArraySize(X)  (int)(sizeof(X)/sizeof(X[0]))

/*
** Compute a string length that is limited to what can be stored in
................................................................................

/*
** Output the given string as a quoted string using SQL quoting conventions.
*/
static void output_quoted_string(FILE *out, const char *z){
  int i;
  int nSingle = 0;
  setBinaryMode(out);
  for(i=0; z[i]; i++){
    if( z[i]=='\'' ) nSingle++;
  }
  if( nSingle==0 ){
    fprintf(out,"'%s'",z);
  }else{
    fprintf(out,"'");
................................................................................
      }else{
        fprintf(out,"%s",z);
        break;
      }
    }
    fprintf(out,"'");
  }
  setTextMode(out);
}

/*
** Output the given string as a quoted according to C or TCL quoting rules.
*/
static void output_c_string(FILE *out, const char *z){
  unsigned int c;
................................................................................
  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
};

/*
** Output a single term of CSV.  Actually, p->colSeparator is used for
** the separator, which may or may not be a comma.  p->nullValue is
** the null value.  Strings are quoted if necessary.  The separator
** is only issued if bSep is true.
*/
static void output_csv(ShellState *p, const char *z, int bSep){
  FILE *out = p->out;
  if( z==0 ){
    fprintf(out,"%s",p->nullValue);
  }else{
    int i;
    int nSep = strlen30(p->colSeparator);
    for(i=0; z[i]; i++){
      if( needCsvQuote[((unsigned char*)z)[i]] 
         || (z[i]==p->colSeparator[0] && 
             (nSep==1 || memcmp(z, p->colSeparator, nSep)==0)) ){
        i = 0;
        break;
      }
    }
    if( i==0 ){
      putc('"', out);
      for(i=0; z[i]; i++){
................................................................................
      }
      putc('"', out);
    }else{
      fprintf(out, "%s", z);
    }
  }
  if( bSep ){
    fprintf(p->out, "%s", p->colSeparator);
  }
}

#ifdef SIGINT
/*
** This routine runs when the user presses Ctrl-C
*/
................................................................................
    case MODE_Line: {
      int w = 5;
      if( azArg==0 ) break;
      for(i=0; i<nArg; i++){
        int len = strlen30(azCol[i] ? azCol[i] : "");
        if( len>w ) w = len;
      }
      if( p->cnt++>0 ) fprintf(p->out, "%s", p->rowSeparator);
      for(i=0; i<nArg; i++){
        fprintf(p->out,"%*s = %s%s", w, azCol[i],
                azArg[i] ? azArg[i] : p->nullValue, p->rowSeparator);
      }
      break;
    }
    case MODE_Explain:
    case MODE_Column: {
      if( p->cnt++==0 ){
        for(i=0; i<nArg; i++){
................................................................................
            w = p->colWidth[i];
          }else{
            w = 0;
          }
          if( w==0 ){
            w = strlen30(azCol[i] ? azCol[i] : "");
            if( w<10 ) w = 10;
            n = strlen30(azArg && azArg[i] ? azArg[i] : p->nullValue);
            if( w<n ) w = n;
          }
          if( i<ArraySize(p->actualWidth) ){
            p->actualWidth[i] = w;
          }
          if( p->showHeader ){
            if( w<0 ){
              fprintf(p->out,"%*.*s%s",-w,-w,azCol[i],
                      i==nArg-1 ? p->rowSeparator : "  ");
            }else{
              fprintf(p->out,"%-*.*s%s",w,w,azCol[i],
                      i==nArg-1 ? p->rowSeparator : "  ");
            }
          }
        }
        if( p->showHeader ){
          for(i=0; i<nArg; i++){
            int w;
            if( i<ArraySize(p->actualWidth) ){
................................................................................
               w = p->actualWidth[i];
               if( w<0 ) w = -w;
            }else{
               w = 10;
            }
            fprintf(p->out,"%-*.*s%s",w,w,"-----------------------------------"
                   "----------------------------------------------------------",
                    i==nArg-1 ? p->rowSeparator : "  ");
          }
        }
      }
      if( azArg==0 ) break;
      for(i=0; i<nArg; i++){
        int w;
        if( i<ArraySize(p->actualWidth) ){
................................................................................
          if( p->iIndent<p->nIndent ){
            fprintf(p->out, "%*.s", p->aiIndent[p->iIndent], "");
          }
          p->iIndent++;
        }
        if( w<0 ){
          fprintf(p->out,"%*.*s%s",-w,-w,
              azArg[i] ? azArg[i] : p->nullValue,
              i==nArg-1 ? p->rowSeparator : "  ");
        }else{
          fprintf(p->out,"%-*.*s%s",w,w,
              azArg[i] ? azArg[i] : p->nullValue,
              i==nArg-1 ? p->rowSeparator : "  ");
        }
      }
      break;
    }
    case MODE_Semi:
    case MODE_List: {
      if( p->cnt++==0 && p->showHeader ){
        for(i=0; i<nArg; i++){
          fprintf(p->out,"%s%s",azCol[i],
                  i==nArg-1 ? p->rowSeparator : p->colSeparator);
        }
      }
      if( azArg==0 ) break;
      for(i=0; i<nArg; i++){
        char *z = azArg[i];
        if( z==0 ) z = p->nullValue;
        fprintf(p->out, "%s", z);
        if( i<nArg-1 ){
          fprintf(p->out, "%s", p->colSeparator);
        }else if( p->mode==MODE_Semi ){
          fprintf(p->out, ";%s", p->rowSeparator);
        }else{
          fprintf(p->out, "%s", p->rowSeparator);
        }
      }
      break;
    }
    case MODE_Html: {
      if( p->cnt++==0 && p->showHeader ){
        fprintf(p->out,"<TR>");
................................................................................
        }
        fprintf(p->out,"</TR>\n");
      }
      if( azArg==0 ) break;
      fprintf(p->out,"<TR>");
      for(i=0; i<nArg; i++){
        fprintf(p->out,"<TD>");
        output_html_string(p->out, azArg[i] ? azArg[i] : p->nullValue);
        fprintf(p->out,"</TD>\n");
      }
      fprintf(p->out,"</TR>\n");
      break;
    }
    case MODE_Tcl: {
      if( p->cnt++==0 && p->showHeader ){
        for(i=0; i<nArg; i++){
          output_c_string(p->out,azCol[i] ? azCol[i] : "");
          if(i<nArg-1) fprintf(p->out, "%s", p->colSeparator);
        }
        fprintf(p->out, "%s", p->rowSeparator);
      }
      if( azArg==0 ) break;
      for(i=0; i<nArg; i++){
        output_c_string(p->out, azArg[i] ? azArg[i] : p->nullValue);
        if(i<nArg-1) fprintf(p->out, "%s", p->colSeparator);
      }
      fprintf(p->out, "%s", p->rowSeparator);
      break;
    }
    case MODE_Csv: {

      setBinaryMode(p->out);


      if( p->cnt++==0 && p->showHeader ){
        for(i=0; i<nArg; i++){
          output_csv(p, azCol[i] ? azCol[i] : "", i<nArg-1);
        }
        fprintf(p->out, "%s", p->rowSeparator);
      }
      if( nArg>0 ){
        for(i=0; i<nArg; i++){
          output_csv(p, azArg[i], i<nArg-1);
        }
        fprintf(p->out, "%s", p->rowSeparator);
      }

      setTextMode(p->out);


      break;
    }
    case MODE_Insert: {
      p->cnt++;
      if( azArg==0 ) break;
      fprintf(p->out,"INSERT INTO %s VALUES(",p->zDestTable);
      for(i=0; i<nArg; i++){
................................................................................
        }else{
          if( zSep[0] ) fprintf(p->out,"%s",zSep);
          output_quoted_string(p->out, azArg[i]);
        }
      }
      fprintf(p->out,");\n");
      break;
    }
    case MODE_Ascii: {
      if( p->cnt++==0 && p->showHeader ){
        for(i=0; i<nArg; i++){
          if( i>0 ) fprintf(p->out, "%s", p->colSeparator);
          fprintf(p->out,"%s",azCol[i] ? azCol[i] : "");
        }
        fprintf(p->out, "%s", p->rowSeparator);
      }
      if( azArg==0 ) break;
      for(i=0; i<nArg; i++){
        if( i>0 ) fprintf(p->out, "%s", p->colSeparator);
        fprintf(p->out,"%s",azArg[i] ? azArg[i] : p->nullValue);
      }
      fprintf(p->out, "%s", p->rowSeparator);
      break;
    }
  }
  return 0;
}

/*
** This is the callback routine that the SQLite library
................................................................................
            fprintf(pArg->out,"%d,", sqlite3_column_int(pExplain, 2));
            fprintf(pArg->out,"%s\n", sqlite3_column_text(pExplain, 3));
          }
        }
        sqlite3_finalize(pExplain);
        sqlite3_free(zEQP);
      }

#if USE_SYSTEM_SQLITE+0==1
      /* Output TESTCTRL_EXPLAIN text of requested */
      if( pArg && pArg->mode==MODE_Explain && sqlite3_libversion_number()<3008007 ){
        const char *zExplain = 0;
        sqlite3_test_control(SQLITE_TESTCTRL_EXPLAIN_STMT, pStmt, &zExplain);
        if( zExplain && zExplain[0] ){
          fprintf(pArg->out, "%s", zExplain);
        }
      }
#endif

      /* If the shell is currently in ".explain" mode, gather the extra
      ** data required to add indents to the output.*/
      if( pArg && pArg->mode==MODE_Explain ){
        explain_data_prepare(pArg, pStmt);
      }

................................................................................
  ".iotrace FILE          Enable I/O diagnostic logging to FILE\n"
#endif
#ifndef SQLITE_OMIT_LOAD_EXTENSION
  ".load FILE ?ENTRY?     Load an extension library\n"
#endif
  ".log FILE|off          Turn logging on or off.  FILE can be stderr/stdout\n"
  ".mode MODE ?TABLE?     Set output mode where MODE is one of:\n"
  "                         ascii    Columns/rows delimited by 0x1F and 0x1E\n"
  "                         csv      Comma-separated values\n"
  "                         column   Left-aligned columns.  (See .width)\n"
  "                         html     HTML <table> code\n"
  "                         insert   SQL insert statements for TABLE\n"
  "                         line     One value per line\n"
  "                         list     Values delimited by .separator strings\n"
  "                         tabs     Tab-separated values\n"
  "                         tcl      TCL list elements\n"
  ".nullvalue STRING      Use STRING in place of NULL values\n"
  ".once FILENAME         Output for the next SQL command only to FILENAME\n"
  ".open ?FILENAME?       Close existing database and reopen FILENAME\n"
  ".output ?FILENAME?     Send output to FILENAME or stdout\n"
  ".print STRING...       Print literal STRING\n"
................................................................................
  ".read FILENAME         Execute SQL in FILENAME\n"
  ".restore ?DB? FILE     Restore content of DB (default \"main\") from FILE\n"
  ".save FILE             Write in-memory database into FILE\n"
  ".scanstats on|off      Turn sqlite3_stmt_scanstatus() metrics on or off\n"
  ".schema ?TABLE?        Show the CREATE statements\n"
  "                         If TABLE specified, only show tables matching\n"
  "                         LIKE pattern TABLE.\n"
  ".separator COL ?ROW?   Change the column separator and optionally the row\n"
  "                         separator for both the output mode and .import\n"
  ".shell CMD ARGS...     Run CMD ARGS... in a system shell\n"
  ".show                  Show the current values for various settings\n"
  ".stats on|off          Turn stats on or off\n"
  ".system CMD ARGS...    Run CMD ARGS... in a system shell\n"
  ".tables ?TABLE?        List names of tables\n"
  "                         If TABLE specified, only list tables matching\n"
  "                         LIKE pattern TABLE.\n"
................................................................................
*/
static void test_breakpoint(void){
  static int nCall = 0;
  nCall++;
}

/*
** An object used to read a CSV and other files for import.
*/
typedef struct ImportCtx ImportCtx;
struct ImportCtx {
  const char *zFile;  /* Name of the input file */
  FILE *in;           /* Read the CSV text from this input stream */
  char *z;            /* Accumulated text for a field */
  int n;              /* Number of bytes in z */
  int nAlloc;         /* Space allocated for z[] */
  int nLine;          /* Current line number */
  int cTerm;          /* Character that terminated the most recent field */
  int cColSep;        /* The column separator character.  (Usually ",") */
  int cRowSep;        /* The row separator character.  (Usually "\n") */
};

/* Append a single byte to z[] */
static void import_append_char(ImportCtx *p, int c){
  if( p->n+1>=p->nAlloc ){
    p->nAlloc += p->nAlloc + 100;
    p->z = sqlite3_realloc(p->z, p->nAlloc);
    if( p->z==0 ){
      fprintf(stderr, "out of memory\n");
      exit(1);
    }
................................................................................

/* Read a single field of CSV text.  Compatible with rfc4180 and extended
** with the option of having a separator other than ",".
**
**   +  Input comes from p->in.
**   +  Store results in p->z of length p->n.  Space to hold p->z comes
**      from sqlite3_malloc().
**   +  Use p->cSep as the column separator.  The default is ",".
**   +  Use p->rSep as the row separator.  The default is "\n".
**   +  Keep track of the line number in p->nLine.
**   +  Store the character that terminates the field in p->cTerm.  Store
**      EOF on end-of-file.
**   +  Report syntax errors on stderr
*/
static char *csv_read_one_field(ImportCtx *p){
  int c;
  int cSep = p->cColSep;
  int rSep = p->cRowSep;
  p->n = 0;
  c = fgetc(p->in);
  if( c==EOF || seenInterrupt ){
    p->cTerm = EOF;
    return 0;
  }
  if( c=='"' ){
    int pc, ppc;
    int startLine = p->nLine;
    int cQuote = c;
    pc = ppc = 0;
    while( 1 ){
      c = fgetc(p->in);
      if( c==rSep ) p->nLine++;
      if( c==cQuote ){
        if( pc==cQuote ){
          pc = 0;
          continue;
        }
      }
      if( (c==cSep && pc==cQuote)
       || (c==rSep && pc==cQuote)
       || (c==rSep && pc=='\r' && ppc==cQuote)
       || (c==EOF && pc==cQuote)
      ){
        do{ p->n--; }while( p->z[p->n]!=cQuote );
        p->cTerm = c;
        break;
      }
      if( pc==cQuote && c!='\r' ){
        fprintf(stderr, "%s:%d: unescaped %c character\n",
                p->zFile, p->nLine, cQuote);
      }
      if( c==EOF ){
        fprintf(stderr, "%s:%d: unterminated %c-quoted field\n",
                p->zFile, startLine, cQuote);
        p->cTerm = c;
        break;
      }
      import_append_char(p, c);
      ppc = pc;
      pc = c;
    }
  }else{
    while( c!=EOF && c!=cSep && c!=rSep ){
      import_append_char(p, c);
      c = fgetc(p->in);
    }
    if( c==rSep ){
      p->nLine++;
      if( p->n>0 && p->z[p->n-1]=='\r' ) p->n--;
    }
    p->cTerm = c;
  }
  if( p->z ) p->z[p->n] = 0;
  return p->z;
}

/* Read a single field of ASCII delimited text.
**
**   +  Input comes from p->in.
**   +  Store results in p->z of length p->n.  Space to hold p->z comes
**      from sqlite3_malloc().
**   +  Use p->cSep as the column separator.  The default is "\x1F".
**   +  Use p->rSep as the row separator.  The default is "\x1E".
**   +  Keep track of the row number in p->nLine.
**   +  Store the character that terminates the field in p->cTerm.  Store
**      EOF on end-of-file.
**   +  Report syntax errors on stderr
*/
static char *ascii_read_one_field(ImportCtx *p){
  int c;
  int cSep = p->cColSep;
  int rSep = p->cRowSep;
  p->n = 0;
  c = fgetc(p->in);
  if( c==EOF || seenInterrupt ){
    p->cTerm = EOF;
    return 0;
  }
  while( c!=EOF && c!=cSep && c!=rSep ){
    import_append_char(p, c);
    c = fgetc(p->in);
  }
  if( c==rSep ){
    p->nLine++;
  }
  p->cTerm = c;
  if( p->z ) p->z[p->n] = 0;
  return p->z;
}

/*
** Try to transfer data for table zTable.  If an error is seen while
** moving forward, try to go backwards.  The backwards movement won't
** work for WITHOUT ROWID tables.
*/
static void tryToCloneData(
................................................................................
    char *zTable;               /* Insert data into this table */
    char *zFile;                /* Name of file to extra content from */
    sqlite3_stmt *pStmt = NULL; /* A statement */
    int nCol;                   /* Number of columns in the table */
    int nByte;                  /* Number of bytes in an SQL string */
    int i, j;                   /* Loop counters */
    int needCommit;             /* True to COMMIT or ROLLBACK at end */
    int nSep;                   /* Number of bytes in p->colSeparator[] */
    char *zSql;                 /* An SQL statement */
    ImportCtx sCtx;             /* Reader context */
    char *(*xRead)(ImportCtx*); /* Procedure to read one value */
    int (*xCloser)(FILE*);      /* Procedure to close th3 connection */

    if( nArg!=3 ){
      fprintf(stderr, "Usage: .import FILE TABLE\n");
      goto meta_command_exit;
    }
    zFile = azArg[1];
    zTable = azArg[2];
    seenInterrupt = 0;
    memset(&sCtx, 0, sizeof(sCtx));
    open_db(p, 0);
    nSep = strlen30(p->colSeparator);
    if( nSep==0 ){
      fprintf(stderr, "Error: non-null column separator required for import\n");
      return 1;
    }
    if( nSep>1 ){
      fprintf(stderr, "Error: multi-character column separators not allowed"
                      " for import\n");
      return 1;
    }
    nSep = strlen30(p->rowSeparator);
    if( nSep==0 ){
      fprintf(stderr, "Error: non-null row separator required for import\n");
      return 1;
    }
    if( nSep==2 && p->mode==MODE_Csv && strcmp(p->rowSeparator, SEP_CrLf)==0 ){
      /* When importing CSV (only), if the row separator is set to the
      ** default output row separator, change it to the default input
      ** row separator.  This avoids having to maintain different input
      ** and output row separators. */
      sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
      nSep = strlen30(p->rowSeparator);
    }
    if( nSep>1 ){
      fprintf(stderr, "Error: multi-character row separators not allowed"
                      " for import\n");
      return 1;
    }
    sCtx.zFile = zFile;
    sCtx.nLine = 1;
    if( sCtx.zFile[0]=='|' ){
      sCtx.in = popen(sCtx.zFile+1, "r");
      sCtx.zFile = "<pipe>";
      xCloser = pclose;
    }else{
      sCtx.in = fopen(sCtx.zFile, "rb");
      xCloser = fclose;
    }
    if( p->mode==MODE_Ascii ){
      xRead = ascii_read_one_field;
    }else{
      xRead = csv_read_one_field;
    }
    if( sCtx.in==0 ){
      fprintf(stderr, "Error: cannot open \"%s\"\n", zFile);
      return 1;
    }
    sCtx.cColSep = p->colSeparator[0];
    sCtx.cRowSep = p->rowSeparator[0];
    zSql = sqlite3_mprintf("SELECT * FROM %s", zTable);
    if( zSql==0 ){
      fprintf(stderr, "Error: out of memory\n");
      xCloser(sCtx.in);
      return 1;
    }
    nByte = strlen30(zSql);
    rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
    import_append_char(&sCtx, 0);    /* To ensure sCtx.z is allocated */
    if( rc && sqlite3_strglob("no such table: *", sqlite3_errmsg(db))==0 ){
      char *zCreate = sqlite3_mprintf("CREATE TABLE %s", zTable);
      char cSep = '(';
      while( xRead(&sCtx) ){
        zCreate = sqlite3_mprintf("%z%c\n  \"%s\" TEXT", zCreate, cSep, sCtx.z);
        cSep = ',';
        if( sCtx.cTerm!=sCtx.cColSep ) break;
      }
      if( cSep=='(' ){
        sqlite3_free(zCreate);
        sqlite3_free(sCtx.z);
        xCloser(sCtx.in);
        fprintf(stderr,"%s: empty file\n", sCtx.zFile);
        return 1;
      }
      zCreate = sqlite3_mprintf("%z\n)", zCreate);
      rc = sqlite3_exec(p->db, zCreate, 0, 0, 0);
      sqlite3_free(zCreate);
      if( rc ){
        fprintf(stderr, "CREATE TABLE %s(...) failed: %s\n", zTable,
                sqlite3_errmsg(db));
        sqlite3_free(sCtx.z);
        xCloser(sCtx.in);
        return 1;
      }
      rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
    }
    sqlite3_free(zSql);
    if( rc ){
      if (pStmt) sqlite3_finalize(pStmt);
      fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db));
      xCloser(sCtx.in);
      return 1;
    }
    nCol = sqlite3_column_count(pStmt);
    sqlite3_finalize(pStmt);
    pStmt = 0;
    if( nCol==0 ) return 0; /* no columns, no error */
    zSql = sqlite3_malloc( nByte*2 + 20 + nCol*2 );
    if( zSql==0 ){
      fprintf(stderr, "Error: out of memory\n");
      xCloser(sCtx.in);
      return 1;
    }
    sqlite3_snprintf(nByte+20, zSql, "INSERT INTO \"%w\" VALUES(?", zTable);
    j = strlen30(zSql);
    for(i=1; i<nCol; i++){
      zSql[j++] = ',';
      zSql[j++] = '?';
................................................................................
    zSql[j++] = ')';
    zSql[j] = 0;
    rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
    sqlite3_free(zSql);
    if( rc ){
      fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db));
      if (pStmt) sqlite3_finalize(pStmt);
      xCloser(sCtx.in);
      return 1;
    }
    needCommit = sqlite3_get_autocommit(db);
    if( needCommit ) sqlite3_exec(db, "BEGIN", 0, 0, 0);
    do{
      int startLine = sCtx.nLine;
      for(i=0; i<nCol; i++){
        char *z = xRead(&sCtx);
        /*
        ** Did we reach end-of-file before finding any columns?
        ** If so, stop instead of NULL filling the remaining columns.
        */
        if( z==0 && i==0 ) break;
        /*
        ** Did we reach end-of-file OR end-of-line before finding any
        ** columns in ASCII mode?  If so, stop instead of NULL filling
        ** the remaining columns.
        */
        if( p->mode==MODE_Ascii && (z==0 || z[0]==0) && i==0 ) break;
        sqlite3_bind_text(pStmt, i+1, z, -1, SQLITE_TRANSIENT);
        if( i<nCol-1 && sCtx.cTerm!=sCtx.cColSep ){
          fprintf(stderr, "%s:%d: expected %d columns but found %d - "
                          "filling the rest with NULL\n",
                          sCtx.zFile, startLine, nCol, i+1);
          i++;
          while( i<=nCol ){ sqlite3_bind_null(pStmt, i); i++; }
        }
      }
      if( sCtx.cTerm==sCtx.cColSep ){
        do{
          xRead(&sCtx);
          i++;
        }while( sCtx.cTerm==sCtx.cColSep );
        fprintf(stderr, "%s:%d: expected %d columns but found %d - "
                        "extras ignored\n",
                        sCtx.zFile, startLine, nCol, i);
      }
      if( i>=nCol ){
        sqlite3_step(pStmt);
        rc = sqlite3_reset(pStmt);
        if( rc!=SQLITE_OK ){
          fprintf(stderr, "%s:%d: INSERT failed: %s\n", sCtx.zFile, startLine,
                  sqlite3_errmsg(db));
        }
      }
    }while( sCtx.cTerm!=EOF );

    xCloser(sCtx.in);
    sqlite3_free(sCtx.z);
    sqlite3_finalize(pStmt);
    if( needCommit ) sqlite3_exec(db, "COMMIT", 0, 0, 0);
  }else

  if( c=='i' && strncmp(azArg[0], "indices", n)==0 ){
    ShellState data;
    char *zErrMsg = 0;
................................................................................
      p->mode = MODE_Column;
    }else if( c2=='l' && n2>2 && strncmp(azArg[1],"list",n2)==0 ){
      p->mode = MODE_List;
    }else if( c2=='h' && strncmp(azArg[1],"html",n2)==0 ){
      p->mode = MODE_Html;
    }else if( c2=='t' && strncmp(azArg[1],"tcl",n2)==0 ){
      p->mode = MODE_Tcl;
      sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Space);
    }else if( c2=='c' && strncmp(azArg[1],"csv",n2)==0 ){
      p->mode = MODE_Csv;
      sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma);
      sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_CrLf);
    }else if( c2=='t' && strncmp(azArg[1],"tabs",n2)==0 ){
      p->mode = MODE_List;
      sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Tab);
    }else if( c2=='i' && strncmp(azArg[1],"insert",n2)==0 ){
      p->mode = MODE_Insert;
      set_table_name(p, nArg>=3 ? azArg[2] : "table");
    }else if( c2=='a' && strncmp(azArg[1],"ascii",n2)==0 ){
      p->mode = MODE_Ascii;
      sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Unit);
      sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Record);
    }else {
      fprintf(stderr,"Error: mode should be one of: "
         "ascii column csv html insert line list tabs tcl\n");
      rc = 1;
    }
  }else

  if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 ){
    if( nArg==2 ){
      sqlite3_snprintf(sizeof(p->nullValue), p->nullValue,
                       "%.*s", (int)ArraySize(p->nullValue)-1, azArg[1]);
    }else{
      fprintf(stderr, "Usage: .nullvalue STRING\n");
      rc = 1;
    }
  }else

  if( c=='o' && strncmp(azArg[0], "open", n)==0 && n>=2 ){
................................................................................
    }
  }else


#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
  if( c=='s' && n==11 && strncmp(azArg[0], "selecttrace", n)==0 ){
    extern int sqlite3SelectTrace;
    sqlite3SelectTrace = integerValue(azArg[1]);
  }else
#endif


#ifdef SQLITE_DEBUG
  /* Undocumented commands for internal testing.  Subject to change
  ** without notice. */
................................................................................
      }
    }
  }else
#endif

  if( c=='s' && strncmp(azArg[0], "separator", n)==0 ){
    if( nArg<2 || nArg>3 ){
      fprintf(stderr, "Usage: .separator COL ?ROW?\n");
      rc = 1;
    }
    if( nArg>=2 ){
      sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator,
                       "%.*s", (int)ArraySize(p->colSeparator)-1, azArg[1]);
    }
    if( nArg>=3 ){
      sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator,
                       "%.*s", (int)ArraySize(p->rowSeparator)-1, azArg[2]);
    }
  }else

  if( c=='s'
   && (strncmp(azArg[0], "shell", n)==0 || strncmp(azArg[0],"system",n)==0)
  ){
    char *zCmd;
................................................................................
  if( c=='s' && strncmp(azArg[0], "show", n)==0 ){
    int i;
    if( nArg!=1 ){
      fprintf(stderr, "Usage: .show\n");
      rc = 1;
      goto meta_command_exit;
    }
    fprintf(p->out,"%12.12s: %s\n","echo", p->echoOn ? "on" : "off");
    fprintf(p->out,"%12.12s: %s\n","eqp", p->autoEQP ? "on" : "off");
    fprintf(p->out,"%9.9s: %s\n","explain", p->normalMode.valid ? "on" :"off");
    fprintf(p->out,"%12.12s: %s\n","headers", p->showHeader ? "on" : "off");
    fprintf(p->out,"%12.12s: %s\n","mode", modeDescr[p->mode]);
    fprintf(p->out,"%12.12s: ", "nullvalue");
      output_c_string(p->out, p->nullValue);
      fprintf(p->out, "\n");
    fprintf(p->out,"%12.12s: %s\n","output",
            strlen30(p->outfile) ? p->outfile : "stdout");
    fprintf(p->out,"%12.12s: ", "colseparator");
      output_c_string(p->out, p->colSeparator);
      fprintf(p->out, "\n");
    fprintf(p->out,"%12.12s: ", "rowseparator");
      output_c_string(p->out, p->rowSeparator);
      fprintf(p->out, "\n");
    fprintf(p->out,"%12.12s: %s\n","stats", p->statsOn ? "on" : "off");
    fprintf(p->out,"%12.12s: ","width");
    for (i=0;i<(int)ArraySize(p->colWidth) && p->colWidth[i] != 0;i++) {
      fprintf(p->out,"%d ",p->colWidth[i]);
    }
    fprintf(p->out,"\n");
  }else

  if( c=='s' && strncmp(azArg[0], "stats", n)==0 ){
................................................................................
      { "assert",                SQLITE_TESTCTRL_ASSERT                 },
      { "always",                SQLITE_TESTCTRL_ALWAYS                 },
      { "reserve",               SQLITE_TESTCTRL_RESERVE                },
      { "optimizations",         SQLITE_TESTCTRL_OPTIMIZATIONS          },
      { "iskeyword",             SQLITE_TESTCTRL_ISKEYWORD              },
      { "scratchmalloc",         SQLITE_TESTCTRL_SCRATCHMALLOC          },
      { "byteorder",             SQLITE_TESTCTRL_BYTEORDER              },
      { "never_corrupt",         SQLITE_TESTCTRL_NEVER_CORRUPT          },
    };
    int testctrl = -1;
    int rc = 0;
    int i, n;
    open_db(p, 0);

    /* convert testctrl text option to value. allow any unique prefix
................................................................................
            fprintf(stderr,"Error: testctrl %s takes a single unsigned"
                           " int option\n", azArg[1]);
          }
          break;
          
        /* sqlite3_test_control(int, int) */
        case SQLITE_TESTCTRL_ASSERT:              
        case SQLITE_TESTCTRL_ALWAYS:      
        case SQLITE_TESTCTRL_NEVER_CORRUPT:        
          if( nArg==3 ){
            int opt = booleanValue(azArg[2]);        
            rc = sqlite3_test_control(testctrl, opt);
            fprintf(p->out, "%d (0x%08x)\n", rc, rc);
          } else {
            fprintf(stderr,"Error: testctrl %s takes a single int option\n",
                            azArg[1]);
................................................................................
  return rc;
}

/*
** Show available command line options
*/
static const char zOptions[] = 
  "   -ascii               set output mode to 'ascii'\n"
  "   -bail                stop after hitting an error\n"
  "   -batch               force batch I/O\n"
  "   -column              set output mode to 'column'\n"
  "   -cmd COMMAND         run \"COMMAND\" before reading stdin\n"
  "   -csv                 set output mode to 'csv'\n"
  "   -echo                print commands before execution\n"
  "   -init FILENAME       read/process named file\n"
................................................................................
  "   -line                set output mode to 'line'\n"
  "   -list                set output mode to 'list'\n"
  "   -lookaside SIZE N    use N entries of SZ bytes for lookaside memory\n"
  "   -mmap N              default mmap size set to N\n"
#ifdef SQLITE_ENABLE_MULTIPLEX
  "   -multiplex           enable the multiplexor VFS\n"
#endif
  "   -newline SEP         set output row separator. Default: '\\n'\n"
  "   -nullvalue TEXT      set text string for NULL values. Default ''\n"
  "   -pagecache SIZE N    use N slots of SZ bytes each for page cache memory\n"
  "   -scratch SIZE N      use N slots of SZ bytes each for scratch memory\n"
  "   -separator SEP       set output column separator. Default: '|'\n"
  "   -stats               print memory stats before each finalize\n"
  "   -version             show SQLite version\n"
  "   -vfs NAME            use NAME as the default VFS\n"
#ifdef SQLITE_ENABLE_VFSTRACE
  "   -vfstrace            enable tracing of all VFS calls\n"
#endif
;
................................................................................

/*
** Initialize the state information in data
*/
static void main_init(ShellState *data) {
  memset(data, 0, sizeof(*data));
  data->mode = MODE_List;
  memcpy(data->colSeparator,SEP_Column, 2);
  memcpy(data->rowSeparator,SEP_Row, 2);
  data->showHeader = 0;
  data->shellFlgs = SHFLG_Lookaside;
  sqlite3_config(SQLITE_CONFIG_URI, 1);
  sqlite3_config(SQLITE_CONFIG_LOG, shellLog, data);
  sqlite3_config(SQLITE_CONFIG_MULTITHREAD);
  sqlite3_snprintf(sizeof(mainPrompt), mainPrompt,"sqlite> ");
  sqlite3_snprintf(sizeof(continuePrompt), continuePrompt,"   ...> ");
................................................................................
#if USE_SYSTEM_SQLITE+0!=1
  if( strcmp(sqlite3_sourceid(),SQLITE_SOURCE_ID)!=0 ){
    fprintf(stderr, "SQLite header and source version mismatch\n%s\n%s\n",
            sqlite3_sourceid(), SQLITE_SOURCE_ID);
    exit(1);
  }
#endif
  setBinaryMode(stdin);
  setvbuf(stderr, 0, _IONBF, 0); /* Make sure stderr is unbuffered */
  Argv0 = argv[0];
  main_init(&data);
  stdin_is_interactive = isatty(0);

  /* Make sure we have a valid signal handler early, before anything
  ** else is done.
  */
................................................................................
      data.mode = MODE_List;
    }else if( strcmp(z,"-line")==0 ){
      data.mode = MODE_Line;
    }else if( strcmp(z,"-column")==0 ){
      data.mode = MODE_Column;
    }else if( strcmp(z,"-csv")==0 ){
      data.mode = MODE_Csv;
      memcpy(data.colSeparator,",",2);
    }else if( strcmp(z,"-ascii")==0 ){
      data.mode = MODE_Ascii;
      sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator,
                       SEP_Unit);
      sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator,
                       SEP_Record);
    }else if( strcmp(z,"-separator")==0 ){
      sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator,
                       "%s",cmdline_option_value(argc,argv,++i));
    }else if( strcmp(z,"-newline")==0 ){
      sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator,
                       "%s",cmdline_option_value(argc,argv,++i));
    }else if( strcmp(z,"-nullvalue")==0 ){
      sqlite3_snprintf(sizeof(data.nullValue), data.nullValue,
                       "%s",cmdline_option_value(argc,argv,++i));
    }else if( strcmp(z,"-header")==0 ){
      data.showHeader = 1;
    }else if( strcmp(z,"-noheader")==0 ){
      data.showHeader = 0;
    }else if( strcmp(z,"-echo")==0 ){
      data.echoOn = 1;
................................................................................
      zHome = find_home_dir();
      if( zHome ){
        nHistory = strlen30(zHome) + 20;
        if( (zHistory = malloc(nHistory))!=0 ){
          sqlite3_snprintf(nHistory, zHistory,"%s/.sqlite_history", zHome);
        }
      }
#if HAVE_READLINE
      if( zHistory ) read_history(zHistory);
#endif
      rc = process_input(&data, 0);
      if( zHistory ){
        stifle_history(100);
        write_history(zHistory);
        free(zHistory);

Changes to src/sitemap.c.

25
26
27
28
29
30
31

32
33
34
35
36
37
38
** WEBPAGE:  sitemap
**
** Show an incomplete list of web pages offered by the Fossil web engine.
*/
void sitemap_page(void){
  login_check_credentials();
  style_header("Site Map");

  @ <p>
  @ The following links are just a few of the many web-pages available for
  @ this Fossil repository:
  @ </p>
  @
  @ <ul>
  @ <li>%z(href("%R/home"))Home Page</a></li>







>







25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
** WEBPAGE:  sitemap
**
** Show an incomplete list of web pages offered by the Fossil web engine.
*/
void sitemap_page(void){
  login_check_credentials();
  style_header("Site Map");
  style_adunit_config(ADUNIT_RIGHT_OK);
  @ <p>
  @ The following links are just a few of the many web-pages available for
  @ this Fossil repository:
  @ </p>
  @
  @ <ul>
  @ <li>%z(href("%R/home"))Home Page</a></li>

Changes to src/skins.c.

17
18
19
20
21
22
23
24
25
26
27

28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228

229
230
231

232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951


952
953
954
955
956


957
958
959
960
961
962
963

964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261


1262
1263
1264
1265
1266
1267
1268


1269
1270
1271
1272
1273
1274
1275
....
1284
1285
1286
1287
1288
1289
1290












1291
1292



1293
1294
1295
1296




1297
1298













1299
1300
1301

1302
1303
1304
1305









































1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316


1317
1318
1319

































1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331

1332
1333
1334
1335
1336
1337




1338
1339
1340
1341
1342
1343
1344
....
1349
1350
1351
1352
1353
1354
1355
1356

1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374




1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390

1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
....
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422

1423
1424

1425
1426
1427
1428
1429
1430
1431

1432
1433
1434
1435
1436
1437
1438
1439
1440



1441
1442

1443
1444
1445
1446
1447
1448
1449
1450



1451
1452





1453


1454
1455
1456
**
** Implementation of the Setup page for "skins".
*/
#include "config.h"
#include <assert.h>
#include "skins.h"

/* @-comment: ## */
/*
** A black-and-white theme with the project title in a bar across the top
** and no logo image.

*/
static const char zBuiltinSkin1[] =
@ REPLACE INTO config(name,mtime,value)
@ VALUES('css',now(),'/* General settings for the entire page */
@ body {
@   margin: 0ex 1ex;
@   padding: 0px;
@   background-color: white;
@   font-family: sans-serif;
@ }
@
@ /* The project logo in the upper left-hand corner of each page */
@ div.logo {
@   display: table-row;
@   text-align: center;
@   /* vertical-align: bottom;*/
@   font-size: 2em;
@   font-weight: bold;
@   background-color: #707070;
@   color: #ffffff;
@   min-width: 200px;
@   white-space: nowrap;
@ }
@
@ /* The page title centered at the top of each page */
@ div.title {
@   display: table-cell;
@   font-size: 1.5em;
@   font-weight: bold;
@   text-align: center;
@   padding: 0 0 0 10px;
@   color: #404040;
@   vertical-align: bottom;
@   width: 100%;
@ }
@
@ /* The login status message in the top right-hand corner */
@ div.status {
@   display: table-cell;
@   text-align: right;
@   vertical-align: bottom;
@   color: #404040;
@   font-size: 0.8em;
@   font-weight: bold;
@   min-width: 200px;
@   white-space: nowrap;
@ }
@
@ /* The header across the top of the page */
@ div.header {
@   display: table;
@   width: 100%;
@ }
@
@ /* The main menu bar that appears at the top of the page beneath
@ ** the header */
@ div.mainmenu {
@   padding: 5px 10px 5px 10px;
@   font-size: 0.9em;
@   font-weight: bold;
@   text-align: center;
@   letter-spacing: 1px;
@   background-color: #404040;
@   color: white;
@ }
@
@ /* The submenu bar that *sometimes* appears below the main menu */
@ div.submenu, div.sectionmenu {
@   padding: 3px 10px 3px 0px;
@   font-size: 0.9em;
@   text-align: center;
@   background-color: #606060;
@   color: white;
@ }
@ div.mainmenu a, div.mainmenu a:visited, div.submenu a, div.submenu a:visited,
@ div.sectionmenu>a.button:link, div.sectionmenu>a.button:visited {
@   padding: 3px 10px 3px 10px;
@   color: white;
@   text-decoration: none;
@ }
@ div.mainmenu a:hover, div.submenu a:hover, div.sectionmenu>a.button:hover {
@   color: #404040;
@   background-color: white;
@ }
@
@ /* All page content from the bottom of the menu or submenu down to
@ ** the footer */
@ div.content {
@   padding: 0ex 0ex 0ex 0ex;
@ }
@ /* Hyperlink colors */
@ div.content a { color: #604000; }
@ div.content a:link { color: #604000;}
@ div.content a:visited { color: #600000; }
@
@ /* <verbatim> blocks */
@ pre.verbatim {
@   background-color: #ffffff;
@   padding: 0.5em;
@   white-space: pre-wrap;
@ }
@
@ /* Some pages have section dividers */
@ div.section {
@   margin-bottom: 0px;
@   margin-top: 1em;
@   padding: 1px 1px 1px 1px;
@   font-size: 1.2em;
@   font-weight: bold;
@   background-color: #404040;
@   color: white;
@   white-space: nowrap;
@ }
@
@ /* The "Date" that occurs on the left hand side of timelines */
@ div.divider {
@   background: #a0a0a0;
@   border: 2px #505050 solid;
@   font-size: 1em; font-weight: normal;
@   padding: .25em;
@   margin: .2em 0 .2em 0;
@   float: left;
@   clear: left;
@   white-space: nowrap;
@ }
@
@ /* The footer at the very bottom of the page */
@ div.footer {
@   font-size: 0.8em;
@   margin-top: 12px;
@   padding: 5px 10px 5px 10px;
@   text-align: right;
@   background-color: #404040;
@   color: white;
@ }
@
@ /* The label/value pairs on (for example) the vinfo page */
@ table.label-value th {
@   vertical-align: top;
@   text-align: right;
@   padding: 0.2ex 2ex;
@ }');
@ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
@ <head>
@ <base href="$baseurl/$current_page" />
@ <title>$<project_name>: $<title></title>
@ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
@       href="$home/timeline.rss">
@ <link rel="stylesheet" href="$stylesheet_url" type="text/css"
@       media="screen">
@ </head>
@ <body>
@ <div class="header">
@   <div class="title"><small>$<project_name></small><br />$<title></div>
@   <div class="status"><th1>
@      if {[info exists login]} {
@        puts "Logged in as $login"
@      } else {
@        puts "Not logged in"
@      }
@   </th1></div>
@ </div>
@ <div class="mainmenu">
@ <th1>
@ html "<a href=''$home$index_page''>Home</a>\n"
@ if {[anycap jor]} {
@   html "<a href=''$home/timeline''>Timeline</a>\n"
@ }
@ if {[hascap oh]} {
@   html "<a href=''$home/tree?ci=tip''>Files</a>\n"
@ }
@ if {[hascap o]} {
@   html "<a href=''$home/brlist''>Branches</a>\n"
@   html "<a href=''$home/taglist''>Tags</a>\n"
@ }
@ if {[hascap r]} {
@   html "<a href=''$home/reportlist''>Tickets</a>\n"
@ }
@ if {[hascap j]} {
@   html "<a href=''$home/wiki''>Wiki</a>\n"
@ }
@ if {[hascap s]} {
@   html "<a href=''$home/setup''>Admin</a>\n"
@ } elseif {[hascap a]} {
@   html "<a href=''$home/setup_ulist''>Users</a>\n"
@ }
@ if {[info exists login]} {
@   html "<a href=''$home/login''>Logout</a>\n"
@ } else {
@   html "<a href=''$home/login''>Login</a>\n"
@ }
@ </th1></div>
@ ');
@ REPLACE INTO config(name,mtime,value)
@ VALUES('footer',now(),'<div class="footer">
@ Fossil version $manifest_version $manifest_date
@ </div>
@ </body></html>
@ ');
;


/*
** A tan theme with the project title above the user identification
** and no logo image.

*/
static const char zBuiltinSkin2[] =
@ REPLACE INTO config(name,mtime,value)
@ VALUES('css',now(),'/* General settings for the entire page */
@ body {
@   margin: 0ex 0ex;
@   padding: 0px;
@   background-color: #fef3bc;
@   font-family: sans-serif;
@ }
@
@ /* The project logo in the upper left-hand corner of each page */
@ div.logo {
@   display: inline;
@   text-align: center;
@   vertical-align: bottom;
@   font-weight: bold;
@   font-size: 2.5em;
@   color: #a09048;
@   white-space: nowrap;
@ }
@
@ /* The page title centered at the top of each page */
@ div.title {
@   display: table-cell;
@   font-size: 2em;
@   font-weight: bold;
@   text-align: left;
@   padding: 0 0 0 5px;
@   color: #a09048;
@   vertical-align: bottom;
@   width: 100%;
@ }
@
@ /* The login status message in the top right-hand corner */
@ div.status {
@   display: table-cell;
@   text-align: right;
@   vertical-align: bottom;
@   color: #a09048;
@   padding: 5px 5px 0 0;
@   font-size: 0.8em;
@   font-weight: bold;
@   white-space: nowrap;
@ }
@
@ /* The header across the top of the page */
@ div.header {
@   display: table;
@   width: 100%;
@ }
@
@ /* The main menu bar that appears at the top of the page beneath
@ ** the header */
@ div.mainmenu {
@   padding: 5px 10px 5px 10px;
@   font-size: 0.9em;
@   font-weight: bold;
@   text-align: center;
@   letter-spacing: 1px;
@   background-color: #a09048;
@   color: black;
@ }
@
@ /* The submenu bar that *sometimes* appears below the main menu */
@ div.submenu, div.sectionmenu {
@   padding: 3px 10px 3px 0px;
@   font-size: 0.9em;
@   text-align: center;
@   background-color: #c0af58;
@   color: white;
@ }
@ div.mainmenu a, div.mainmenu a:visited, div.submenu a, div.submenu a:visited,
@ div.sectionmenu>a.button:link, div.sectionmenu>a.button:visited {
@   padding: 3px 10px 3px 10px;
@   color: white;
@   text-decoration: none;
@ }
@ div.mainmenu a:hover, div.submenu a:hover, div.sectionmenu>a.button:hover {
@   color: #a09048;
@   background-color: white;
@ }
@
@ /* All page content from the bottom of the menu or submenu down to
@ ** the footer */
@ div.content {
@   padding: 1ex 5px;
@ }
@ div.content a { color: #706532; }
@ div.content a:link { color: #706532; }
@ div.content a:visited { color: #704032; }
@ div.content a:hover { background-color: white; color: #706532; }
@
@ /* Some pages have section dividers */
@ div.section {
@   margin-bottom: 0px;
@   margin-top: 1em;
@   padding: 3px 3px 0 3px;
@   font-size: 1.2em;
@   font-weight: bold;
@   background-color: #a09048;
@   color: white;
@   white-space: nowrap;
@ }
@
@ /* The "Date" that occurs on the left hand side of timelines */
@ div.divider {
@   background: #e1d498;
@   border: 2px #a09048 solid;
@   font-size: 1em; font-weight: normal;
@   padding: .25em;
@   margin: .2em 0 .2em 0;
@   float: left;
@   clear: left;
@   white-space: nowrap;
@ }
@
@ /* The footer at the very bottom of the page */
@ div.footer {
@   font-size: 0.8em;
@   margin-top: 12px;
@   padding: 5px 10px 5px 10px;
@   text-align: right;
@   background-color: #a09048;
@   color: white;
@ }
@
@ /* Hyperlink colors */
@ div.footer a { color: white; }
@ div.footer a:link { color: white; }
@ div.footer a:visited { color: white; }
@ div.footer a:hover { background-color: white; color: #558195; }
@
@ /* <verbatim> blocks */
@ pre.verbatim {
@   background-color: #f5f5f5;
@   padding: 0.5em;
@   white-space: pre-wrap;
@ }
@
@ /* The label/value pairs on (for example) the ci page */
@ table.label-value th {
@   vertical-align: top;
@   text-align: right;
@   padding: 0.2ex 2ex;
@ }');
@ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
@ <head>
@ <base href="$baseurl/$current_page" />
@ <title>$<project_name>: $<title></title>
@ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
@       href="$home/timeline.rss">
@ <link rel="stylesheet" href="$stylesheet_url" type="text/css"
@       media="screen">
@ </head>
@ <body>
@ <div class="header">
@   <div class="title">$<title></div>
@   <div class="status">
@     <div class="logo">$<project_name></div><br/>
@     <th1>
@      if {[info exists login]} {
@        puts "Logged in as $login"
@      } else {
@        puts "Not logged in"
@      }
@   </th1></div>
@ </div>
@ <div class="mainmenu">
@ <th1>
@ html "<a href=''$home$index_page''>Home</a>\n"
@ if {[anycap jor]} {
@   html "<a href=''$home/timeline''>Timeline</a>\n"
@ }
@ if {[hascap oh]} {
@   html "<a href=''$home/tree?ci=tip''>Files</a>\n"
@ }
@ if {[hascap o]} {
@   html "<a href=''$home/brlist''>Branches</a>\n"
@   html "<a href=''$home/taglist''>Tags</a>\n"
@ }
@ if {[hascap r]} {
@   html "<a href=''$home/reportlist''>Tickets</a>\n"
@ }
@ if {[hascap j]} {
@   html "<a href=''$home/wiki''>Wiki</a>\n"
@ }
@ if {[hascap s]} {
@   html "<a href=''$home/setup''>Admin</a>\n"
@ } elseif {[hascap a]} {
@   html "<a href=''$home/setup_ulist''>Users</a>\n"
@ }
@ if {[info exists login]} {
@   html "<a href=''$home/login''>Logout</a>\n"
@ } else {
@   html "<a href=''$home/login''>Login</a>\n"
@ }
@ </th1></div>
@ ');
@ REPLACE INTO config(name,mtime,value)
@ VALUES('footer',now(),'<div class="footer">
@ Fossil version $manifest_version $manifest_date
@ </div>
@ </body></html>
@ ');
;

/*
** Black letters on a white or cream background with the main menu
** stuck on the left-hand side.
*/
static const char zBuiltinSkin3[] =
@ REPLACE INTO config(name,mtime,value)
@ VALUES('css',now(),'/* General settings for the entire page */
@ body {
@     margin:0px 0px 0px 0px;
@     padding:0px;
@     font-family:verdana, arial, helvetica, "sans serif";
@     color:#333;
@     background-color:white;
@ }
@
@ /* consistent colours */
@ h2 {
@   color: #333;
@ }
@ h3 {
@   color: #333;
@ }
@
@ /* The project logo in the upper left-hand corner of each page */
@ div.logo {
@   display: table-cell;
@   text-align: left;
@   vertical-align: bottom;
@   font-weight: bold;
@   color: #333;
@   white-space: nowrap;
@ }
@
@ /* The page title centered at the top of each page */
@ div.title {
@   display: table-cell;
@   font-size: 2em;
@   font-weight: bold;
@   text-align: center;
@   color: #333;
@   vertical-align: bottom;
@   width: 100%;
@ }
@
@ /* The login status message in the top right-hand corner */
@ div.status {
@   display: table-cell;
@   padding-right: 10px;
@   text-align: right;
@   vertical-align: bottom;
@   padding-bottom: 5px;
@   color: #333;
@   font-size: 0.8em;
@   font-weight: bold;
@   white-space: nowrap;
@ }
@
@ /* The header across the top of the page */
@ div.header {
@     margin:10px 0px 10px 0px;
@     padding:1px 0px 0px 20px;
@     border-style:solid;
@     border-color:black;
@     border-width:1px 0px;
@     background-color:#eee;
@ }
@
@ /* The main menu bar that appears at the top left of the page beneath
@ ** the header. Width must be co-ordinated with the container below */
@ div.mainmenu {
@   float: left;
@   margin-left: 10px;
@   margin-right: 10px;
@   font-size: 0.9em;
@   font-weight: bold;
@   padding:5px;
@   background-color:#eee;
@   border:1px solid #999;
@   width:8em;
@ }
@
@ /* Main menu is now a list */
@ div.mainmenu ul {
@   padding: 0;
@   list-style:none;
@ }
@ div.mainmenu a, div.mainmenu a:visited{
@   padding: 1px 10px 1px 10px;
@   color: #333;
@   text-decoration: none;
@ }
@ div.mainmenu a:hover {
@   color: #eee;
@   background-color: #333;
@ }
@
@ /* Container for the sub-menu and content so they don''t spread
@ ** out underneath the main menu */
@ #container {
@   padding-left: 9em;
@ }
@
@ /* The submenu bar that *sometimes* appears below the main menu */
@ div.submenu, div.sectionmenu {
@   padding: 3px 10px 3px 10px;
@   font-size: 0.9em;
@   text-align: center;
@   border:1px solid #999;
@   border-width:1px 0px;
@   background-color: #eee;
@   color: #333;
@ }
@ div.submenu a, div.submenu a:visited, div.sectionmenu>a.button:link,
@ div.sectionmenu>a.button:visited {
@   padding: 3px 10px 3px 10px;
@   color: #333;
@   text-decoration: none;
@ }
@ div.submenu a:hover, div.sectionmenu>a.button:hover {
@   color: #eee;
@   background-color: #333;
@ }
@
@ /* All page content from the bottom of the menu or submenu down to
@ ** the footer */
@ div.content {
@   padding: 2ex 1ex 0ex 2ex;
@ }
@
@ /* Some pages have section dividers */
@ div.section {
@   margin-bottom: 0px;
@   margin-top: 1em;
@   padding: 1px 1px 1px 1px;
@   font-size: 1.2em;
@   font-weight: bold;
@   border-style:solid;
@   border-color:#999;
@   border-width:1px 0px;
@   background-color: #eee;
@   color: #333;
@   white-space: nowrap;
@ }
@
@ /* The "Date" that occurs on the left hand side of timelines */
@ div.divider {
@   background: #eee;
@   border: 2px #999 solid;
@   font-size: 1em; font-weight: normal;
@   padding: .25em;
@   margin: .2em 0 .2em 0;
@   float: left;
@   clear: left;
@   color: #333;
@   white-space: nowrap;
@ }
@
@ /* The footer at the very bottom of the page */
@ div.footer {
@   font-size: 0.8em;
@   margin-top: 12px;
@   padding: 5px 10px 5px 10px;
@   text-align: right;
@   background-color: #eee;
@   color: #555;
@ }
@
@ /* <verbatim> blocks */
@ pre.verbatim {
@   background-color: #f5f5f5;
@   padding: 0.5em;
@   white-space: pre-wrap;
@ }
@
@ /* The label/value pairs on (for example) the ci page */
@ table.label-value th {
@   vertical-align: top;
@   text-align: right;
@   padding: 0.2ex 2ex;
@ }');
@ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
@ <head>
@ <base href="$baseurl/$current_page" />
@ <title>$<project_name>: $<title></title>
@ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
@       href="$home/timeline.rss">
@ <link rel="stylesheet" href="$stylesheet_url" type="text/css"
@       media="screen">
@ </head>
@ <body>
@ <div class="header">
@   <div class="logo">
@     <img src="$logo_image_url" alt="logo">
@     <br />$<project_name>
@   </div>
@   <div class="title">$<title></div>
@   <div class="status"><th1>
@      if {[info exists login]} {
@        puts "Logged in as $login"
@      } else {
@        puts "Not logged in"
@      }
@   </th1></div>
@ </div>
@ <div class="mainmenu">
@ <th1>
@ html "<a href=''$home$index_page''>Home</a>\n"
@ if {[anycap jor]} {
@   html "<a href=''$home/timeline''>Timeline</a>\n"
@ }
@ if {[hascap oh]} {
@   html "<a href=''$home/tree?ci=tip''>Files</a>\n"
@ }
@ if {[hascap o]} {
@   html "<a href=''$home/brlist''>Branches</a>\n"
@   html "<a href=''$home/taglist''>Tags</a>\n"
@ }
@ if {[hascap r]} {
@   html "<a href=''$home/reportlist''>Tickets</a>\n"
@ }
@ if {[hascap j]} {
@   html "<a href=''$home/wiki''>Wiki</a>\n"
@ }
@ if {[hascap s]} {
@   html "<a href=''$home/setup''>Admin</a>\n"
@ } elseif {[hascap a]} {
@   html "<a href=''$home/setup_ulist''>Users</a>\n"
@ }
@ if {[info exists login]} {
@   html "<a href=''$home/login''>Logout</a>\n"
@ } else {
@   html "<a href=''$home/login''>Login</a>\n"
@ }
@ </th1></ul></div>
@ <div id="container">
@ ');
@ REPLACE INTO config(name,mtime,value) VALUES('footer',now(),'</div>
@ <div class="footer">
@ Fossil version $manifest_version $manifest_date
@ </div>
@ </body></html>
@ ');
;


/*
** Shadow boxes and rounded corners.
*/
static const char zBuiltinSkin4[] =
@ REPLACE INTO config(name,mtime,value)
@ VALUES('css',now(),'/* General settings for the entire page */
@ html {
@   min-height: 100%;
@ }
@ body {
@   margin: 0ex 1ex;
@   padding: 0px;
@   background-color: white;
@   color: #333;
@   font-family: Verdana, sans-serif;
@   font-size: 0.8em;
@ }
@
@ /* The project logo in the upper left-hand corner of each page */
@ div.logo {
@   display: table-cell;
@   text-align: right;
@   vertical-align: bottom;
@   font-weight: normal;
@   white-space: nowrap;
@ }
@
@ /* Widths */
@ div.header, div.mainmenu, div.submenu, div.content, div.footer {
@   max-width: 900px;
@   margin: auto;
@   padding: 3px 20px 3px 20px;
@   clear: both;
@ }
@
@ /* The page title at the top of each page */
@ div.title {
@   display: table-cell;
@   padding-left: 10px;
@   font-size: 2em;
@   margin: 10px 0 10px -20px;
@   vertical-align: bottom;
@   text-align: left;
@   width: 80%;
@   font-family: Verdana, sans-serif;
@   font-weight: bold;
@   color: #558195;
@   text-shadow: 0px 2px 2px #999999;
@ }
@
@ /* The login status message in the top right-hand corner */
@ div.status {
@   display: table-cell;
@   text-align: right;
@   vertical-align: bottom;
@   color: #333;
@   margin-right: -20px;
@   white-space: nowrap;
@ }
@
@ /* The main menu bar that appears at the top of the page beneath
@  ** the header */
@ div.mainmenu {
@   text-align: center;
@   color: white;
@   border-top-left-radius: 5px;
@   border-top-right-radius: 5px;
@   vertical-align: middle;
@   padding-top: 8px;
@   padding-bottom: 8px;
@   background-color: #446979;
@   box-shadow: 0px 3px 4px #333333;
@ }
@
@ /* The submenu bar that *sometimes* appears below the main menu */
@ div.submenu {
@   padding-top:10px;
@   padding-bottom:0;
@   text-align: right;
@   color: #000;
@   background-color: #fff;
@   height: 1.5em;
@   vertical-align:middle;
@   box-shadow: 0px 3px 4px #999;
@ }
@ div.mainmenu a, div.mainmenu a:visited {
@   padding: 3px 10px 3px 10px;
@   color: white;
@   text-decoration: none;
@ }
@ div.submenu a, div.submenu a:visited, a.button,
@ div.sectionmenu>a.button:link, div.sectionmenu>a.button:visited {
@   padding: 2px 8px;
@   color: #000;
@   font-family: Arial;
@   text-decoration: none;
@   margin:auto;
@   border-radius: 5px;
@   background-color: #e0e0e0;
@   text-shadow: 0px -1px 0px #eee;
@   border: 1px solid #000;
@ }
@
@ div.mainmenu a:hover {
@   color: #000;
@   background-color: white;
@ }
@
@ div.submenu a:hover, div.sectionmenu>a.button:hover {
@   background-color: #c0c0c0;
@ }
@
@ /* All page content from the bottom of the menu or submenu down to
@  ** the footer */
@ div.content {
@   background-color: #fff;
@   box-shadow: 0px 3px 4px #999;
@   border-bottom-right-radius: 5px;
@   border-bottom-left-radius: 5px;
@   padding-bottom: 1em;
@   min-height:40%;
@ }
@
@
@ /* Some pages have section dividers */
@ div.section {
@   margin-bottom: 0.5em;
@   margin-top: 1em;
@   margin-right: auto;
@   padding: 1px 1px 1px 1px;
@   font-size: 1.2em;
@   font-weight: bold;
@   text-align: center;
@   color: white;
@   border-radius: 5px;
@   background-color: #446979;
@   box-shadow: 0px 3px 4px #333333;
@   white-space: nowrap;
@ }
@
@ /* The "Date" that occurs on the left hand side of timelines */
@ div.divider {
@   font-size: 1.2em;
@   font-family: Georgia, serif;
@   font-weight: bold;
@   margin-top: 1em;
@   white-space: nowrap;
@ }
@
@ /* The footer at the very bottom of the page */
@ div.footer {
@   font-size: 0.9em;
@   text-align: right;
@   margin-bottom: 1em;
@   color: #666;
@ }
@
@ /* Hyperlink colors in the footer */
@ div.footer a { color: white; }
@ div.footer a:link { color: white; }
@ div.footer a:visited { color: white; }
@ div.footer a:hover { background-color: white; color: #558195; }
@
@ /* <verbatim> blocks */
@ pre.verbatim, blockquote pre {
@   font-family: Dejavu Sans Mono, Monaco, Lucida Console, monospace;
@   background-color: #f3f3f3;
@   padding: 0.5em;
@   white-space: pre-wrap;
@ }
@
@ blockquote pre {
@   border: 1px #000 dashed;
@ }
@
@ /* The label/value pairs on (for example) the ci page */
@ table.label-value th {
@   vertical-align: top;
@   text-align: right;
@   padding: 0.2ex 2ex;
@ }
@
@ table.report tr th {
@   padding: 3px 5px;
@   text-transform: capitalize;
@   cursor: pointer;
@ }
@
@ table.report tr td {
@   padding: 3px 5px;
@   cursor: pointer;
@ }
@
@ textarea {
@   font-size: 1em;
@ }
@
@ .fullsize-text {
@   font-size: 1.25em;
@ }');
@ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
@ <head>
@ <base href="$baseurl/$current_page" />
@ <title>$<project_name>: $<title></title>
@ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
@       href="$home/timeline.rss">
@ <link rel="stylesheet" href="$stylesheet_url" type="text/css"
@       media="screen">
@ </head>
@ <body>
@ <div class="header">
@   <div class="logo">
@     <img src="$logo_image_url" alt="logo">
@     <br />$<project_name>
@   </div>
@   <div class="title">$<title></div>
@   <div class="status"><th1>
@      if {[info exists login]} {
@        puts "Logged in as $login"
@      } else {
@        puts "Not logged in"
@      }
@   </th1></div>
@ </div>
@ <div class="mainmenu">
@ <th1>
@ html "<a href=''$home$index_page''>Home</a>\n"
@ if {[anycap jor]} {
@   html "<a href=''$home/timeline''>Timeline</a>\n"
@ }
@ if {[hascap oh]} {
@   html "<a href=''$home/tree?ci=tip''>Files</a>\n"
@ }
@ if {[hascap o]} {
@   html "<a href=''$home/brlist''>Branches</a>\n"
@   html "<a href=''$home/taglist''>Tags</a>\n"
@ }
@ if {[hascap r]} {
@   html "<a href=''$home/reportlist''>Tickets</a>\n"
@ }
@ if {[hascap j]} {
@   html "<a href=''$home/wiki''>Wiki</a>\n"
@ }
@ if {[hascap s]} {
@   html "<a href=''$home/setup''>Admin</a>\n"
@ } elseif {[hascap a]} {
@   html "<a href=''$home/setup_ulist''>Users</a>\n"
@ }
@ if {[info exists login]} {
@   html "<a href=''$home/login''>Logout</a>\n"
@ } else {
@   html "<a href=''$home/login''>Login</a>\n"
@ }
@ </th1></div>
@ <div id="container">
@ ');
@ REPLACE INTO config(name,mtime,value) VALUES('footer',now(),'</div>
@ <div class="footer">
@ Fossil version $manifest_version $manifest_date
@ </div>
@ </body></html>
@ ');
;


/*
** This skin is intended to be almost identical to the default one, with the
** following changes to the header and footer:


**
** 1. The logo image in the header has been modified to be a hyperlink to the
**    root of the web site containing the repository using the same scheme
**    (i.e. HTTP or HTTPS) as the base URL for the repository.  The header
**    contains a TH1 script block to help accomplish these tasks.


**
** 2. The Fossil version information in the footer has been augmented with
**    hyperlinks to the corresponding points on the timeline in the official
**    Fossil repository.  Additionally, if the Tcl integration feature is
**    enabled, the loaded version of Tcl is included, with a hyperlink to the
**    official Tcl/Tk web site.  The footer also contains a TH1 script block
**    to help accomplish these tasks.

*/
static const char zBuiltinSkin5[] =
@ REPLACE INTO config(name,mtime,value)
@ VALUES('css',now(),'/* General settings for the entire page */
@ body {
@   margin: 0ex 1ex;
@   padding: 0px;
@   background-color: white;
@   font-family: sans-serif;
@ }
@
@ /* The project logo in the upper left-hand corner of each page */
@ div.logo {
@   display: table-cell;
@   text-align: center;
@   vertical-align: bottom;
@   font-weight: bold;
@   color: #558195;
@   min-width: 200px;
@   white-space: nowrap;
@ }
@
@ /* The page title centered at the top of each page */
@ div.title {
@   display: table-cell;
@   font-size: 2em;
@   font-weight: bold;
@   text-align: center;
@   padding: 0 0 0 1em;
@   color: #558195;
@   vertical-align: bottom;
@   width: 100%;
@ }
@
@ /* The login status message in the top right-hand corner */
@ div.status {
@   display: table-cell;
@   text-align: right;
@   vertical-align: bottom;
@   color: #558195;
@   font-size: 0.8em;
@   font-weight: bold;
@   min-width: 200px;
@   white-space: nowrap;
@ }
@
@ /* The header across the top of the page */
@ div.header {
@   display: table;
@   width: 100%;
@ }
@
@ /* The main menu bar that appears at the top of the page beneath
@ ** the header */
@ div.mainmenu {
@   padding: 5px 10px 5px 10px;
@   font-size: 0.9em;
@   font-weight: bold;
@   text-align: center;
@   letter-spacing: 1px;
@   background-color: #558195;
@   border-top-left-radius: 8px;
@   border-top-right-radius: 8px;
@   color: white;
@ }
@
@ /* The submenu bar that *sometimes* appears below the main menu */
@ div.submenu, div.sectionmenu {
@   padding: 3px 10px 3px 0px;
@   font-size: 0.9em;
@   text-align: center;
@   background-color: #456878;
@   color: white;
@ }
@ div.mainmenu a, div.mainmenu a:visited, div.submenu a, div.submenu a:visited,
@ div.sectionmenu>a.button:link, div.sectionmenu>a.button:visited {
@   padding: 3px 10px 3px 10px;
@   color: white;
@   text-decoration: none;
@ }
@ div.mainmenu a:hover, div.submenu a:hover, div.sectionmenu>a.button:hover {
@   color: #558195;
@   background-color: white;
@ }
@
@ /* All page content from the bottom of the menu or submenu down to
@ ** the footer */
@ div.content {
@   padding: 0ex 1ex 1ex 1ex;
@   border: solid #aaa;
@   border-width: 1px;
@ }
@
@ /* Some pages have section dividers */
@ div.section {
@   margin-bottom: 0px;
@   margin-top: 1em;
@   padding: 1px 1px 1px 1px;
@   font-size: 1.2em;
@   font-weight: bold;
@   background-color: #558195;
@   color: white;
@   white-space: nowrap;
@ }
@
@ /* The "Date" that occurs on the left hand side of timelines */
@ div.divider {
@   background: #a1c4d4;
@   border: 2px #558195 solid;
@   font-size: 1em; font-weight: normal;
@   padding: .25em;
@   margin: .2em 0 .2em 0;
@   float: left;
@   clear: left;
@   white-space: nowrap;
@ }
@
@ /* The footer at the very bottom of the page */
@ div.footer {
@   clear: both;
@   font-size: 0.8em;
@   padding: 5px 10px 5px 10px;
@   text-align: right;
@   background-color: #558195;
@   border-bottom-left-radius: 8px;
@   border-bottom-right-radius: 8px;
@   color: white;
@ }
@
@ /* Hyperlink colors in the footer */
@ div.footer a { color: white; }
@ div.footer a:link { color: white; }
@ div.footer a:visited { color: white; }
@ div.footer a:hover { background-color: white; color: #558195; }
@
@ /* verbatim blocks */
@ pre.verbatim {
@   background-color: #f5f5f5;
@   padding: 0.5em;
@   white-space: pre-wrap;
@ }
@
@ /* The label/value pairs on (for example) the ci page */
@ table.label-value th {
@   vertical-align: top;
@   text-align: right;
@   padding: 0.2ex 2ex;
@ }');
@ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
@ <head>
@ <base href="$baseurl/$current_page" />
@ <title>$<project_name>: $<title></title>
@ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
@       href="$home/timeline.rss" />
@ <link rel="stylesheet" href="$stylesheet_url" type="text/css"
@       media="screen" />
@ </head>
@ <body>
@ <div class="header">
@   <div class="logo">
@     <th1>
@     ##
@     ## NOTE: The purpose of this procedure is to take the base URL of the
@     ##       Fossil project and return the root of the entire web site using
@     ##       the same URI scheme as the base URL (e.g. http or https).
@     ##
@     proc getLogoUrl { baseurl } {
@       set idx(first) [string first // $baseurl]
@       if {$idx(first) != -1} {
@         ##
@         ## NOTE: Skip second slash.
@         ##
@         set idx(first+1) [expr {$idx(first) + 2}]
@         ##
@         ## NOTE: (part 1) The [string first] command does NOT actually
@         ##       the optional startIndex argument as specified in the
@         ##       TH1 support manual; therefore, we fake it by using the
@         ##       [string range] command and then adding the necessary
@         ##       offset to the resulting index manually (below).  In Tcl,
@         ##       we could use the following instead:
@         ##
@         ##       set idx(next) [string first / $baseurl $idx(first+1)]
@         ##
@         set idx(nextRange) [string range $baseurl $idx(first+1) end]
@         set idx(next) [string first / $idx(nextRange)]
@         if {$idx(next) != -1} {
@           ##
@           ## NOTE: (part 2) Add the necessary offset to the result of the
@           ##       search for the next slash (i.e. the one after the initial
@           ##       search for the two slashes).
@           ##
@           set idx(next) [expr {$idx(next) + $idx(first+1)}]
@           ##
@           ## NOTE: Back up one character from the next slash.
@           ##
@           set idx(next-1) [expr {$idx(next) - 1}]
@           ##
@           ## NOTE: Extract the URI scheme and host from the base URL.
@           ##
@           set scheme [string range $baseurl 0 $idx(first)]
@           set host [string range $baseurl $idx(first+1) $idx(next-1)]
@           ##
@           ## NOTE: Try to stay in SSL mode if we are there now.
@           ##
@           if {[string compare $scheme http:/] == 0} {
@             set scheme http://
@           } else {
@             set scheme https://
@           }
@           set logourl $scheme$host/
@         } else {
@           set logourl $baseurl
@         }
@       } else {
@         set logourl $baseurl
@       }
@       return $logourl
@     }
@     set logourl [getLogoUrl $baseurl]
@     </th1>
@     <a href="$logourl">
@       <img src="$logo_image_url" border="0" alt="$project_name">
@     </a>
@   </div>
@   <div class="title"><small>$<project_name></small><br />$<title></div>
@   <div class="status"><th1>
@      if {[info exists login]} {
@        puts "Logged in as $login"
@      } else {
@        puts "Not logged in"
@      }
@   </th1></div>
@ </div>
@ <div class="mainmenu">
@ <th1>
@ html "<a href=''$home$index_page''>Home</a>\n"
@ if {[anycap jor]} {
@   html "<a href=''$home/timeline''>Timeline</a>\n"
@ }
@ if {[hascap oh]} {
@   html "<a href=''$home/tree?ci=tip''>Files</a>\n"
@ }
@ if {[hascap o]} {
@   html "<a href=''$home/brlist''>Branches</a>\n"
@   html "<a href=''$home/taglist''>Tags</a>\n"
@ }
@ if {[hascap r]} {
@   html "<a href=''$home/reportlist''>Tickets</a>\n"
@ }
@ if {[hascap j]} {
@   html "<a href=''$home/wiki''>Wiki</a>\n"
@ }
@ if {[hascap s]} {
@   html "<a href=''$home/setup''>Admin</a>\n"
@ } elseif {[hascap a]} {
@   html "<a href=''$home/setup_ulist''>Users</a>\n"
@ }
@ if {[info exists login]} {
@   html "<a href=''$home/login''>Logout</a>\n"
@ } else {
@   html "<a href=''$home/login''>Login</a>\n"
@ }
@ </th1></div>
@ ');
@ REPLACE INTO config(name,mtime,value)
@ VALUES('footer',now(),'<div class="footer">
@   <th1>
@   proc getTclVersion {} {
@     if {[catch {tclEval info patchlevel} tclVersion] == 0} {
@       return "<a href=\"http://www.tcl.tk/\">Tcl</a> version $tclVersion"
@     }
@     return ""
@   }
@   proc getVersion { version } {
@     set length [string length $version]
@     return [string range $version 1 [expr {$length - 2}]]
@   }
@   set version [getVersion $manifest_version]
@   set tclVersion [getTclVersion]
@   set fossilUrl http://www.fossil-scm.org
@   </th1>
@   This page was generated in about
@   <th1>puts [expr {([utime]+[stime]+1000)/1000*0.001}]</th1>s by
@   <a href="$fossilUrl/">Fossil</a>
@   version $release_version $tclVersion
@   <a href="$fossilUrl/index.html/info/$version">$manifest_version</a>
@   <a href="$fossilUrl/index.html/timeline?c=$manifest_date&amp;y=ci">$manifest_date</a>
@ </div>
@ </body></html>
@ ');
;

/*
** An array of available built-in skins.
*/
static struct BuiltinSkin {
  const char *zName;
  const char *zValue;


} aBuiltinSkin[] = {
  { "Default",                     0 /* Filled in at runtime */ },
  { "Plain Gray, No Logo",         zBuiltinSkin1                },
  { "Khaki, No Logo",              zBuiltinSkin2                },
  { "Black & White, Menu on Left", zBuiltinSkin3                },
  { "Shadow boxes & Rounded Corners", zBuiltinSkin4             },
  { "Enhanced Default",            zBuiltinSkin5                },


};

/*
** For a skin named zSkinName, compute the name of the CONFIG table
** entry where that skin is stored and return it.
**
** Return NULL if zSkinName is NULL or an empty string.
................................................................................
    free(z);
    z = 0;
  }
  return z;
}

/*












** Construct and return a string that represents the current skin if
** useDefault==0 or a string for the default skin if useDefault==1.



**
** Memory to hold the returned string is obtained from malloc.
*/
static char *getSkin(int useDefault){




  Blob val;
  blob_zero(&val);













  blob_appendf(&val,
     "REPLACE INTO config(name,value,mtime) VALUES('css',%Q,now());\n",
     useDefault ? zDefaultCSS : db_get("css", (char*)zDefaultCSS)

  );
  blob_appendf(&val,
     "REPLACE INTO config(name,value,mtime) VALUES('header',%Q,now());\n",
     useDefault ? zDefaultHeader : db_get("header", (char*)zDefaultHeader)









































  );
  blob_appendf(&val,
     "REPLACE INTO config(name,value,mtime) VALUES('footer',%Q,now());\n",
     useDefault ? zDefaultFooter : db_get("footer", (char*)zDefaultFooter)
  );
  return blob_str(&val);
}

/*
** Construct the default skin string and fill in the corresponding
** entry in aBuildinSkin[]


*/
static void setDefaultSkin(void){
  aBuiltinSkin[0].zValue = getSkin(1);

































}

/*
** WEBPAGE: setup_skin
*/
void setup_skin(void){
  const char *z;
  char *zName;
  char *zErr = 0;
  const char *zCurrent;  /* Current skin */
  int i;                 /* Loop counter */
  Stmt q;


  login_check_credentials();
  if( !g.perm.Setup ){
    login_needed();
  }
  db_begin_transaction();





  /* Process requests to delete a user-defined skin */
  if( P("del1") && (zName = skinVarName(P("sn"), 1))!=0 ){
    style_header("Confirm Custom Skin Delete");
    @ <form action="%s(g.zTop)/setup_skin" method="post"><div>
    @ <p>Deletion of a custom skin is a permanent action that cannot
    @ be undone.  Please confirm that this is what you want to do:</p>
................................................................................
    @ </div></form>
    style_footer();
    return;
  }
  if( P("del2")!=0 && (zName = skinVarName(P("sn"), 1))!=0 ){
    db_multi_exec("DELETE FROM config WHERE name=%Q", zName);
  }


  setDefaultSkin();
  zCurrent = getSkin(0);

  if( P("save")!=0 && (zName = skinVarName(P("save"),0))!=0 ){
    if( db_exists("SELECT 1 FROM config WHERE name=%Q", zName)
          || fossil_strcmp(zName, "Default")==0 ){
      zErr = mprintf("Skin name \"%h\" already exists. "
                     "Choose a different name.", P("sn"));
    }else{
      db_multi_exec("INSERT INTO config(name,value,mtime) VALUES(%Q,%Q,now())",
         zName, zCurrent
      );
    }
  }

  /* The user pressed the "Use This Skin" button. */
  if( P("load") && (z = P("sn"))!=0 && z[0] ){
    int seen = 0;




    for(i=0; i<sizeof(aBuiltinSkin)/sizeof(aBuiltinSkin[0]); i++){
      if( fossil_strcmp(aBuiltinSkin[i].zValue, zCurrent)==0 ){
        seen = 1;
        break;
      }
    }
    if( !seen ){
      seen = db_exists("SELECT 1 FROM config WHERE name GLOB 'skin:*'"
                       " AND value=%Q", zCurrent);
    }
    if( !seen ){
      db_multi_exec(
        "INSERT INTO config(name,value,mtime) VALUES("
        "  strftime('skin:Backup On %%Y-%%m-%%d %%H:%%M:%%S'),"
        "  %Q,now())", zCurrent
      );

    }
    seen = 0;
    for(i=0; i<sizeof(aBuiltinSkin)/sizeof(aBuiltinSkin[0]); i++){
      if( fossil_strcmp(aBuiltinSkin[i].zName, z)==0 ){
        seen = 1;
        zCurrent = aBuiltinSkin[i].zValue;
        db_multi_exec("%s", zCurrent/*safe-for-%s*/);
        break;
      }
    }
    if( !seen ){
      zName = skinVarName(z,0);
      zCurrent = db_get(zName, 0);
................................................................................

  style_header("Skins");
  if( zErr ){
    @ <p><font color="red">%h(zErr)</font></p>
  }
  @ <p>A "skin" is a combination of
  @ <a href="setup_editcss">CSS</a>,
  @ <a href="setup_header">Header</a>,
  @ <a href="setup_footer">Footer</a>, and
  @ <a href="setup_logo">Logo</a> that determines the look and feel
  @ of the web interface.</p>
  @
  @ <h2>Available Skins:</h2>
  @ <ol>
  for(i=0; i<sizeof(aBuiltinSkin)/sizeof(aBuiltinSkin[0]); i++){
    z = aBuiltinSkin[i].zName;

    if( fossil_strcmp(aBuiltinSkin[i].zValue, zCurrent)==0 ){
      @ <li><p>%h(z).&nbsp;&nbsp; <b>Currently In Use</b></p>

    }else{
      @ <li><form action="%s(g.zTop)/setup_skin" method="post"><div>
      @ %h(z).&nbsp;&nbsp;
      @ <input type="hidden" name="sn" value="%h(z)" />
      @ <input type="submit" name="load" value="Use This Skin" />
      @ </div></form></li>
    }

  }
  db_prepare(&q,
     "SELECT substr(name, 6), value FROM config"
     " WHERE name GLOB 'skin:*'"
     " ORDER BY name"
  );
  while( db_step(&q)==SQLITE_ROW ){
    const char *zN = db_column_text(&q, 0);
    const char *zV = db_column_text(&q, 1);



    if( fossil_strcmp(zV, zCurrent)==0 ){
      @ <li><p>%h(zN).&nbsp;&nbsp;  <b>Currently In Use</b></p>

    }else{
      @ <li><form action="%s(g.zTop)/setup_skin" method="post">
      @ %h(zN).&nbsp;&nbsp;
      @ <input type="hidden" name="sn" value="%h(zN)">
      @ <input type="submit" name="load" value="Use This Skin">
      @ <input type="submit" name="del1" value="Delete This Skin">
      @ </form></li>
    }



  }
  db_finalize(&q);





  @ </ol>


  style_footer();
  db_end_transaction(0);
}







<

<
<
>
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
>
|
<
<
>
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
>
>

<
<
<
<
>
>

<
<
<
<
<
<
>

<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<

|
<
>
>

|
|
|
|
|
|
>
>







 







>
>
>
>
>
>
>
>
>
>
>
>
|
<
>
>
>



|
>
>
>
>


>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
<
>
|
<
<
<
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

<
<
<
<
|



<
<
>
>

<
<
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>









|
|

>






>
>
>
>







 







<
>
|
<

<
<
<
<
<
<
<
<
<
<
<
<
|


>
>
>
>

|







<
|
|
|
|
|
|
>



|

|







 







|
|
<



|

|
>
|
|
>

|
<

|
|

>









>
>
>

|
>

<
<
<
|
|
<

>
>
>


>
>
>
>
>
|
>
>



17
18
19
20
21
22
23

24


25
26








































































































































































































27
28


29
30















































































































































































































































































































































































































































































































































































































































































































































31
32
33




34
35
36






37
38






































































































































































































































































































39
40

41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
..
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86

87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114

115
116



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158




159
160
161
162


163
164
165


166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
...
233
234
235
236
237
238
239

240
241

242












243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258

259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
...
282
283
284
285
286
287
288
289
290

291
292
293
294
295
296
297
298
299
300
301
302

303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323



324
325

326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
**
** Implementation of the Setup page for "skins".
*/
#include "config.h"
#include <assert.h>
#include "skins.h"


/*


** An array of available built-in skins.
**








































































































































































































** To add new built-in skins:
**


**    1.  Pick a name for the new skin.  (Here we use "xyzzy").
**















































































































































































































































































































































































































































































































































































































































































































































**    2.  Install files skins/xyzzy/css.txt, skins/xyzzy/header.txt, 
**        and skins/xyzzy/footer.txt into the source tree.
**




**    3.  Rerun "tclsh makemake.tcl" in the src/ folder in order to
**        rebuild the makefiles to reference the new CSS, headers, and footers.
**






**    4.  Make an entry in the following array for the new skin.
*/






































































































































































































































































































static struct BuiltinSkin {
  const char *zDesc;    /* Description of this skin */

  const char *zLabel;   /* The directory under skins/ holding this skin */
  char *zSQL;           /* Filled in at run-time with SQL to insert this skin */
} aBuiltinSkin[] = {
  { "Default",                           "default",           0 },
  { "Plain Gray, No Logo",               "plain_gray",        0 },
  { "Khaki, No Logo",                    "khaki",             0 },
  { "Black & White, Menu on Left",       "black_and_white",   0 }, 
  { "Shadow boxes & Rounded Corners",    "rounded1",          0 },
  { "Enhanced Default",                  "enhanced1",         0 },
  { "San Francisco Modern",              "etienne1",          0 },
  { "Eagle",                             "eagle",             0 },
};

/*
** For a skin named zSkinName, compute the name of the CONFIG table
** entry where that skin is stored and return it.
**
** Return NULL if zSkinName is NULL or an empty string.
................................................................................
    free(z);
    z = 0;
  }
  return z;
}

/*
** Return true if there exists a skin name "zSkinName".
*/
static int skinExists(const char *zSkinName){
  int i;
  if( zSkinName==0 ) return 0;
  for(i=0; i<sizeof(aBuiltinSkin)/sizeof(aBuiltinSkin[0]); i++){
    if( fossil_strcmp(zSkinName, aBuiltinSkin[i].zDesc)==0 ) return 1;
  }
  return db_exists("SELECT 1 FROM config WHERE name='skin:%q'", zSkinName);
}

/*
** Construct and return an string of SQL statements that represents

** a "skin" setting.  If zName==0 then return the skin currently
** installed.  Otherwise, return one of the built-in skins designated
** by zName.
**
** Memory to hold the returned string is obtained from malloc.
*/
static char *getSkin(const char *zName){
  const char *z;
  char *zLabel;
  static const char *azType[] = { "css", "header", "footer" };
  int i;
  Blob val;
  blob_zero(&val);
  for(i=0; i<sizeof(azType)/sizeof(azType[0]); i++){
    if( zName ){
      zLabel = mprintf("skins/%s/%s.txt", zName, azType[i]);
      z = builtin_text(zLabel);
      fossil_free(zLabel);
    }else{
      z = db_get(azType[i], 0);
      if( z==0 ){
        zLabel = mprintf("skins/default/%s.txt", azType[i]);
        z = builtin_text(zLabel);
        fossil_free(zLabel);
      }
    }
    blob_appendf(&val,
       "REPLACE INTO config(name,value,mtime) VALUES(%Q,%Q,now());\n",

       azType[i], z
    );



  }
  return blob_str(&val);
}

/*
** Respond to a Rename button press.  Return TRUE if a dialog was painted.
** Return FALSE to continue with the main Skins page.
*/
static int skinRename(void){
  const char *zOldName;
  const char *zNewName;
  int ex = 0;
  if( P("rename")==0 ) return 0;
  zOldName = P("sn");
  zNewName = P("newname");
  if( zOldName==0 ) return 0;
  if( zNewName==0 || zNewName[0]==0 || (ex = skinExists(zNewName))!=0 ){
    if( zNewName==0 ) zNewName = zOldName;
    style_header("Rename A Skin");
    if( ex ){
      @ <p><span class="generalError">There is already another skin
      @ named "%h(zNewName)".  Choose a different name.</span></p>
    }
    @ <form action="%s(g.zTop)/setup_skin" method="post"><div>
    @ <table border="0"><tr>
    @ <tr><td align="right">Current name:<td align="left"><b>%h(zOldName)</b>
    @ <tr><td align="right">New name:<td align="left">
    @ <input type="text" size="35" name="newname" value="%h(zNewName)">
    @ <tr><td><td>
    @ <input type="hidden" name="sn" value="%h(zOldName)">
    @ <input type="submit" name="rename" value="Rename">
    @ <input type="submit" name="canren" value="Cancel">
    @ </table>
    login_insert_csrf_secret();
    @ </div></form>
    style_footer();
    return 1;
  }
  db_multi_exec(
    "UPDATE config SET name='skin:%q' WHERE name='skin:%q';",
    zNewName, zOldName
  );




  return 0;
}

/*


** Respond to a Save button press.  Return TRUE if a dialog was painted.
** Return FALSE to continue with the main Skins page.
*/


static int skinSave(const char *zCurrent){
  const char *zNewName;
  int ex = 0;
  if( P("save")==0 ) return 0;
  zNewName = P("svname");
  if( zNewName && zNewName[0]!=0 ){
  }
  if( zNewName==0 || zNewName[0]==0 || (ex = skinExists(zNewName))!=0 ){
    if( zNewName==0 ) zNewName = "";
    style_header("Save Current Skin");
    if( ex ){
      @ <p><span class="generalError">There is already another skin
      @ named "%h(zNewName)".  Choose a different name.</span></p>
    }
    @ <form action="%s(g.zTop)/setup_skin" method="post"><div>
    @ <table border="0"><tr>
    @ <tr><td align="right">Name for this skin:<td align="left">
    @ <input type="text" size="35" name="svname" value="%h(zNewName)">
    @ <tr><td><td>
    @ <input type="submit" name="save" value="Save">
    @ <input type="submit" name="cansave" value="Cancel">
    @ </table>
    login_insert_csrf_secret();
    @ </div></form>
    style_footer();
    return 1;
  }
  db_multi_exec(
    "INSERT OR IGNORE INTO config(name, value, mtime)"
    "VALUES('skin:%q',%Q,now())",
    zNewName, zCurrent
  );
  return 0;
}

/*
** WEBPAGE: setup_skin
*/
void setup_skin(void){
  const char *z;
  char *zName;
  char *zErr = 0;
  const char *zCurrent = 0;  /* Current skin */
  int i;                     /* Loop counter */
  Stmt q;
  int seenCurrent = 0;

  login_check_credentials();
  if( !g.perm.Setup ){
    login_needed();
  }
  db_begin_transaction();
  zCurrent = getSkin(0);
  for(i=0; i<sizeof(aBuiltinSkin)/sizeof(aBuiltinSkin[0]); i++){
    aBuiltinSkin[i].zSQL = getSkin(aBuiltinSkin[i].zLabel);
  }

  /* Process requests to delete a user-defined skin */
  if( P("del1") && (zName = skinVarName(P("sn"), 1))!=0 ){
    style_header("Confirm Custom Skin Delete");
    @ <form action="%s(g.zTop)/setup_skin" method="post"><div>
    @ <p>Deletion of a custom skin is a permanent action that cannot
    @ be undone.  Please confirm that this is what you want to do:</p>
................................................................................
    @ </div></form>
    style_footer();
    return;
  }
  if( P("del2")!=0 && (zName = skinVarName(P("sn"), 1))!=0 ){
    db_multi_exec("DELETE FROM config WHERE name=%Q", zName);
  }

  if( skinRename() ) return;
  if( skinSave(zCurrent) ) return;














  /* The user pressed one of the "Install" buttons. */
  if( P("load") && (z = P("sn"))!=0 && z[0] ){
    int seen = 0;

    /* Check to see if the current skin is already saved.  If it is, there
    ** is no need to create a backup */
    zCurrent = getSkin(0);
    for(i=0; i<sizeof(aBuiltinSkin)/sizeof(aBuiltinSkin[0]); i++){
      if( fossil_strcmp(aBuiltinSkin[i].zSQL, zCurrent)==0 ){
        seen = 1;
        break;
      }
    }
    if( !seen ){
      seen = db_exists("SELECT 1 FROM config WHERE name GLOB 'skin:*'"
                       " AND value=%Q", zCurrent);

      if( !seen ){
        db_multi_exec(
          "INSERT INTO config(name,value,mtime) VALUES("
          "  strftime('skin:Backup On %%Y-%%m-%%d %%H:%%M:%%S'),"
          "  %Q,now())", zCurrent
        );
      }
    }
    seen = 0;
    for(i=0; i<sizeof(aBuiltinSkin)/sizeof(aBuiltinSkin[0]); i++){
      if( fossil_strcmp(aBuiltinSkin[i].zDesc, z)==0 ){
        seen = 1;
        zCurrent = aBuiltinSkin[i].zSQL;
        db_multi_exec("%s", zCurrent/*safe-for-%s*/);
        break;
      }
    }
    if( !seen ){
      zName = skinVarName(z,0);
      zCurrent = db_get(zName, 0);
................................................................................

  style_header("Skins");
  if( zErr ){
    @ <p><font color="red">%h(zErr)</font></p>
  }
  @ <p>A "skin" is a combination of
  @ <a href="setup_editcss">CSS</a>,
  @ <a href="setup_header">Header</a>, and
  @ <a href="setup_footer">Footer</a> that determines the look and feel

  @ of the web interface.</p>
  @
  @ <h2>Available Skins:</h2>
  @ <table border="0">
  for(i=0; i<sizeof(aBuiltinSkin)/sizeof(aBuiltinSkin[0]); i++){
    z = aBuiltinSkin[i].zDesc;
    @ <tr><td>%d(i+1).<td>%h(z)<td>&nbsp;&nbsp;<td>
    if( fossil_strcmp(aBuiltinSkin[i].zSQL, zCurrent)==0 ){
      @ (Currently In Use)
      seenCurrent = 1;
    }else{
      @ <form action="%s(g.zTop)/setup_skin" method="post">

      @ <input type="hidden" name="sn" value="%h(z)" />
      @ <input type="submit" name="load" value="Install" />
      @ </form>
    }
    @ </tr>
  }
  db_prepare(&q,
     "SELECT substr(name, 6), value FROM config"
     " WHERE name GLOB 'skin:*'"
     " ORDER BY name"
  );
  while( db_step(&q)==SQLITE_ROW ){
    const char *zN = db_column_text(&q, 0);
    const char *zV = db_column_text(&q, 1);
    i++;
    @ <tr><td>%d(i).<td>%h(zN)<td>&nbsp;&nbsp;<td>
    @ <form action="%s(g.zTop)/setup_skin" method="post">
    if( fossil_strcmp(zV, zCurrent)==0 ){
      @ (Currently In Use)
      seenCurrent = 1;
    }else{



      @ <input type="submit" name="load" value="Install">
      @ <input type="submit" name="del1" value="Delete">

    }
    @ <input type="submit" name="rename" value="Rename">
    @ <input type="hidden" name="sn" value="%h(zN)">
    @ </form></tr>
  }
  db_finalize(&q);
  if( !seenCurrent ){
    i++;
    @ <tr><td>%d(i).<td><i>Current Configuration</i><td>&nbsp;&nbsp;<td>
    @ <form action="%s(g.zTop)/setup_skin" method="post">
    @ <input type="submit" name="save" value="Save">
    @ </form>
  }
  @ </table>
  style_footer();
  db_end_transaction(0);
}

Changes to src/sqlcmd.c.

106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
...
130
131
132
133
134
135
136

137

138
139
140
141
142
143
144
...
145
146
147
148
149
150
151
152

153
154
155
156





























157
158
159
160
161
162
163
    sqlite3_result_blob(context, pOut, nOut, sqlite3_free);
  }else{
    sqlite3_result_error(context, "input is not zlib compressed", -1);
  }
}

/*
** Add the content(), compress(), and decompress() SQL functions to 
** database connection db.
*/
int add_content_sql_commands(sqlite3 *db){
  sqlite3_create_function(db, "content", 1, SQLITE_UTF8, 0,
                          sqlcmd_content, 0, 0);
  sqlite3_create_function(db, "compress", 1, SQLITE_UTF8, 0,
                          sqlcmd_compress, 0, 0);
................................................................................
*/
static int sqlcmd_autoinit(
  sqlite3 *db,
  const char **pzErrMsg,
  const void *notUsed
){
  add_content_sql_commands(db);

  re_add_sql_func(db);

  g.zMainDbType = "repository";
  foci_register(db);
  g.repositoryOpen = 1;
  g.db = db;
  return SQLITE_OK;
}

................................................................................
/*
** COMMAND: sqlite3
**
** Usage: %fossil sqlite3 ?DATABASE? ?OPTIONS?
**
** Run the standalone sqlite3 command-line shell on DATABASE with OPTIONS.
** If DATABASE is omitted, then the repository that serves the working
** directory is opened.

**
** WARNING:  Careless use of this command can corrupt a Fossil repository
** in ways that are unrecoverable.  Be sure you know what you are doing before
** running any SQL commands that modifies the repository database.





























*/
void cmd_sqlite3(void){
  extern int sqlite3_shell(int, char**);
  db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
  db_close(1);
  sqlite3_shutdown();
  sqlite3_shell(g.argc-1, g.argv+1);







|







 







>

>







 







|
>




>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
...
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
...
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
    sqlite3_result_blob(context, pOut, nOut, sqlite3_free);
  }else{
    sqlite3_result_error(context, "input is not zlib compressed", -1);
  }
}

/*
** Add the content(), compress(), and decompress() SQL functions to
** database connection db.
*/
int add_content_sql_commands(sqlite3 *db){
  sqlite3_create_function(db, "content", 1, SQLITE_UTF8, 0,
                          sqlcmd_content, 0, 0);
  sqlite3_create_function(db, "compress", 1, SQLITE_UTF8, 0,
                          sqlcmd_compress, 0, 0);
................................................................................
*/
static int sqlcmd_autoinit(
  sqlite3 *db,
  const char **pzErrMsg,
  const void *notUsed
){
  add_content_sql_commands(db);
  db_add_aux_functions(db);
  re_add_sql_func(db);
  search_sql_setup(db);
  g.zMainDbType = "repository";
  foci_register(db);
  g.repositoryOpen = 1;
  g.db = db;
  return SQLITE_OK;
}

................................................................................
/*
** COMMAND: sqlite3
**
** Usage: %fossil sqlite3 ?DATABASE? ?OPTIONS?
**
** Run the standalone sqlite3 command-line shell on DATABASE with OPTIONS.
** If DATABASE is omitted, then the repository that serves the working
** directory is opened.  See https://www.sqlite.org/cli.html for additional
** information.
**
** WARNING:  Careless use of this command can corrupt a Fossil repository
** in ways that are unrecoverable.  Be sure you know what you are doing before
** running any SQL commands that modifies the repository database.
**
** The following extensions to the usual SQLite commands are provided:
**
**    content(X)                Return the contenxt of artifact X.  X can be a
**                              SHA1 hash or prefix or a tag.
**
**    compress(X)               Compress text X.
**
**    decompress(X)             Decompress text X.  Undoes the work of
**                              compress(X).
**
**    checkin_mtime(X,Y)        Return the mtime for the file Y (a BLOB.RID)
**                              found in check-in X (another BLOB.RID value).
**
**    symbolic_name_to_rid(X)   Return a the BLOB.RID corresponding to symbolic
**                              name X.
**
**    now()                     Return the number of seconds since 1970.
**
**    REGEXP                    The REGEXP operator works, unlike in
**                              standard SQLite.
**
**    files_of_checkin          The "files_of_check" virtual table is
**                              available for decoding manifests.
**
** Usage example for files_of_checkin:
**
**     CREATE VIRTUAL TABLE temp.foci USING files_of_checkin;
**     SELECT * FROM foci WHERE checkinID=symbolic_name_to_rid('trunk');
*/
void cmd_sqlite3(void){
  extern int sqlite3_shell(int, char**);
  db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
  db_close(1);
  sqlite3_shutdown();
  sqlite3_shell(g.argc-1, g.argv+1);

Changes to src/sqlite3.c.

1
2
3
4
5
6
7
8
9
10
..
39
40
41
42
43
44
45















































46
47
48
49
50
51
52
...
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
...
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
....
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
....
1870
1871
1872
1873
1874
1875
1876











1877
1878
1879
1880
1881
1882
1883
....
1896
1897
1898
1899
1900
1901
1902

1903
1904
1905
1906
1907
1908
1909
....
7305
7306
7307
7308
7309
7310
7311
7312
7313
7314
7315
7316
7317
7318
7319
7320
7321
7322
7323
7324
....
7601
7602
7603
7604
7605
7606
7607




7608
7609
7610
7611
7612
7613
7614
....
7646
7647
7648
7649
7650
7651
7652
7653







7654
7655
7656
7657
7658
7659
7660
....
7664
7665
7666
7667
7668
7669
7670
7671
7672
7673
7674
7675
7676
7677
7678
7679
7680
....
9098
9099
9100
9101
9102
9103
9104
9105
9106
9107
9108
9109
9110
9111
9112
....
9213
9214
9215
9216
9217
9218
9219





9220
9221
9222
9223
9224
9225
9226
9227
9228
9229

9230
9231
9232
9233
9234
9235
9236
.....
10004
10005
10006
10007
10008
10009
10010

10011
10012
10013
10014
10015
10016
10017
.....
10745
10746
10747
10748
10749
10750
10751

10752
10753
10754
10755
10756
10757
10758
.....
10846
10847
10848
10849
10850
10851
10852
10853

10854
10855
10856
10857
10858
10859
10860
.....
11470
11471
11472
11473
11474
11475
11476
11477
11478
11479
11480
11481
11482
11483
11484
.....
12034
12035
12036
12037
12038
12039
12040
12041
12042
12043
12044
12045
12046
12047
12048
.....
12524
12525
12526
12527
12528
12529
12530

12531
12532
12533
12534
12535
12536
12537
.....
12661
12662
12663
12664
12665
12666
12667
12668
12669
12670
12671
12672
12673
12674
12675
.....
13446
13447
13448
13449
13450
13451
13452
13453
13454
13455
13456
13457
13458
13459
13460
.....
13659
13660
13661
13662
13663
13664
13665







13666
13667
13668
13669
13670
13671
13672
.....
13689
13690
13691
13692
13693
13694
13695

13696
13697
13698
13699
13700
13701
13702
.....
13795
13796
13797
13798
13799
13800
13801
13802
13803
13804
13805
13806
13807
13808
13809
13810
13811
13812
13813
13814
13815
13816
13817
13818
13819
13820
13821
13822
13823
13824
13825
13826
13827
13828
13829
13830
13831
13832
13833
13834
13835
13836
13837
13838
13839
13840
13841
13842
13843
13844
13845
13846
13847
13848
13849
13850
13851
13852
13853
13854
13855
13856
13857
13858
13859
13860
13861
13862
13863
13864
13865
13866
13867
13868
13869
13870
13871
13872
13873
13874
13875
13876
13877
13878
13879
13880
13881
13882
13883
13884
13885
13886
13887
13888
13889
13890
13891
13892
13893
13894
13895
13896
13897
13898
13899
13900
13901
13902
13903
13904
13905
13906
13907
13908
13909
13910
13911
13912
13913
13914
13915
13916
13917
13918
13919
13920
13921
13922
13923
13924
13925
13926
13927
13928
13929
13930
13931
13932
13933
13934
13935
13936
13937
13938
13939
13940
13941
13942
13943
13944
13945
13946
13947
13948
13949
13950
13951
13952
13953
13954
13955
13956
13957
13958
13959
13960
13961
13962
13963
13964
13965
13966
13967
13968
13969
13970
13971
13972
13973
13974
13975
13976
13977
13978
13979
13980
13981
13982
13983
13984
13985
13986
13987
13988
13989
13990
13991
13992
13993
13994
13995
13996
13997
13998
13999
14000
14001
14002
14003
14004
14005
14006
14007
14008
14009
14010
14011
14012
14013
14014
14015
14016
14017
14018
14019
14020
14021
14022
14023
14024
14025
14026
14027
14028
14029
14030
14031
14032
14033
14034
14035
14036
14037
14038
14039
14040
14041
14042
14043
14044
14045
14046
14047
14048
14049
14050
14051
14052
14053
14054
14055
14056
14057
14058
14059
14060
14061
14062
14063
14064
14065
14066
14067
14068
14069
14070
14071
14072
14073
14074
14075
14076
14077
14078
14079
14080
14081
14082
14083
14084
14085
14086
14087
14088
14089
14090
14091
14092
14093
14094
14095
14096
14097
14098
14099
14100
14101
14102
14103
14104
14105
14106
14107
14108
14109
14110
14111
14112
14113
14114
14115
14116
14117
14118
14119
14120
14121
14122
14123
14124
14125
14126
14127
14128
14129
14130
14131
14132
14133
14134
14135
14136
14137
14138
14139
14140
14141
14142
14143
14144
14145
14146
14147
14148
14149
14150
14151
14152
14153
.....
14154
14155
14156
14157
14158
14159
14160
14161
14162
14163
14164
14165
14166
14167
14168
.....
15382
15383
15384
15385
15386
15387
15388
15389
15390

15391
15392
15393
15394
15395
15396
15397
.....
15403
15404
15405
15406
15407
15408
15409
15410
15411
15412
15413
15414
15415
15416
15417
15418
.....
15421
15422
15423
15424
15425
15426
15427
15428
15429
15430
15431
15432
15433
15434
15435
.....
15865
15866
15867
15868
15869
15870
15871
15872
15873


15874
15875
15876
15877
15878
15879
15880
.....
16060
16061
16062
16063
16064
16065
16066
16067
16068
16069
16070
16071
16072
16073
16074
.....
16734
16735
16736
16737
16738
16739
16740
16741
16742
16743
16744
16745
16746
16747
16748
16749
16750
.....
19974
19975
19976
19977
19978
19979
19980






19981
19982
19983
19984
19985
19986
19987
.....
20969
20970
20971
20972
20973
20974
20975
20976
20977
20978
20979
20980
20981
20982
20983
20984
20985
20986
20987
20988
20989
20990
20991
20992
20993
.....
22278
22279
22280
22281
22282
22283
22284


22285
22286
22287
22288
22289
22290
22291
.....
23064
23065
23066
23067
23068
23069
23070
23071
23072
23073
23074
23075
23076
23077
23078
.....
23105
23106
23107
23108
23109
23110
23111
23112
23113
23114
23115
23116
23117
23118
23119
.....
23135
23136
23137
23138
23139
23140
23141
23142
23143
23144
23145
23146
23147
23148
23149
23150
23151
.....
28458
28459
28460
28461
28462
28463
28464
28465
28466
28467
28468
28469
28470
28471
28472
28473
28474
.....
28781
28782
28783
28784
28785
28786
28787
28788
28789
28790
28791

28792
28793
28794

28795
28796
28797
28798
28799
28800
28801



28802
28803
28804
28805




28806
28807
28808
28809
28810
28811
28812
.....
34016
34017
34018
34019
34020
34021
34022
34023
34024
34025
34026
34027
34028
34029
34030
34031
.....
35292
35293
35294
35295
35296
35297
35298
35299
35300
35301
35302
35303
35304
35305
35306
.....
35324
35325
35326
35327
35328
35329
35330
35331
35332
35333
35334
35335
35336
35337
35338
.....
35396
35397
35398
35399
35400
35401
35402
35403
35404
35405
35406
35407
35408
35409
35410
35411
35412
35413
35414
35415
35416
35417
35418
35419
35420
35421
35422
35423
35424
35425
35426
35427
35428
35429
35430
35431
35432
35433
35434
35435
35436
35437
35438
35439
35440
35441
35442
35443
35444
.....
38811
38812
38813
38814
38815
38816
38817
38818
38819
38820
38821
38822
38823
38824
38825
38826
38827
38828
38829
38830
38831
38832
38833
38834
38835
38836
.....
38976
38977
38978
38979
38980
38981
38982
38983

38984
38985
38986
38987
38988
38989
38990
.....
39435
39436
39437
39438
39439
39440
39441
39442
39443
39444
39445
39446
39447
39448
39449
.....
39751
39752
39753
39754
39755
39756
39757
39758
39759
39760
39761
39762
39763
39764
39765
.....
40439
40440
40441
40442
40443
40444
40445
40446
40447
40448
40449
40450
40451
40452
40453
.....
41797
41798
41799
41800
41801
41802
41803


41804
41805
41806
41807
41808
41809
41810
.....
41814
41815
41816
41817
41818
41819
41820

41821
41822
41823
41824
41825
41826
41827
41828
41829
41830
.....
42832
42833
42834
42835
42836
42837
42838

42839
42840
42841








42842
42843
42844
42845
42846
42847
42848
.....
45038
45039
45040
45041
45042
45043
45044
45045
45046
45047
45048
45049
45050
45051
45052
.....
46269
46270
46271
46272
46273
46274
46275
46276
46277
46278
46279
46280
46281
46282
46283
46284
46285
46286
46287
46288
46289
46290
46291
46292
.....
46443
46444
46445
46446
46447
46448
46449

46450
46451
46452
46453
46454
46455
46456
.....
46592
46593
46594
46595
46596
46597
46598

46599
46600
46601
46602
46603
46604
46605
.....
47458
47459
47460
47461
47462
47463
47464

47465
47466
47467
47468
47469
47470
47471
.....
50109
50110
50111
50112
50113
50114
50115
50116
50117
50118
50119
50120
50121
50122
50123
50124
50125
50126
50127
50128
50129
50130
50131
50132
50133
50134
50135
50136
50137
50138
50139
50140
50141
50142
50143
50144
50145
50146
50147
50148
50149
50150
50151
50152
50153
50154
50155
50156
50157
50158
50159
50160
50161
50162
50163
50164
50165
50166
50167
50168
50169
50170
50171
50172
50173
50174
50175
50176
50177
50178
50179
50180
50181
50182
50183
50184
50185
50186
50187
50188
50189
50190
50191
50192
50193
50194


50195
50196
50197
50198
50199
50200
50201
50202
50203
50204
50205
50206
50207
50208
50209
50210
50211
50212
50213
50214
50215
50216
50217
50218
50219
50220
50221
50222
50223
50224
50225
50226
50227

50228
50229
50230
50231
50232
50233
50234
.....
50235
50236
50237
50238
50239
50240
50241
50242
50243
50244
50245
50246
50247
50248
50249
.....
50827
50828
50829
50830
50831
50832
50833
50834
50835
50836
50837
50838
50839
50840
50841
.....
51933
51934
51935
51936
51937
51938
51939

51940
51941
51942
51943
51944
51945
51946
.....
56096
56097
56098
56099
56100
56101
56102

56103
56104
56105
56106
56107
56108
56109
.....
56459
56460
56461
56462
56463
56464
56465
56466
56467
56468
56469
56470
56471
56472
56473
.....
56753
56754
56755
56756
56757
56758
56759

56760
56761
56762
56763
56764
56765
56766
.....
56771
56772
56773
56774
56775
56776
56777
56778
56779
56780
56781
56782
56783
56784
56785
56786
.....
56819
56820
56821
56822
56823
56824
56825

56826
56827
56828
56829
56830
56831
56832
.....
59408
59409
59410
59411
59412
59413
59414
59415
59416
59417
59418
59419
59420
59421
59422
59423
.....
60721
60722
60723
60724
60725
60726
60727







60728
60729
60730
60731
60732
60733
60734
60735
60736
60737



60738

60739
60740
60741
60742
60743
60744
60745
.....
60822
60823
60824
60825
60826
60827
60828
60829
60830
60831
60832
60833
60834
60835
60836
.....
61678
61679
61680
61681
61682
61683
61684
61685
61686
61687
61688
61689
61690
61691
61692
.....
64442
64443
64444
64445
64446
64447
64448

64449
64450
64451
64452
64453
64454
64455
64456
64457
64458
64459
64460
64461
64462
64463
64464
64465





64466
64467
64468
64469
64470
64471
64472
64473
64474
64475
64476
64477
64478
64479
64480
64481
.....
67392
67393
67394
67395
67396
67397
67398



































67399
67400
67401
67402
67403
67404
67405
.....
67803
67804
67805
67806
67807
67808
67809

67810
67811
67812
67813
67814
67815
67816
.....
67890
67891
67892
67893
67894
67895
67896

67897
67898
67899
67900
67901
67902
67903
.....
68591
68592
68593
68594
68595
68596
68597


68598

68599
68600
68601
68602
68603
68604
68605
.....
68771
68772
68773
68774
68775
68776
68777
68778
68779
68780
68781
68782
68783
68784
68785
.....
73836
73837
73838
73839
73840
73841
73842
73843
73844
73845
73846
73847
73848
73849
73850
73851
.....
77133
77134
77135
77136
77137
77138
77139
77140
77141
77142
77143
77144
77145
77146
77147
.....
77429
77430
77431
77432
77433
77434
77435
77436
77437
77438
77439
77440
77441
77442
77443
77444
77445
77446
77447
.....
77832
77833
77834
77835
77836
77837
77838

77839
77840
77841

77842
77843
77844
77845
77846
77847
77848
77849
.....
78113
78114
78115
78116
78117
78118
78119
78120
78121
78122



78123
78124
78125
78126
78127
78128
78129
78130
78131
78132
.....
79399
79400
79401
79402
79403
79404
79405

79406
79407
79408
79409
79410
79411
79412
.....
82165
82166
82167
82168
82169
82170
82171
82172
82173
82174
82175
82176
82177
82178
82179
.....
85719
85720
85721
85722
85723
85724
85725

85726
85727
85728
85729
85730
85731
85732
85733
85734
85735
85736
.....
87300
87301
87302
87303
87304
87305
87306
87307
87308
87309
87310
87311
87312
87313
87314
.....
88893
88894
88895
88896
88897
88898
88899

88900
88901
88902
88903
88904
88905
88906

88907
88908
88909
88910
88911
88912
88913
.....
90025
90026
90027
90028
90029
90030
90031
90032
90033
90034
90035
90036
90037
90038
90039
.....
91304
91305
91306
91307
91308
91309
91310













91311
91312
91313
91314
91315
91316
91317
.....
93780
93781
93782
93783
93784
93785
93786
93787
93788
93789
93790
93791
93792
93793
93794
93795
93796
93797
93798

93799
93800
93801
93802
93803
93804
93805
93806
93807
93808
93809
93810
93811
93812
93813
93814
93815
93816

93817
93818
93819
93820

93821
93822
93823
93824
93825
93826
93827
.....
94594
94595
94596
94597
94598
94599
94600
94601
94602
94603
94604
94605
94606
94607
94608
94609
.....
97434
97435
97436
97437
97438
97439
97440
97441
97442
97443
97444
97445
97446
97447
97448
.....
97505
97506
97507
97508
97509
97510
97511




97512
97513
97514
97515
97516
97517
97518
.....
97622
97623
97624
97625
97626
97627
97628
97629
97630
97631
97632
97633
97634
97635
97636
97637
97638
97639
97640
97641
97642
.....
97806
97807
97808
97809
97810
97811
97812


















97813
97814
97815
97816
97817
97818
97819
.....
97859
97860
97861
97862
97863
97864
97865
97866
97867
97868
97869
97870
97871
97872
97873
.....
97918
97919
97920
97921
97922
97923
97924
97925
97926
97927
97928
97929
97930
97931
97932
.....
97933
97934
97935
97936
97937
97938
97939
97940
97941
97942
97943
97944






97945
97946
97947
97948
97949
97950
97951
97952
.....
97959
97960
97961
97962
97963
97964
97965
97966
97967
97968
97969
97970
97971
97972
97973
97974
.....
97984
97985
97986
97987
97988
97989
97990
97991
97992
97993
97994
97995
97996
97997




















97998
97999
98000
98001
98002
98003
98004
......
101893
101894
101895
101896
101897
101898
101899

101900
101901
101902
101903
101904
101905
101906
......
101909
101910
101911
101912
101913
101914
101915
101916
101917
101918
101919
101920
101921
101922
101923
......
101975
101976
101977
101978
101979
101980
101981






101982
101983
101984
101985
101986
101987
101988
......
102030
102031
102032
102033
102034
102035
102036
102037
102038
102039
102040
102041
102042
102043
102044
102045
......
102183
102184
102185
102186
102187
102188
102189
102190
102191
102192
102193
102194
102195
102196
102197
......
102249
102250
102251
102252
102253
102254
102255
102256
102257
102258
102259
102260
102261
102262
102263
......
102292
102293
102294
102295
102296
102297
102298
102299
102300
102301
102302
102303
102304
102305
102306
......
102542
102543
102544
102545
102546
102547
102548
102549
102550
102551
102552
102553
102554
102555
102556
......
103902
103903
103904
103905
103906
103907
103908

103909
103910
103911
103912
103913
103914
103915
103916
......
103947
103948
103949
103950
103951
103952
103953
103954
103955
103956
103957
103958
103959
103960
103961
103962
103963
103964
103965
103966
103967
103968
103969
103970
103971
103972
103973
103974
103975
103976
103977
103978
......
104610
104611
104612
104613
104614
104615
104616

104617
104618
104619

104620
104621
104622
104623
104624
104625
104626
......
105167
105168
105169
105170
105171
105172
105173
105174
105175
105176
105177


105178
105179
105180
105181
105182
105183
105184
105185
105186
105187




105188
105189
105190
105191
105192
105193
105194
......
105239
105240
105241
105242
105243
105244
105245
105246
105247
105248
105249
105250
105251
105252
105253
105254
......
105265
105266
105267
105268
105269
105270
105271
105272
105273
105274
105275
105276
105277
105278
105279
105280
105281
105282
......
105651
105652
105653
105654
105655
105656
105657

105658

105659
105660
105661
105662
105663
105664
105665
......
106162
106163
106164
106165
106166
106167
106168
106169
106170
106171
106172
106173
106174
106175
106176
......
107184
107185
107186
107187
107188
107189
107190




























































107191
107192
107193
107194
107195
107196
107197
......
107264
107265
107266
107267
107268
107269
107270







107271
107272
107273
107274
107275
107276
107277
107278
107279
107280
107281
107282
107283
107284
107285
107286
107287
107288
107289
......
109161
109162
109163
109164
109165
109166
109167

109168

109169
109170
109171
109172
109173
109174
109175
......
109452
109453
109454
109455
109456
109457
109458

109459

109460
109461
109462
109463
109464
109465
109466
......
109966
109967
109968
109969
109970
109971
109972
109973
109974
109975
109976
109977
109978
109979
109980
......
110140
110141
110142
110143
110144
110145
110146
110147
110148
110149
110150
110151
110152
110153
110154
......
110754
110755
110756
110757
110758
110759
110760
110761
110762
110763
110764
110765
110766
110767
110768
......
118624
118625
118626
118627
118628
118629
118630
118631
118632
118633
118634
118635
118636
118637
118638
......
123781
123782
123783
123784
123785
123786
123787

123788
123789
123790
123791

123792



123793
123794

123795
123796
123797
123798
123799
123800
123801
......
125631
125632
125633
125634
125635
125636
125637



125638
125639
125640
125641
125642
125643
125644
......
125869
125870
125871
125872
125873
125874
125875
125876
125877
125878
125879
125880
125881
125882
125883
125884
125885
125886
125887
125888
125889
......
125904
125905
125906
125907
125908
125909
125910







125911
125912
125913
125914
125915
125916
125917
......
126206
126207
126208
126209
126210
126211
126212
126213
126214
126215
126216
126217
126218
126219
126220
......
126415
126416
126417
126418
126419
126420
126421







126422
126423
126424
126425
126426
126427
126428
......
126730
126731
126732
126733
126734
126735
126736





126737
126738
126739
126740
126741
126742
126743
......
127176
127177
127178
127179
127180
127181
127182
127183
127184
127185
127186
127187
127188
127189
127190
127191
127192
127193
127194
127195
127196
127197
127198
127199
......
127492
127493
127494
127495
127496
127497
127498
127499
127500
127501
127502
127503
127504
127505
127506
......
128108
128109
128110
128111
128112
128113
128114

128115
128116
128117
128118
128119
128120
128121
......
128313
128314
128315
128316
128317
128318
128319
128320
128321
128322
128323
128324
128325
128326
128327
128328
128329
128330
128331
128332
128333
128334
128335
128336
128337
128338
128339
128340
128341
128342
128343
128344
128345
128346
128347
128348
128349
128350
128351
128352
......
128382
128383
128384
128385
128386
128387
128388
128389
128390
128391
128392
128393
128394
128395
128396
......
128939
128940
128941
128942
128943
128944
128945

128946
128947
128948
128949
128950
128951
128952
......
129097
129098
129099
129100
129101
129102
129103
129104
129105
129106
129107
129108
129109
129110
129111
......
129308
129309
129310
129311
129312
129313
129314
129315
129316
129317
129318
129319
129320
129321
129322
......
129839
129840
129841
129842
129843
129844
129845

129846
129847
129848
129849
129850
129851
129852
129853
129854
129855
129856
129857
129858
129859
129860

129861
129862
129863
129864
129865
129866
129867
129868
129869
129870
129871
129872
129873
129874
......
132929
132930
132931
132932
132933
132934
132935
132936
132937
132938
132939
132940
132941
132942
132943
132944
132945
132946
132947
132948
132949
132950
132951
132952
132953
132954
......
134162
134163
134164
134165
134166
134167
134168
134169
134170
134171
134172
134173
134174
134175
134176
......
140650
140651
140652
140653
140654
140655
140656
140657
140658
140659
140660
140661
140662
140663
140664
......
144025
144026
144027
144028
144029
144030
144031
144032
144033
144034
144035
144036
144037
144038
144039
144040
......
149258
149259
149260
149261
149262
149263
149264
149265
149266
149267
149268
149269
149270
149271
149272
149273
149274
149275
149276
149277
149278
......
149293
149294
149295
149296
149297
149298
149299
149300
149301
149302
149303
149304
149305
149306
149307
......
149624
149625
149626
149627
149628
149629
149630
149631
149632

149633
149634
149635
149636

149637
149638
149639
149640
149641
149642
149643
149644
149645
......
150071
150072
150073
150074
150075
150076
150077
150078
150079
150080
150081
150082
150083
150084
150085
......
151694
151695
151696
151697
151698
151699
151700


151701
151702
151703
151704
151705
151706
151707
/******************************************************************************
** This file is an amalgamation of many separate C source files from SQLite
** version 3.8.8.  By combining all the individual C code files into this 
** single large file, the entire code can be compiled as a single translation
** unit.  This allows many compilers to do optimizations that would not be
** possible if the files were compiled separately.  Performance improvements
** of 5% or more are commonly seen when SQLite is compiled as a single
** translation unit.
**
** This file is all you need to compile SQLite.  To use SQLite in other
................................................................................
*************************************************************************
** Internal interface definitions for SQLite.
**
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_
















































/*
** These #defines should enable >2GB file support on POSIX if the
** underlying operating system supports it.  If the OS lacks
** large file support, or if the OS is windows, these should be no-ops.
**
** Ticket #2739:  The _LARGEFILE_SOURCE macro must appear before any
** system #includes.  Hence, this block of code must be the very first
................................................................................
** string contains the date and time of the check-in (UTC) and an SHA1
** hash of the entire source tree.
**
** See also: [sqlite3_libversion()],
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
#define SQLITE_VERSION        "3.8.8"
#define SQLITE_VERSION_NUMBER 3008008
#define SQLITE_SOURCE_ID      "2014-12-10 04:58:43 3528f8dd39acace8eeb7337994c8617313f4b04b"

/*
** CAPI3REF: Run-Time Library Version Numbers
** KEYWORDS: sqlite3_version, sqlite3_sourceid
**
** These interfaces provide the same information as the [SQLITE_VERSION],
** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros
................................................................................
** the desired setting of the [SQLITE_THREADSAFE] macro.
**
** This interface only reports on the compile-time mutex setting
** of the [SQLITE_THREADSAFE] flag.  If SQLite is compiled with
** SQLITE_THREADSAFE=1 or =2 then mutexes are enabled by default but
** can be fully or partially disabled using a call to [sqlite3_config()]
** with the verbs [SQLITE_CONFIG_SINGLETHREAD], [SQLITE_CONFIG_MULTITHREAD],
** or [SQLITE_CONFIG_MUTEX].  ^(The return value of the
** sqlite3_threadsafe() function shows only the compile-time setting of
** thread safety, not any run-time changes to that setting made by
** sqlite3_config(). In other words, the return value from sqlite3_threadsafe()
** is unchanged by calls to sqlite3_config().)^
**
** See the [threading mode] documentation for additional information.
*/
................................................................................
** This configuration should not be used if an application-define page
** cache implementation is loaded using the [SQLITE_CONFIG_PCACHE2]
** configuration option.
** ^There are three arguments to SQLITE_CONFIG_PAGECACHE: A pointer to
** 8-byte aligned
** memory, the size of each page buffer (sz), and the number of pages (N).
** The sz argument should be the size of the largest database page
** (a power of two between 512 and 32768) plus some extra bytes for each
** page header.  ^The number of extra bytes needed by the page header
** can be determined using the [SQLITE_CONFIG_PCACHE_HDRSZ] option 
** to [sqlite3_config()].
** ^It is harmless, apart from the wasted memory,
** for the sz parameter to be larger than necessary.  The first
** argument should pointer to an 8-byte aligned block of memory that
** is at least sz*N bytes of memory, otherwise subsequent behavior is
................................................................................
** [[SQLITE_CONFIG_PCACHE_HDRSZ]]
** <dt>SQLITE_CONFIG_PCACHE_HDRSZ
** <dd>^The SQLITE_CONFIG_PCACHE_HDRSZ option takes a single parameter which
** is a pointer to an integer and writes into that integer the number of extra
** bytes per page required for each page in [SQLITE_CONFIG_PAGECACHE].
** The amount of extra space required can change depending on the compiler,
** target platform, and SQLite version.











** </dl>
*/
#define SQLITE_CONFIG_SINGLETHREAD  1  /* nil */
#define SQLITE_CONFIG_MULTITHREAD   2  /* nil */
#define SQLITE_CONFIG_SERIALIZED    3  /* nil */
#define SQLITE_CONFIG_MALLOC        4  /* sqlite3_mem_methods* */
#define SQLITE_CONFIG_GETMALLOC     5  /* sqlite3_mem_methods* */
................................................................................
#define SQLITE_CONFIG_PCACHE2      18  /* sqlite3_pcache_methods2* */
#define SQLITE_CONFIG_GETPCACHE2   19  /* sqlite3_pcache_methods2* */
#define SQLITE_CONFIG_COVERING_INDEX_SCAN 20  /* int */
#define SQLITE_CONFIG_SQLLOG       21  /* xSqllog, void* */
#define SQLITE_CONFIG_MMAP_SIZE    22  /* sqlite3_int64, sqlite3_int64 */
#define SQLITE_CONFIG_WIN32_HEAPSIZE      23  /* int nByte */
#define SQLITE_CONFIG_PCACHE_HDRSZ        24  /* int *psz */


/*
** CAPI3REF: Database Connection Configuration Options
**
** These constants are the available integer configuration options that
** can be passed as the second argument to the [sqlite3_db_config()] interface.
**
................................................................................
*/
SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...);

/*
** CAPI3REF: Write-Ahead Log Commit Hook
**
** ^The [sqlite3_wal_hook()] function is used to register a callback that
** will be invoked each time a database connection commits data to a
** [write-ahead log] (i.e. whenever a transaction is committed in
** [journal_mode | journal_mode=WAL mode]). 
**
** ^The callback is invoked by SQLite after the commit has taken place and 
** the associated write-lock on the database released, so the implementation 
** may read, write or [checkpoint] the database as required.
**
** ^The first parameter passed to the callback function when it is invoked
** is a copy of the third parameter passed to sqlite3_wal_hook() when
** registering the callback. ^The second is a copy of the database handle.
** ^The third parameter is the name of the database that was written to -
** either "main" or the name of an [ATTACH]-ed database. ^The fourth parameter
................................................................................
** CAPI3REF: Prepared Statement Scan Status Opcodes
** KEYWORDS: {scanstatus options}
**
** The following constants can be used for the T parameter to the
** [sqlite3_stmt_scanstatus(S,X,T,V)] interface.  Each constant designates a
** different metric for sqlite3_stmt_scanstatus() to return.
**




** <dl>
** [[SQLITE_SCANSTAT_NLOOP]] <dt>SQLITE_SCANSTAT_NLOOP</dt>
** <dd>^The [sqlite3_int64] variable pointed to by the T parameter will be
** set to the total number of times that the X-th loop has run.</dd>
**
** [[SQLITE_SCANSTAT_NVISIT]] <dt>SQLITE_SCANSTAT_NVISIT</dt>
** <dd>^The [sqlite3_int64] variable pointed to by the T parameter will be set
................................................................................
#define SQLITE_SCANSTAT_NAME     3
#define SQLITE_SCANSTAT_EXPLAIN  4
#define SQLITE_SCANSTAT_SELECTID 5

/*
** CAPI3REF: Prepared Statement Scan Status
**
** Return status data for a single loop within query pStmt.







**
** The "iScanStatusOp" parameter determines which status information to return.
** The "iScanStatusOp" must be one of the [scanstatus options] or the behavior
** of this interface is undefined.
** ^The requested measurement is written into a variable pointed to by
** the "pOut" parameter.
** Parameter "idx" identifies the specific loop to retrieve statistics for.
................................................................................
** points to is unchanged.
**
** ^Statistics might not be available for all loops in all statements. ^In cases
** where there exist loops with no available statistics, this function behaves
** as if the loop did not exist - it returns non-zero and leave the variable
** that pOut points to unchanged.
**
** This API is only available if the library is built with pre-processor
** symbol [SQLITE_ENABLE_STMT_SCANSTATUS] defined.
**
** See also: [sqlite3_stmt_scanstatus_reset()]
*/
SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_stmt_scanstatus(
  sqlite3_stmt *pStmt,      /* Prepared statement for which info desired */
  int idx,                  /* Index of loop to report on */
  int iScanStatusOp,        /* Information desired.  SQLITE_SCANSTAT_* */
  void *pOut                /* Result written here */
................................................................................
*/
#ifndef _BTREE_H_
#define _BTREE_H_

/* TODO: This definition is just included so other modules compile. It
** needs to be revisited.
*/
#define SQLITE_N_BTREE_META 10

/*
** If defined as non-zero, auto-vacuum is enabled by default. Otherwise
** it must be turned on for each database using "PRAGMA auto_vacuum = 1".
*/
#ifndef SQLITE_DEFAULT_AUTOVACUUM
  #define SQLITE_DEFAULT_AUTOVACUUM 0
................................................................................
** SQLite database header may be found using the following formula:
**
**   offset = 36 + (idx * 4)
**
** For example, the free-page-count field is located at byte offset 36 of
** the database file header. The incr-vacuum-flag field is located at
** byte offset 64 (== 36+4*7).





*/
#define BTREE_FREE_PAGE_COUNT     0
#define BTREE_SCHEMA_VERSION      1
#define BTREE_FILE_FORMAT         2
#define BTREE_DEFAULT_CACHE_SIZE  3
#define BTREE_LARGEST_ROOT_PAGE   4
#define BTREE_TEXT_ENCODING       5
#define BTREE_USER_VERSION        6
#define BTREE_INCR_VACUUM         7
#define BTREE_APPLICATION_ID      8


/*
** Values that may be OR'd together to form the second argument of an
** sqlite3BtreeCursorHints() call.
*/
#define BTREE_BULKLOAD 0x00000001

................................................................................

#ifdef SQLITE_ENABLE_ZIPVFS
SQLITE_PRIVATE   int sqlite3PagerWalFramesize(Pager *pPager);
#endif

/* Functions used to query pager state and configuration. */
SQLITE_PRIVATE u8 sqlite3PagerIsreadonly(Pager*);

SQLITE_PRIVATE int sqlite3PagerRefcount(Pager*);
SQLITE_PRIVATE int sqlite3PagerMemUsed(Pager*);
SQLITE_PRIVATE const char *sqlite3PagerFilename(Pager*, int);
SQLITE_PRIVATE const sqlite3_vfs *sqlite3PagerVfs(Pager*);
SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager*);
SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager*);
SQLITE_PRIVATE int sqlite3PagerNosync(Pager*);
................................................................................
  int flags;                    /* Miscellaneous flags. See below */
  i64 lastRowid;                /* ROWID of most recent insert (see above) */
  i64 szMmap;                   /* Default mmap_size setting */
  unsigned int openFlags;       /* Flags passed to sqlite3_vfs.xOpen() */
  int errCode;                  /* Most recent error code (SQLITE_*) */
  int errMask;                  /* & result codes with this before returning */
  u16 dbOptFlags;               /* Flags to enable/disable optimizations */

  u8 autoCommit;                /* The auto-commit flag. */
  u8 temp_store;                /* 1: file 2: memory 0: default */
  u8 mallocFailed;              /* True if we have seen a malloc failure */
  u8 dfltLockMode;              /* Default locking-mode for attached dbs */
  signed char nextAutovac;      /* Autovac setting after VACUUM if >=0 */
  u8 suppressErr;               /* Do not issue error messages if true */
  u8 vtabOnConflict;            /* Value to return for s3_vtab_on_conflict() */
................................................................................
  sqlite3_userauth auth;        /* User authentication information */
#endif
};

/*
** A macro to discover the encoding of a database.
*/
#define ENC(db) ((db)->aDb[0].pSchema->enc)


/*
** Possible values for the sqlite3.flags.
*/
#define SQLITE_VdbeTrace      0x00000001  /* True to trace VDBE execution */
#define SQLITE_InternChanges  0x00000002  /* Uncommitted Hash table changes */
#define SQLITE_FullFSync      0x00000004  /* Use full fsync on the backend */
................................................................................
  Table *pTable;           /* The SQL table being indexed */
  char *zColAff;           /* String defining the affinity of each column */
  Index *pNext;            /* The next index associated with the same table */
  Schema *pSchema;         /* Schema containing this index */
  u8 *aSortOrder;          /* for each column: True==DESC, False==ASC */
  char **azColl;           /* Array of collation sequence names for index */
  Expr *pPartIdxWhere;     /* WHERE clause for partial indices */
  KeyInfo *pKeyInfo;       /* A KeyInfo object suitable for this index */
  int tnum;                /* DB Page containing root of this index */
  LogEst szIdxRow;         /* Estimated average row size in bytes */
  u16 nKeyCol;             /* Number of columns forming the key */
  u16 nColumn;             /* Number of columns stored in the index */
  u8 onError;              /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
  unsigned idxType:2;      /* 1==UNIQUE, 2==PRIMARY KEY, 0==CREATE INDEX */
  unsigned bUnordered:1;   /* Use this index for == or IN queries only */
................................................................................
#define SF_Resolved        0x0002  /* Identifiers have been resolved */
#define SF_Aggregate       0x0004  /* Contains aggregate functions */
#define SF_UsesEphemeral   0x0008  /* Uses the OpenEphemeral opcode */
#define SF_Expanded        0x0010  /* sqlite3SelectExpand() called on this */
#define SF_HasTypeInfo     0x0020  /* FROM subqueries have Table metadata */
#define SF_Compound        0x0040  /* Part of a compound query */
#define SF_Values          0x0080  /* Synthesized from VALUES clause */
                    /*     0x0100  NOT USED */
#define SF_NestedFrom      0x0200  /* Part of a parenthesized FROM clause */
#define SF_MaybeConvert    0x0400  /* Need convertCompoundSelectToSubquery() */
#define SF_Recursive       0x0800  /* The recursive part of a recursive CTE */
#define SF_MinMaxAgg       0x1000  /* Aggregate containing min() or max() */


/*
................................................................................
  int szScratch;                    /* Size of each scratch buffer */
  int nScratch;                     /* Number of scratch buffers */
  void *pPage;                      /* Page cache memory */
  int szPage;                       /* Size of each page in pPage[] */
  int nPage;                        /* Number of pages in pPage[] */
  int mxParserStack;                /* maximum depth of the parser stack */
  int sharedCacheEnabled;           /* true if shared-cache mode enabled */

  /* The above might be initialized to non-zero.  The following need to always
  ** initially be zero, however. */
  int isInit;                       /* True after initialization has finished */
  int inProgress;                   /* True while initialization in progress */
  int isMutexInit;                  /* True after mutexes are initialized */
  int isMallocInit;                 /* True after malloc is initialized */
  int isPCacheInit;                 /* True after malloc is initialized */
................................................................................

/*
** FTS4 is really an extension for FTS3.  It is enabled using the
** SQLITE_ENABLE_FTS3 macro.  But to avoid confusion we also call
** the SQLITE_ENABLE_FTS4 macro to serve as an alias for SQLITE_ENABLE_FTS3.
*/
#if defined(SQLITE_ENABLE_FTS4) && !defined(SQLITE_ENABLE_FTS3)
# define SQLITE_ENABLE_FTS3
#endif

/*
** The ctype.h header is needed for non-ASCII systems.  It is also
** needed by FTS3 when FTS3 is included in the amalgamation.
*/
#if !defined(SQLITE_ASCII) || \
................................................................................
** If the SQLITE_ENABLE IOTRACE exists then the global variable
** sqlite3IoTrace is a pointer to a printf-like routine used to
** print I/O tracing messages. 
*/
#ifdef SQLITE_ENABLE_IOTRACE
# define IOTRACE(A)  if( sqlite3IoTrace ){ sqlite3IoTrace A; }
SQLITE_PRIVATE   void sqlite3VdbeIOTraceSql(Vdbe*);
SQLITE_PRIVATE void (*sqlite3IoTrace)(const char*,...);
#else
# define IOTRACE(A)
# define sqlite3VdbeIOTraceSql(X)
#endif

/*
** These routines are available for the mem2.c debugging memory allocator
................................................................................
** SQLITE_ALLOW_COVERING_INDEX_SCAN compile-time option, or is "on" if
** that compile-time option is omitted.
*/
#ifndef SQLITE_ALLOW_COVERING_INDEX_SCAN
# define SQLITE_ALLOW_COVERING_INDEX_SCAN 1
#endif








/*
** The following singleton contains the global configuration for
** the SQLite library.
*/
SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = {
   SQLITE_DEFAULT_MEMSTATUS,  /* bMemstat */
   1,                         /* bCoreMutex */
................................................................................
   0,                         /* szScratch */
   0,                         /* nScratch */
   (void*)0,                  /* pPage */
   0,                         /* szPage */
   0,                         /* nPage */
   0,                         /* mxParserStack */
   0,                         /* sharedCacheEnabled */

   /* All the rest should always be initialized to zero */
   0,                         /* isInit */
   0,                         /* inProgress */
   0,                         /* isMutexInit */
   0,                         /* isMallocInit */
   0,                         /* isPCacheInit */
   0,                         /* nRefInitMutex */
................................................................................
static const char * const azCompileOpt[] = {

/* These macros are provided to "stringify" the value of the define
** for those options in which the value is meaningful. */
#define CTIMEOPT_VAL_(opt) #opt
#define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt)

#ifdef SQLITE_32BIT_ROWID
  "32BIT_ROWID",
#endif
#ifdef SQLITE_4_BYTE_ALIGNED_MALLOC
  "4_BYTE_ALIGNED_MALLOC",
#endif
#ifdef SQLITE_CASE_SENSITIVE_LIKE
  "CASE_SENSITIVE_LIKE",
#endif
#ifdef SQLITE_CHECK_PAGES
  "CHECK_PAGES",
#endif
#ifdef SQLITE_COVERAGE_TEST
  "COVERAGE_TEST",
#endif
#ifdef SQLITE_DEBUG
  "DEBUG",
#endif
#ifdef SQLITE_DEFAULT_LOCKING_MODE
  "DEFAULT_LOCKING_MODE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOCKING_MODE),
#endif
#if defined(SQLITE_DEFAULT_MMAP_SIZE) && !defined(SQLITE_DEFAULT_MMAP_SIZE_xc)
  "DEFAULT_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_MMAP_SIZE),
#endif
#ifdef SQLITE_DISABLE_DIRSYNC
  "DISABLE_DIRSYNC",
#endif
#ifdef SQLITE_DISABLE_LFS
  "DISABLE_LFS",
#endif
#ifdef SQLITE_ENABLE_API_ARMOR
  "ENABLE_API_ARMOR",
#endif
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
  "ENABLE_ATOMIC_WRITE",
#endif
#ifdef SQLITE_ENABLE_CEROD
  "ENABLE_CEROD",
#endif
#ifdef SQLITE_ENABLE_COLUMN_METADATA
  "ENABLE_COLUMN_METADATA",
#endif
#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
  "ENABLE_EXPENSIVE_ASSERT",
#endif
#ifdef SQLITE_ENABLE_FTS1
  "ENABLE_FTS1",
#endif
#ifdef SQLITE_ENABLE_FTS2
  "ENABLE_FTS2",
#endif
#ifdef SQLITE_ENABLE_FTS3
  "ENABLE_FTS3",
#endif
#ifdef SQLITE_ENABLE_FTS3_PARENTHESIS
  "ENABLE_FTS3_PARENTHESIS",
#endif
#ifdef SQLITE_ENABLE_FTS4
  "ENABLE_FTS4",
#endif
#ifdef SQLITE_ENABLE_ICU
  "ENABLE_ICU",
#endif
#ifdef SQLITE_ENABLE_IOTRACE
  "ENABLE_IOTRACE",
#endif
#ifdef SQLITE_ENABLE_LOAD_EXTENSION
  "ENABLE_LOAD_EXTENSION",
#endif
#ifdef SQLITE_ENABLE_LOCKING_STYLE
  "ENABLE_LOCKING_STYLE=" CTIMEOPT_VAL(SQLITE_ENABLE_LOCKING_STYLE),
#endif
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
  "ENABLE_MEMORY_MANAGEMENT",
#endif
#ifdef SQLITE_ENABLE_MEMSYS3
  "ENABLE_MEMSYS3",
#endif
#ifdef SQLITE_ENABLE_MEMSYS5
  "ENABLE_MEMSYS5",
#endif
#ifdef SQLITE_ENABLE_OVERSIZE_CELL_CHECK
  "ENABLE_OVERSIZE_CELL_CHECK",
#endif
#ifdef SQLITE_ENABLE_RTREE
  "ENABLE_RTREE",
#endif
#if defined(SQLITE_ENABLE_STAT4)
  "ENABLE_STAT4",
#elif defined(SQLITE_ENABLE_STAT3)
  "ENABLE_STAT3",
#endif
#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
  "ENABLE_UNLOCK_NOTIFY",
#endif
#ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
  "ENABLE_UPDATE_DELETE_LIMIT",
#endif
#ifdef SQLITE_HAS_CODEC
  "HAS_CODEC",
#endif
#ifdef SQLITE_HAVE_ISNAN
  "HAVE_ISNAN",
#endif
#ifdef SQLITE_HOMEGROWN_RECURSIVE_MUTEX
  "HOMEGROWN_RECURSIVE_MUTEX",
#endif
#ifdef SQLITE_IGNORE_AFP_LOCK_ERRORS
  "IGNORE_AFP_LOCK_ERRORS",
#endif
#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS
  "IGNORE_FLOCK_LOCK_ERRORS",
#endif
#ifdef SQLITE_INT64_TYPE
  "INT64_TYPE",
#endif
#ifdef SQLITE_LOCK_TRACE
  "LOCK_TRACE",
#endif
#if defined(SQLITE_MAX_MMAP_SIZE) && !defined(SQLITE_MAX_MMAP_SIZE_xc)
  "MAX_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_MAX_MMAP_SIZE),
#endif
#ifdef SQLITE_MAX_SCHEMA_RETRY
  "MAX_SCHEMA_RETRY=" CTIMEOPT_VAL(SQLITE_MAX_SCHEMA_RETRY),
#endif
#ifdef SQLITE_MEMDEBUG
  "MEMDEBUG",
#endif
#ifdef SQLITE_MIXED_ENDIAN_64BIT_FLOAT
  "MIXED_ENDIAN_64BIT_FLOAT",
#endif
#ifdef SQLITE_NO_SYNC
  "NO_SYNC",
#endif
#ifdef SQLITE_OMIT_ALTERTABLE
  "OMIT_ALTERTABLE",
#endif
#ifdef SQLITE_OMIT_ANALYZE
  "OMIT_ANALYZE",
#endif
#ifdef SQLITE_OMIT_ATTACH
  "OMIT_ATTACH",
#endif
#ifdef SQLITE_OMIT_AUTHORIZATION
  "OMIT_AUTHORIZATION",
#endif
#ifdef SQLITE_OMIT_AUTOINCREMENT
  "OMIT_AUTOINCREMENT",
#endif
#ifdef SQLITE_OMIT_AUTOINIT
  "OMIT_AUTOINIT",
#endif
#ifdef SQLITE_OMIT_AUTOMATIC_INDEX
  "OMIT_AUTOMATIC_INDEX",
#endif
#ifdef SQLITE_OMIT_AUTORESET
  "OMIT_AUTORESET",
#endif
#ifdef SQLITE_OMIT_AUTOVACUUM
  "OMIT_AUTOVACUUM",
#endif
#ifdef SQLITE_OMIT_BETWEEN_OPTIMIZATION
  "OMIT_BETWEEN_OPTIMIZATION",
#endif
#ifdef SQLITE_OMIT_BLOB_LITERAL
  "OMIT_BLOB_LITERAL",
#endif
#ifdef SQLITE_OMIT_BTREECOUNT
  "OMIT_BTREECOUNT",
#endif
#ifdef SQLITE_OMIT_BUILTIN_TEST
  "OMIT_BUILTIN_TEST",
#endif
#ifdef SQLITE_OMIT_CAST
  "OMIT_CAST",
#endif
#ifdef SQLITE_OMIT_CHECK
  "OMIT_CHECK",
#endif
#ifdef SQLITE_OMIT_COMPLETE
  "OMIT_COMPLETE",
#endif
#ifdef SQLITE_OMIT_COMPOUND_SELECT
  "OMIT_COMPOUND_SELECT",
#endif
#ifdef SQLITE_OMIT_CTE
  "OMIT_CTE",
#endif
#ifdef SQLITE_OMIT_DATETIME_FUNCS
  "OMIT_DATETIME_FUNCS",
#endif
#ifdef SQLITE_OMIT_DECLTYPE
  "OMIT_DECLTYPE",
#endif
#ifdef SQLITE_OMIT_DEPRECATED
  "OMIT_DEPRECATED",
#endif
#ifdef SQLITE_OMIT_DISKIO
  "OMIT_DISKIO",
#endif
#ifdef SQLITE_OMIT_EXPLAIN
  "OMIT_EXPLAIN",
#endif
#ifdef SQLITE_OMIT_FLAG_PRAGMAS
  "OMIT_FLAG_PRAGMAS",
#endif
#ifdef SQLITE_OMIT_FLOATING_POINT
  "OMIT_FLOATING_POINT",
#endif
#ifdef SQLITE_OMIT_FOREIGN_KEY
  "OMIT_FOREIGN_KEY",
#endif
#ifdef SQLITE_OMIT_GET_TABLE
  "OMIT_GET_TABLE",
#endif
#ifdef SQLITE_OMIT_INCRBLOB
  "OMIT_INCRBLOB",
#endif
#ifdef SQLITE_OMIT_INTEGRITY_CHECK
  "OMIT_INTEGRITY_CHECK",
#endif
#ifdef SQLITE_OMIT_LIKE_OPTIMIZATION
  "OMIT_LIKE_OPTIMIZATION",
#endif
#ifdef SQLITE_OMIT_LOAD_EXTENSION
  "OMIT_LOAD_EXTENSION",
#endif
#ifdef SQLITE_OMIT_LOCALTIME
  "OMIT_LOCALTIME",
#endif
#ifdef SQLITE_OMIT_LOOKASIDE
  "OMIT_LOOKASIDE",
#endif
#ifdef SQLITE_OMIT_MEMORYDB
  "OMIT_MEMORYDB",
#endif
#ifdef SQLITE_OMIT_OR_OPTIMIZATION
  "OMIT_OR_OPTIMIZATION",
#endif
#ifdef SQLITE_OMIT_PAGER_PRAGMAS
  "OMIT_PAGER_PRAGMAS",
#endif
#ifdef SQLITE_OMIT_PRAGMA
  "OMIT_PRAGMA",
#endif
#ifdef SQLITE_OMIT_PROGRESS_CALLBACK
  "OMIT_PROGRESS_CALLBACK",
#endif
#ifdef SQLITE_OMIT_QUICKBALANCE
  "OMIT_QUICKBALANCE",
#endif
#ifdef SQLITE_OMIT_REINDEX
  "OMIT_REINDEX",
#endif
#ifdef SQLITE_OMIT_SCHEMA_PRAGMAS
  "OMIT_SCHEMA_PRAGMAS",
#endif
#ifdef SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS
  "OMIT_SCHEMA_VERSION_PRAGMAS",
#endif
#ifdef SQLITE_OMIT_SHARED_CACHE
  "OMIT_SHARED_CACHE",
#endif
#ifdef SQLITE_OMIT_SUBQUERY
  "OMIT_SUBQUERY",
#endif
#ifdef SQLITE_OMIT_TCL_VARIABLE
  "OMIT_TCL_VARIABLE",
#endif
#ifdef SQLITE_OMIT_TEMPDB
  "OMIT_TEMPDB",
#endif
#ifdef SQLITE_OMIT_TRACE
  "OMIT_TRACE",
#endif
#ifdef SQLITE_OMIT_TRIGGER
  "OMIT_TRIGGER",
#endif
#ifdef SQLITE_OMIT_TRUNCATE_OPTIMIZATION
  "OMIT_TRUNCATE_OPTIMIZATION",
#endif
#ifdef SQLITE_OMIT_UTF16
  "OMIT_UTF16",
#endif
#ifdef SQLITE_OMIT_VACUUM
  "OMIT_VACUUM",
#endif
#ifdef SQLITE_OMIT_VIEW
  "OMIT_VIEW",
#endif
#ifdef SQLITE_OMIT_VIRTUALTABLE
  "OMIT_VIRTUALTABLE",
#endif
#ifdef SQLITE_OMIT_WAL
  "OMIT_WAL",
#endif
#ifdef SQLITE_OMIT_WSD
  "OMIT_WSD",
#endif
#ifdef SQLITE_OMIT_XFER_OPT
  "OMIT_XFER_OPT",
#endif
#ifdef SQLITE_PERFORMANCE_TRACE
  "PERFORMANCE_TRACE",
#endif
#ifdef SQLITE_PROXY_DEBUG
  "PROXY_DEBUG",
#endif
#ifdef SQLITE_RTREE_INT_ONLY
  "RTREE_INT_ONLY",
#endif
#ifdef SQLITE_SECURE_DELETE
  "SECURE_DELETE",
#endif
#ifdef SQLITE_SMALL_STACK
  "SMALL_STACK",
#endif
#ifdef SQLITE_SOUNDEX
  "SOUNDEX",
#endif
#ifdef SQLITE_SYSTEM_MALLOC
  "SYSTEM_MALLOC",
#endif
#ifdef SQLITE_TCL
  "TCL",
#endif
#if defined(SQLITE_TEMP_STORE) && !defined(SQLITE_TEMP_STORE_xc)
  "TEMP_STORE=" CTIMEOPT_VAL(SQLITE_TEMP_STORE),
#endif
#ifdef SQLITE_TEST
  "TEST",
#endif
#if defined(SQLITE_THREADSAFE)
  "THREADSAFE=" CTIMEOPT_VAL(SQLITE_THREADSAFE),
#endif
#ifdef SQLITE_USE_ALLOCA
  "USE_ALLOCA",
#endif
#ifdef SQLITE_USER_AUTHENTICATION
  "USER_AUTHENTICATION",
#endif
#ifdef SQLITE_WIN32_MALLOC
  "WIN32_MALLOC",
#endif
#ifdef SQLITE_ZERO_MALLOC
  "ZERO_MALLOC"
#endif
};

/*
** Given the name of a compile-time option, return true if that option
** was used and false if not.
................................................................................
**
** The name can optionally begin with "SQLITE_" but the "SQLITE_" prefix
** is not required for a match.
*/
SQLITE_API int sqlite3_compileoption_used(const char *zOptName){
  int i, n;

#ifdef SQLITE_ENABLE_API_ARMOR
  if( zOptName==0 ){
    (void)SQLITE_MISUSE_BKPT;
    return 0;
  }
#endif
  if( sqlite3StrNICmp(zOptName, "SQLITE_", 7)==0 ) zOptName += 7;
  n = sqlite3Strlen30(zOptName);
................................................................................
**
** See http://msdn.microsoft.com/en-us/library/a442x3ye(VS.80).aspx.
**
** If the user has not indicated to use localtime_r() or localtime_s()
** already, check for an MSVC build environment that provides 
** localtime_s().
*/
#if !defined(HAVE_LOCALTIME_R) && !defined(HAVE_LOCALTIME_S) && \
     defined(_MSC_VER) && defined(_CRT_INSECURE_DEPRECATE)

#define HAVE_LOCALTIME_S 1
#endif

#ifndef SQLITE_OMIT_LOCALTIME
/*
** The following routine implements the rough equivalent of localtime_r()
** using whatever operating-system specific localtime facility that
................................................................................
**
** EVIDENCE-OF: R-62172-00036 In this implementation, the standard C
** library function localtime_r() is used to assist in the calculation of
** local time.
*/
static int osLocaltime(time_t *t, struct tm *pTm){
  int rc;
#if (!defined(HAVE_LOCALTIME_R) || !HAVE_LOCALTIME_R) \
      && (!defined(HAVE_LOCALTIME_S) || !HAVE_LOCALTIME_S)
  struct tm *pX;
#if SQLITE_THREADSAFE>0
  sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
#endif
  sqlite3_mutex_enter(mutex);
  pX = localtime(t);
#ifndef SQLITE_OMIT_BUILTIN_TEST
................................................................................
  if( pX ) *pTm = *pX;
  sqlite3_mutex_leave(mutex);
  rc = pX==0;
#else
#ifndef SQLITE_OMIT_BUILTIN_TEST
  if( sqlite3GlobalConfig.bLocaltimeFault ) return 1;
#endif
#if defined(HAVE_LOCALTIME_R) && HAVE_LOCALTIME_R
  rc = localtime_r(t, pTm)==0;
#else
  rc = localtime_s(pTm, t);
#endif /* HAVE_LOCALTIME_R */
#endif /* HAVE_LOCALTIME_R || HAVE_LOCALTIME_S */
  return rc;
}
................................................................................
  sqlite3_value **argv
){
  DateTime x;
  u64 n;
  size_t i,j;
  char *z;
  sqlite3 *db;
  const char *zFmt = (const char*)sqlite3_value_text(argv[0]);
  char zBuf[100];


  if( zFmt==0 || isDate(context, argc-1, argv+1, &x) ) return;
  db = sqlite3_context_db_handle(context);
  for(i=0, n=1; zFmt[i]; i++, n++){
    if( zFmt[i]=='%' ){
      switch( zFmt[i+1] ){
        case 'd':
        case 'H':
................................................................................

  UNUSED_PARAMETER(argc);
  UNUSED_PARAMETER(argv);

  iT = sqlite3StmtCurrentTime(context);
  if( iT<=0 ) return;
  t = iT/1000 - 10000*(sqlite3_int64)21086676;
#ifdef HAVE_GMTIME_R
  pTm = gmtime_r(&t, &sNow);
#else
  sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
  pTm = gmtime(&t);
  if( pTm ) memcpy(&sNow, pTm, sizeof(sNow));
  sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
#endif
................................................................................
#define SQLITE_FREE(x)               free(x)
#define SQLITE_REALLOC(x,y)          realloc((x),(y))

/*
** The malloc.h header file is needed for malloc_usable_size() function
** on some systems (e.g. Linux).
*/
#if defined(HAVE_MALLOC_H) && defined(HAVE_MALLOC_USABLE_SIZE)
#  define SQLITE_USE_MALLOC_H
#  define SQLITE_USE_MALLOC_USABLE_SIZE
/*
** The MSVCRT has malloc_usable_size(), but it is called _msize().  The
** use of _msize() is automatic, but can be disabled by compiling with
** -DSQLITE_WITHOUT_MSIZE.  Using the _msize() function also requires
** the malloc.h header file.
*/
#elif defined(_MSC_VER) && !defined(SQLITE_WITHOUT_MSIZE)
................................................................................
#else
        InitializeCriticalSection(&p->mutex);
#endif
      }
      break;
    }
    default: {






      assert( iType-2 >= 0 );
      assert( iType-2 < ArraySize(winMutex_staticMutexes) );
      assert( winMutex_isInit==1 );
      p = &winMutex_staticMutexes[iType-2];
#ifdef SQLITE_DEBUG
      p->id = iType;
#ifdef SQLITE_WIN32_MUTEX_TRACE_STATIC
................................................................................
**************************************************************************
**
** This file contains code for a set of "printf"-like routines.  These
** routines format strings much like the printf() from the standard C
** library, though the implementation here has enhancements to support
** SQLlite.
*/

/*
** If the strchrnul() library function is available, then set
** HAVE_STRCHRNUL.  If that routine is not available, this module
** will supply its own.  The built-in version is slower than
** the glibc version so the glibc version is definitely preferred.
*/
#if !defined(HAVE_STRCHRNUL)
# define HAVE_STRCHRNUL 0
#endif


/*
** Conversion types fall into various categories as defined by the
** following enumeration.
*/
#define etRADIX       1 /* Integer types.  %d, %x, %o, and so forth */
#define etFLOAT       2 /* Floating point.  %f */
................................................................................
** "thread" is done by the main thread at either the sqlite3ThreadCreate()
** or sqlite3ThreadJoin() call.  This is, in fact, what happens in
** single threaded systems.  Nothing in SQLite requires multiple threads.
** This interface exists so that applications that want to take advantage
** of multiple cores can do so, while also allowing applications to stay
** single-threaded if desired.
*/



#if SQLITE_MAX_WORKER_THREADS>0

/********************************* Unix Pthreads ****************************/
#if SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) && SQLITE_THREADSAFE>0

#define SQLITE_THREADS_IMPLEMENTED 1  /* Prevent the single-thread code below */
................................................................................
** Utility functions used throughout sqlite.
**
** This file contains functions for allocating memory, comparing
** strings, and stuff like that.
**
*/
/* #include <stdarg.h> */
#ifdef SQLITE_HAVE_ISNAN
# include <math.h>
#endif

/*
** Routine needed to support the testcase() macro.
*/
#ifdef SQLITE_COVERAGE_TEST
................................................................................
** Return true if the floating point value is Not a Number (NaN).
**
** Use the math library isnan() function if compiled with SQLITE_HAVE_ISNAN.
** Otherwise, we have our own implementation that works on most systems.
*/
SQLITE_PRIVATE int sqlite3IsNaN(double x){
  int rc;   /* The value return */
#if !defined(SQLITE_HAVE_ISNAN)
  /*
  ** Systems that support the isnan() library function should probably
  ** make use of it by compiling with -DSQLITE_HAVE_ISNAN.  But we have
  ** found that many systems do not have a working isnan() function so
  ** this implementation is provided as an alternative.
  **
  ** This NaN test sometimes fails if compiled on GCC with -ffast-math.
................................................................................
  */
#ifdef __FAST_MATH__
# error SQLite will not work correctly with the -ffast-math option of GCC.
#endif
  volatile double y = x;
  volatile double z = y;
  rc = (y!=z);
#else  /* if defined(SQLITE_HAVE_ISNAN) */
  rc = isnan(x);
#endif /* SQLITE_HAVE_ISNAN */
  testcase( rc );
  return rc;
}
#endif /* SQLITE_OMIT_FLOATING_POINT */

/*
** Compute a string length that is limited to what can be stored in
................................................................................
SQLITE_API int sqlite3_fullsync_count = 0;
#endif

/*
** We do not trust systems to provide a working fdatasync().  Some do.
** Others do no.  To be safe, we will stick with the (slightly slower)
** fsync(). If you know that your system does support fdatasync() correctly,
** then simply compile with -Dfdatasync=fdatasync
*/
#if !defined(fdatasync)
# define fdatasync fsync
#endif

/*
** Define HAVE_FULLFSYNC to 0 or 1 depending on whether or not
** the F_FULLFSYNC macro is defined.  F_FULLFSYNC is currently
** only available on Mac OS X.  But that could change.
................................................................................
      ** or an error number on  failure". See the manpage for details. */
      int err;
      do{
        err = osFallocate(pFile->h, buf.st_size, nSize-buf.st_size);
      }while( err==EINTR );
      if( err ) return SQLITE_IOERR_WRITE;
#else
      /* If the OS does not have posix_fallocate(), fake it. First use
      ** ftruncate() to set the file size, then write a single byte to
      ** the last byte in each block within the extended region. This
      ** is the same technique used by glibc to implement posix_fallocate()

      ** on systems that do not have a real fallocate() system call.
      */
      int nBlk = buf.st_blksize;  /* File-system block size */

      i64 iWrite;                 /* Next offset to write to */

      if( robust_ftruncate(pFile->h, nSize) ){
        pFile->lastErrno = errno;
        return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath);
      }
      iWrite = ((buf.st_size + 2*nBlk - 1)/nBlk)*nBlk-1;



      while( iWrite<nSize ){
        int nWrite = seekAndWrite(pFile, iWrite, "", 1);
        if( nWrite!=1 ) return SQLITE_IOERR_WRITE;
        iWrite += nBlk;




      }
#endif
    }
  }

#if SQLITE_MAX_MMAP_SIZE>0
  if( pFile->mmapSizeMax>0 && nByte>pFile->mmapSize ){
................................................................................
** the sqlite3_memory_used() function does not return zero, SQLITE_BUSY will
** be returned and no changes will be made to the Win32 native heap.
*/
SQLITE_API int sqlite3_win32_reset_heap(){
  int rc;
  MUTEX_LOGIC( sqlite3_mutex *pMaster; ) /* The main static mutex */
  MUTEX_LOGIC( sqlite3_mutex *pMem; )    /* The memsys static mutex */
  MUTEX_LOGIC( pMaster = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); )
  MUTEX_LOGIC( pMem = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM); )
  sqlite3_mutex_enter(pMaster);
  sqlite3_mutex_enter(pMem);
  winMemAssertMagic();
  if( winMemGetHeap()!=NULL && winMemGetOwned() && sqlite3_memory_used()==0 ){
    /*
    ** At this point, there should be no outstanding memory allocations on
    ** the heap.  Also, since both the master and memsys locks are currently
................................................................................
*/
static int winRead(
  sqlite3_file *id,          /* File to read from */
  void *pBuf,                /* Write content into this buffer */
  int amt,                   /* Number of bytes to read */
  sqlite3_int64 offset       /* Begin reading at this offset */
){
#if !SQLITE_OS_WINCE
  OVERLAPPED overlapped;          /* The offset for ReadFile. */
#endif
  winFile *pFile = (winFile*)id;  /* file handle */
  DWORD nRead;                    /* Number of bytes actually read from file */
  int nRetry = 0;                 /* Number of retrys */

  assert( id!=0 );
................................................................................
      pBuf = &((u8 *)pBuf)[nCopy];
      amt -= nCopy;
      offset += nCopy;
    }
  }
#endif

#if SQLITE_OS_WINCE
  if( winSeekFile(pFile, offset) ){
    OSTRACE(("READ file=%p, rc=SQLITE_FULL\n", pFile->h));
    return SQLITE_FULL;
  }
  while( !osReadFile(pFile->h, pBuf, amt, &nRead, 0) ){
#else
  memset(&overlapped, 0, sizeof(OVERLAPPED));
................................................................................
      pBuf = &((u8 *)pBuf)[nCopy];
      amt -= nCopy;
      offset += nCopy;
    }
  }
#endif

#if SQLITE_OS_WINCE
  rc = winSeekFile(pFile, offset);
  if( rc==0 ){
#else
  {
#endif
#if !SQLITE_OS_WINCE
    OVERLAPPED overlapped;        /* The offset for WriteFile. */
#endif
    u8 *aRem = (u8 *)pBuf;        /* Data yet to be written */
    int nRem = amt;               /* Number of bytes yet to be written */
    DWORD nWrite;                 /* Bytes written by each WriteFile() call */
    DWORD lastErrno = NO_ERROR;   /* Value returned by GetLastError() */

#if !SQLITE_OS_WINCE
    memset(&overlapped, 0, sizeof(OVERLAPPED));
    overlapped.Offset = (LONG)(offset & 0xffffffff);
    overlapped.OffsetHigh = (LONG)((offset>>32) & 0x7fffffff);
#endif

    while( nRem>0 ){
#if SQLITE_OS_WINCE
      if( !osWriteFile(pFile->h, aRem, nRem, &nWrite, 0) ){
#else
      if( !osWriteFile(pFile->h, aRem, nRem, &nWrite, &overlapped) ){
#endif
        if( winRetryIoerr(&nRetry, &lastErrno) ) continue;
        break;
      }
      assert( nWrite==0 || nWrite<=(DWORD)nRem );
      if( nWrite==0 || nWrite>(DWORD)nRem ){
        lastErrno = osGetLastError();
        break;
      }
#if !SQLITE_OS_WINCE
      offset += nWrite;
      overlapped.Offset = (LONG)(offset & 0xffffffff);
      overlapped.OffsetHigh = (LONG)((offset>>32) & 0x7fffffff);
#endif
      aRem += nWrite;
      nRem -= nWrite;
    }
................................................................................
  u8 eCreate;                         /* eCreate value for for xFetch() */
  int (*xStress)(void*,PgHdr*);       /* Call to try make a page clean */
  void *pStress;                      /* Argument to xStress */
  sqlite3_pcache *pCache;             /* Pluggable cache module */
  PgHdr *pPage1;                      /* Reference to page 1 */
};

/*
** Some of the assert() macros in this code are too expensive to run
** even during normal debugging.  Use them only rarely on long-running
** tests.  Enable the expensive asserts using the
** -DSQLITE_ENABLE_EXPENSIVE_ASSERT=1 compile-time option.
*/
#ifdef SQLITE_