Fossil

Check-in [7124f09f]
Login

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

Overview
Comment:Merge latest changes from trunk.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | ashish-ipv6
Files: files | file ages | folders
SHA1:7124f09f0770f64948f18d1866b37aa52e8048dd
User & Date: ashish 2012-03-10 13:17:50
Context
2013-04-21
08:08
Merge with trunk - Remove reverse-proxying support which is already provided by --baseurl option. check-in: 940b0b33 user: ashish tags: ashish-ipv6
2012-03-10
13:17
Merge latest changes from trunk. check-in: 7124f09f user: ashish tags: ashish-ipv6
03:59
Removed some dead code in /json/timeline/wiki. check-in: fe5cf37e user: stephan tags: trunk
2012-01-15
18:06
Merge latest changes from trunk check-in: b3130baa user: ashish tags: ashish-ipv6
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to Makefile.in.

38
39
40
41
42
43
44

45
46
47
48
49
#
TCLSH = tclsh

LIB =	@LDFLAGS@ @EXTRA_LDFLAGS@ @LIBS@
TCC +=	@EXTRA_CFLAGS@ @CPPFLAGS@ @CFLAGS@ -DHAVE_AUTOCONFIG_H
INSTALLDIR = $(DESTDIR)@prefix@/bin
USE_SYSTEM_SQLITE = @USE_SYSTEM_SQLITE@


include $(SRCDIR)/main.mk

distclean: clean
	rm -f autoconfig.h config.log Makefile







>





38
39
40
41
42
43
44
45
46
47
48
49
50
#
TCLSH = tclsh

LIB =	@LDFLAGS@ @EXTRA_LDFLAGS@ @LIBS@
TCC +=	@EXTRA_CFLAGS@ @CPPFLAGS@ @CFLAGS@ -DHAVE_AUTOCONFIG_H
INSTALLDIR = $(DESTDIR)@prefix@/bin
USE_SYSTEM_SQLITE = @USE_SYSTEM_SQLITE@
FOSSIL_ENABLE_TCL = @FOSSIL_ENABLE_TCL@

include $(SRCDIR)/main.mk

distclean: clean
	rm -f autoconfig.h config.log Makefile

Changes to VERSION.

1
1.21
|
1
1.22

Changes to ajax/i-test/rhino-test.js.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
...
169
170
171
172
173
174
175
















176
177
178
179
180
181
182
...
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
...
235
236
237
238
239
240
241

242
243
244
245
246
247
248
249
250
var TestApp = {
    serverUrl:
        'http://localhost:8080'
        //'http://fjson/cgi-bin/fossil-json.cgi'
        //'http://192.168.1.62:8080'
        //'http://fossil.wanderinghorse.net/repos/fossil-json-java/index.cgi'
        ,
    verbose:false,
    fossilBinary:'fossil',
    wiki:{}
};
(function bootstrap() {
    var srcdir = '../js/';
    var includes = [srcdir+'json2.js',
                    srcdir+'whajaj.js',
................................................................................
    assertResponseOK(rs);
    assert(rs.payload.name == TestApp.wiki.list[0], "Fetched page name matches expectations.");
    print("Got first wiki page: "+WhAjaj.stringify(rs.payload));

}
testAnonWiki.description = 'Fetch wiki list as anonymous user.';

















function testAnonLogout(){
    var rs;
    TestApp.fossil.logout({
        onResponse:function(resp,req){
            rs = resp;
        }
    });
................................................................................
    var args = [TestApp.fossilBinary, 'json', '--json-input', '-'];
    var p = java.lang.Runtime.getRuntime().exec(args);
    var outs = p.getOutputStream();
    var osr = new java.io.OutputStreamWriter(outs);
    var osb = new java.io.BufferedWriter(osr);
    var json = JSON.stringify(req);
    osb.write(json,0, json.length);
    //osb.flush();
    osb.close();

    var ins = p.getInputStream();
    var isr = new java.io.InputStreamReader(ins);
    var br = new java.io.BufferedReader(isr);
    var line;
    
    while( null !== (line=br.readLine())){
        print(line);
    }
    //outs.close();

    ins.close();

}
testExternalProcess.description = 'Run fossil as external process.';

function testExternalProcessHandler(){
    var aj = TestApp.fossil.ajaj;
    var oldImpl = aj.sendImpl;
    aj.sendImpl = FossilAjaj.rhinoLocalBinarySendImpl;
................................................................................

(function runAllTests(){
    var testList = [
        testHAI,
        testIAmNobody,
        testAnonymousLogin,
        testAnonWiki,

        testAnonLogout,
        //testExternalProcess,
        testExternalProcessHandler
    ];
    var i, f;
    for( i = 0; i < testList.length; ++i ){
        f = testList[i];
        try{
            print("Running test #"+(i+1)+": "+(f.description || "no description."));







|







 







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







 







<

>








|
>

>







 







>

|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
...
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
...
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
...
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
var TestApp = {
    serverUrl:
        'http://localhost:8080'
        //'http://fjson/cgi-bin/fossil-json.cgi'
        //'http://192.168.1.62:8080'
        //'http://fossil.wanderinghorse.net/repos/fossil-json-java/index.cgi'
        ,
    verbose:true,
    fossilBinary:'fossil',
    wiki:{}
};
(function bootstrap() {
    var srcdir = '../js/';
    var includes = [srcdir+'json2.js',
                    srcdir+'whajaj.js',
................................................................................
    assertResponseOK(rs);
    assert(rs.payload.name == TestApp.wiki.list[0], "Fetched page name matches expectations.");
    print("Got first wiki page: "+WhAjaj.stringify(rs.payload));

}
testAnonWiki.description = 'Fetch wiki list as anonymous user.';

function testFetchCheckinArtifact(){
    var art = '18dd383e5e7684ece';
    var rs;
    TestApp.fossil.sendCommand('/json/artifact',{
        'name': art
        },
        {
            onResponse:function(resp,req){
                rs = resp;
            }
        });
    assertResponseOK(rs);
    assert(3 == rs.payload.artifact.parents.length, 'Got 3 parent artifacts.');
}
testFetchCheckinArtifact.description = '/json/artifact/CHECKIN';

function testAnonLogout(){
    var rs;
    TestApp.fossil.logout({
        onResponse:function(resp,req){
            rs = resp;
        }
    });
................................................................................
    var args = [TestApp.fossilBinary, 'json', '--json-input', '-'];
    var p = java.lang.Runtime.getRuntime().exec(args);
    var outs = p.getOutputStream();
    var osr = new java.io.OutputStreamWriter(outs);
    var osb = new java.io.BufferedWriter(osr);
    var json = JSON.stringify(req);
    osb.write(json,0, json.length);

    osb.close();
    req = json = outs = osr = osb = undefined;
    var ins = p.getInputStream();
    var isr = new java.io.InputStreamReader(ins);
    var br = new java.io.BufferedReader(isr);
    var line;
    
    while( null !== (line=br.readLine())){
        print(line);
    }
    br.close();
    isr.close();
    ins.close();
    p.waitFor();
}
testExternalProcess.description = 'Run fossil as external process.';

function testExternalProcessHandler(){
    var aj = TestApp.fossil.ajaj;
    var oldImpl = aj.sendImpl;
    aj.sendImpl = FossilAjaj.rhinoLocalBinarySendImpl;
................................................................................

(function runAllTests(){
    var testList = [
        testHAI,
        testIAmNobody,
        testAnonymousLogin,
        testAnonWiki,
        testFetchCheckinArtifact,
        testAnonLogout,
        testExternalProcess,
        testExternalProcessHandler
    ];
    var i, f;
    for( i = 0; i < testList.length; ++i ){
        f = testList[i];
        try{
            print("Running test #"+(i+1)+": "+(f.description || "no description."));

Changes to ajax/index.html.

231
232
233
234
235
236
237



238

239
240

241
242
243
244
245
246
247
...
265
266
267
268
269
270
271


272
273
274
275
276
277
278
<br/>

<input type='button' value='branch/list' onclick='TheApp.cgi.sendCommand("/json/branch/list")' />
<input type='button' value='timeline/ci' onclick='TheApp.cgi.sendCommand("/json/timeline/ci?files=true")' />
<input type='button' value='timeline/wiki' onclick='TheApp.cgi.sendCommand("/json/timeline/wiki")' />
<input type='button' value='timeline/ticket' onclick='TheApp.cgi.sendCommand("/json/timeline/ticket")' />
<input type='button' value='timeline/branch' onclick='TheApp.cgi.sendCommand("/json/timeline/branch")' />



<input type='button' value='wiki/list' onclick='TheApp.cgi.sendCommand("/json/wiki/list")' />

<input type='button' value='wiki/get Fossil' onclick='TheApp.cgi.sendCommand("/json/wiki/get",{name:"Fossil"})' />
<input type='button' value='wiki/get/Fossil' onclick='TheApp.cgi.sendCommand("/json/wiki/get/Fossil")' />


<br/>

<input type='button' value='user/list' onclick='TheApp.cgi.sendCommand("/json/user/list")' />
<input type='button' value='user/get' onclick='TheApp.cgi.sendCommand("/json/user/get?name=anonymous")' />
<input type='button' value='tag/list' onclick='TheApp.cgi.sendCommand("/json/tag/list?includeTickets=false&raw=false")' />
<input type='button' value='tag/list/json' onclick='TheApp.cgi.sendCommand("/json/tag/list/json?raw=false")' />
................................................................................
<input type='button' value='report list'
    onclick='TheApp.cgi.sendCommand("/json/report/list")' />
<input type='button' value='report get'
    onclick='TheApp.cgi.sendCommand("/json/report/get",2)' />

<input type='button' value='report run'
    onclick='TheApp.cgi.sendCommand("/json/report/run",{"report":2,"format":"o"})' />



<!-- not yet ready...
<input type='button' value='artifact/XYZ' onclick='TheApp.cgi.sendCommand("/json/artifact?uuid=json")' />
-->

<!--
<input type='button' value='get whiki' onclick='TheApp.cgi.getPages("whiki")' />







>
>
>

>


>







 







>
>







231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
...
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
<br/>

<input type='button' value='branch/list' onclick='TheApp.cgi.sendCommand("/json/branch/list")' />
<input type='button' value='timeline/ci' onclick='TheApp.cgi.sendCommand("/json/timeline/ci?files=true")' />
<input type='button' value='timeline/wiki' onclick='TheApp.cgi.sendCommand("/json/timeline/wiki")' />
<input type='button' value='timeline/ticket' onclick='TheApp.cgi.sendCommand("/json/timeline/ticket")' />
<input type='button' value='timeline/branch' onclick='TheApp.cgi.sendCommand("/json/timeline/branch")' />

<br/>

<input type='button' value='wiki/list' onclick='TheApp.cgi.sendCommand("/json/wiki/list")' />
<input type='button' value='wiki/list verbose' onclick='TheApp.cgi.sendCommand("/json/wiki/list",{verbose:1})' />
<input type='button' value='wiki/get Fossil' onclick='TheApp.cgi.sendCommand("/json/wiki/get",{name:"Fossil"})' />
<input type='button' value='wiki/get/Fossil' onclick='TheApp.cgi.sendCommand("/json/wiki/get/Fossil")' />
<input type='button' value='wiki/diff' onclick='TheApp.cgi.sendCommand("/json/wiki/diff/e32ccdcda59e930c77c/e15992f475760cdf3a9")' />

<br/>

<input type='button' value='user/list' onclick='TheApp.cgi.sendCommand("/json/user/list")' />
<input type='button' value='user/get' onclick='TheApp.cgi.sendCommand("/json/user/get?name=anonymous")' />
<input type='button' value='tag/list' onclick='TheApp.cgi.sendCommand("/json/tag/list?includeTickets=false&raw=false")' />
<input type='button' value='tag/list/json' onclick='TheApp.cgi.sendCommand("/json/tag/list/json?raw=false")' />
................................................................................
<input type='button' value='report list'
    onclick='TheApp.cgi.sendCommand("/json/report/list")' />
<input type='button' value='report get'
    onclick='TheApp.cgi.sendCommand("/json/report/get",2)' />

<input type='button' value='report run'
    onclick='TheApp.cgi.sendCommand("/json/report/run",{"report":2,"format":"o"})' />

<input type='button' value='config/get' onclick='TheApp.cgi.sendCommand("/json/config/get")' />

<!-- not yet ready...
<input type='button' value='artifact/XYZ' onclick='TheApp.cgi.sendCommand("/json/artifact?uuid=json")' />
-->

<!--
<input type='button' value='get whiki' onclick='TheApp.cgi.getPages("whiki")' />

Changes to ajax/js/whajaj.js.

107
108
109
110
111
112
113

114
115
116
117
118
119
120
    if( 0 === arguments.length ) {
        if( ('undefined' === typeof window) ||
            !window.location ||
            !window.location.search )  return false;
        else str = (''+window.location.search).substring(1);
    }
    if( ! str ) return false;

    var args = {};
    var sp = str.split(/&+/);
    var rx = /^([^=]+)(=(.+))?/;
    var i, m;
    for( i in sp ) {
        m = rx.exec( sp[i] );
        if( ! m ) continue;







>







107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
    if( 0 === arguments.length ) {
        if( ('undefined' === typeof window) ||
            !window.location ||
            !window.location.search )  return false;
        else str = (''+window.location.search).substring(1);
    }
    if( ! str ) return false;
    str = (''+str).split(/#/,2)[0]; // remove #... to avoid it being added as part of the last value.
    var args = {};
    var sp = str.split(/&+/);
    var rx = /^([^=]+)(=(.+))?/;
    var i, m;
    for( i in sp ) {
        m = rx.exec( sp[i] );
        if( ! m ) continue;

Changes to auto.def.

164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
            if {$dir eq ""} {
                set msg "system ssl"
                set cflags ""
                set ldflags ""
            } else {
                set msg "ssl in $dir"
                set cflags "-I$dir/include"
                set ldflags "-L$dir/include"
            }
            if {[check-for-openssl $msg "$cflags $ldflags"]} {
                incr found
                break
            }
        }
    }







|







164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
            if {$dir eq ""} {
                set msg "system ssl"
                set cflags ""
                set ldflags ""
            } else {
                set msg "ssl in $dir"
                set cflags "-I$dir/include"
                set ldflags "-L$dir/lib"
            }
            if {[check-for-openssl $msg "$cflags $ldflags"]} {
                incr found
                break
            }
        }
    }

Changes to autosetup/README.autosetup.

1
This is autosetup v0.6.2. See http://msteveb.github.com/autosetup/
|
1
This is autosetup v0.6.4. See http://msteveb.github.com/autosetup/

Changes to autosetup/autosetup.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
...
514
515
516
517
518
519
520

521
522
523
524
525
526



527
528
529
530
531
532
533
....
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
....
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
#!/bin/sh
# Copyright (c) 2006-2011 WorkWare Systems http://www.workware.net.au/
# All rights reserved
# vim:se syntax=tcl:
# \
dir=`dirname "$0"`; exec "`$dir/find-tclsh`" "$0" "$@"

set autosetup(version) 0.6.2

# Can be set to 1 to debug early-init problems
set autosetup(debug) 0

##################################################################
#
# Main flow of control, option handling
................................................................................
	}
	getenv $name $default
}

# @env-is-set name
#
# Returns 1 if the $name was specified on the command line or in the environment.

#
proc env-is-set {name} {
	if {[dict exists $::autosetup(cmdline) $name]} {
		return 1
	}
	info exists ::env($name)



}

# @readfile filename ?default=""?
#
# Return the contents of the file, without the trailing newline.
# If the doesn't exist or can't be read, returns $default.
#
................................................................................
	} else {
		puts "I don't see configure, so I will create it."
	}
	if {$create_configure} {
		if {!$::autosetup(installed)} {
			user-notice "Warning: Initialising from the development version of autosetup"

			writefile configure "#!/bin/sh\nWRAPPER=\"\$0\" exec $::autosetup(dir)/autosetup \"\$@\"\n"
		} else {
			writefile configure \
{#!/bin/sh
dir="`dirname "$0"`/autosetup"
WRAPPER="$0" exec "`$dir/find-tclsh`" "$dir/autosetup" "$@"
}
		}
		catch {exec chmod 755 configure}
	}
	if {![file exists auto.def]} {
		puts "I don't see auto.def, so I will create a default one."
		writefile auto.def {# Initial auto.def created by 'autosetup --init'
................................................................................
	}
} elseif {$autosetup(iswin)} {
	# On Windows, backslash convert all environment variables
	# (Assume that Tcl does this for us)
	proc getenv {name args} {
		string map {\\ /} [env $name {*}$args]
	}
	# Jim uses system() for exec under mingw, so
	# we need to fetch the output ourselves
	proc exec-with-stderr {args} {
			set tmpfile auto[format %04x [rand 10000]].tmp
			set rc [catch [list exec {*}$args >$tmpfile 2>&1] result]
			set result [readfile $tmpfile]
			file delete $tmpfile
			return -code $rc $result
	}
} else {
	# Jim on unix is simple
	alias getenv env
}

# In case 'file normalize' doesn't exist
#







|







 







>





|
>
>
>







 







|




|







 







<
<
<
<
<
<
<
<
<







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
...
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
....
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
....
1543
1544
1545
1546
1547
1548
1549









1550
1551
1552
1553
1554
1555
1556
#!/bin/sh
# Copyright (c) 2006-2011 WorkWare Systems http://www.workware.net.au/
# All rights reserved
# vim:se syntax=tcl:
# \
dir=`dirname "$0"`; exec "`$dir/find-tclsh`" "$0" "$@"

set autosetup(version) 0.6.4

# Can be set to 1 to debug early-init problems
set autosetup(debug) 0

##################################################################
#
# Main flow of control, option handling
................................................................................
	}
	getenv $name $default
}

# @env-is-set name
#
# Returns 1 if the $name was specified on the command line or in the environment.
# Note that an empty environment variable is not considered to be set.
#
proc env-is-set {name} {
	if {[dict exists $::autosetup(cmdline) $name]} {
		return 1
	}
	if {[getenv $name ""] ne ""} {
		return 1
	}
	return 0
}

# @readfile filename ?default=""?
#
# Return the contents of the file, without the trailing newline.
# If the doesn't exist or can't be read, returns $default.
#
................................................................................
	} else {
		puts "I don't see configure, so I will create it."
	}
	if {$create_configure} {
		if {!$::autosetup(installed)} {
			user-notice "Warning: Initialising from the development version of autosetup"

			writefile configure "#!/bin/sh\nWRAPPER=\"\$0\"; export WRAPPER; exec $::autosetup(dir)/autosetup \"\$@\"\n"
		} else {
			writefile configure \
{#!/bin/sh
dir="`dirname "$0"`/autosetup"
WRAPPER="$0"; export WRAPPER; exec "`$dir/find-tclsh`" "$dir/autosetup" "$@"
}
		}
		catch {exec chmod 755 configure}
	}
	if {![file exists auto.def]} {
		puts "I don't see auto.def, so I will create a default one."
		writefile auto.def {# Initial auto.def created by 'autosetup --init'
................................................................................
	}
} elseif {$autosetup(iswin)} {
	# On Windows, backslash convert all environment variables
	# (Assume that Tcl does this for us)
	proc getenv {name args} {
		string map {\\ /} [env $name {*}$args]
	}









} else {
	# Jim on unix is simple
	alias getenv env
}

# In case 'file normalize' doesn't exist
#

Added autosetup/cc-db.tcl.































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Copyright (c) 2011 WorkWare Systems http://www.workware.net.au/
# All rights reserved

# @synopsis:
#
# The 'cc-db' module provides a knowledge based of system idiosyncracies
# In general, this module can always be included

use cc

module-options {}

# openbsd needs sys/types.h to detect some system headers
cc-include-needs sys/socket.h sys/types.h
cc-include-needs netinet/in.h sys/types.h

Changes to autosetup/cc-shared.tcl.

5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
..
23
24
25
26
27
28
29

30
31
32
33
34

35
36
37
38
39
40
41
..
48
49
50
51
52
53
54








55
56
57
58
59
60
61
62
63




#
# The 'cc-shared' module provides support for shared libraries and shared objects.
# It defines the following variables:
#
## SH_CFLAGS         Flags to use compiling sources destined for a shared library
## SH_LDFLAGS        Flags to use linking a shared library
## SHOBJ_CFLAGS      Flags to use compiling sources destined for a shared object
## SHOBJ_LDFLAGS     Flags to use linking a shared object

## SH_LINKFLAGS      Flags to use linking an executable which will load shared objects
## LD_LIBRARY_PATH   Environment variable which specifies path to shared libraries

module-options {}

foreach i {SH_LINKFLAGS SH_CFLAGS SH_LDFLAGS SHOBJ_CFLAGS SHOBJ_LDFLAGS} {
	define $i ""
................................................................................

switch -glob -- [get-define host] {
	*-*-darwin* {
		define SH_CFLAGS -dynamic
		define SH_LDFLAGS "-dynamiclib"
		define SHOBJ_CFLAGS "-dynamic -fno-common"
		define SHOBJ_LDFLAGS "-bundle -undefined dynamic_lookup"

		define LD_LIBRARY_PATH DYLD_LIBRARY_PATH
	}
	*-*-ming* {
		define SH_LDFLAGS -shared
		define SHOBJ_LDFLAGS -shared

	}
	*-*-cygwin {
		define SH_LDFLAGS -shared
		define SHOBJ_LDFLAGS -shared
	}
	*-*-solaris* {
		# XXX: These haven't been fully tested. 
................................................................................
		# XXX: These haven't been tested
		define SH_LINKFLAGS -Wl,+s
		define SH_CFLAGS +z
		define SHOBJ_CFLAGS "+O3 +z"
		define SHOBJ_LDFLAGS -b
		define LD_LIBRARY_PATH SHLIB_PATH
	}








	* {
		# Generic Unix settings
		define SH_LINKFLAGS -rdynamic
		define SH_CFLAGS -fpic
		define SH_LDFLAGS -shared
		define SHOBJ_CFLAGS -fpic
		define SHOBJ_LDFLAGS "-shared -nostartfiles"
	}
}











|
>







 







>





>







 







>
>
>
>
>
>
>
>






|


>
>
>
>
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
..
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
..
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
#
# The 'cc-shared' module provides support for shared libraries and shared objects.
# It defines the following variables:
#
## SH_CFLAGS         Flags to use compiling sources destined for a shared library
## SH_LDFLAGS        Flags to use linking a shared library
## SHOBJ_CFLAGS      Flags to use compiling sources destined for a shared object
## SHOBJ_LDFLAGS     Flags to use linking a shared object, undefined symbols allowed
## SHOBJ_LDFLAGS_R   - as above, but all symbols must be resolved
## SH_LINKFLAGS      Flags to use linking an executable which will load shared objects
## LD_LIBRARY_PATH   Environment variable which specifies path to shared libraries

module-options {}

foreach i {SH_LINKFLAGS SH_CFLAGS SH_LDFLAGS SHOBJ_CFLAGS SHOBJ_LDFLAGS} {
	define $i ""
................................................................................

switch -glob -- [get-define host] {
	*-*-darwin* {
		define SH_CFLAGS -dynamic
		define SH_LDFLAGS "-dynamiclib"
		define SHOBJ_CFLAGS "-dynamic -fno-common"
		define SHOBJ_LDFLAGS "-bundle -undefined dynamic_lookup"
		define SHOBJ_LDFLAGS_R "-bundle"
		define LD_LIBRARY_PATH DYLD_LIBRARY_PATH
	}
	*-*-ming* {
		define SH_LDFLAGS -shared
		define SHOBJ_LDFLAGS -shared
		define SHOBJ_LDFLAGS_R -shared
	}
	*-*-cygwin {
		define SH_LDFLAGS -shared
		define SHOBJ_LDFLAGS -shared
	}
	*-*-solaris* {
		# XXX: These haven't been fully tested. 
................................................................................
		# XXX: These haven't been tested
		define SH_LINKFLAGS -Wl,+s
		define SH_CFLAGS +z
		define SHOBJ_CFLAGS "+O3 +z"
		define SHOBJ_LDFLAGS -b
		define LD_LIBRARY_PATH SHLIB_PATH
	}
	sparc* {
		# sparc has a very small GOT table limit, so use -fPIC
		define SH_LINKFLAGS -rdynamic
		define SH_CFLAGS -fPIC
		define SH_LDFLAGS -shared
		define SHOBJ_CFLAGS -fPIC
		define SHOBJ_LDFLAGS -shared
	}
	* {
		# Generic Unix settings
		define SH_LINKFLAGS -rdynamic
		define SH_CFLAGS -fpic
		define SH_LDFLAGS -shared
		define SHOBJ_CFLAGS -fpic
		define SHOBJ_LDFLAGS -shared
	}
}

if {![is-defined SHOBJ_LDFLAGS_R]} {
	define SHOBJ_LDFLAGS_R [get-define SHOBJ_LDFLAGS]
}

Changes to autosetup/cc.tcl.

109
110
111
112
113
114
115












116
117


118










119
120
121
122
123
124
125
...
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
...
644
645
646
647
648
649
650

651
652
653
654
655
656
657
658
659
660
}

# @cc-check-includes includes ...
#
# Checks that the given include files can be used
proc cc-check-includes {args} {
	cc-check-some-feature $args {












		cctest -includes $each
	}


}











# @cc-check-types type ...
#
# Checks that the types exist.
proc cc-check-types {args} {
	cc-check-some-feature $args {
		cctest_type $each
................................................................................
	} elseif {[llength $args] > 1} {
		autosetup-error "usage: cc-with settings ?script?"
	} else {
		set save [cc-add-settings $settings]
		set rc [catch {uplevel 1 [lindex $args 0]} result info]
		cc-store-settings $save
		if {$rc != 0} {
			return $result -code [dict get $info -code]
		}
		return $result
	}
}

# @cctest ?settings?
# 
................................................................................
	user-error "Could not find a C compiler. Tried: [join $try ", "]"
}

define CCACHE [find-an-executable [get-env CCACHE ccache]]

# Initial cctest settings
cc-store-settings {-cflags {} -includes {} -declare {} -link 0 -lang c -libs {} -code {}}


msg-result "C compiler...[get-define CCACHE] [get-define CC] [get-define CFLAGS]"
if {[get-define CXX] ne "false"} {
	msg-result "C++ compiler...[get-define CCACHE] [get-define CXX] [get-define CXXFLAGS]"
}
msg-result "Build C compiler...[get-define CC_FOR_BUILD]"

if {![cc-check-includes stdlib.h]} {
	user-error "Compiler does not work. See config.log"
}







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







 







|







 







>










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
...
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
...
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
}

# @cc-check-includes includes ...
#
# Checks that the given include files can be used
proc cc-check-includes {args} {
	cc-check-some-feature $args {
		set with {}
		if {[dict exists $::autosetup(cc-include-deps) $each]} {
			set deps [dict keys [dict get $::autosetup(cc-include-deps) $each]]
			msg-quiet cc-check-includes $deps
			foreach i $deps {
				if {[have-feature $i]} {
					lappend with $i
				}
			}
		}
		if {[llength $with]} {
			cc-with [list -includes $with] {
				cctest -includes $each
			}
		} else {
			cctest -includes $each
		}
	}
}

# @cc-include-needs include required
#
# Ensures that when checking for 'include', a check is first
# made for 'required', and if found, it is #included
proc cc-include-needs {file depfile} {
	dict set ::autosetup(cc-include-deps) $file $depfile 1
}

# @cc-check-types type ...
#
# Checks that the types exist.
proc cc-check-types {args} {
	cc-check-some-feature $args {
		cctest_type $each
................................................................................
	} elseif {[llength $args] > 1} {
		autosetup-error "usage: cc-with settings ?script?"
	} else {
		set save [cc-add-settings $settings]
		set rc [catch {uplevel 1 [lindex $args 0]} result info]
		cc-store-settings $save
		if {$rc != 0} {
			return -code [dict get $info -code] $result
		}
		return $result
	}
}

# @cctest ?settings?
# 
................................................................................
	user-error "Could not find a C compiler. Tried: [join $try ", "]"
}

define CCACHE [find-an-executable [get-env CCACHE ccache]]

# Initial cctest settings
cc-store-settings {-cflags {} -includes {} -declare {} -link 0 -lang c -libs {} -code {}}
set autosetup(cc-include-deps) {}

msg-result "C compiler...[get-define CCACHE] [get-define CC] [get-define CFLAGS]"
if {[get-define CXX] ne "false"} {
	msg-result "C++ compiler...[get-define CCACHE] [get-define CXX] [get-define CXXFLAGS]"
}
msg-result "Build C compiler...[get-define CC_FOR_BUILD]"

if {![cc-check-includes stdlib.h]} {
	user-error "Compiler does not work. See config.log"
}

Changes to autosetup/find-tclsh.

1
2
3
4

5
6
7
8
9
10
11
12
13
14
15
#!/bin/sh
# Looks for a suitable tclsh or jimsh in the PATH
# If not found, builds a bootstrap jimsh from source
d=`dirname "$0"`

PATH="$PATH:$d"
for tclsh in jimsh tclsh tclsh8.5 tclsh8.6 jimsh0; do
	{ $tclsh "$d/test-tclsh"; } 2>/dev/null && exit 0
done
echo 1>&2 "No installed jimsh or tclsh, building local bootstrap jimsh0"
for cc in ${CC_FOR_BUILD:-cc} gcc; do
	{ $cc -o "$d/jimsh0" "$d/jimsh0.c"; } 2>/dev/null || continue
	"$d/jimsh0" "$d/test-tclsh" && exit 0
done
echo 1>&2 "No working C compiler found. Tried ${CC_FOR_BUILD:-cc} and gcc."
echo false




>
|
|









1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/bin/sh
# Looks for a suitable tclsh or jimsh in the PATH
# If not found, builds a bootstrap jimsh from source
d=`dirname "$0"`
{ "$d/jimsh0" "$d/test-tclsh"; } 2>/dev/null && exit 0
PATH="$PATH:$d"; export PATH
for tclsh in jimsh tclsh tclsh8.5 tclsh8.6; do
	{ $tclsh "$d/test-tclsh"; } 2>/dev/null && exit 0
done
echo 1>&2 "No installed jimsh or tclsh, building local bootstrap jimsh0"
for cc in ${CC_FOR_BUILD:-cc} gcc; do
	{ $cc -o "$d/jimsh0" "$d/jimsh0.c"; } 2>/dev/null || continue
	"$d/jimsh0" "$d/test-tclsh" && exit 0
done
echo 1>&2 "No working C compiler found. Tried ${CC_FOR_BUILD:-cc} and gcc."
echo false

Changes to autosetup/jimsh0.c.

more than 10,000 changes

Changes to autosetup/system.tcl.

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
define prefix $prefix
define builddir $autosetup(builddir)
define srcdir $autosetup(srcdir)
# Allow this to come from the environment
define top_srcdir [get-env top_srcdir [get-define srcdir]]

# autoconf supports all of these
define exec_prefix [opt-val exec-prefix [get-env exec-prefix \${prefix}]]

foreach {name defpath} {
	bindir \${exec_prefix}/bin
	sbindir \${exec_prefix}/sbin
	libexecdir \${exec_prefix}/libexec
	libdir \${exec_prefix}/lib




	datadir \${prefix}/share
	sysconfdir \${prefix}/etc
	sharedstatedir \${prefix}/com
	localstatedir \${prefix}/var
	infodir \${prefix}/share/info
	mandir \${prefix}/share/man
	includedir \${prefix}/include
} {
	define $name [opt-val $name [get-env $name $defpath]]
}

define SHELL [get-env SHELL [find-an-executable sh bash ksh]]

# Windows vs. non-Windows
switch -glob -- [get-define host] {
	*-*-ming* - *-*-cygwin {







|
>

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

|







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
define prefix $prefix
define builddir $autosetup(builddir)
define srcdir $autosetup(srcdir)
# Allow this to come from the environment
define top_srcdir [get-env top_srcdir [get-define srcdir]]

# autoconf supports all of these
set exec_prefix [opt-val exec-prefix $prefix]
define exec_prefix $exec_prefix
foreach {name defpath} {
	bindir /bin
	sbindir /sbin
	libexecdir /libexec
	libdir /lib
} {
	define $name [opt-val $name $exec_prefix$defpath]
}
foreach {name defpath} {
	datadir /share
	sysconfdir /etc
	sharedstatedir /com
	localstatedir /var
	infodir /share/info
	mandir /share/man
	includedir /include
} {
	define $name [opt-val $name $prefix$defpath]
}

define SHELL [get-env SHELL [find-an-executable sh bash ksh]]

# Windows vs. non-Windows
switch -glob -- [get-define host] {
	*-*-ming* - *-*-cygwin {

Changes to autosetup/test-tclsh.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# A small Tcl script to verify that the chosen
# interpreter works. Sometimes we might e.g. pick up
# an interpreter for a different arch.
# Outputs the full path to the interpreter

if {[catch {info version} version] == 0} {
	# This is Jim Tcl
	if {$version >= 0.70} {
		# Ensure that regexp works
		regexp (a.*?) a

		# Older versions of jimsh may return a relative path for [info nameofexecutable]
		puts [file join [pwd] [info nameofexecutable]]
		exit 0
	}
} elseif {[catch {info tclversion} version] == 0} {
	if {$version >= 8.5 && ![string match 8.5a* [info patchlevel]]} {
		puts [info nameofexecutable]
		exit 0
	}
}
exit 1







|


<
<
|









1
2
3
4
5
6
7
8
9
10


11
12
13
14
15
16
17
18
19
20
# A small Tcl script to verify that the chosen
# interpreter works. Sometimes we might e.g. pick up
# an interpreter for a different arch.
# Outputs the full path to the interpreter

if {[catch {info version} version] == 0} {
	# This is Jim Tcl
	if {$version >= 0.72} {
		# Ensure that regexp works
		regexp (a.*?) a


		puts [info nameofexecutable]
		exit 0
	}
} elseif {[catch {info tclversion} version] == 0} {
	if {$version >= 8.5 && ![string match 8.5a* [info patchlevel]]} {
		puts [info nameofexecutable]
		exit 0
	}
}
exit 1

Changes to configure.

1
2
3
#!/bin/sh
dir="`dirname "$0"`/autosetup"
WRAPPER="$0" exec "`$dir/find-tclsh`" "$dir/autosetup" "$@"


|
1
2
3
#!/bin/sh
dir="`dirname "$0"`/autosetup"
WRAPPER="$0"; export WRAPPER; exec "`$dir/find-tclsh`" "$dir/autosetup" "$@"

Changes to debian/makedeb.sh.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
..
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
..
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
#!/bin/bash
# A quick hack to generate a Debian package of fossil. i took most of this
# from Martin Krafft's "The Debian System" book.

DEB_REV=${1-1} # .deb package build/revision number.
PACKAGE_DEBNAME=fossil-scm
THISDIR=${PWD}

if uname -a | grep -i nexenta &>/dev/null; then
# Assume NexentaOS/GnuSolaris:
    DEB_PLATFORM=nexenta
    DEB_ARCH_NAME=solaris-i386
    DEB_ARCH_PKGDEPENDS="sunwcsl" # for -lsocket
else
    DEB_PLATFORM=${DEB_PLATFORM-ubuntu-gutsy}
    DEB_ARCH_NAME=i386
fi

SRCDIR=$(cd ..; pwd)
test -e ${SRCDIR}/fossil || {
    echo "This script must be run from a BUILT copy of the source tree."
    exit 1
}
................................................................................


rm -fr DEBIAN
mkdir DEBIAN

PACKAGE_VERSION=$(date +%Y.%m.%d)
PACKAGE_DEB_VERSION=${PACKAGE_VERSION}-${DEB_REV}
DEBFILE=${THISDIR}/${PACKAGE_DEBNAME}-${PACKAGE_DEB_VERSION}-dev-${DEB_ARCH_NAME}-${DEB_PLATFORM}.deb
PACKAGE_TIME=$(/bin/date)

rm -f ${DEBFILE}
echo "Creating .deb package [${DEBFILE}]..."

echo "Generating md5 sums..."
find ${DEBLOCALPREFIX} -type f -exec md5sum {} \; > DEBIAN/md5sums

true && {
    echo "Generating Debian-specific files..."
    COPYRIGHT=${DEBLOCALPREFIX}/share/doc/${PACKAGE_DEBNAME}/copyright
    cat <<EOF > ${COPYRIGHT}
This package was created by stephan beal <stephan@s11n.net>
on ${PACKAGE_TIME}.

The original sources for fossil can be downloaded for free from:

http://www.fossil-scm.org/

fossil is released under the terms of the GNU General Public License.
................................................................................
    CHANGELOG=${DEBLOCALPREFIX}/share/doc/${PACKAGE_DEBNAME}/changelog.gz
    cat <<EOF | gzip -c > ${CHANGELOG}
${PACKAGE_DEBNAME} ${PACKAGE_DEB_VERSION}; urgency=low

This release has no changes over the core source distribution. It has
simply been Debianized.

Packaged by stephan beal <stephan@s11n.net> on
${PACKAGE_TIME}.

EOF

}


true && {
    CONTROL=DEBIAN/control
    echo "Generating ${CONTROL}..."
    cat <<EOF > ${CONTROL}
Package: ${PACKAGE_DEBNAME}
Section: devel
Priority: optional
Maintainer: stephan beal <stephan@s11n.net>
Architecture: ${DEB_ARCH_NAME}
Depends: libc6-dev ${DEB_ARCH_PKGDEPENDS+, }${DEB_ARCH_PKGDEPENDS}
Version: ${PACKAGE_DEB_VERSION}
Description: Fossil is a unique SCM (Software Configuration Management) system.
 This package contains the Fossil binary for *buntu/Debian systems.
 Fossil is a unique SCM program which supports distributed source control
 management using local repositories, access over HTTP CGI, or using the
 built-in HTTP server. It has a built-in wiki, file browsing, etc.
 Fossil home page: http://fossil-scm.org





|




<



<
|







 







|












|







 







|












|

|

|







1
2
3
4
5
6
7
8
9
10

11
12
13

14
15
16
17
18
19
20
21
..
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
..
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
#!/bin/bash
# A quick hack to generate a Debian package of fossil. i took most of this
# from Martin Krafft's "The Debian System" book.

DEB_REV=${1-1} # .deb package build/revision number.
PACKAGE_DEBNAME=fossil
THISDIR=${PWD}

if uname -a | grep -i nexenta &>/dev/null; then
# Assume NexentaOS/GnuSolaris:

    DEB_ARCH_NAME=solaris-i386
    DEB_ARCH_PKGDEPENDS="sunwcsl" # for -lsocket
else

    DEB_ARCH_NAME=$(dpkg --print-architecture)
fi

SRCDIR=$(cd ..; pwd)
test -e ${SRCDIR}/fossil || {
    echo "This script must be run from a BUILT copy of the source tree."
    exit 1
}
................................................................................


rm -fr DEBIAN
mkdir DEBIAN

PACKAGE_VERSION=$(date +%Y.%m.%d)
PACKAGE_DEB_VERSION=${PACKAGE_VERSION}-${DEB_REV}
DEBFILE=${THISDIR}/${PACKAGE_DEBNAME}-${PACKAGE_DEB_VERSION}-dev-${DEB_ARCH_NAME}.deb
PACKAGE_TIME=$(/bin/date)

rm -f ${DEBFILE}
echo "Creating .deb package [${DEBFILE}]..."

echo "Generating md5 sums..."
find ${DEBLOCALPREFIX} -type f -exec md5sum {} \; > DEBIAN/md5sums

true && {
    echo "Generating Debian-specific files..."
    COPYRIGHT=${DEBLOCALPREFIX}/share/doc/${PACKAGE_DEBNAME}/copyright
    cat <<EOF > ${COPYRIGHT}
This package was created by fossil-scm <fossil-dev@lists.fossil-scm.org>
on ${PACKAGE_TIME}.

The original sources for fossil can be downloaded for free from:

http://www.fossil-scm.org/

fossil is released under the terms of the GNU General Public License.
................................................................................
    CHANGELOG=${DEBLOCALPREFIX}/share/doc/${PACKAGE_DEBNAME}/changelog.gz
    cat <<EOF | gzip -c > ${CHANGELOG}
${PACKAGE_DEBNAME} ${PACKAGE_DEB_VERSION}; urgency=low

This release has no changes over the core source distribution. It has
simply been Debianized.

Packaged by fossil-dev <fossil-dev@lists.fossil-scm.org> on
${PACKAGE_TIME}.

EOF

}


true && {
    CONTROL=DEBIAN/control
    echo "Generating ${CONTROL}..."
    cat <<EOF > ${CONTROL}
Package: ${PACKAGE_DEBNAME}
Section: vcs
Priority: optional
Maintainer: fossil-dev <fossil-dev@lists.fossil-scm.org>
Architecture: ${DEB_ARCH_NAME}
Depends: libc6 ${DEB_ARCH_PKGDEPENDS+, }${DEB_ARCH_PKGDEPENDS}
Version: ${PACKAGE_DEB_VERSION}
Description: Fossil is a unique SCM (Software Configuration Management) system.
 This package contains the Fossil binary for *buntu/Debian systems.
 Fossil is a unique SCM program which supports distributed source control
 management using local repositories, access over HTTP CGI, or using the
 built-in HTTP server. It has a built-in wiki, file browsing, etc.
 Fossil home page: http://fossil-scm.org

Changes to src/add.c.

42
43
44
45
46
47
48








49
50
51
52
53
54
55
...
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
  ** its associated journals
  */
  static const char *azName[] = {
     "_FOSSIL_",
     "_FOSSIL_-journal",
     "_FOSSIL_-wal",
     "_FOSSIL_-shm",








     ".fos",
     ".fos-journal",
     ".fos-wal",
     ".fos-shm",
  };

  /* Names of auxiliary files generated by SQLite when the "manifest"
................................................................................
** Move or rename one or more files or directories within the repository tree.
** You can either rename a file or directory or move it to another subdirectory.
**
** This command does NOT rename or move the files on disk.  This command merely
** records the fact that filenames have changed so that appropriate notations
** can be made at the next commit/checkin.
**
**
** SUMMARY: fossil mv|rename OLDNAME NEWNAME
**      or: fossil mv|rename OLDNAME... DIR
*/
void mv_cmd(void){
  int i;
  int vid;
  char *zDest;
  Blob dest;
  Stmt q;







>
>
>
>
>
>
>
>







 







|
<
<







42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
...
505
506
507
508
509
510
511
512


513
514
515
516
517
518
519
  ** its associated journals
  */
  static const char *azName[] = {
     "_FOSSIL_",
     "_FOSSIL_-journal",
     "_FOSSIL_-wal",
     "_FOSSIL_-shm",
     ".fslckout",
     ".fslckout-journal",
     ".fslckout-wal",
     ".fslckout-shm",

     /* The use of ".fos" as the name of the checkout database is 
     ** deprecated.  Use ".fslckout" instead.  At some point, the following
     ** entries should be removed.  2012-02-04 */
     ".fos",
     ".fos-journal",
     ".fos-wal",
     ".fos-shm",
  };

  /* Names of auxiliary files generated by SQLite when the "manifest"
................................................................................
** Move or rename one or more files or directories within the repository tree.
** You can either rename a file or directory or move it to another subdirectory.
**
** This command does NOT rename or move the files on disk.  This command merely
** records the fact that filenames have changed so that appropriate notations
** can be made at the next commit/checkin.
**
** See also: changes, status


*/
void mv_cmd(void){
  int i;
  int vid;
  char *zDest;
  Blob dest;
  Stmt q;

Changes to src/branch.c.

144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
    prompt_user("unable to sign manifest.  continue (y/N)? ", &ans);
    if( blob_str(&ans)[0]!='y' ){
      db_end_transaction(1);
      fossil_exit(1);
    }
  }

  brid = content_put(&branch);
  if( brid==0 ){
    fossil_panic("trouble committing manifest: %s", g.zErrMsg);
  }
  db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", brid);
  if( manifest_crosslink(brid, &branch)==0 ){
    fossil_panic("unable to install new manifest");
  }







|







144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
    prompt_user("unable to sign manifest.  continue (y/N)? ", &ans);
    if( blob_str(&ans)[0]!='y' ){
      db_end_transaction(1);
      fossil_exit(1);
    }
  }

  brid = content_put_ex(&branch, 0, 0, 0, isPrivate);
  if( brid==0 ){
    fossil_panic("trouble committing manifest: %s", g.zErrMsg);
  }
  db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", brid);
  if( manifest_crosslink(brid, &branch)==0 ){
    fossil_panic("unable to install new manifest");
  }

Changes to src/cgi.c.

913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
  }

  /* If no match is found and the name begins with an upper-case
  ** letter, then check to see if there is an environment variable
  ** with the given name.
  */
  if( fossil_isupper(zName[0]) ){
    const char *zValue = getenv(zName);
    if( zValue ){
      cgi_set_parameter_nocopy(zName, zValue);
      CGIDEBUG(("env-match [%s] = [%s]\n", zName, zValue));
      return zValue;
    }
  }
  CGIDEBUG(("no-match [%s]\n", zName));







|







913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
  }

  /* If no match is found and the name begins with an upper-case
  ** letter, then check to see if there is an environment variable
  ** with the given name.
  */
  if( fossil_isupper(zName[0]) ){
    const char *zValue = fossil_getenv(zName);
    if( zValue ){
      cgi_set_parameter_nocopy(zName, zValue);
      CGIDEBUG(("env-match [%s] = [%s]\n", zName, zValue));
      return zValue;
    }
  }
  CGIDEBUG(("no-match [%s]\n", zName));

Changes to src/checkin.c.

178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
...
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
**
** See also: changes, extra, ls
*/
void status_cmd(void){
  int vid;
  db_must_be_within_tree();
       /* 012345678901234 */
  fossil_print("repository:   %s\n", db_lget("repository",""));
  fossil_print("local-root:   %s\n", g.zLocalRoot);
  vid = db_lget_int("checkout", 0);
  if( vid ){
    show_common_info(vid, "checkout:", 1, 1);
  }
  db_record_repository_filename(0);
  changes_cmd();
................................................................................
      "# repositories.\n"
      "#\n", -1
    );
  }
  status_report(&text, "# ", 1, 0);
  zEditor = db_get("editor", 0);
  if( zEditor==0 ){
    zEditor = getenv("VISUAL");
  }
  if( zEditor==0 ){
    zEditor = getenv("EDITOR");
  }
  if( zEditor==0 ){
    blob_append(&text,
       "#\n"
       "# Since no default text editor is set using EDITOR or VISUAL\n"
       "# environment variables or the \"fossil set editor\" command,\n"
       "# and because no check-in comment was specified using the \"-m\"\n"







|







 







|


|







178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
...
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
**
** See also: changes, extra, ls
*/
void status_cmd(void){
  int vid;
  db_must_be_within_tree();
       /* 012345678901234 */
  fossil_print("repository:   %s\n", db_repository_filename());
  fossil_print("local-root:   %s\n", g.zLocalRoot);
  vid = db_lget_int("checkout", 0);
  if( vid ){
    show_common_info(vid, "checkout:", 1, 1);
  }
  db_record_repository_filename(0);
  changes_cmd();
................................................................................
      "# repositories.\n"
      "#\n", -1
    );
  }
  status_report(&text, "# ", 1, 0);
  zEditor = db_get("editor", 0);
  if( zEditor==0 ){
    zEditor = fossil_getenv("VISUAL");
  }
  if( zEditor==0 ){
    zEditor = fossil_getenv("EDITOR");
  }
  if( zEditor==0 ){
    blob_append(&text,
       "#\n"
       "# Since no default text editor is set using EDITOR or VISUAL\n"
       "# environment variables or the \"fossil set editor\" command,\n"
       "# and because no check-in comment was specified using the \"-m\"\n"

Changes to src/clone.c.

17
18
19
20
21
22
23























































24
25
26
27
28
29
30
..
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
**
** This file contains code used to clone a repository
*/
#include "config.h"
#include "clone.h"
#include <assert.h>


























































/*
** COMMAND: clone
**
** Usage: %fossil clone ?OPTIONS? URL FILENAME
**
................................................................................
    db_multi_exec(
      "REPLACE INTO config(name,value,mtime)"
      " VALUES('server-code', lower(hex(randomblob(20))),now());"
      "REPLACE INTO config(name,value,mtime)"
      " VALUES('last-sync-url', '%q',now());",
      g.urlCanonical
    );
    db_multi_exec(
       "DELETE FROM blob WHERE rid IN private;"
       "DELETE FROM delta wHERE rid IN private;"
       "DELETE FROM private;"
    );
    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%%'");
    }







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







 







|
<
<
<
<







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
...
125
126
127
128
129
130
131
132




133
134
135
136
137
138
139
**
** This file contains code used to clone a repository
*/
#include "config.h"
#include "clone.h"
#include <assert.h>

/*
** If there are public BLOBs that deltas from private BLOBs, then
** undeltify the public BLOBs so that the private BLOBs may be safely
** deleted.
*/
void fix_private_blob_dependencies(int showWarning){
  Bag toUndelta;
  Stmt q;
  int rid;

  /* Careful:  We are about to delete all BLOB entries that are private.
  ** So make sure that any no public BLOBs are deltas from a private BLOB.
  ** Otherwise after the deletion, we won't be able to recreate the public
  ** BLOBs.
  */
  db_prepare(&q,
    "SELECT "
    "   rid, (SELECT uuid FROM blob WHERE rid=delta.rid),"
    "   srcid, (SELECT uuid FROM blob WHERE rid=delta.srcid)"
    "  FROM delta"
    " WHERE srcid in private AND rid NOT IN private"
  );
  bag_init(&toUndelta);
  while( db_step(&q)==SQLITE_ROW ){
    int rid = db_column_int(&q, 0);
    const char *zId = db_column_text(&q, 1);
    int srcid = db_column_int(&q, 2);
    const char *zSrc = db_column_text(&q, 3);
    if( showWarning ){
      fossil_warning(
        "public artifact %S (%d) is a delta from private artifact %S (%d)",
        zId, rid, zSrc, srcid
      );
    }
    bag_insert(&toUndelta, rid);
  }
  db_finalize(&q);
  while( (rid = bag_first(&toUndelta))>0 ){
    content_undelta(rid);
    bag_remove(&toUndelta, rid);
  }
  bag_clear(&toUndelta);
}

/*
** Delete all private content from a repository.
*/
void delete_private_content(void){
  fix_private_blob_dependencies(1);
  db_multi_exec(
    "DELETE FROM blob WHERE rid IN private;"
    "DELETE FROM delta wHERE rid IN private;"
    "DELETE FROM private;"
  );
}


/*
** COMMAND: clone
**
** Usage: %fossil clone ?OPTIONS? URL FILENAME
**
................................................................................
    db_multi_exec(
      "REPLACE INTO config(name,value,mtime)"
      " VALUES('server-code', lower(hex(randomblob(20))),now());"
      "REPLACE INTO config(name,value,mtime)"
      " VALUES('last-sync-url', '%q',now());",
      g.urlCanonical
    );
    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%%'");
    }

Changes to src/configure.c.

31
32
33
34
35
36
37

38
39
40
41
42
43
44
..
53
54
55
56
57
58
59

60
61
62
63
64
65
66
..
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
...
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
*/
#define CONFIGSET_SKIN      0x000001     /* WWW interface appearance */
#define CONFIGSET_TKT       0x000002     /* Ticket configuration */
#define CONFIGSET_PROJ      0x000004     /* Project name */
#define CONFIGSET_SHUN      0x000008     /* Shun settings */
#define CONFIGSET_USER      0x000010     /* The USER table */
#define CONFIGSET_ADDR      0x000020     /* The CONCEALED table */


#define CONFIGSET_ALL       0x0000ff     /* Everything */

#define CONFIGSET_OVERWRITE 0x100000     /* Causes overwrite instead of merge */
#define CONFIGSET_OLDFORMAT 0x200000     /* Use the legacy format */

#endif /* INTERFACE */
................................................................................
} aGroupName[] = {
  { "/email",        CONFIGSET_ADDR,  "Concealed email addresses in tickets" },
  { "/project",      CONFIGSET_PROJ,  "Project name and description"         },
  { "/skin",         CONFIGSET_SKIN,  "Web interface apparance settings"     },
  { "/shun",         CONFIGSET_SHUN,  "List of shunned artifacts"            },
  { "/ticket",       CONFIGSET_TKT,   "Ticket setup",                        },
  { "/user",         CONFIGSET_USER,  "Users and privilege settings"         },

  { "/all",          CONFIGSET_ALL,   "All of the above"                     },
};


/*
** The following is a list of settings that we are willing to
** transfer.  
................................................................................
  { "manifest",               CONFIGSET_PROJ },
  { "ignore-glob",            CONFIGSET_PROJ },
  { "crnl-glob",              CONFIGSET_PROJ },
  { "empty-dirs",             CONFIGSET_PROJ },
  { "allow-symlinks",         CONFIGSET_PROJ },
  { "index-page",             CONFIGSET_SKIN },
#ifdef FOSSIL_ENABLE_TCL
  { "tcl",                    CONFIGSET_SKIN|CONFIGSET_TKT },
#endif
  { "timeline-block-markup",  CONFIGSET_SKIN },
  { "timeline-max-comment",   CONFIGSET_SKIN },
  { "ticket-table",           CONFIGSET_TKT  },
  { "ticket-common",          CONFIGSET_TKT  },

  { "ticket-newpage",         CONFIGSET_TKT  },
  { "ticket-viewpage",        CONFIGSET_TKT  },
  { "ticket-editpage",        CONFIGSET_TKT  },
  { "ticket-reportlist",      CONFIGSET_TKT  },
  { "ticket-report-template", CONFIGSET_TKT  },
  { "ticket-key-template",    CONFIGSET_TKT  },
  { "ticket-title-expr",      CONFIGSET_TKT  },
  { "ticket-closed-expr",     CONFIGSET_TKT  },
  { "@reportfmt",             CONFIGSET_TKT  },
  { "@user",                  CONFIGSET_USER },
  { "@concealed",             CONFIGSET_ADDR },
  { "@shun",                  CONFIGSET_SHUN },


};
static int iConfig = 0;

/*
** Return name of first configuration property matching the given mask.
*/
const char *configure_first_name(int iMask){
................................................................................
**
**         Synchronize configuration changes in the local repository with
**         the remote repository at URL.  
**
** Options:
**    -R|--repository FILE       Extract info from repository FILE
**
** See also: set
*/
void configuration_cmd(void){
  int n;
  const char *zMethod;
  if( g.argc<3 ){
    usage("export|import|merge|pull|reset ...");
  }







>







 







>







 







|





>












>
>







 







|







31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
..
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
..
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
...
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
*/
#define CONFIGSET_SKIN      0x000001     /* WWW interface appearance */
#define CONFIGSET_TKT       0x000002     /* Ticket configuration */
#define CONFIGSET_PROJ      0x000004     /* Project name */
#define CONFIGSET_SHUN      0x000008     /* Shun settings */
#define CONFIGSET_USER      0x000010     /* The USER table */
#define CONFIGSET_ADDR      0x000020     /* The CONCEALED table */
#define CONFIGSET_XFER      0x000040     /* Transfer configuration */

#define CONFIGSET_ALL       0x0000ff     /* Everything */

#define CONFIGSET_OVERWRITE 0x100000     /* Causes overwrite instead of merge */
#define CONFIGSET_OLDFORMAT 0x200000     /* Use the legacy format */

#endif /* INTERFACE */
................................................................................
} aGroupName[] = {
  { "/email",        CONFIGSET_ADDR,  "Concealed email addresses in tickets" },
  { "/project",      CONFIGSET_PROJ,  "Project name and description"         },
  { "/skin",         CONFIGSET_SKIN,  "Web interface apparance settings"     },
  { "/shun",         CONFIGSET_SHUN,  "List of shunned artifacts"            },
  { "/ticket",       CONFIGSET_TKT,   "Ticket setup",                        },
  { "/user",         CONFIGSET_USER,  "Users and privilege settings"         },
  { "/xfer",         CONFIGSET_XFER,  "Transfer setup",                      },
  { "/all",          CONFIGSET_ALL,   "All of the above"                     },
};


/*
** The following is a list of settings that we are willing to
** transfer.  
................................................................................
  { "manifest",               CONFIGSET_PROJ },
  { "ignore-glob",            CONFIGSET_PROJ },
  { "crnl-glob",              CONFIGSET_PROJ },
  { "empty-dirs",             CONFIGSET_PROJ },
  { "allow-symlinks",         CONFIGSET_PROJ },
  { "index-page",             CONFIGSET_SKIN },
#ifdef FOSSIL_ENABLE_TCL
  { "tcl",                    CONFIGSET_SKIN|CONFIGSET_TKT|CONFIGSET_XFER },
#endif
  { "timeline-block-markup",  CONFIGSET_SKIN },
  { "timeline-max-comment",   CONFIGSET_SKIN },
  { "ticket-table",           CONFIGSET_TKT  },
  { "ticket-common",          CONFIGSET_TKT  },
  { "ticket-change",          CONFIGSET_TKT  },
  { "ticket-newpage",         CONFIGSET_TKT  },
  { "ticket-viewpage",        CONFIGSET_TKT  },
  { "ticket-editpage",        CONFIGSET_TKT  },
  { "ticket-reportlist",      CONFIGSET_TKT  },
  { "ticket-report-template", CONFIGSET_TKT  },
  { "ticket-key-template",    CONFIGSET_TKT  },
  { "ticket-title-expr",      CONFIGSET_TKT  },
  { "ticket-closed-expr",     CONFIGSET_TKT  },
  { "@reportfmt",             CONFIGSET_TKT  },
  { "@user",                  CONFIGSET_USER },
  { "@concealed",             CONFIGSET_ADDR },
  { "@shun",                  CONFIGSET_SHUN },
  { "xfer-common-script",     CONFIGSET_XFER },
  { "xfer-push-script",       CONFIGSET_XFER },
};
static int iConfig = 0;

/*
** Return name of first configuration property matching the given mask.
*/
const char *configure_first_name(int iMask){
................................................................................
**
**         Synchronize configuration changes in the local repository with
**         the remote repository at URL.  
**
** Options:
**    -R|--repository FILE       Extract info from repository FILE
**
** See also: settings, unset
*/
void configuration_cmd(void){
  int n;
  const char *zMethod;
  if( g.argc<3 ){
    usage("export|import|merge|pull|reset ...");
  }

Changes to src/content.c.

311
312
313
314
315
316
317


318
319
320
321
322
323
324
325
326



327
328
329
330
331
332
333
**
** Extract an artifact by its SHA1 hash and write the results on
** standard output, or if the optional 4th argument is given, in
** the named output file.
**
** Options:
**    -R|--repository FILE       Extract artifacts from repository FILE


*/
void artifact_cmd(void){
  int rid;
  Blob content;
  const char *zFile;
  db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
  if( g.argc!=4 && g.argc!=3 ) usage("ARTIFACT-ID ?FILENAME? ?OPTIONS?");
  zFile = g.argc==4 ? g.argv[3] : "-";
  rid = name_to_rid(g.argv[2]);



  content_get(rid, &content);
  blob_write_to_file(&content, zFile);
}

/*
** COMMAND:  test-content-rawget
**







>
>









>
>
>







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
**
** Extract an artifact by its SHA1 hash and write the results on
** standard output, or if the optional 4th argument is given, in
** the named output file.
**
** Options:
**    -R|--repository FILE       Extract artifacts from repository FILE
**
** See also: finfo
*/
void artifact_cmd(void){
  int rid;
  Blob content;
  const char *zFile;
  db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
  if( g.argc!=4 && g.argc!=3 ) usage("ARTIFACT-ID ?FILENAME? ?OPTIONS?");
  zFile = g.argc==4 ? g.argv[3] : "-";
  rid = name_to_rid(g.argv[2]);
  if( rid==0 ){
    fossil_fatal("%s",g.zErrMsg);
  }
  content_get(rid, &content);
  blob_write_to_file(&content, zFile);
}

/*
** COMMAND:  test-content-rawget
**

Changes to src/cson_amalgamation.c.

1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
....
1595
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
....
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
....
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
....
1946
1947
1948
1949
1950
1951
1952


1953

1954
1955
1956
1957
1958
1959
1960
....
2026
2027
2028
2029
2030
2031
2032



2033
2034
2035
2036
2037
2038
2039
....
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216

2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
....
2248
2249
2250
2251
2252
2253
2254

2255

2256
2257
2258
2259
2260
2261
2262
....
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
....
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
....
2648
2649
2650
2651
2652
2653
2654

2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
....
2863
2864
2865
2866
2867
2868
2869
2870


2871
2872
2873
2874
2875
2876
2877
....
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
....
3281
3282
3283
3284
3285
3286
3287


3288
3289
3290
3291
3292
3293
3294
....
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
....
3384
3385
3386
3387
3388
3389
3390



3391
3392

3393
3394
3395
3396
3397
3398
3399
....
3731
3732
3733
3734
3735
3736
3737
3738

3739

3740
3741
3742
3743
3744
3745
3746
....
4576
4577
4578
4579
4580
4581
4582





























4583
4584
4585
4586
4587
4588
4589
....
4598
4599
4600
4601
4602
4603
4604
4605
4606
4607
4608
4609
4610
4611
4612
4613
4614
4615
4616

4617
4618
4619
4620
4621
4622
4623
4624
4625
4626
4627
4628
....
4637
4638
4639
4640
4641
4642
4643
4644
4645
4646
4647
4648
4649

4650
4651
4652
4653
4654
4655
4656

4657
4658
4659
4660



4661
4662




4663
4664
4665

4666
4667
4668
4669
4670
4671
4672
....
4731
4732
4733
4734
4735
4736
4737
4738
4739
4740
4741
4742
4743
4744
4745
4746
4747
4748
4749
4750
4751
....
4905
4906
4907
4908
4909
4910
4911
4912
4913
4914
4915
4916
4917
4918
4919
....
4952
4953
4954
4955
4956
4957
4958
4959

4960
4961
4962

4963
4964
4965
4966


4967
4968

4969
4970
4971
4972
4973
4974
4975
4976
4977
4978
4979
4980
4981
4982
....
5003
5004
5005
5006
5007
5008
5009
5010
5011
5012
5013
5014
5015
5016
5017
5018
5019
....
5502
5503
5504
5505
5506
5507
5508
5509
5510
5511
5512
5513
5514
5515
5516
....
5524
5525
5526
5527
5528
5529
5530
5531
5532
5533
5534
5535
5536
5537
5538

    
/**
   Type IDs corresponding to JavaScript/JSON types.
*/
enum cson_type_id {
  /**
    The special "null" value constant.

    Its value must be 0 for internal reasons.
 */
 CSON_TYPE_UNDEF = 0,
 /**
    The special "null" value constant.
 */
................................................................................
static const cson_value cson_value_bool_empty = { &cson_value_api_bool, NULL, 0 };
static const cson_value cson_value_integer_empty = { &cson_value_api_integer, NULL, 0 };
static const cson_value cson_value_double_empty = { &cson_value_api_double, NULL, 0 };
static const cson_value cson_value_string_empty = { &cson_value_api_string, NULL, 0 };
static const cson_value cson_value_array_empty = { &cson_value_api_array, NULL, 0 };
static const cson_value cson_value_object_empty = { &cson_value_api_object, NULL, 0 };









struct cson_string
{
    unsigned int length;
};
#define cson_string_empty_m {0/*length*/}
static const cson_string cson_string_empty = cson_string_empty_m;



#define CSON_CAST(T,V) ((T*)((V)->value))
#define CSON_VCAST(V) ((cson_value *)(((unsigned char *)(V))-sizeof(cson_value)))




#define CSON_INT(V) ((cson_int_t*)(V)->value)


#define CSON_DBL(V) CSON_CAST(cson_double_t,(V))
#define CSON_STR(V) CSON_CAST(cson_string,(V))
#define CSON_OBJ(V) CSON_CAST(cson_object,(V))
#define CSON_ARRAY(V) CSON_CAST(cson_array,(V))

/**
 
................................................................................
{ &cson_value_api_undef, NULL, 0 }, /* UNDEF */
{ &cson_value_api_null, NULL, 0 }, /* NULL */
{ &cson_value_api_bool, &CSON_EMPTY_HOLDER.trueValue, 0 }, /* TRUE */
{ &cson_value_api_bool, NULL, 0 }, /* FALSE */
{ &cson_value_api_integer, NULL, 0 }, /* INT_0 */
{ &cson_value_api_double, NULL, 0 }, /* DBL_0 */
{ &cson_value_api_string, &CSON_EMPTY_HOLDER.stringValue, 0 }, /* STR_EMPTY */
{ 0, NULL, 0 }
};


/**
    Returns non-0 (true) if m is one of our special
    "built-in" values, e.g. from CSON_SPECIAL_VALUES and some
    "empty" values.
................................................................................
/**
   Fetches v's string value as a non-const string.

   cson_strings are supposed to be immutable, but this form provides
   access to the immutable bits, which are v->length bytes long. A
   length-0 string is returned as NULL from here, as opposed to
   "". (This is a side-effect of the string allocation mechanism.)
   Returns NULL if !v.
*/
static char * cson_string_str(cson_string *v)
{
    /*
      See http://groups.google.com/group/comp.lang.c.moderated/browse_thread/thread/2e0c0df5e8a0cd6a
    */
#if 1
................................................................................
{
    /*
      See http://groups.google.com/group/comp.lang.c.moderated/browse_thread/thread/2e0c0df5e8a0cd6a
    */
#if 1
    if( ! v ) return NULL;
    else if( v == &CSON_EMPTY_HOLDER.stringValue ) return "";


    else return (char *)((unsigned char *)(v+1));

#else
    return (NULL == v)
        ? NULL
        : (v->length
           ? (char const *) ((unsigned char const *)(v+1))
           : "");
#endif
................................................................................
    cson_value * key;
    cson_value * value;
};
#define cson_kvp_empty_m {NULL,NULL}
static const cson_kvp cson_kvp_empty = cson_kvp_empty_m;

/** @def CSON_OBJECT_PROPS_SORT




   If CSON_OBJECT_PROPS_SORT is set to a true value then
   qsort() and bsearch() are used to sort (upon insertion)
   and search cson_object::kvp property lists. This costs us
   a re-sort on each insertion but searching is O(log n)
   average/worst case (and O(1) best-case).

................................................................................
#  define LIST_T cson_kvp_list
#  define VALUE_T cson_kvp *
#  define VALUE_T_IS_PTR 1
#else
#endif

/**
   Allocates a new value of the specified type ownership of it to the
   caller. It must eventually be destroyed, by the caller or its
   owning container, by passing it to cson_value_free() or transfering
   ownership to a container.

   extra is only valid for type CSON_TYPE_STRING, and must be the length
   of the string to allocate + 1 byte (for the NUL).

   The returned value->api member will be set appropriately and
   val->value will be set to point to the memory allocated to hold the
   native value type. Use the internal CSON_CAST() family of macros to
   convert them.


   Returns NULL on allocation error.

   @see cson_value_new_array()
   @see cson_value_new_object()
   @see cson_value_new_string()
   @see cson_value_new_integer()
   @see cson_value_new_double()
   @see cson_value_new_bool()
   @see cson_value_free()
*/
static cson_value * cson_value_new(cson_type_id t, size_t extra);

cson_value * cson_value_new(cson_type_id t, size_t extra)
{
    static const size_t vsz = sizeof(cson_value);
    const size_t sz = vsz + extra;
    size_t tx = 0;
    cson_value def = cson_value_undef;
    cson_value * v = NULL;
    char const * reason = "cson_value_new";
................................................................................
          def = cson_value_double_empty;
          tx = sizeof(cson_double_t);
          reason = "cson_value:double";
          break;
      case CSON_TYPE_INTEGER:
          assert( 0 == extra );
          def = cson_value_integer_empty;

          tx = sizeof(cson_int_t);

          reason = "cson_value:int";
          break;
      case CSON_TYPE_STRING:
          assert( 0 != extra );
          def = cson_value_string_empty;
          tx = sizeof(cson_string);
          reason = "cson_value:string";
................................................................................
            memset(v+1, 0, tx + extra);
            v->value = (void *)(v+1);
        }
    }
    return v;
}


void cson_value_free(cson_value *v)
{
    cson_refcount_decr( v );
}

#if 0 /* we might actually want this later on. */
/** Returns true if v is not NULL and has the given type ID. */
................................................................................
{
    return (v && v->api) ? v->api->typeID : CSON_TYPE_UNDEF;
}
#endif

char cson_value_is_undef( cson_value const * v )
{
    /**
       This special-case impl is needed because the underlying
       (generic) list operations do not know how to populate
       new entries
     */
    return ( !v || !v->api || (v->api==&cson_value_api_undef))
        ? 1 : 0;
}
#define ISA(T,TID) char cson_value_is_##T( cson_value const * v ) {       \
        /*return (v && v->api) ? cson_value_is_a(v,CSON_TYPE_##TID) : 0;*/ \
        return (v && (v->api == &cson_value_api_##T)) ? 1 : 0; \
    } static const char bogusPlaceHolderForEmacsIndention##TID = CSON_TYPE_##TID
................................................................................
              i = (cson_int_t)d;
              break;
            }
            case CSON_TYPE_STRING:
            case CSON_TYPE_ARRAY:
            case CSON_TYPE_OBJECT:
            default:

              break;
        }
        if(v) *v = i;
        return rc;
    }
}

cson_int_t cson_value_get_integer( cson_value const * val )
{
    cson_int_t i = 0;
................................................................................

cson_value * cson_value_new_integer( cson_int_t v )
{
    if( 0 == v ) return &CSON_SPECIAL_VALUES[CSON_VAL_INT_0];
    else
    {
        cson_value * c = cson_value_new(CSON_TYPE_INTEGER,0);



        if( c )
        {
            *CSON_INT(c) = v;
        }
        return c;
    }
}
................................................................................
                cson_value_free( kvp->value );
                cson_refcount_incr( v );
                kvp->value = v;
            }
            return 0;
        }
        if( !obj->kvp.alloced || (obj->kvp.count == obj->kvp.alloced-1))
        {
            unsigned int const n = obj->kvp.count ? (obj->kvp.count*2) : 6;
            if( n > cson_kvp_list_reserve( &obj->kvp, n ) )
            {
                return cson_rc.AllocError;
            }
        }
        { /* insert new item... */
................................................................................
        kvp = cson_kvp_alloc();
        if( ! kvp )
        {
            cson_value_free(val);
            return cson_rc.AllocError;
        }
        kvp->key = cson_string_value(p->ckey)/*transfer ownership*/;


        p->ckey = NULL;
        kvp->value = val;
        cson_refcount_incr( val );
        rc = cson_kvp_list_append( &obj->kvp, kvp );
        if( 0 != rc )
        {
            cson_kvp_free( kvp );
................................................................................
      case JSON_T_OBJECT_BEGIN: {
          cson_value * obja = (JSON_T_ARRAY_BEGIN == type)
              ? cson_value_new_array()
              : cson_value_new_object();
          if( ! obja )
          {
              p->errNo = cson_rc.AllocError;
              return 0;
          }
          if( 0 != rc ) break;
          if( ! p->root )
          {
              p->root = p->node = obja;
              rc = cson_array_append( &p->stack, obja );
              if( 0 != rc )
................................................................................
                      ;
                  ++p->totalValueCount;
              }
          }
          else
          {
              rc = cson_array_append( &p->stack, obja );



              if( 0 == rc ) rc = cson_parser_push_value( p, obja );
              if( 0 == rc ) p->node = obja;

          }
          break;
      }
      case JSON_T_ARRAY_END:
      case JSON_T_OBJECT_END: {
          if( 0 == p->stack.list.count )
          {
................................................................................
  int c;
  READ_UTF8(z, zTerm, c);
  *pzNext = z;
  return c;
}
#undef READ_UTF8

#if defined(_WIN32)

#  pragma warning( pop )

#endif

unsigned int cson_string_length_utf8( cson_string const * str )
{
    if( ! str ) return 0;
    else
    {
................................................................................
cson_value * cson_object_get_sub2( cson_object const * obj, char const * path )
{
    cson_value * v = NULL;
    cson_object_fetch_sub2( obj, &v, path );
    return v;
}






























static cson_value * cson_value_clone_array( cson_value const * orig )
{
    unsigned int i = 0;
    cson_array const * asrc = cson_value_get_array( orig );
    unsigned int alen = cson_array_length_get( asrc );
    cson_value * destV = NULL;
    cson_array * destA = NULL;
................................................................................
        return NULL;
    }
    for( ; i < alen; ++i )
    {
        cson_value * ch = cson_array_get( asrc, i );
        if( NULL != ch )
        {
            cson_value * cl = cson_value_clone( ch );
            if( NULL == cl )
            {
                cson_value_free( destV );
                return NULL;
            }
            if( 0 != cson_array_set( destA, i, cl ) )
            {
                cson_value_free( cl );
                cson_value_free( destV );
                return NULL;
            }

        }
    }
    return destV;
}

static cson_value * cson_value_clone_object( cson_value const * orig )
{
    cson_object const * src = cson_value_get_object( orig );
    cson_value * destV = NULL;
    cson_object * dest = NULL;
    cson_kvp const * kvp = NULL;
    cson_object_iterator iter = cson_object_iterator_empty;
................................................................................
    assert( dest );
    if( src->kvp.count > cson_kvp_list_reserve( &dest->kvp, src->kvp.count ) ){
        cson_value_free( destV );
        return NULL;
    }
    while( (kvp = cson_object_iter_next( &iter )) )
    {
        /*
          FIXME: refcount the keys! We first need a setter which takes
          a cson_string or cson_value key type.
         */
        cson_value * key = NULL;
        cson_value * val = NULL;

        key = cson_value_clone(kvp->key);
        val = key ? cson_value_clone( kvp->value ) : NULL;
        if( ! key || !val ){
            cson_value_free(key);
            cson_value_free(val);
            cson_value_free(destV);
            return NULL;

        }
        assert( CSON_STR(key) );
        if( 0 != cson_object_set_s( dest, CSON_STR(key), val ) )
        {



            cson_value_free(key);
            cson_value_free(val);




            cson_value_free(destV);
            return NULL;
        }

    }
    return destV;
}

cson_value * cson_value_clone( cson_value const * orig )
{
    if( NULL == orig ) return NULL;
................................................................................
    if(x) cson_value_free(cson_object_value(x));
}
void cson_free_array(cson_array *x)
{
    if(x) cson_value_free(cson_array_value(x));
}

void cson_free_string(cson_string const *x)
{
    if(x) cson_value_free(cson_string_value(x));
}
void cson_free_value(cson_value *x)
{
    cson_value_free(x);
}


#if 0
/* i'm not happy with this... */
char * cson_pod_to_string( cson_value const * orig )
{
................................................................................
          case CSON_TYPE_NULL:
          case CSON_TYPE_BOOL:
              assert( 0 && "Should have been caught by is-builtin check!" );
              break;
          default:
              assert(0 && "Invalid typeID!");
              return 0;

        }
        return rc;
    }
}

int cson_object_merge( cson_object * dest, cson_object const * src, int flags ){
    cson_object_iterator iter = cson_object_iterator_empty;
................................................................................
        else continue;
    }
    return 0;
}

static cson_value * cson_guess_arg_type(char const *arg){
    char * end = NULL;
    if(('0'<=*arg) && ('9'>=*arg)){

        goto do_string;
    }
    {

        long const val = strtol(arg, &end, 10);
        if(!*end){
            return cson_value_new_integer( (cson_int_t)val);
        }


    }
    {

        double const val = strtod(arg, &end);
        if(!*end){
            return cson_value_new_double(val);
        }
    }

    
    do_string:
    return cson_value_new_string(arg, strlen(arg));
}


int cson_parse_argv_flags( int argc, char const * const * argv,
                           cson_object ** tgt, unsigned int * count ){
................................................................................
            break;
        }
        if(!*pos){ /** --key */
            v = cson_value_true();
        }else{ /** --key=...*/
            assert('=' == *pos);
            ++pos /*skip '='*/;
            v = *pos
                ? cson_guess_arg_type(pos)
                : cson_value_null();
        }
        if(0 != (rc=cson_object_set_s(o, k, v))){
            cson_free_string(k);
            cson_value_free(v);
            break;
        }
        else if(count) ++*count;
................................................................................
#define RETURN(RC) { if(rootV) cson_value_free(rootV); return RC; }
    if( ! tgt || !st ) return cson_rc.ArgError;
    else
    {
        cson_value * rootV = NULL;
        cson_object * root = NULL;
        cson_value * aryV = NULL;
        cson_array * ary = NULL;
        cson_value * rowsV = NULL;
        cson_array * rows = NULL;
        int rc = 0;
        int const colCount = sqlite3_column_count(st);
        if( colCount <= 0 ) return cson_rc.ArgError;
        rootV = cson_value_new_object();
        if( ! rootV ) return cson_rc.AllocError;
................................................................................
        rc = cson_object_set( root, "columns", aryV );
        if( rc )
        {
            cson_value_free( aryV );
            RETURN(rc);
        }
        aryV = NULL;
        ary = NULL;
        rowsV = cson_value_new_array();
        if( ! rowsV ) RETURN(cson_rc.AllocError);
        rc = cson_object_set( root, "rows", rowsV );
        if( 0 != rc )
        {
            cson_value_free( rowsV );
            RETURN(rc);







|







 







>
>
>
>
>
>
>
>











>
>
>
>
|
>
>







 







|







 







|







 







>
>
|
>







 







>
>
>







 







|
|
<
|







|
>











|
<
<







 







>

>







 







<







 







<
<
<
<
<







 







>
|

|







 







|
>
>







 







|







 







>
>







 







|







 







>
>
>
|
|
>







 







|
>
|
>







 







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







 







|











>




|







 







<
<
<
<


>
|
|

<
<
<
<
>




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







 







|





|







 







|







 







|
>


<
>




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







 







<
|
<







 







<







 







<







1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
....
1595
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
1626
1627
1628
1629
1630
1631
1632
1633
1634
....
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
....
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
....
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
....
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
....
2218
2219
2220
2221
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
....
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
....
2299
2300
2301
2302
2303
2304
2305

2306
2307
2308
2309
2310
2311
2312
....
2321
2322
2323
2324
2325
2326
2327





2328
2329
2330
2331
2332
2333
2334
....
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
....
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
....
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
....
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
....
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
....
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
....
3754
3755
3756
3757
3758
3759
3760
3761
3762
3763
3764
3765
3766
3767
3768
3769
3770
3771
....
4601
4602
4603
4604
4605
4606
4607
4608
4609
4610
4611
4612
4613
4614
4615
4616
4617
4618
4619
4620
4621
4622
4623
4624
4625
4626
4627
4628
4629
4630
4631
4632
4633
4634
4635
4636
4637
4638
4639
4640
4641
4642
4643
....
4652
4653
4654
4655
4656
4657
4658
4659
4660
4661
4662
4663
4664
4665
4666
4667
4668
4669
4670
4671
4672
4673
4674
4675
4676
4677
4678
4679
4680
4681
4682
4683
....
4692
4693
4694
4695
4696
4697
4698




4699
4700
4701
4702
4703
4704




4705
4706
4707
4708
4709
4710
4711
4712
4713
4714
4715
4716
4717
4718
4719
4720

4721
4722
4723
4724
4725
4726
4727
4728
....
4787
4788
4789
4790
4791
4792
4793
4794
4795
4796
4797
4798
4799
4800
4801
4802
4803
4804
4805
4806
4807
....
4961
4962
4963
4964
4965
4966
4967
4968
4969
4970
4971
4972
4973
4974
4975
....
5008
5009
5010
5011
5012
5013
5014
5015
5016
5017
5018

5019
5020
5021
5022
5023
5024
5025
5026

5027
5028
5029
5030
5031
5032
5033

5034
5035
5036
5037
5038
5039
5040
....
5061
5062
5063
5064
5065
5066
5067

5068

5069
5070
5071
5072
5073
5074
5075
....
5558
5559
5560
5561
5562
5563
5564

5565
5566
5567
5568
5569
5570
5571
....
5579
5580
5581
5582
5583
5584
5585

5586
5587
5588
5589
5590
5591
5592

    
/**
   Type IDs corresponding to JavaScript/JSON types.
*/
enum cson_type_id {
  /**
    The special "undefined" value constant.

    Its value must be 0 for internal reasons.
 */
 CSON_TYPE_UNDEF = 0,
 /**
    The special "null" value constant.
 */
................................................................................
static const cson_value cson_value_bool_empty = { &cson_value_api_bool, NULL, 0 };
static const cson_value cson_value_integer_empty = { &cson_value_api_integer, NULL, 0 };
static const cson_value cson_value_double_empty = { &cson_value_api_double, NULL, 0 };
static const cson_value cson_value_string_empty = { &cson_value_api_string, NULL, 0 };
static const cson_value cson_value_array_empty = { &cson_value_api_array, NULL, 0 };
static const cson_value cson_value_object_empty = { &cson_value_api_object, NULL, 0 };

/**
   Strings are allocated as an instances of this class with N+1
   trailing bytes, where N is the length of the string being
   allocated. To convert a cson_string to c-string we simply increment
   the cson_string pointer. To do the opposite we use (cstr -
   sizeof(cson_string)). Zero-length strings are a special case
   handled by a couple of the cson_string functions.
*/
struct cson_string
{
    unsigned int length;
};
#define cson_string_empty_m {0/*length*/}
static const cson_string cson_string_empty = cson_string_empty_m;



#define CSON_CAST(T,V) ((T*)((V)->value))
#define CSON_VCAST(V) ((cson_value *)(((unsigned char *)(V))-sizeof(cson_value)))

#if CSON_VOID_PTR_IS_BIG
#  define CSON_INT(V) ((cson_int_t*)(&((V)->value)))
#else
#  define CSON_INT(V) ((cson_int_t*)(V)->value)
#endif

#define CSON_DBL(V) CSON_CAST(cson_double_t,(V))
#define CSON_STR(V) CSON_CAST(cson_string,(V))
#define CSON_OBJ(V) CSON_CAST(cson_object,(V))
#define CSON_ARRAY(V) CSON_CAST(cson_array,(V))

/**
 
................................................................................
{ &cson_value_api_undef, NULL, 0 }, /* UNDEF */
{ &cson_value_api_null, NULL, 0 }, /* NULL */
{ &cson_value_api_bool, &CSON_EMPTY_HOLDER.trueValue, 0 }, /* TRUE */
{ &cson_value_api_bool, NULL, 0 }, /* FALSE */
{ &cson_value_api_integer, NULL, 0 }, /* INT_0 */
{ &cson_value_api_double, NULL, 0 }, /* DBL_0 */
{ &cson_value_api_string, &CSON_EMPTY_HOLDER.stringValue, 0 }, /* STR_EMPTY */
{ NULL, NULL, 0 }
};


/**
    Returns non-0 (true) if m is one of our special
    "built-in" values, e.g. from CSON_SPECIAL_VALUES and some
    "empty" values.
................................................................................
/**
   Fetches v's string value as a non-const string.

   cson_strings are supposed to be immutable, but this form provides
   access to the immutable bits, which are v->length bytes long. A
   length-0 string is returned as NULL from here, as opposed to
   "". (This is a side-effect of the string allocation mechanism.)
   Returns NULL if !v or if v is the internal empty-string singleton.
*/
static char * cson_string_str(cson_string *v)
{
    /*
      See http://groups.google.com/group/comp.lang.c.moderated/browse_thread/thread/2e0c0df5e8a0cd6a
    */
#if 1
................................................................................
{
    /*
      See http://groups.google.com/group/comp.lang.c.moderated/browse_thread/thread/2e0c0df5e8a0cd6a
    */
#if 1
    if( ! v ) return NULL;
    else if( v == &CSON_EMPTY_HOLDER.stringValue ) return "";
    else {
        assert((0 < v->length) && "How do we have a non-singleton empty string?");
        return (char const *)((unsigned char const *)(v+1));
    }
#else
    return (NULL == v)
        ? NULL
        : (v->length
           ? (char const *) ((unsigned char const *)(v+1))
           : "");
#endif
................................................................................
    cson_value * key;
    cson_value * value;
};
#define cson_kvp_empty_m {NULL,NULL}
static const cson_kvp cson_kvp_empty = cson_kvp_empty_m;

/** @def CSON_OBJECT_PROPS_SORT

    Don't use this - it has not been updated to account for internal
    changes in cson_object.

   If CSON_OBJECT_PROPS_SORT is set to a true value then
   qsort() and bsearch() are used to sort (upon insertion)
   and search cson_object::kvp property lists. This costs us
   a re-sort on each insertion but searching is O(log n)
   average/worst case (and O(1) best-case).

................................................................................
#  define LIST_T cson_kvp_list
#  define VALUE_T cson_kvp *
#  define VALUE_T_IS_PTR 1
#else
#endif

/**
   Allocates a new value of the specified type. Ownership is
   transfered to the caller, who must eventually free it by passing it

   to cson_value_free() or transfering ownership to a container.

   extra is only valid for type CSON_TYPE_STRING, and must be the length
   of the string to allocate + 1 byte (for the NUL).

   The returned value->api member will be set appropriately and
   val->value will be set to point to the memory allocated to hold the
   native value type. Use the internal CSON_CAST() family of macros to
   convert the cson_values to their corresponding native
   representation.

   Returns NULL on allocation error.

   @see cson_value_new_array()
   @see cson_value_new_object()
   @see cson_value_new_string()
   @see cson_value_new_integer()
   @see cson_value_new_double()
   @see cson_value_new_bool()
   @see cson_value_free()
*/
static cson_value * cson_value_new(cson_type_id t, size_t extra)


{
    static const size_t vsz = sizeof(cson_value);
    const size_t sz = vsz + extra;
    size_t tx = 0;
    cson_value def = cson_value_undef;
    cson_value * v = NULL;
    char const * reason = "cson_value_new";
................................................................................
          def = cson_value_double_empty;
          tx = sizeof(cson_double_t);
          reason = "cson_value:double";
          break;
      case CSON_TYPE_INTEGER:
          assert( 0 == extra );
          def = cson_value_integer_empty;
#if !CSON_VOID_PTR_IS_BIG
          tx = sizeof(cson_int_t);
#endif
          reason = "cson_value:int";
          break;
      case CSON_TYPE_STRING:
          assert( 0 != extra );
          def = cson_value_string_empty;
          tx = sizeof(cson_string);
          reason = "cson_value:string";
................................................................................
            memset(v+1, 0, tx + extra);
            v->value = (void *)(v+1);
        }
    }
    return v;
}


void cson_value_free(cson_value *v)
{
    cson_refcount_decr( v );
}

#if 0 /* we might actually want this later on. */
/** Returns true if v is not NULL and has the given type ID. */
................................................................................
{
    return (v && v->api) ? v->api->typeID : CSON_TYPE_UNDEF;
}
#endif

char cson_value_is_undef( cson_value const * v )
{





    return ( !v || !v->api || (v->api==&cson_value_api_undef))
        ? 1 : 0;
}
#define ISA(T,TID) char cson_value_is_##T( cson_value const * v ) {       \
        /*return (v && v->api) ? cson_value_is_a(v,CSON_TYPE_##TID) : 0;*/ \
        return (v && (v->api == &cson_value_api_##T)) ? 1 : 0; \
    } static const char bogusPlaceHolderForEmacsIndention##TID = CSON_TYPE_##TID
................................................................................
              i = (cson_int_t)d;
              break;
            }
            case CSON_TYPE_STRING:
            case CSON_TYPE_ARRAY:
            case CSON_TYPE_OBJECT:
            default:
                rc = cson_rc.TypeError;
                break;
        }
        if(!rc && v) *v = i;
        return rc;
    }
}

cson_int_t cson_value_get_integer( cson_value const * val )
{
    cson_int_t i = 0;
................................................................................

cson_value * cson_value_new_integer( cson_int_t v )
{
    if( 0 == v ) return &CSON_SPECIAL_VALUES[CSON_VAL_INT_0];
    else
    {
        cson_value * c = cson_value_new(CSON_TYPE_INTEGER,0);
#if !defined(NDEBUG) && CSON_VOID_PTR_IS_BIG
        assert( sizeof(cson_int_t) <= sizeof(void *) );
#endif
        if( c )
        {
            *CSON_INT(c) = v;
        }
        return c;
    }
}
................................................................................
                cson_value_free( kvp->value );
                cson_refcount_incr( v );
                kvp->value = v;
            }
            return 0;
        }
        if( !obj->kvp.alloced || (obj->kvp.count == obj->kvp.alloced-1))
        { /* reserve space */
            unsigned int const n = obj->kvp.count ? (obj->kvp.count*2) : 6;
            if( n > cson_kvp_list_reserve( &obj->kvp, n ) )
            {
                return cson_rc.AllocError;
            }
        }
        { /* insert new item... */
................................................................................
        kvp = cson_kvp_alloc();
        if( ! kvp )
        {
            cson_value_free(val);
            return cson_rc.AllocError;
        }
        kvp->key = cson_string_value(p->ckey)/*transfer ownership*/;
        assert(0 == kvp->key->refcount);
        cson_refcount_incr(kvp->key);
        p->ckey = NULL;
        kvp->value = val;
        cson_refcount_incr( val );
        rc = cson_kvp_list_append( &obj->kvp, kvp );
        if( 0 != rc )
        {
            cson_kvp_free( kvp );
................................................................................
      case JSON_T_OBJECT_BEGIN: {
          cson_value * obja = (JSON_T_ARRAY_BEGIN == type)
              ? cson_value_new_array()
              : cson_value_new_object();
          if( ! obja )
          {
              p->errNo = cson_rc.AllocError;
              break;
          }
          if( 0 != rc ) break;
          if( ! p->root )
          {
              p->root = p->node = obja;
              rc = cson_array_append( &p->stack, obja );
              if( 0 != rc )
................................................................................
                      ;
                  ++p->totalValueCount;
              }
          }
          else
          {
              rc = cson_array_append( &p->stack, obja );
              if(rc) cson_value_free( obja );
              else
              {
                  rc = cson_parser_push_value( p, obja );
                  if( 0 == rc ) p->node = obja;
              }
          }
          break;
      }
      case JSON_T_ARRAY_END:
      case JSON_T_OBJECT_END: {
          if( 0 == p->stack.list.count )
          {
................................................................................
  int c;
  READ_UTF8(z, zTerm, c);
  *pzNext = z;
  return c;
}
#undef READ_UTF8

#ifdef _MSC_VER
#  if _MSC_VER >= 1400 /* Visual Studio 2005 and up */
#    pragma warning( pop )
#  endif
#endif

unsigned int cson_string_length_utf8( cson_string const * str )
{
    if( ! str ) return 0;
    else
    {
................................................................................
cson_value * cson_object_get_sub2( cson_object const * obj, char const * path )
{
    cson_value * v = NULL;
    cson_object_fetch_sub2( obj, &v, path );
    return v;
}


/**
   If v is-a Object or Array then this function returns a deep
   clone, otherwise it returns v. In either case, the refcount
   of the returned value is increased by 1 by this call.
*/
static cson_value * cson_value_clone_ref( cson_value * v )
{
    cson_value * rc = NULL;
#define TRY_SHARING 1
#if TRY_SHARING
    if(!v ) return rc;
    else if( cson_value_is_object(v)
             || cson_value_is_array(v))
    {
        rc = cson_value_clone( v );
    }
    else
    {
        rc = v;
    }
#else
    rc = cson_value_clone(v);
#endif
#undef TRY_SHARING
    cson_value_add_reference(rc);
    return rc;
}
    
static cson_value * cson_value_clone_array( cson_value const * orig )
{
    unsigned int i = 0;
    cson_array const * asrc = cson_value_get_array( orig );
    unsigned int alen = cson_array_length_get( asrc );
    cson_value * destV = NULL;
    cson_array * destA = NULL;
................................................................................
        return NULL;
    }
    for( ; i < alen; ++i )
    {
        cson_value * ch = cson_array_get( asrc, i );
        if( NULL != ch )
        {
            cson_value * cl = cson_value_clone_ref( ch );
            if( NULL == cl )
            {
                cson_value_free( destV );
                return NULL;
            }
            if( 0 != cson_array_set( destA, i, cl ) )
            {
                cson_value_free( cl );
                cson_value_free( destV );
                return NULL;
            }
            cson_value_free(cl)/*remove our artificial reference */;
        }
    }
    return destV;
}
    
static cson_value * cson_value_clone_object( cson_value const * orig )
{
    cson_object const * src = cson_value_get_object( orig );
    cson_value * destV = NULL;
    cson_object * dest = NULL;
    cson_kvp const * kvp = NULL;
    cson_object_iterator iter = cson_object_iterator_empty;
................................................................................
    assert( dest );
    if( src->kvp.count > cson_kvp_list_reserve( &dest->kvp, src->kvp.count ) ){
        cson_value_free( destV );
        return NULL;
    }
    while( (kvp = cson_object_iter_next( &iter )) )
    {




        cson_value * key = NULL;
        cson_value * val = NULL;
        assert( kvp->key && (kvp->key->refcount>0) );
        key = cson_value_clone_ref(kvp->key);
        val = key ? cson_value_clone_ref(kvp->value) : NULL;
        if( ! key || !val ){




            goto error;
        }
        assert( CSON_STR(key) );
        if( 0 != cson_object_set_s( dest, CSON_STR(key), val ) )
        {
            goto error;
        }
        /* remove our references */
        cson_value_free(key);
        cson_value_free(val);
        continue;
        error:
        cson_value_free(key);
        cson_value_free(val);
        cson_value_free(destV);
        destV = NULL;

        break;
    }
    return destV;
}

cson_value * cson_value_clone( cson_value const * orig )
{
    if( NULL == orig ) return NULL;
................................................................................
    if(x) cson_value_free(cson_object_value(x));
}
void cson_free_array(cson_array *x)
{
    if(x) cson_value_free(cson_array_value(x));
}

void cson_free_string(cson_string *x)
{
    if(x) cson_value_free(cson_string_value(x));
}
void cson_free_value(cson_value *x)
{
    if(x) cson_value_free(x);
}


#if 0
/* i'm not happy with this... */
char * cson_pod_to_string( cson_value const * orig )
{
................................................................................
          case CSON_TYPE_NULL:
          case CSON_TYPE_BOOL:
              assert( 0 && "Should have been caught by is-builtin check!" );
              break;
          default:
              assert(0 && "Invalid typeID!");
              return 0;
#undef RCCHECK
        }
        return rc;
    }
}

int cson_object_merge( cson_object * dest, cson_object const * src, int flags ){
    cson_object_iterator iter = cson_object_iterator_empty;
................................................................................
        else continue;
    }
    return 0;
}

static cson_value * cson_guess_arg_type(char const *arg){
    char * end = NULL;
    if(!arg || !*arg) return cson_value_null();
    else if(('0'>*arg) || ('9'<*arg)){
        goto do_string;
    }

    else{ /* try numbers... */
        long const val = strtol(arg, &end, 10);
        if(!*end){
            return cson_value_new_integer( (cson_int_t)val);
        }
        else if( '.' != *end ) {
            goto do_string;
        }

        else {
            double const val = strtod(arg, &end);
            if(!*end){
                return cson_value_new_double(val);
            }
        }
    }

    do_string:
    return cson_value_new_string(arg, strlen(arg));
}


int cson_parse_argv_flags( int argc, char const * const * argv,
                           cson_object ** tgt, unsigned int * count ){
................................................................................
            break;
        }
        if(!*pos){ /** --key */
            v = cson_value_true();
        }else{ /** --key=...*/
            assert('=' == *pos);
            ++pos /*skip '='*/;

            v = cson_guess_arg_type(pos);

        }
        if(0 != (rc=cson_object_set_s(o, k, v))){
            cson_free_string(k);
            cson_value_free(v);
            break;
        }
        else if(count) ++*count;
................................................................................
#define RETURN(RC) { if(rootV) cson_value_free(rootV); return RC; }
    if( ! tgt || !st ) return cson_rc.ArgError;
    else
    {
        cson_value * rootV = NULL;
        cson_object * root = NULL;
        cson_value * aryV = NULL;

        cson_value * rowsV = NULL;
        cson_array * rows = NULL;
        int rc = 0;
        int const colCount = sqlite3_column_count(st);
        if( colCount <= 0 ) return cson_rc.ArgError;
        rootV = cson_value_new_object();
        if( ! rootV ) return cson_rc.AllocError;
................................................................................
        rc = cson_object_set( root, "columns", aryV );
        if( rc )
        {
            cson_value_free( aryV );
            RETURN(rc);
        }
        aryV = NULL;

        rowsV = cson_value_new_array();
        if( ! rowsV ) RETURN(cson_rc.AllocError);
        rc = cson_object_set( root, "rows", rowsV );
        if( 0 != rc )
        {
            cson_value_free( rowsV );
            RETURN(rc);

Changes to src/cson_amalgamation.h.

72
73
74
75
76
77
78




































79
80
81
82
83
84
85
...
926
927
928
929
930
931
932
933

934
935
936
937
938
939
940
....
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
....
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
....
2077
2078
2079
2080
2081
2082
2083
2084
2085

2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
#define CSON_DOUBLE_T_SFMT "Lf"
#define CSON_DOUBLE_T_PFMT "Lf"
#else
typedef double cson_double_t;
#define CSON_DOUBLE_T_SFMT "f"
#define CSON_DOUBLE_T_PFMT "f"
#endif





































/** @def CSON_INT_T_SFMT

scanf()-compatible format token for cson_int_t.
*/

/** @def CSON_INT_T_PFMT
................................................................................
cson_string * cson_value_get_string( cson_value const * val );

/**
   Returns a pointer to the NULL-terminated string bytes of str.
   The bytes are owned by string and will be invalided when it
   is cleaned up.

   If str is NULL then NULL is returned.


   @see cson_string_length_bytes()
   @see cson_value_get_string()
*/
char const * cson_string_cstr( cson_string const * str );

/**
................................................................................
   Equivalent to cson_value_free(cson_array_value(x)).
*/
void cson_free_array(cson_array *x);

/**
   Equivalent to cson_value_free(cson_string_value(x)).
*/
void cson_free_string(cson_string const *x);


/**
   Allocates a new "array" value and transfers ownership of it to the
   caller. It must eventually be destroyed, by the caller or its
   owning container, by passing it to cson_value_free().

................................................................................
int cson_value_refcount_set( cson_value * v, unsigned short rc );
#endif

/**
   Deeply copies a JSON value, be it an object/array or a "plain"
   value (e.g. number/string/boolean). If cv is not NULL then this
   function makes a deep clone of it and returns that clone. Ownership
   of the clone is transfered to the caller, who must eventually free
   the value using cson_value_free() or add it to a container
   object/array to transfer ownership to the container. The returned
   object will be of the same logical type as orig.

   ACHTUNG: if orig contains any cyclic references at any depth level
   this function will endlessly recurse. (Having _any_ cyclic
   references violates this library's requirements.)
   
   Returns NULL if orig is NULL or if cloning fails. Assuming that
   orig is in a valid state, the only "likely" error case is that an
   allocation fails while constructing the clone. In other words, if
   cloning fails due to something other than an allocation error then
   either orig is in an invalid state or there is a bug.


























*/
cson_value * cson_value_clone( cson_value const * orig );

/**
   Returns the value handle associated with s. The handle itself owns
   s, and ownership of the handle is not changed by calling this
   function. If the returned handle is part of a container, calling
   cson_value_free() on the returned handle invoked undefined
   behaviour (quite possibly downstream when the container tries to
   use it).

   This function only returns NULL if s. is NULL.

*/
cson_value * cson_string_value(cson_string const * s);
/**
   The Object form of cson_string_value(). See that function
   for full details.
*/
cson_value * cson_object_value(cson_object const * s);
................................................................................
   The Array form of cson_string_value(). See that function
   for full details.
*/
cson_value * cson_array_value(cson_array const * s);


/**
   Calculates the in-memory-allocated size of v, recursively if it is
   a container type, with the following caveats and limitations:


   If a given value is reference counted and multiple times within a
   traversed container, each reference is counted at full cost. We
   have no what of knowing if a given reference has been visited
   already and whether it should or should not be counted, so we
   pessimistically count them even though the _might_ not really count
   for the given object tree (it depends on where the other open
   references live).

   This function returns 0 if any of the following are true:

   - v is NULL

   - v is one of the special singleton values (null, bools, empty







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







 







|
>







 







|







 







|
|
|
|










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











|
>







 







|
|
>

|
|
|
|
|
|







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
...
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
....
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
....
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
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
....
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
#define CSON_DOUBLE_T_SFMT "Lf"
#define CSON_DOUBLE_T_PFMT "Lf"
#else
typedef double cson_double_t;
#define CSON_DOUBLE_T_SFMT "f"
#define CSON_DOUBLE_T_PFMT "f"
#endif

/** @def CSON_VOID_PTR_IS_BIG

ONLY define this to a true value if you know that

(sizeof(cson_int_t) <= sizeof(void*))

If that is the case, cson does not need to dynamically
allocate integers. However, enabling this may cause
compilation warnings in 32-bit builds even though the code
being warned about cannot ever be called. To get around such
warnings, when building on a 64-bit environment you can define
this to 1 to get "big" integer support. HOWEVER, all clients must
also use the same value for this macro. If i knew a halfway reliable
way to determine this automatically at preprocessor-time, i would
automate this. We might be able to do halfway reliably by looking
for a large INT_MAX value?
*/
#if !defined(CSON_VOID_PTR_IS_BIG)

/* Largely taken from http://predef.sourceforge.net/prearch.html

See also: http://poshlib.hookatooka.com/poshlib/trac.cgi/browser/posh.h
*/
#  if defined(_WIN64) || defined(__LP64__)/*gcc*/ \
    || defined(_M_X64) || defined(__amd64__) || defined(__amd64) \
    ||  defined(__x86_64__) || defined(__x86_64) \
    || defined(__ia64__) || defined(__ia64) || defined(_IA64) || defined(__IA64__) \
    || defined(_M_IA64) \
    || defined(__sparc_v9__) || defined(__sparcv9) || defined(_ADDR64) \
    || defined(__64BIT__)
#    define CSON_VOID_PTR_IS_BIG 1
#  else
#    define CSON_VOID_PTR_IS_BIG 0
#  endif
#endif

/** @def CSON_INT_T_SFMT

scanf()-compatible format token for cson_int_t.
*/

/** @def CSON_INT_T_PFMT
................................................................................
cson_string * cson_value_get_string( cson_value const * val );

/**
   Returns a pointer to the NULL-terminated string bytes of str.
   The bytes are owned by string and will be invalided when it
   is cleaned up.

   If str is NULL then NULL is returned. If the string has a length
   of 0 then "" is returned.

   @see cson_string_length_bytes()
   @see cson_value_get_string()
*/
char const * cson_string_cstr( cson_string const * str );

/**
................................................................................
   Equivalent to cson_value_free(cson_array_value(x)).
*/
void cson_free_array(cson_array *x);

/**
   Equivalent to cson_value_free(cson_string_value(x)).
*/
void cson_free_string(cson_string *x);


/**
   Allocates a new "array" value and transfers ownership of it to the
   caller. It must eventually be destroyed, by the caller or its
   owning container, by passing it to cson_value_free().

................................................................................
int cson_value_refcount_set( cson_value * v, unsigned short rc );
#endif

/**
   Deeply copies a JSON value, be it an object/array or a "plain"
   value (e.g. number/string/boolean). If cv is not NULL then this
   function makes a deep clone of it and returns that clone. Ownership
   of the clone is identical t transfered to the caller, who must
   eventually free the value using cson_value_free() or add it to a
   container object/array to transfer ownership to the container. The
   returned object will be of the same logical type as orig.

   ACHTUNG: if orig contains any cyclic references at any depth level
   this function will endlessly recurse. (Having _any_ cyclic
   references violates this library's requirements.)
   
   Returns NULL if orig is NULL or if cloning fails. Assuming that
   orig is in a valid state, the only "likely" error case is that an
   allocation fails while constructing the clone. In other words, if
   cloning fails due to something other than an allocation error then
   either orig is in an invalid state or there is a bug.

   When this function clones Objects or Arrays it shares any immutable
   values (including object keys) between the parent and the
   clone. Mutable values (Objects and Arrays) are copied, however.
   For example, if we clone:

   @code
   { a: 1, b: 2, c:["hi"] }
   @endcode

   The cloned object and the array "c" would be a new Object/Array
   instances but the object keys (a,b,b) and the values of (a,b), as
   well as the string value within the "c" array, would be shared
   between the original and the clone. The "c" array itself would be
   deeply cloned, such that future changes to the clone are not
   visible to the parent, and vice versa, but immutable values within
   the array are shared (in this case the string "hi"). The
   justification for this heuristic is that immutable values can never
   be changed, so there is no harm in sharing them across
   clones. Additionally, such types can never contribute to cycles in
   a JSON tree, so they are safe to share this way. Objects and
   Arrays, on the other hand, can be modified later and can contribute
   to cycles, and thus the clone needs to be an independent instance.
   Note, however, that if this function directly passed a
   non-Object/Array, that value is deeply cloned. The sharing
   behaviour only applies when traversing Objects/Arrays.
*/
cson_value * cson_value_clone( cson_value const * orig );

/**
   Returns the value handle associated with s. The handle itself owns
   s, and ownership of the handle is not changed by calling this
   function. If the returned handle is part of a container, calling
   cson_value_free() on the returned handle invoked undefined
   behaviour (quite possibly downstream when the container tries to
   use it).

   This function only returns NULL if s is NULL. The length of the
   returned string is cson_string_length_bytes().
*/
cson_value * cson_string_value(cson_string const * s);
/**
   The Object form of cson_string_value(). See that function
   for full details.
*/
cson_value * cson_object_value(cson_object const * s);
................................................................................
   The Array form of cson_string_value(). See that function
   for full details.
*/
cson_value * cson_array_value(cson_array const * s);


/**
   Calculates the approximate in-memory-allocated size of v,
   recursively if it is a container type, with the following caveats
   and limitations:

   If a given value is reference counted then it is only and multiple
   times within a traversed container, each reference is counted at
   full cost. We have no way of knowing if a given reference has been
   visited already and whether it should or should not be counted, so
   we pessimistically count them even though the _might_ not really
   count for the given object tree (it depends on where the other open
   references live).

   This function returns 0 if any of the following are true:

   - v is NULL

   - v is one of the special singleton values (null, bools, empty

Changes to src/db.c.

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
...
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
...
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
...
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
...
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
...
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
...
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
...
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
...
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
...
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
....
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
....
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
....
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
....
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
....
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
....
2005
2006
2007
2008
2009
2010
2011






2012
2013
2014
2015
2016
2017
2018
    fprintf(stderr, "%s: %s\n\n%s", fossil_nameofexe(), z, zRebuildMsg);
  }
  free(z);
  db_force_rollback();
  fossil_exit(rc);
}






static int nBegin = 0;      /* Nesting depth of BEGIN */
static int doRollback = 0;  /* True to force a rollback */
static int nCommitHook = 0; /* Number of commit hooks */



static struct sCommitHook {
  int (*xHook)(void);  /* Functions to call at db_end_transaction() */
  int sequence;        /* Call functions in sequence order */
} aHook[5];
static Stmt *pAllStmt = 0;  /* List of all unfinalized statements */
static int nPrepare = 0;    /* Number of calls to sqlite3_prepare() */
static int nDeleteOnFail = 0;  /* Number of entries in azDeleteOnFail[] */
static char *azDeleteOnFail[3]; /* Files to delete on a failure */



/*
** Arrange for the given file to be deleted on a failure.
*/
void db_delete_on_failure(const char *zFilename){
  assert( nDeleteOnFail<count(azDeleteOnFail) );
  azDeleteOnFail[nDeleteOnFail++] = fossil_strdup(zFilename);
}

/*
** This routine is called by the SQLite commit-hook mechanism
** just prior to each commit.  All this routine does is verify
** that nBegin really is zero.  That insures that transactions
** cannot commit by any means other than by calling db_end_transaction()
** below.
**
** This is just a safety and sanity check.
*/
static int db_verify_at_commit(void *notUsed){
  if( nBegin ){
    fossil_panic("illegal commit attempt");
    return 1;
  }
  return 0;
}

/*
** Begin and end a nested transaction
*/
void db_begin_transaction(void){
  if( nBegin==0 ){
    db_multi_exec("BEGIN");
    sqlite3_commit_hook(g.db, db_verify_at_commit, 0);
  }
  nBegin++;
}
void db_end_transaction(int rollbackFlag){
  if( g.db==0 ) return;
  if( nBegin<=0 ) return;
  if( rollbackFlag ) doRollback = 1;
  nBegin--;
  if( nBegin==0 ){
    int i;
    if( doRollback==0 ) leaf_do_pending_checks();
    for(i=0; doRollback==0 && i<nCommitHook; i++){
      doRollback |= aHook[i].xHook();
    }
    while( pAllStmt ){
      db_finalize(pAllStmt);
    }
    db_multi_exec(doRollback ? "ROLLBACK" : "COMMIT");
    doRollback = 0;
  }
}

/*
** Force a rollback and shutdown the database
*/
void db_force_rollback(void){
................................................................................
  sqlite3_stmt *pStmt = 0;
  if( busy || g.db==0 ) return;
  busy = 1;
  undo_rollback();
  while( (pStmt = sqlite3_next_stmt(g.db,pStmt))!=0 ){
    sqlite3_reset(pStmt);
  }
  while( pAllStmt ){
    db_finalize(pAllStmt);
  }
  if( nBegin ){
    sqlite3_exec(g.db, "ROLLBACK", 0, 0, 0);
    nBegin = 0;
  }
  busy = 0;
  db_close(0);
  for(i=0; i<nDeleteOnFail; i++){
    file_delete(azDeleteOnFail[i]);
  }
}

/*
** Install a commit hook.  Hooks are installed in sequence order.
** It is an error to install the same commit hook more than once.
**
................................................................................
** each commit operation.  If any commit hook returns non-zero,
** the subsequence commit hooks are omitted and the transaction
** rolls back rather than commit.  It is the responsibility of the
** hooks themselves to issue any error messages.
*/
void db_commit_hook(int (*x)(void), int sequence){
  int i;
  assert( nCommitHook < sizeof(aHook)/sizeof(aHook[1]) );
  for(i=0; i<nCommitHook; i++){
    assert( x!=aHook[i].xHook );
    if( aHook[i].sequence>sequence ){
      int s = sequence;
      int (*xS)(void) = x;
      sequence = aHook[i].sequence;
      x = aHook[i].xHook;
      aHook[i].sequence = s;
      aHook[i].xHook = xS;
    }
  }
  aHook[nCommitHook].sequence = sequence;
  aHook[nCommitHook].xHook = x;
  nCommitHook++;
}

/*
** Prepare a Stmt.  Assume that the Stmt is previously uninitialized.
** If the input string contains multiple SQL statements, only the first
** one is processed.  All statements beyond the first are silently ignored.
*/
................................................................................
int db_vprepare(Stmt *pStmt, int errOk, const char *zFormat, va_list ap){
  int rc;
  char *zSql;
  blob_zero(&pStmt->sql);
  blob_vappendf(&pStmt->sql, zFormat, ap);
  va_end(ap);
  zSql = blob_str(&pStmt->sql);
  nPrepare++;
  rc = sqlite3_prepare_v2(g.db, zSql, -1, &pStmt->pStmt, 0);
  if( rc!=0 && !errOk ){
    db_err("%s\n%s", sqlite3_errmsg(g.db), zSql);
  }
  pStmt->pNext = pStmt->pPrev = 0;
  pStmt->nStep = 0;
  return rc;
................................................................................
}
int db_static_prepare(Stmt *pStmt, const char *zFormat, ...){
  int rc = SQLITE_OK;
  if( blob_size(&pStmt->sql)==0 ){
    va_list ap;
    va_start(ap, zFormat);
    rc = db_vprepare(pStmt, 0, zFormat, ap);
    pStmt->pNext = pAllStmt;
    pStmt->pPrev = 0;
    if( pAllStmt ) pAllStmt->pPrev = pStmt;
    pAllStmt = pStmt;
    va_end(ap);
  }
  return rc;
}

/*
** Return the index of a bind parameter
................................................................................
  db_check_result(rc);
  pStmt->pStmt = 0;
  if( pStmt->pNext ){
    pStmt->pNext->pPrev = pStmt->pPrev;
  }
  if( pStmt->pPrev ){
    pStmt->pPrev->pNext = pStmt->pNext;
  }else if( pAllStmt==pStmt ){
    pAllStmt = pStmt->pNext;
  }
  pStmt->pNext = 0;
  pStmt->pPrev = 0;
  return rc;
}

/*
................................................................................
** connection.  An error results in process abort.
*/
static sqlite3 *openDatabase(const char *zDbName){
  int rc;
  const char *zVfs;
  sqlite3 *db;

  zVfs = getenv("FOSSIL_VFS");
  rc = sqlite3_open_v2(
       zDbName, &db,
       SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
       zVfs
  );
  if( rc!=SQLITE_OK ){
    db_err(sqlite3_errmsg(db));
................................................................................
** case, invoke this routine with useAttach as 1.
*/
void db_open_config(int useAttach){
  char *zDbName;
  const char *zHome;
  if( g.configOpen ) return;
#if defined(_WIN32)
  zHome = getenv("LOCALAPPDATA");
  if( zHome==0 ){
    zHome = getenv("APPDATA");
    if( zHome==0 ){
      char *zDrive = getenv("HOMEDRIVE");
      zHome = 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");
  }
  zHome = fossil_mbcs_to_utf8(zHome);
#else
  zHome = 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);
................................................................................
static int isValidLocalDb(const char *zDbName){
  i64 lsize;

  if( file_access(zDbName, F_OK) ) return 0;
  lsize = file_size(zDbName);
  if( lsize%1024!=0 || lsize<4096 ) return 0;
  db_open_or_attach(zDbName, "localdb");
  g.localOpen = 1;
  db_open_config(0);
  db_open_repository(0);

  /* If the "isexe" column is missing from the vfile table, then
  ** add it now.   This code added on 2010-03-06.  After all users have
  ** upgraded, this code can be safely deleted. 
  */
  if( !db_local_column_exists("vfile", "isexe") )
    db_multi_exec("ALTER TABLE vfile ADD COLUMN isexe BOOLEAN DEFAULT 0");


  /* If "islink"/"isLink" columns are missing from tables, then
  ** add them now.   This code added on 2011-01-17 and 2011-08-27.
  ** After all users have upgraded, this code can be safely deleted. 
  */
  if( !db_local_column_exists("vfile", "islink") )
    db_multi_exec("ALTER TABLE vfile ADD COLUMN islink BOOLEAN DEFAULT 0");
  

  if( !db_local_column_exists("stashfile", "isLink") &&
       db_local_table_exists("stashfile") )
    db_multi_exec("ALTER TABLE stashfile ADD COLUMN isLink BOOLEAN DEFAULT 0");


  if( !db_local_column_exists("undo", "isLink") &&
       db_local_table_exists("undo") )
    db_multi_exec("ALTER TABLE undo ADD COLUMN isLink BOOLEAN DEFAULT 0");
  

  if( !db_local_column_exists("undo_vfile", "islink") &&
       db_local_table_exists("undo_vfile") )
    db_multi_exec("ALTER TABLE undo_vfile ADD COLUMN islink BOOLEAN DEFAULT 0");

  return 1;
}

/*
** Locate the root directory of the local repository tree.  The root
** directory is found by searching for a file named "_FOSSIL_" or ".fos"
** that contains a valid repository database.



**
** If no valid _FOSSIL_ or .fos file is found, we move up one level and 
** try again. Once the file is found, the g.zLocalRoot variable is set
** to the root of the repository tree and this routine returns 1.  If
** no database is found, then this routine return 0.
**
** This routine always opens the user database regardless of whether or
** not the repository database is found.  If the _FOSSIL_ or .fos file
** is found, it is attached to the open database connection too.
*/
int db_open_local(void){
  int i, n;
  char zPwd[2000];
  static const char *aDbName[] = { "/_FOSSIL_", "/.fos" };
  
  if( g.localOpen) return 1;
  file_getcwd(zPwd, sizeof(zPwd)-20);
  n = strlen(zPwd);
  if( n==1 && zPwd[0]=='/' ) zPwd[0] = '.';
  while( n>0 ){
    if( file_access(zPwd, W_OK) ) break;
................................................................................
        /* Found a valid checkout database file */
        zPwd[n] = 0;
        while( n>1 && zPwd[n-1]=='/' ){
          n--;
          zPwd[n] = 0;
        }
        g.zLocalRoot = mprintf("%s/", zPwd);



        return 1;
      }
    }
    n--;
    while( n>0 && zPwd[n]!='/' ){ n--; }
    while( n>0 && zPwd[n-1]=='/' ){ n--; }
    zPwd[n] = 0;
  }

  /* A checkout database file could not be found */
  return 0;
}



















/*
** Open the repository database given by zDbName.  If zDbName==NULL then
** get the name from the already open local database.
*/
void db_open_repository(const char *zDbName){
  if( g.repositoryOpen ) return;
  if( zDbName==0 ){
    if( g.localOpen ){
      zDbName = db_lget("repository", 0);
    }
    if( zDbName==0 ){
      db_err("unable to find the name of a repository database");
    }
  }
  if( file_access(zDbName, R_OK) || file_size(zDbName)<1024 ){
    if( file_access(zDbName, 0) ){
................................................................................
  if( zRep==0 && nArgUsed && g.argc==nArgUsed+1 ){
    zRep = g.argv[nArgUsed];
  }
  if( zRep==0 ){
    if( db_open_local()==0 ){
      goto rep_not_found;
    }
    zRep = db_lget("repository", 0)/*leak here*/;
    if( zRep==0 ){
      goto rep_not_found;
    }
  }
  db_open_repository(zRep);
  if( g.repositoryOpen ){
    if( (bFlags & OPEN_ANY_SCHEMA)==0 ) db_verify_schema();
................................................................................
    fprintf(stderr, "-- MEMORY_USED            %10d %10d\n", cur, hiwtr);
    sqlite3_status(SQLITE_STATUS_MALLOC_SIZE, &cur, &hiwtr, 0);
    fprintf(stderr, "-- MALLOC_SIZE                       %10d\n", hiwtr);
    sqlite3_status(SQLITE_STATUS_MALLOC_COUNT, &cur, &hiwtr, 0);
    fprintf(stderr, "-- MALLOC_COUNT           %10d %10d\n", cur, hiwtr);
    sqlite3_status(SQLITE_STATUS_PAGECACHE_OVERFLOW, &cur, &hiwtr, 0);
    fprintf(stderr, "-- PCACHE_OVFLOW          %10d %10d\n", cur, hiwtr);
    fprintf(stderr, "-- prepared statements    %10d\n", nPrepare);
  }
  while( pAllStmt ){
    db_finalize(pAllStmt);
  }
  db_end_transaction(1);
  pStmt = 0;
  if( reportErrors ){
    while( (pStmt = sqlite3_next_stmt(g.db, pStmt))!=0 ){
      fossil_warning("unfinalized SQL statement: [%s]", sqlite3_sql(pStmt));
    }
................................................................................
void db_create_default_users(int setupUserOnly, const char *zDefaultUser){
  const char *zUser = zDefaultUser;
  if( zUser==0 ){
    zUser = db_get("default-user", 0);
  }
  if( zUser==0 ){
#if defined(_WIN32)
    zUser = getenv("USERNAME");
#else
    zUser = getenv("USER");
#endif
  }
  if( zUser==0 ){
    zUser = "root";
  }
  db_multi_exec(
     "INSERT OR IGNORE INTO user(login, info) VALUES(%Q,'')", zUser
................................................................................
**
** Where %s is the checkout root.  The value is the repository file.
*/
void db_record_repository_filename(const char *zName){
  Blob full;
  if( zName==0 ){
    if( !g.localOpen ) return;
    zName = db_lget("repository", 0);
  }
  file_canonical_name(zName, &full);
  db_swap_connections();
  db_multi_exec(
     "INSERT OR IGNORE INTO global_config(name,value)"
     "VALUES('repo:%q',1)",
     blob_str(&full)
................................................................................
    fossil_panic("already within an open tree rooted at %s", g.zLocalRoot);
  }
  file_canonical_name(g.argv[2], &path);
  db_open_repository(blob_str(&path));
  db_init_database("./_FOSSIL_", zLocalSchema, (char*)0);
  db_delete_on_failure("./_FOSSIL_");
  db_open_local();
  db_lset("repository", blob_str(&path));
  db_record_repository_filename(blob_str(&path));
  vid = db_int(0, "SELECT pid FROM plink y"
                  " WHERE NOT EXISTS(SELECT 1 FROM plink x WHERE x.cid=y.pid)");
  if( vid==0 ){
    db_lset_int("checkout", 1);
  }else{
    char **oldArgv = g.argv;
................................................................................
  { 0,0,0,0,0 }
};

/*
** COMMAND: settings
** COMMAND: unset*
**
** %fossil settings ?PROPERTY? ?VALUE? ?-global?
** %fossil unset PROPERTY ?-global?
**
** The "settings" command with no arguments lists all properties and their
** values.  With just a property name it shows the value of that property.
** With a value argument it changes the property for the current repository.
**
** Settings marked as versionable are overridden by the contents of the
** file named .fossil-settings/PROPERTY in the checked out files, if that
................................................................................
**                     Tcl interpreter will be able to evaluate TH1 expressions
**                     and scripts.  Default: off.
**
**    web-browser      A shell command used to launch your preferred
**                     web browser when given a URL as an argument.
**                     Defaults to "start" on windows, "open" on Mac,
**                     and "firefox" on Unix.






*/
void setting_cmd(void){
  int i;
  int globalFlag = find_option("global","g",0)!=0;
  int unsetFlag = g.argv[1][0]=='u';
  db_open_config(1);
  if( !globalFlag ){







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





|
|












|










|



|



|
|
|
|

|
|
|

|
|

|
|







 







|
|

|

|



|
|







 







|
|
|
|


|
|
|
|


|
|
|







 







|







 







|

|
|







 







|
|







 







|







 







|

|

|
|








<

|







 







<
<
<





|

>





|

|
>

|

|
>

|

|
>

|

|





|

>
>
>













|







 







>
>
>












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









|







 







|







 







|

|
|







 







|

|







 







|







 







|







 







|
|







 







>
>
>
>
>
>







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
...
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
...
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
...
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
...
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
...
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
...
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
...
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
...
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
...
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
....
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
....
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
....
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
....
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
....
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
....
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
    fprintf(stderr, "%s: %s\n\n%s", fossil_nameofexe(), z, zRebuildMsg);
  }
  free(z);
  db_force_rollback();
  fossil_exit(rc);
}

/*
** All static variable that a used by only this file are gathered into
** the following structure.
*/
static struct DbLocalData {
  int nBegin;               /* Nesting depth of BEGIN */
  int doRollback;           /* True to force a rollback */
  int nCommitHook;          /* Number of commit hooks */
  Stmt *pAllStmt;           /* List of all unfinalized statements */
  int nPrepare;             /* Number of calls to sqlite3_prepare() */
  int nDeleteOnFail;        /* Number of entries in azDeleteOnFail[] */
  struct sCommitHook {
    int (*xHook)(void);         /* Functions to call at db_end_transaction() */
    int sequence;               /* Call functions in sequence order */
  } aHook[5];



  char *azDeleteOnFail[3];  /* Files to delete on a failure */

} db = {0, 0, 0, 0, 0, 0, };

/*
** Arrange for the given file to be deleted on a failure.
*/
void db_delete_on_failure(const char *zFilename){
  assert( db.nDeleteOnFail<count(db.azDeleteOnFail) );
  db.azDeleteOnFail[db.nDeleteOnFail++] = fossil_strdup(zFilename);
}

/*
** This routine is called by the SQLite commit-hook mechanism
** just prior to each commit.  All this routine does is verify
** that nBegin really is zero.  That insures that transactions
** cannot commit by any means other than by calling db_end_transaction()
** below.
**
** This is just a safety and sanity check.
*/
static int db_verify_at_commit(void *notUsed){
  if( db.nBegin ){
    fossil_panic("illegal commit attempt");
    return 1;
  }
  return 0;
}

/*
** Begin and end a nested transaction
*/
void db_begin_transaction(void){
  if( db.nBegin==0 ){
    db_multi_exec("BEGIN");
    sqlite3_commit_hook(g.db, db_verify_at_commit, 0);
  }
  db.nBegin++;
}
void db_end_transaction(int rollbackFlag){
  if( g.db==0 ) return;
  if( db.nBegin<=0 ) return;
  if( rollbackFlag ) db.doRollback = 1;
  db.nBegin--;
  if( db.nBegin==0 ){
    int i;
    if( db.doRollback==0 ) leaf_do_pending_checks();
    for(i=0; db.doRollback==0 && i<db.nCommitHook; i++){
      db.doRollback |= db.aHook[i].xHook();
    }
    while( db.pAllStmt ){
      db_finalize(db.pAllStmt);
    }
    db_multi_exec(db.doRollback ? "ROLLBACK" : "COMMIT");
    db.doRollback = 0;
  }
}

/*
** Force a rollback and shutdown the database
*/
void db_force_rollback(void){
................................................................................
  sqlite3_stmt *pStmt = 0;
  if( busy || g.db==0 ) return;
  busy = 1;
  undo_rollback();
  while( (pStmt = sqlite3_next_stmt(g.db,pStmt))!=0 ){
    sqlite3_reset(pStmt);
  }
  while( db.pAllStmt ){
    db_finalize(db.pAllStmt);
  }
  if( db.nBegin ){
    sqlite3_exec(g.db, "ROLLBACK", 0, 0, 0);
    db.nBegin = 0;
  }
  busy = 0;
  db_close(0);
  for(i=0; i<db.nDeleteOnFail; i++){
    file_delete(db.azDeleteOnFail[i]);
  }
}

/*
** Install a commit hook.  Hooks are installed in sequence order.
** It is an error to install the same commit hook more than once.
**
................................................................................
** each commit operation.  If any commit hook returns non-zero,
** the subsequence commit hooks are omitted and the transaction
** rolls back rather than commit.  It is the responsibility of the
** hooks themselves to issue any error messages.
*/
void db_commit_hook(int (*x)(void), int sequence){
  int i;
  assert( db.nCommitHook < sizeof(db.aHook)/sizeof(db.aHook[1]) );
  for(i=0; i<db.nCommitHook; i++){
    assert( x!=db.aHook[i].xHook );
    if( db.aHook[i].sequence>sequence ){
      int s = sequence;
      int (*xS)(void) = x;
      sequence = db.aHook[i].sequence;
      x = db.aHook[i].xHook;
      db.aHook[i].sequence = s;
      db.aHook[i].xHook = xS;
    }
  }
  db.aHook[db.nCommitHook].sequence = sequence;
  db.aHook[db.nCommitHook].xHook = x;
  db.nCommitHook++;
}

/*
** Prepare a Stmt.  Assume that the Stmt is previously uninitialized.
** If the input string contains multiple SQL statements, only the first
** one is processed.  All statements beyond the first are silently ignored.
*/
................................................................................
int db_vprepare(Stmt *pStmt, int errOk, const char *zFormat, va_list ap){
  int rc;
  char *zSql;
  blob_zero(&pStmt->sql);
  blob_vappendf(&pStmt->sql, zFormat, ap);
  va_end(ap);
  zSql = blob_str(&pStmt->sql);
  db.nPrepare++;
  rc = sqlite3_prepare_v2(g.db, zSql, -1, &pStmt->pStmt, 0);
  if( rc!=0 && !errOk ){
    db_err("%s\n%s", sqlite3_errmsg(g.db), zSql);
  }
  pStmt->pNext = pStmt->pPrev = 0;
  pStmt->nStep = 0;
  return rc;
................................................................................
}
int db_static_prepare(Stmt *pStmt, const char *zFormat, ...){
  int rc = SQLITE_OK;
  if( blob_size(&pStmt->sql)==0 ){
    va_list ap;
    va_start(ap, zFormat);
    rc = db_vprepare(pStmt, 0, zFormat, ap);
    pStmt->pNext = db.pAllStmt;
    pStmt->pPrev = 0;
    if( db.pAllStmt ) db.pAllStmt->pPrev = pStmt;
    db.pAllStmt = pStmt;
    va_end(ap);
  }
  return rc;
}

/*
** Return the index of a bind parameter
................................................................................
  db_check_result(rc);
  pStmt->pStmt = 0;
  if( pStmt->pNext ){
    pStmt->pNext->pPrev = pStmt->pPrev;
  }
  if( pStmt->pPrev ){
    pStmt->pPrev->pNext = pStmt->pNext;
  }else if( db.pAllStmt==pStmt ){
    db.pAllStmt = pStmt->pNext;
  }
  pStmt->pNext = 0;
  pStmt->pPrev = 0;
  return rc;
}

/*
................................................................................
** connection.  An error results in process abort.
*/
static sqlite3 *openDatabase(const char *zDbName){
  int rc;
  const char *zVfs;
  sqlite3 *db;

  zVfs = fossil_getenv("FOSSIL_VFS");
  rc = sqlite3_open_v2(
       zDbName, &db,
       SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
       zVfs
  );
  if( rc!=SQLITE_OK ){
    db_err(sqlite3_errmsg(db));
................................................................................
** case, invoke this routine with useAttach as 1.
*/
void db_open_config(int useAttach){
  char *zDbName;
  const char *zHome;
  if( g.configOpen ) return;
#if defined(_WIN32)
  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);
................................................................................
static int isValidLocalDb(const char *zDbName){
  i64 lsize;

  if( file_access(zDbName, F_OK) ) return 0;
  lsize = file_size(zDbName);
  if( lsize%1024!=0 || lsize<4096 ) return 0;
  db_open_or_attach(zDbName, "localdb");




  /* If the "isexe" column is missing from the vfile table, then
  ** add it now.   This code added on 2010-03-06.  After all users have
  ** upgraded, this code can be safely deleted. 
  */
  if( !db_local_column_exists("vfile", "isexe") ){
    db_multi_exec("ALTER TABLE vfile ADD COLUMN isexe BOOLEAN DEFAULT 0");
  }

  /* If "islink"/"isLink" columns are missing from tables, then
  ** add them now.   This code added on 2011-01-17 and 2011-08-27.
  ** After all users have upgraded, this code can be safely deleted. 
  */
  if( !db_local_column_exists("vfile", "islink") ){
    db_multi_exec("ALTER TABLE vfile ADD COLUMN islink BOOLEAN DEFAULT 0");
  }
  
  if( !db_local_column_exists("stashfile", "isLink") &&
       db_local_table_exists("stashfile") ){
    db_multi_exec("ALTER TABLE stashfile ADD COLUMN isLink BOOLEAN DEFAULT 0");
  }

  if( !db_local_column_exists("undo", "isLink") &&
       db_local_table_exists("undo") ){
    db_multi_exec("ALTER TABLE undo ADD COLUMN isLink BOOLEAN DEFAULT 0");
  }
  
  if( !db_local_column_exists("undo_vfile", "islink") &&
       db_local_table_exists("undo_vfile") ){
    db_multi_exec("ALTER TABLE undo_vfile ADD COLUMN islink BOOLEAN DEFAULT 0");
  }
  return 1;
}

/*
** Locate the root directory of the local repository tree.  The root
** directory is found by searching for a file named "_FOSSIL_" or ".fslckout"
** that contains a valid repository database.
**
** For legacy, also look for ".fos".  The use of ".fos" is deprecated
** since "fos" has negative connotations in Hungarian, we are told.
**
** If no valid _FOSSIL_ or .fos file is found, we move up one level and 
** try again. Once the file is found, the g.zLocalRoot variable is set
** to the root of the repository tree and this routine returns 1.  If
** no database is found, then this routine return 0.
**
** This routine always opens the user database regardless of whether or
** not the repository database is found.  If the _FOSSIL_ or .fos file
** is found, it is attached to the open database connection too.
*/
int db_open_local(void){
  int i, n;
  char zPwd[2000];
  static const char *aDbName[] = { "/_FOSSIL_", "/.fslckout", "/.fos" };
  
  if( g.localOpen) return 1;
  file_getcwd(zPwd, sizeof(zPwd)-20);
  n = strlen(zPwd);
  if( n==1 && zPwd[0]=='/' ) zPwd[0] = '.';
  while( n>0 ){
    if( file_access(zPwd, W_OK) ) break;
................................................................................
        /* Found a valid checkout database file */
        zPwd[n] = 0;
        while( n>1 && zPwd[n-1]=='/' ){
          n--;
          zPwd[n] = 0;
        }
        g.zLocalRoot = mprintf("%s/", zPwd);
        g.localOpen = 1;
        db_open_config(0);
        db_open_repository(0);
        return 1;
      }
    }
    n--;
    while( n>0 && zPwd[n]!='/' ){ n--; }
    while( n>0 && zPwd[n-1]=='/' ){ n--; }
    zPwd[n] = 0;
  }

  /* A checkout database file could not be found */
  return 0;
}

/*
** Get the full pathname to the repository database file.  The
** local database (the _FOSSIL_ or .fslckout database) must have already
** been opened before this routine is called.
*/
const char *db_repository_filename(void){
  static char *zRepo = 0;
  assert( g.localOpen );
  assert( g.zLocalRoot );
  if( zRepo==0 ){
    zRepo = db_lget("repository", 0);
    if( zRepo && !file_is_absolute_path(zRepo) ){
      zRepo = mprintf("%s%s", g.zLocalRoot, zRepo);
    }
  }
  return zRepo;
}

/*
** Open the repository database given by zDbName.  If zDbName==NULL then
** get the name from the already open local database.
*/
void db_open_repository(const char *zDbName){
  if( g.repositoryOpen ) return;
  if( zDbName==0 ){
    if( g.localOpen ){
      zDbName = db_repository_filename();
    }
    if( zDbName==0 ){
      db_err("unable to find the name of a repository database");
    }
  }
  if( file_access(zDbName, R_OK) || file_size(zDbName)<1024 ){
    if( file_access(zDbName, 0) ){
................................................................................
  if( zRep==0 && nArgUsed && g.argc==nArgUsed+1 ){
    zRep = g.argv[nArgUsed];
  }
  if( zRep==0 ){
    if( db_open_local()==0 ){
      goto rep_not_found;
    }
    zRep = db_repository_filename();
    if( zRep==0 ){
      goto rep_not_found;
    }
  }
  db_open_repository(zRep);
  if( g.repositoryOpen ){
    if( (bFlags & OPEN_ANY_SCHEMA)==0 ) db_verify_schema();
................................................................................
    fprintf(stderr, "-- MEMORY_USED            %10d %10d\n", cur, hiwtr);
    sqlite3_status(SQLITE_STATUS_MALLOC_SIZE, &cur, &hiwtr, 0);
    fprintf(stderr, "-- MALLOC_SIZE                       %10d\n", hiwtr);
    sqlite3_status(SQLITE_STATUS_MALLOC_COUNT, &cur, &hiwtr, 0);
    fprintf(stderr, "-- MALLOC_COUNT           %10d %10d\n", cur, hiwtr);
    sqlite3_status(SQLITE_STATUS_PAGECACHE_OVERFLOW, &cur, &hiwtr, 0);
    fprintf(stderr, "-- PCACHE_OVFLOW          %10d %10d\n", cur, hiwtr);
    fprintf(stderr, "-- prepared statements    %10d\n", db.nPrepare);
  }
  while( db.pAllStmt ){
    db_finalize(db.pAllStmt);
  }
  db_end_transaction(1);
  pStmt = 0;
  if( reportErrors ){
    while( (pStmt = sqlite3_next_stmt(g.db, pStmt))!=0 ){
      fossil_warning("unfinalized SQL statement: [%s]", sqlite3_sql(pStmt));
    }
................................................................................
void db_create_default_users(int setupUserOnly, const char *zDefaultUser){
  const char *zUser = zDefaultUser;
  if( zUser==0 ){
    zUser = db_get("default-user", 0);
  }
  if( zUser==0 ){
#if defined(_WIN32)
    zUser = fossil_getenv("USERNAME");
#else
    zUser = fossil_getenv("USER");
#endif
  }
  if( zUser==0 ){
    zUser = "root";
  }
  db_multi_exec(
     "INSERT OR IGNORE INTO user(login, info) VALUES(%Q,'')", zUser
................................................................................
**
** Where %s is the checkout root.  The value is the repository file.
*/
void db_record_repository_filename(const char *zName){
  Blob full;
  if( zName==0 ){
    if( !g.localOpen ) return;
    zName = db_repository_filename();
  }
  file_canonical_name(zName, &full);
  db_swap_connections();
  db_multi_exec(
     "INSERT OR IGNORE INTO global_config(name,value)"
     "VALUES('repo:%q',1)",
     blob_str(&full)
................................................................................
    fossil_panic("already within an open tree rooted at %s", g.zLocalRoot);
  }
  file_canonical_name(g.argv[2], &path);
  db_open_repository(blob_str(&path));
  db_init_database("./_FOSSIL_", zLocalSchema, (char*)0);
  db_delete_on_failure("./_FOSSIL_");
  db_open_local();
  db_lset("repository", g.argv[2]);
  db_record_repository_filename(blob_str(&path));
  vid = db_int(0, "SELECT pid FROM plink y"
                  " WHERE NOT EXISTS(SELECT 1 FROM plink x WHERE x.cid=y.pid)");
  if( vid==0 ){
    db_lset_int("checkout", 1);
  }else{
    char **oldArgv = g.argv;
................................................................................
  { 0,0,0,0,0 }
};

/*
** COMMAND: settings
** COMMAND: unset*
**
** %fossil settings ?PROPERTY? ?VALUE? ?OPTIONS?
** %fossil unset PROPERTY ?OPTIONS?
**
** The "settings" command with no arguments lists all properties and their
** values.  With just a property name it shows the value of that property.
** With a value argument it changes the property for the current repository.
**
** Settings marked as versionable are overridden by the contents of the
** file named .fossil-settings/PROPERTY in the checked out files, if that
................................................................................
**                     Tcl interpreter will be able to evaluate TH1 expressions
**                     and scripts.  Default: off.
**
**    web-browser      A shell command used to launch your preferred
**                     web browser when given a URL as an argument.
**                     Defaults to "start" on windows, "open" on Mac,
**                     and "firefox" on Unix.
**
** Options:
**   --global   set or unset the given property globally instead of
**              setting or unsetting it for the open repository only.
** 
** See also: configuration
*/
void setting_cmd(void){
  int i;
  int globalFlag = find_option("global","g",0)!=0;
  int unsetFlag = g.argv[1][0]=='u';
  db_open_config(1);
  if( !globalFlag ){

Changes to src/diff.c.

23
24
25
26
27
28
29
30
31
32
33
34






35
36
37
38
39
40
41
..
57
58
59
60
61
62
63





64










65
66
67
68
69
70
71
...
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
...
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
...
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
...
550
551
552
553
554
555
556

557

558
559
560
561
562
563
564
...
583
584
585
586
587
588
589
590



591
592
593
594
595
596




597
598
599
600
601
602
603
604
605
606
...
624
625
626
627
628
629
630









































631
632
633
634
635
636
637
...
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
...
716
717
718
719
720
721
722






































































































723
724
725
726
727
728
729
...
761
762
763
764
765
766
767





768
769
770
771
772
773
774
...
781
782
783
784
785
786
787

788
789
790

791
792
793
794

795
796
797
798
799
800
801
802
...
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
....
1032
1033
1034
1035
1036
1037
1038





1039
1040























1041
1042
1043
1044
1045
1046
1047
....
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
....
1317
1318
1319
1320
1321
1322
1323


1324
1325
1326
1327
1328
1329
1330
#include <assert.h>


#if INTERFACE
/*
** Allowed flag parameters to the text_diff() and html_sbsdiff() funtions:
*/
#define DIFF_CONTEXT_MASK  0x0000fff  /* Lines of context.  Default if 0 */
#define DIFF_WIDTH_MASK    0x00ff000  /* side-by-side column width */
#define DIFF_IGNORE_EOLWS  0x0100000  /* Ignore end-of-line whitespace */
#define DIFF_SIDEBYSIDE    0x0200000  /* Generate a side-by-side diff */
#define DIFF_NEWFILE       0x0400000  /* Missing files are as empty files */







#endif /* INTERFACE */

/*
** Maximum length of a line in a text file.  (8192)
*/
#define LENGTH_MASK_SZ  13
................................................................................
  /* an array of DLine elements services two purposes.  The fields
  ** above are one per line of input text.  But each entry is also
  ** a bucket in a hash table, as follows: */
  unsigned int iHash;   /* 1+(first entry in the hash chain) */
};

/*





** A context for running a diff.










*/
typedef struct DContext DContext;
struct DContext {
  int *aEdit;        /* Array of copy/delete/insert triples */
  int nEdit;         /* Number of integers (3x num of triples) in aEdit[] */
  int nEditAlloc;    /* Space allocated for aEdit[] */
  DLine *aFrom;      /* File on left side of the diff */
................................................................................
** Return true if two DLine elements are identical.
*/
static int same_dline(DLine *pA, DLine *pB){
  return pA->h==pB->h && memcmp(pA->z,pB->z,pA->h & LENGTH_MASK)==0;
}

/*
** Append a single line of "diff" output to pOut.
*/
static void appendDiffLine(Blob *pOut, char *zPrefix, DLine *pLine){





  blob_append(pOut, zPrefix, 1);








  blob_append(pOut, pLine->z, pLine->h & LENGTH_MASK);


  blob_append(pOut, "\n", 1);
}



/*
** Expand the size of aEdit[] array to hold nEdit elements.
*/
static void expandEdit(DContext *p, int nEdit){
  p->aEdit = fossil_realloc(p->aEdit, nEdit*sizeof(int));
  p->nEditAlloc = nEdit;

}

/*
** Append a new COPY/DELETE/INSERT triple.




*/
static void appendTriple(DContext *p, int nCopy, int nDel, int nIns){
  /* printf("APPEND %d/%d/%d\n", nCopy, nDel, nIns); */
  if( p->nEdit>=3 ){
    if( p->aEdit[p->nEdit-1]==0 ){
      if( p->aEdit[p->nEdit-2]==0 ){
        p->aEdit[p->nEdit-3] += nCopy;
        p->aEdit[p->nEdit-2] += nDel;
        p->aEdit[p->nEdit-1] += nIns;
        return;
      }
      if( nCopy==0 ){
        p->aEdit[p->nEdit-2] += nDel;
        p->aEdit[p->nEdit-1] += nIns;
        return;
      }
    }

    if( nCopy==0 && nDel==0 ){
      p->aEdit[p->nEdit-1] += nIns;
      return;
    }

  }  
  if( p->nEdit+3>p->nEditAlloc ){
    expandEdit(p, p->nEdit*2 + 15);
    if( p->aEdit==0 ) return;


  }
  p->aEdit[p->nEdit++] = nCopy;
  p->aEdit[p->nEdit++] = nDel;
  p->aEdit[p->nEdit++] = nIns;
}


/*
** Given a diff context in which the aEdit[] array has been filled
** in, compute a context diff into pOut.
*/
static void contextDiff(DContext *p, Blob *pOut, int nContext){






  DLine *A;     /* Left side of the diff */
  DLine *B;     /* Right side of the diff */  
  int a = 0;    /* Index of next line in A[] */
  int b = 0;    /* Index of next line in B[] */
  int *R;       /* Array of COPY/DELETE/INSERT triples */
  int r;        /* Index into R[] */
  int nr;       /* Number of COPY/DELETE/INSERT triples to process */
  int mxr;      /* Maximum value for r */
  int na, nb;   /* Number of lines shown from A and B */
  int i, j;     /* Loop counters */
  int m;        /* Number of lines to output */
  int skip;     /* Number of lines to skip */


  A = p->aFrom;
  B = p->aTo;
  R = p->aEdit;
  mxr = p->nEdit;
  while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; }
  for(r=0; r<mxr; r += 3*nr){
................................................................................
      na += R[r+nr*3];
      nb += R[r+nr*3];
    }
    for(i=1; i<nr; i++){
      na += R[r+i*3];
      nb += R[r+i*3];
    }

















    /*
     * If the patch changes an empty file or results in an empty file,
     * the block header must use 0,0 as position indicator and not 1,0.
     * Otherwise, patch would be confused and may reject the diff.
     */
    blob_appendf(pOut,"@@ -%d,%d +%d,%d @@\n",
      na ? a+skip+1 : 0, na,
      nb ? b+skip+1 : 0, nb);




    /* Show the initial common area */
    a += skip;
    b += skip;
    m = R[r] - skip;
    for(j=0; j<m; j++){

      appendDiffLine(pOut, " ", &A[a+j]);
    }
    a += m;
    b += m;

    /* Show the differences */
    for(i=0; i<nr; i++){
      m = R[r+i*3+1];
      for(j=0; j<m; j++){

        appendDiffLine(pOut, "-", &A[a+j]);
      }
      a += m;
      m = R[r+i*3+2];
      for(j=0; j<m; j++){

        appendDiffLine(pOut, "+", &B[b+j]);
      }
      b += m;
      if( i<nr-1 ){
        m = R[r+i*3+3];
        for(j=0; j<m; j++){

          appendDiffLine(pOut, " ", &B[b+j]);
        }
        b += m;
        a += m;
      }
    }

    /* Show the final common area */
    assert( nr==i );
    m = R[r+nr*3];
    if( m>nContext ) m = nContext;
    for(j=0; j<m; j++){

      appendDiffLine(pOut, " ", &B[b+j]);
    }
  }
}

/*
** Write a 6-digit line number into the buffer z[].  z[] is guaranteed to
** have space for at least 7 characters.
*/

static void sbsWriteLineno(char *z, int ln){
  sqlite3_snprintf(7, z, "%6d", ln+1);
  z[6] = ' ';








}

/*






** Write up to width characters of pLine into z[].  Translate tabs into
** spaces.  If trunc is true, then append \n\000 after the last character
** written.


*/
static int sbsWriteText(char *z, DLine *pLine, int width, int trunc){

  int n = pLine->h & LENGTH_MASK;
  int i, j;




  const char *zIn = pLine->z;
  for(i=j=0; i<n && j<width; i++){



    char c = zIn[i];





















    if( c=='\t' ){
      z[j++] = ' ';
      while( (j&7)!=0 && j<width ) z[j++] = ' ';

    }else if( c=='\r' || c=='\f' ){
      z[j++] = ' ';









    }else{
      z[j++] = c;
    }
  }
  if( trunc ){







    z[j++] = '\n';






































































    z[j] = 0;








  }





















  return j;
}










































































































































/*
















































































































































































** Given a diff context in which the aEdit[] array has been filled
** in, compute a side-by-side diff into pOut.
*/
static void sbsDiff(DContext *p, Blob *pOut, int nContext, int width){






  DLine *A;     /* Left side of the diff */
  DLine *B;     /* Right side of the diff */  
  int a = 0;    /* Index of next line in A[] */
  int b = 0;    /* Index of next line in B[] */
  int *R;       /* Array of COPY/DELETE/INSERT triples */
  int r;        /* Index into R[] */
  int nr;       /* Number of COPY/DELETE/INSERT triples to process */
  int mxr;      /* Maximum value for r */
  int na, nb;   /* Number of lines shown from A and B */
  int i, j;     /* Loop counters */
  int m, ma, mb;/* Number of lines to output */
  int skip;     /* Number of lines to skip */
  int mxLine;   /* Length of a line of text */
  char *zLine;  /* A line of text being formatted */
  int len;      /* Length of an output line */

  mxLine = width*2 + 2*7 + 3 + 1;
  zLine = fossil_malloc( mxLine + 1 );
  if( zLine==0 ) return;


  zLine[mxLine] = 0;

  A = p->aFrom;
  B = p->aTo;
  R = p->aEdit;
  mxr = p->nEdit;
  while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; }
  for(r=0; r<mxr; r += 3*nr){
    /* Figure out how many triples to show in a single block */
................................................................................
      na += R[r+nr*3];
      nb += R[r+nr*3];
    }
    for(i=1; i<nr; i++){
      na += R[r+i*3];
      nb += R[r+i*3];
    }
    /*

     * If the patch changes an empty file or results in an empty file,
     * the block header must use 0,0 as position indicator and not 1,0.
     * Otherwise, patch would be confused and may reject the diff.
     */


    if( r>0 ) blob_appendf(pOut,"%.*c\n", width*2+16, '.');







    /* Show the initial common area */
    a += skip;
    b += skip;
    m = R[r] - skip;
    for(j=0; j<m; j++){
      memset(zLine, ' ', mxLine);
      sbsWriteLineno(zLine, a+j);
      sbsWriteText(&zLine[7], &A[a+j], width, 0);
      sbsWriteLineno(&zLine[width+10], b+j);
      len = sbsWriteText(&zLine[width+17], &B[b+j], width, 1);
      blob_append(pOut, zLine, len+width+17);
    }
    a += m;
    b += m;

    /* Show the differences */
    for(i=0; i<nr; i++){
      ma = R[r+i*3+1];
      mb = R[r+i*3+2];
      m = ma<mb ? ma : mb;
      for(j=0; j<m; j++){
        memset(zLine, ' ', mxLine);
        sbsWriteLineno(zLine, a+j);
        sbsWriteText(&zLine[7], &A[a+j], width, 0);
        zLine[width+8] = '|';
        sbsWriteLineno(&zLine[width+10], b+j);
        len = sbsWriteText(&zLine[width+17], &B[b+j], width, 1);
        blob_append(pOut, zLine, len+width+17);
      }
      a += m;
      b += m;
      ma -= m;
      mb -= m;
      for(j=0; j<ma; j++){
        memset(zLine, ' ', width+7);
        sbsWriteLineno(zLine, a+j);
        sbsWriteText(&zLine[7], &A[a+j], width, 0);
        zLine[width+8] = '<';
        zLine[width+9] = '\n';
        zLine[width+10] = 0;
        blob_append(pOut, zLine, width+10);
      }
      a += ma;
      for(j=0; j<mb; j++){
        memset(zLine, ' ', mxLine);
        zLine[width+8] = '>';
        sbsWriteLineno(&zLine[width+10], b+j);
        len = sbsWriteText(&zLine[width+17], &B[b+j], width, 1);
        blob_append(pOut, zLine, len+width+17);
      }
      b += mb;
      if( i<nr-1 ){
        m = R[r+i*3+3];
        for(j=0; j<m; j++){
          memset(zLine, ' ', mxLine);
          sbsWriteLineno(zLine, a+j);
          sbsWriteText(&zLine[7], &A[a+j], width, 0);
          sbsWriteLineno(&zLine[width+10], b+j);
          len = sbsWriteText(&zLine[width+17], &B[b+j], width, 1);
          blob_append(pOut, zLine, len+width+17);












        }
        b += m;
        a += m;
      }
    }

    /* Show the final common area */
    assert( nr==i );
    m = R[r+nr*3];
    if( m>nContext ) m = nContext;
    for(j=0; j<m; j++){
      memset(zLine, ' ', mxLine);
      sbsWriteLineno(zLine, a+j);
      sbsWriteText(&zLine[7], &A[a+j], width, 0);


      sbsWriteLineno(&zLine[width+10], b+j);
      len = sbsWriteText(&zLine[width+17], &B[b+j], width, 1);

      blob_append(pOut, zLine, len+width+17);
    }
  }
  free(zLine);
}

/*
** Compute the optimal longest common subsequence (LCS) using an
** exhaustive search.  This version of the LCS is only used for
** shorter input strings since runtime is O(N*N) where N is the
** input string length.
................................................................................
  DContext *p,               /* Two files being compared */
  int iS1, int iE1,          /* Range of lines in p->aFrom[] */
  int iS2, int iE2,          /* Range of lines in p->aTo[] */
  int *piSX, int *piEX,      /* Write p->aFrom[] common segment here */
  int *piSY, int *piEY       /* Write p->aTo[] common segment here */
){
  double bestScore = -1e30;  /* Best score seen so far */

  int i, j;                  /* Loop counters */

  int iSX, iSY, iEX, iEY;    /* Current match */
  double score;              /* Current score */
  int skew;                  /* How lopsided is the match */
  int dist;                  /* Distance of match from center */
  int mid;                   /* Center of the span */
  int iSXb, iSYb, iEXb, iEYb;   /* Best match so far */
  int iSXp, iSYp, iEXp, iEYp;   /* Previous match */
................................................................................
    }
    if( j==0 ) continue;
    assert( i>=iSXb && i>=iSXp );
    if( i<iEXb && j>=iSYb && j<iEYb ) continue;
    if( i<iEXp && j>=iSYp && j<iEYp ) continue;
    iSX = i;
    iSY = j-1;
    while( iSX>iS1 && iSY>iS2 && same_dline(&p->aFrom[iSX-1],&p->aTo[iSY-1]) ){



      iSX--;
      iSY--;
    }
    iEX = i+1;
    iEY = j;
    while( iEX<iE1 && iEY<iE2 && same_dline(&p->aFrom[iEX],&p->aTo[iEY]) ){




      iEX++;
      iEY++;
    }
    skew = (iSX-iS1) - (iSY-iS2);
    if( skew<0 ) skew = -skew;
    dist = (iSX+iEX)/2 - mid;
    if( dist<0 ) dist = -dist;
    score = (iEX - iSX) - 0.05*skew - 0.05*dist;
    if( score>bestScore ){
      bestScore = score;
................................................................................
    *piSY = iSYb;
    *piEX = iEXb;
    *piEY = iEYb;
  }
  /* printf("LCS(%d..%d/%d..%d) = %d..%d/%d..%d\n", 
     iS1, iE1, iS2, iE2, *piSX, *piEX, *piSY, *piEY);  */
}










































/*
** Do a single step in the difference.  Compute a sequence of
** copy/delete/insert steps that will convert lines iS1 through iE1-1 of
** the input into lines iS2 through iE2-1 of the output and write
** that sequence into the difference context.
**
................................................................................
    return;
  }

  /* Find the longest matching segment between the two sequences */
  longestCommonSequence(p, iS1, iE1, iS2, iE2, &iSX, &iEX, &iSY, &iEY);

  if( iEX>iSX ){
    /* A common segement has been found.
    ** Recursively diff either side of the matching segment */
    diff_step(p, iS1, iSX, iS2, iSY);
    if( iEX>iSX ){
      appendTriple(p, iEX - iSX, 0, 0);
    }
    diff_step(p, iEX, iE1, iEY, iE2);
  }else{
................................................................................
  expandEdit(p, p->nEdit+3);
  if( p->aEdit ){
    p->aEdit[p->nEdit++] = 0;
    p->aEdit[p->nEdit++] = 0;
    p->aEdit[p->nEdit++] = 0;
  }
}







































































































/*
** Extract the number of lines of context from diffFlags.  Supply an
** appropriate default if no context width is specified.
*/
int diff_context_lines(int diffFlags){
  int n = diffFlags & DIFF_CONTEXT_MASK;
................................................................................
  Blob *pOut,      /* Write diff here if not NULL */
  int diffFlags    /* DIFF_* flags defined above */
){
  int ignoreEolWs; /* Ignore whitespace at the end of lines */
  int nContext;    /* Amount of context to display */	
  DContext c;






  nContext = diff_context_lines(diffFlags);
  ignoreEolWs = (diffFlags & DIFF_IGNORE_EOLWS)!=0;

  /* Prepare the input files */
  memset(&c, 0, sizeof(c));
  c.aFrom = break_into_lines(blob_str(pA_Blob), blob_size(pA_Blob),
                             &c.nFrom, ignoreEolWs);
................................................................................
      blob_appendf(pOut, "cannot compute difference between binary files\n");
    }
    return 0;
  }

  /* Compute the difference */
  diff_all(&c);


  if( pOut ){
    /* Compute a context or side-by-side diff into pOut */

    if( diffFlags & DIFF_SIDEBYSIDE ){
      int width = diff_width(diffFlags);
      sbsDiff(&c, pOut, nContext, width);
    }else{

      contextDiff(&c, pOut, nContext);
    }
    free(c.aFrom);
    free(c.aTo);
    free(c.aEdit);
    return 0;
  }else{
    /* If a context diff is not requested, then return the
................................................................................
    */
    free(c.aFrom);
    free(c.aTo);
    return c.aEdit;
  }
}

/*
** Copy a line with a limit. Used for side-by-side diffs to enforce a maximum
** line length limit.
*/
static char *copylimline(char *out, DLine *dl, int lim){
  int len;
  len = dl->h & LENGTH_MASK;
  if( lim && len > lim ){
    memcpy(out, dl->z, lim-3);
    memcpy(&out[lim-3], "...", 4);
  }else{
    memcpy(out, dl->z, len);
    out[len] = '\0';
  }
  return out;
}

/*
** Output table body of a side-by-side diff. Prior to the call, the caller
** should have output:
**   <table class="sbsdiff">
**   <tr><th colspan="2" class="diffhdr">Old title</th><th/>
**   <th colspan="2" class="diffhdr">New title</th></tr>
**
** And after the call, it should output:
**   </table>
**
** Some good reference diffs in the fossil repository for testing:
** /vdiff?from=080d27a&to=4b0f813&detail=1
** /vdiff?from=636804745b&to=c1d78e0556&detail=1
** /vdiff?from=c0b6c28d29&to=25169506b7&detail=1
** /vdiff?from=e3d022dffa&to=48bcfbd47b&detail=1
*/
int html_sbsdiff(
  Blob *pA_Blob,   /* FROM file */
  Blob *pB_Blob,   /* TO file */
  int nContext,    /* Amount of context to unified diff */
  int ignoreEolWs  /* Ignore whitespace at the end of lines */
){
  DContext c;
  int i;
  int iFrom, iTo;
  char *linebuf;
  int collim=0; /* Currently not settable; allows a column limit for diffs */
  int allowExp=0; /* Currently not settable; (dis)allow expansion of rows */

  /* Prepare the input files */
  memset(&c, 0, sizeof(c));
  c.aFrom = break_into_lines(blob_str(pA_Blob), blob_size(pA_Blob),
                             &c.nFrom, ignoreEolWs);
  c.aTo = break_into_lines(blob_str(pB_Blob), blob_size(pB_Blob),
                           &c.nTo, ignoreEolWs);
  if( c.aFrom==0 || c.aTo==0 ){
    free(c.aFrom);
    free(c.aTo);
    /* Note: This would be generated within a table. */
    @ <p class="generalError" style="white-space: nowrap">cannot compute
    @ difference between binary files</p>
    return 0;
  }

  collim = collim < 4 ? 0 : collim;

  /* Compute the difference */
  diff_all(&c);

  linebuf = fossil_malloc(LENGTH_MASK+1);
  if( !linebuf ){
    free(c.aFrom);
    free(c.aTo);
    free(c.aEdit);
    return 0;
  }

  iFrom=iTo=0;
  i=0;
  while( i<c.nEdit ){
    int j;
    /* Copied lines */
    for( j=0; j<c.aEdit[i]; j++){
      /* Hide lines which are copied and are further away from block boundaries
      ** than nContext lines. For each block with hidden lines, show a row
      ** notifying the user about the hidden rows.
      */
      if( j<nContext || j>c.aEdit[i]-nContext-1 ){
        @ <tr>
      }else if( j==nContext && j<c.aEdit[i]-nContext-1 ){
        @ <tr>
        @ <td class="meta" colspan="5" style="white-space: nowrap;">
        @ %d(c.aEdit[i]-2*nContext) hidden lines</td>
        @ </tr>
        if( !allowExp )
           continue;
        @ <tr style="display:none;">
      }else{
        if( !allowExp )
           continue;
        @ <tr style="display:none;">
      }

      copylimline(linebuf, &c.aFrom[iFrom+j], collim);
      @ <td class="lineno">%d(iFrom+j+1)</td>
      @ <td class="srcline">%h(linebuf)</td>

      @ <td> </td>

      copylimline(linebuf, &c.aTo[iTo+j], collim);
      @ <td class="lineno">%d(iTo+j+1)</td>
      @ <td class="srcline">%h(linebuf)</td>

      @ </tr>
    }
    iFrom+=c.aEdit[i];
    iTo+=c.aEdit[i];

    if( c.aEdit[i+1]!=0 && c.aEdit[i+2]!=0 ){
      int lim;
      lim = c.aEdit[i+1] > c.aEdit[i+2] ? c.aEdit[i+1] : c.aEdit[i+2];

      /* Assume changed lines */
      for( j=0; j<lim; j++ ){
        @ <tr>

        if( j<c.aEdit[i+1] ){
          copylimline(linebuf, &c.aFrom[iFrom+j], collim);
          @ <td class="changed lineno">%d(iFrom+j+1)</td>
          @ <td class="changed srcline">%h(linebuf)</td>
        }else{
          @ <td colspan="2" class="changedvoid"/>
        }

        @ <td class="changed">|</td>

        if( j<c.aEdit[i+2] ){
          copylimline(linebuf, &c.aTo[iTo+j], collim);
          @ <td class="changed lineno">%d(iTo+j+1)</td>
          @ <td class="changed srcline">%h(linebuf)</td>
        }else{
          @ <td colspan="2" class="changedvoid"/>
        }

        @ </tr>
      }
      iFrom+=c.aEdit[i+1];
      iTo+=c.aEdit[i+2];
    }else{

      /* Process deleted lines */
      for( j=0; j<c.aEdit[i+1]; j++ ){
        @ <tr>

        copylimline(linebuf, &c.aFrom[iFrom+j], collim);
        @ <td class="removed lineno">%d(iFrom+j+1)</td>
        @ <td class="removed srcline">%h(linebuf)</td>
        @ <td>&lt;</td>
        @ <td colspan="2" class="removedvoid"/>
        @ </tr>
      }
      iFrom+=c.aEdit[i+1];

      /* Process inserted lines */
      for( j=0; j<c.aEdit[i+2]; j++ ){
        @ <tr>
        @ <td colspan="2" class="addedvoid"/>
        @ <td>&gt;</td>
        copylimline(linebuf, &c.aTo[iTo+j], collim);
        @ <td class="added lineno">%d(iTo+j+1)</td>
        @ <td class="added srcline">%h(linebuf)</td>
        @ </tr>
      }
      iTo+=c.aEdit[i+2];
    }

    i+=3;
  }

  free(linebuf);
  free(c.aFrom);
  free(c.aTo);
  free(c.aEdit);
  return 1;
}


/*
** COMMAND: test-rawdiff
*/
void test_rawdiff_cmd(void){
  Blob a, b;
  int r;
  int i;
  int *R;
  if( g.argc<4 ) usage("FILE1 FILE2 ...");
  blob_read_from_file(&a, g.argv[2]);
  for(i=3; i<g.argc; i++){
    if( i>3 ) fossil_print("-------------------------------\n");
    blob_read_from_file(&b, g.argv[i]);
    R = text_diff(&a, &b, 0, 0);
    for(r=0; R[r] || R[r+1] || R[r+2]; r += 3){
      fossil_print(" copy %4d  delete %4d  insert %4d\n", R[r], R[r+1], R[r+2]);
    }
    /* free(R); */
    blob_reset(&b);
  }
}

/*
** Process diff-related command-line options and return an appropriate
** "diffFlags" integer.  
**
**   --side-by-side|-y      Side-by-side diff.     DIFF_SIDEBYSIDE

**   --context|-c N         N lines of context.    DIFF_CONTEXT_MASK





**   --width|-W N           N character lines.     DIFF_WIDTH_MASK
*/
int diff_options(void){
  int diffFlags = 0;
  const char *z;
  int f;
  if( find_option("side-by-side","y",0)!=0 ) diffFlags |= DIFF_SIDEBYSIDE;
................................................................................
    diffFlags |= f;
  }
  if( (z = find_option("width","W",1))!=0 && (f = atoi(z))>0 ){
    f *= DIFF_CONTEXT_MASK+1;
    if( f > DIFF_WIDTH_MASK ) f = DIFF_CONTEXT_MASK;
    diffFlags |= f;
  }





  return diffFlags;
}
























/*
** COMMAND: test-udiff
**
** Print the difference between two files.  The usual diff options apply.
*/
void test_udiff_cmd(void){
................................................................................
  while( db_step(&q)==SQLITE_ROW ){
    int pid = db_column_int(&q, 0);
    const char *zUuid = db_column_text(&q, 1);
    const char *zDate = db_column_text(&q, 2);
    const char *zUser = db_column_text(&q, 3);
    if( webLabel ){
      zLabel = mprintf(
          "<a href='%s/info/%s' target='infowindow'>%.10s</a> %s %9.9s", 
          g.zTop, zUuid, zUuid, zDate, zUser
      );
    }else{
      zLabel = mprintf("%.10s %s %9.9s", zUuid, zDate, zUser);
    }
    p->nVers++;
    p->azVers = fossil_realloc(p->azVers, p->nVers*sizeof(p->azVers[0]) );
    p->azVers[p->nVers-1] = zLabel;
    content_get(pid, &step);
    annotation_step(p, &step, zLabel);
    blob_reset(&step);
................................................................................
** Output the text of a file with markings to show when each line of
** the file was last modified.
**
** Options:
**   --limit N       Only look backwards in time by N versions
**   --log           List all versions analyzed
**   --filevers      Show file version numbers rather than check-in versions


*/
void annotate_cmd(void){
  int fnid;         /* Filename ID */
  int fid;          /* File instance ID */
  int mid;          /* Manifest where file was checked in */
  int cid;          /* Checkout ID */
  Blob treename;    /* FILENAME translated to canonical form */







|
|
|
|
|
>
>
>
>
>
>







 







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







 







|

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



<
>
>
>
>

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

<
<
|







|
>
>
>
>
>
>












>







 







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






>
|








>
|




>
|





>
|











>
|





|
<

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


>
>
>
>
>
>

<
<
>
>

<
>

<
>
>
>
>

<
>
>
>

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


<
>


>
>
>
>
>
>
>
>
>




|
>
>
>
>
>
>
>

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

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


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

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

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



|
>
>
>
>
>
>












|
|
<

<
|
|
>
>
|
>







 







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






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











|
|
|
>
>
|
<
>
|


|







 







>
|
>







 







|
>
>
>
|
|
<


<
>
>
>
>
|
|
<







 







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







 







|







 







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







 







>
>
>
>
>







 







>



>


|

>
|







 








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



<
>

>
>
>
>
>







 







>
>
>
>
>


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







 







|



|







 







>
>







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
..
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
...
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
...
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
...
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
....
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
....
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
....
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
....
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
....
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
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
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
....
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
....
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
....
1510
1511
1512
1513
1514
1515
1516
1517














































































































































































































1518
1519
1520

1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
....
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
....
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
....
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
#include <assert.h>


#if INTERFACE
/*
** Allowed flag parameters to the text_diff() and html_sbsdiff() funtions:
*/
#define DIFF_CONTEXT_MASK  0x0000ffff  /* Lines of context.  Default if 0 */
#define DIFF_WIDTH_MASK    0x00ff0000  /* side-by-side column width */
#define DIFF_IGNORE_EOLWS  0x01000000  /* Ignore end-of-line whitespace */
#define DIFF_SIDEBYSIDE    0x02000000  /* Generate a side-by-side diff */
#define DIFF_NEWFILE       0x04000000  /* Missing files are as empty files */
#define DIFF_BRIEF         0x08000000  /* Show filenames only */
#define DIFF_INLINE        0x00000000  /* Inline (not side-by-side) diff */
#define DIFF_HTML          0x10000000  /* Render for HTML */
#define DIFF_LINENO        0x20000000  /* Show line numbers in context diff */
#define DIFF_NOOPT         0x40000000  /* Suppress optimizations for debug */
#define DIFF_INVERT        0x80000000  /* Invert the diff for debug */

#endif /* INTERFACE */

/*
** Maximum length of a line in a text file.  (8192)
*/
#define LENGTH_MASK_SZ  13
................................................................................
  /* an array of DLine elements services two purposes.  The fields
  ** above are one per line of input text.  But each entry is also
  ** a bucket in a hash table, as follows: */
  unsigned int iHash;   /* 1+(first entry in the hash chain) */
};

/*
** Length of a dline
*/
#define LENGTH(X)   ((X)->h & LENGTH_MASK)

/*
** A context for running a raw diff.
**
** The aEdit[] array describes the raw diff.  Each triple of integers in
** aEdit[] means:
**
**   (1) COPY:   Number of lines aFrom and aTo have in common
**   (2) DELETE: Number of lines found only in aFrom
**   (3) INSERT: Number of lines found only in aTo
**
** The triples repeat until all lines of both aFrom and aTo are accounted
** for.
*/
typedef struct DContext DContext;
struct DContext {
  int *aEdit;        /* Array of copy/delete/insert triples */
  int nEdit;         /* Number of integers (3x num of triples) in aEdit[] */
  int nEditAlloc;    /* Space allocated for aEdit[] */
  DLine *aFrom;      /* File on left side of the diff */
................................................................................
** Return true if two DLine elements are identical.
*/
static int same_dline(DLine *pA, DLine *pB){
  return pA->h==pB->h && memcmp(pA->z,pB->z,pA->h & LENGTH_MASK)==0;
}

/*
** Append a single line of context-diff output to pOut.
*/
static void appendDiffLine(
  Blob *pOut,         /* Where to write the line of output */
  char cPrefix,       /* One of " ", "+",  or "-" */
  DLine *pLine,       /* The line to be output */
  int html            /* True if generating HTML.  False for plain text */
){
  blob_append(pOut, &cPrefix, 1);
  if( html ){
    char *zHtml;
    if( cPrefix=='+' ){
      blob_append(pOut, "<span class=\"diffadd\">", -1);
    }else if( cPrefix=='-' ){
      blob_append(pOut, "<span class=\"diffrm\">", -1);
    }
    zHtml = htmlize(pLine->z, (pLine->h & LENGTH_MASK));
    blob_append(pOut, zHtml, -1);
    fossil_free(zHtml);
    if( cPrefix!=' ' ){
      blob_append(pOut, "</span>", -1);
    }
  }else{
    blob_append(pOut, pLine->z, pLine->h & LENGTH_MASK);
  }






  blob_append(pOut, "\n", 1);
}

/*

** Add two line numbers to the beginning of an output line for a context
** diff.  One or of the other of the two numbers might be zero, which means
** to leave that number field blank.  The "html" parameter means to format
** the output for HTML.  
*/
















static void appendDiffLineno(Blob *pOut, int lnA, int lnB, int html){
  if( html ) blob_append(pOut, "<span class=\"diffln\">", -1);
  if( lnA>0 ){
    blob_appendf(pOut, "%6d ", lnA);
  }else{
    blob_append(pOut, "       ", 7);
  }

  if( lnB>0 ){
    blob_appendf(pOut, "%6d  ", lnB);
  }else{
    blob_append(pOut, "        ", 8);
  }


  if( html ) blob_append(pOut, "</span>", -1);
}


/*
** Given a diff context in which the aEdit[] array has been filled
** in, compute a context diff into pOut.
*/
static void contextDiff(
  DContext *p,      /* The difference */
  Blob *pOut,       /* Output a context diff to here */
  int nContext,     /* Number of lines of context */
  int showLn,       /* Show line numbers */
  int html          /* Render as HTML */
){
  DLine *A;     /* Left side of the diff */
  DLine *B;     /* Right side of the diff */  
  int a = 0;    /* Index of next line in A[] */
  int b = 0;    /* Index of next line in B[] */
  int *R;       /* Array of COPY/DELETE/INSERT triples */
  int r;        /* Index into R[] */
  int nr;       /* Number of COPY/DELETE/INSERT triples to process */
  int mxr;      /* Maximum value for r */
  int na, nb;   /* Number of lines shown from A and B */
  int i, j;     /* Loop counters */
  int m;        /* Number of lines to output */
  int skip;     /* Number of lines to skip */
  int nChunk = 0;  /* Number of diff chunks seen so far */

  A = p->aFrom;
  B = p->aTo;
  R = p->aEdit;
  mxr = p->nEdit;
  while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; }
  for(r=0; r<mxr; r += 3*nr){
................................................................................
      na += R[r+nr*3];
      nb += R[r+nr*3];
    }
    for(i=1; i<nr; i++){
      na += R[r+i*3];
      nb += R[r+i*3];
    }

    /* Show the header for this block, or if we are doing a modified
    ** context diff that contains line numbers, show the separate from
    ** the previous block.
    */
    nChunk++;
    if( showLn ){
      if( r==0 ){
        /* Do not show a top divider */
      }else if( html ){
        blob_appendf(pOut, "<span class=\"diffhr\">%.80c</span>\n", '.');
        blob_appendf(pOut, "<a name=\"chunk%d\"></a>\n", nChunk);
      }else{
        blob_appendf(pOut, "%.80c\n", '.');
      }
    }else{
      if( html ) blob_appendf(pOut, "<span class=\"diffln\">");
      /*
       * If the patch changes an empty file or results in an empty file,
       * the block header must use 0,0 as position indicator and not 1,0.
       * Otherwise, patch would be confused and may reject the diff.
       */
      blob_appendf(pOut,"@@ -%d,%d +%d,%d @@",
        na ? a+skip+1 : 0, na,
        nb ? b+skip+1 : 0, nb);
      if( html ) blob_appendf(pOut, "</span>");
      blob_append(pOut, "\n", 1);
    }

    /* Show the initial common area */
    a += skip;
    b += skip;
    m = R[r] - skip;
    for(j=0; j<m; j++){
      if( showLn ) appendDiffLineno(pOut, a+j+1, b+j+1, html);
      appendDiffLine(pOut, ' ', &A[a+j], html);
    }
    a += m;
    b += m;

    /* Show the differences */
    for(i=0; i<nr; i++){
      m = R[r+i*3+1];
      for(j=0; j<m; j++){
        if( showLn ) appendDiffLineno(pOut, a+j+1, 0, html);
        appendDiffLine(pOut, '-', &A[a+j], html);
      }
      a += m;
      m = R[r+i*3+2];
      for(j=0; j<m; j++){
        if( showLn ) appendDiffLineno(pOut, 0, b+j+1, html);
        appendDiffLine(pOut, '+', &B[b+j], html);
      }
      b += m;
      if( i<nr-1 ){
        m = R[r+i*3+3];
        for(j=0; j<m; j++){
          if( showLn ) appendDiffLineno(pOut, a+j+1, b+j+1, html);
          appendDiffLine(pOut, ' ', &B[b+j], html);
        }
        b += m;
        a += m;
      }
    }

    /* Show the final common area */
    assert( nr==i );
    m = R[r+nr*3];
    if( m>nContext ) m = nContext;
    for(j=0; j<m; j++){
      if( showLn ) appendDiffLineno(pOut, a+j+1, b+j+1, html);
      appendDiffLine(pOut, ' ', &B[b+j], html);
    }
  }
}

/*
** Status of a single output line

*/
typedef struct SbsLine SbsLine;
struct SbsLine {
  char *zLine;             /* The output line under construction */
  int n;                   /* Index of next unused slot in the zLine[] */
  int width;               /* Maximum width of a column in the output */
  unsigned char escHtml;   /* True to escape html characters */
  int iStart;              /* Write zStart prior to character iStart */
  const char *zStart;      /* A <span> tag */
  int iEnd;                /* Write </span> prior to character iEnd */
  int iStart2;             /* Write zStart2 prior to character iStart2 */
  const char *zStart2;     /* A <span> tag */
  int iEnd2;               /* Write </span> prior to character iEnd2 */
};

/*
** Flags for sbsWriteText()
*/
#define SBS_NEWLINE      0x0001   /* End with \n\000 */
#define SBS_PAD          0x0002   /* Pad output to width spaces */

/*
** Write up to width characters of pLine into z[].  Translate tabs into


** spaces.  Add a newline if SBS_NEWLINE is set.  Translate HTML characters
** if SBS_HTML is set.  Pad the rendering out width bytes if SBS_PAD is set.
*/

static void sbsWriteText(SbsLine *p, DLine *pLine, unsigned flags){
  int n = pLine->h & LENGTH_MASK;

  int i;   /* Number of input characters consumed */
  int j;   /* Number of output characters generated */
  int k;   /* Cursor position */
  int needEndSpan = 0;
  const char *zIn = pLine->z;

  char *z = &p->zLine[p->n];
  int w = p->width;
  for(i=j=k=0; k<w && i<n; i++, k++){
    char c = zIn[i];
    if( p->escHtml ){
      if( i==p->iStart ){
        int x = strlen(p->zStart);
        memcpy(z+j, p->zStart, x);
        j += x;
        needEndSpan = 1;
        if( p->iStart2 ){
          p->iStart = p->iStart2;
          p->zStart = p->zStart2;
          p->iStart2 = 0;
        }
      }else if( i==p->iEnd ){
        memcpy(z+j, "</span>", 7);
        j += 7;
        needEndSpan = 0;
        if( p->iEnd2 ){
          p->iEnd = p->iEnd2;
          p->iEnd2 = 0;
        }
      }
    }
    if( c=='\t' ){
      z[j++] = ' ';

      while( (k&7)!=7 && k<w ){ z[j++] = ' '; k++; }
    }else if( c=='\r' || c=='\f' ){
      z[j++] = ' ';
    }else if( c=='<' && p->escHtml ){
      memcpy(&z[j], "&lt;", 4);
      j += 4;
    }else if( c=='&' && p->escHtml ){
      memcpy(&z[j], "&amp;", 5);
      j += 5;
    }else if( c=='>' && p->escHtml ){
      memcpy(&z[j], "&gt;", 4);
      j += 4;
    }else{
      z[j++] = c;
    }
  }
  if( needEndSpan ){
    memcpy(&z[j], "</span>", 7);
    j += 7;
  }
  if( (flags & SBS_PAD)!=0 ){
    while( k<w ){ k++;  z[j++] = ' '; }
  }
  if( flags & SBS_NEWLINE ){
    z[j++] = '\n';
  }
  p->n += j;
}

/*
** Append a string to an SbSLine with coding, interpretation, or padding.
*/
static void sbsWrite(SbsLine *p, const char *zIn, int nIn){
  memcpy(p->zLine+p->n, zIn, nIn);
  p->n += nIn;
}

/*
** Append n spaces to the string.
*/
static void sbsWriteSpace(SbsLine *p, int n){
  while( n-- ) p->zLine[p->n++] = ' ';
}

/*
** Append a string to the output only if we are rendering HTML.
*/
static void sbsWriteHtml(SbsLine *p, const char *zIn){
  if( p->escHtml ) sbsWrite(p, zIn, strlen(zIn));
}

/*
** Write a 6-digit line number followed by a single space onto the line.
*/
static void sbsWriteLineno(SbsLine *p, int ln){
  sbsWriteHtml(p, "<span class=\"diffln\">");
  sqlite3_snprintf(7, &p->zLine[p->n], "%5d ", ln+1);
  p->n += 6;
  sbsWriteHtml(p, "</span>");
  p->zLine[p->n++] = ' ';
}

/*
** The two text segments zLeft and zRight are known to be different on 
** both ends, but they might have  a common segment in the middle.  If
** they do not have a common segment, return 0.  If they do have a large
** common segment, return 1 and before doing so set:
**
**   aLCS[0] = start of the common segment in zLeft
**   aLCS[1] = end of the common segment in zLeft
**   aLCS[2] = start of the common segment in zLeft
**   aLCS[3] = end of the common segment in zLeft
**
** This computation is for display purposes only and does not have to be
** optimal or exact.
*/
static int textLCS(
  const char *zLeft,  int nA,       /* String on the left */
  const char *zRight,  int nB,      /* String on the right */
  int *aLCS                         /* Identify bounds of LCS here */
){
  const unsigned char *zA = (const unsigned char*)zLeft;    /* left string */
  const unsigned char *zB = (const unsigned char*)zRight;   /* right string */
  int nt;                    /* Number of target points */
  int ti[3];                 /* Index for start of each 4-byte target */
  unsigned int target[3];    /* 4-byte alignment targets */
  unsigned int probe;        /* probe to compare against target */
  int iAS, iAE, iBS, iBE;    /* Range of common segment */
  int i, j;                  /* Loop counters */
  int rc = 0;                /* Result code.  1 for success */

  if( nA<6 || nB<6 ) return 0;
  memset(aLCS, 0, sizeof(int)*4);
  ti[0] = i = nB/2-2;
  target[0] = (zB[i]<<24) | (zB[i+1]<<16) | (zB[i+2]<<8) | zB[i+3];
  probe = 0;
  if( nB<16 ){
    nt = 1;
  }else{
    ti[1] = i = nB/4-2;
    target[1] = (zB[i]<<24) | (zB[i+1]<<16) | (zB[i+2]<<8) | zB[i+3];
    ti[2] = i = (nB*3)/4-2;
    target[2] = (zB[i]<<24) | (zB[i+1]<<16) | (zB[i+2]<<8) | zB[i+3];
    nt = 3;
  }
  probe = (zA[0]<<16) | (zA[1]<<8) | zA[2];
  for(i=3; i<nA; i++){
    probe = (probe<<8) | zA[i];
    for(j=0; j<nt; j++){
      if( probe==target[j] ){
        iAS = i-3;
        iAE = i+1;
        iBS = ti[j];
        iBE = ti[j]+4;
        while( iAE<nA && iBE<nB && zA[iAE]==zB[iBE] ){ iAE++; iBE++; }
        while( iAS>0 && iBS>0 && zA[iAS-1]==zB[iBS-1] ){ iAS--; iBS--; }
        if( iAE-iAS > aLCS[1] - aLCS[0] ){
          aLCS[0] = iAS;
          aLCS[1] = iAE;
          aLCS[2] = iBS;
          aLCS[3] = iBE;
          rc = 1;
        }
      }
    }
  }
  return rc;
}

/*
** Write out lines that have been edited.  Adjust the highlight to cover
** only those parts of the line that actually changed.
*/
static void sbsWriteLineChange(
  SbsLine *p,          /* The SBS output line */
  DLine *pLeft,        /* Left line of the change */
  int lnLeft,          /* Line number for the left line */
  DLine *pRight,       /* Right line of the change */
  int lnRight          /* Line number of the right line */
){
  int nLeft;           /* Length of left line in bytes */
  int nRight;          /* Length of right line in bytes */
  int nPrefix;         /* Length of common prefix */
  int nSuffix;         /* Length of common suffix */
  const char *zLeft;   /* Text of the left line */
  const char *zRight;  /* Text of the right line */
  int nLeftDiff;       /* nLeft - nPrefix - nSuffix */
  int nRightDiff;      /* nRight - nPrefix - nSuffix */
  int aLCS[4];         /* Bounds of common middle segment */
  static const char zClassRm[]   = "<span class=\"diffrm\">";
  static const char zClassAdd[]  = "<span class=\"diffadd\">";
  static const char zClassChng[] = "<span class=\"diffchng\">";

  nLeft = pLeft->h & LENGTH_MASK;
  zLeft = pLeft->z;
  nRight = pRight->h & LENGTH_MASK;
  zRight = pRight->z;

  nPrefix = 0;
  while( nPrefix<nLeft && nPrefix<nRight && zLeft[nPrefix]==zRight[nPrefix] ){
    nPrefix++;
  }
  nSuffix = 0;
  if( nPrefix<nLeft && nPrefix<nRight ){
    while( nSuffix<nLeft && nSuffix<nRight
           && zLeft[nLeft-nSuffix-1]==zRight[nRight-nSuffix-1] ){
      nSuffix++;
    }
    if( nSuffix==nLeft || nSuffix==nRight ) nPrefix = 0;
  }
  if( nPrefix+nSuffix > nLeft ) nSuffix = nLeft - nPrefix;
  if( nPrefix+nSuffix > nRight ) nSuffix = nRight - nPrefix;

  /* A single chunk of text inserted on the right */
  if( nPrefix+nSuffix==nLeft ){
    sbsWriteLineno(p, lnLeft);
    p->iStart2 = p->iEnd2 = 0;
    p->iStart = p->iEnd = -1;
    sbsWriteText(p, pLeft, SBS_PAD);
    sbsWrite(p, " | ", 3);
    sbsWriteLineno(p, lnRight);
    p->iStart = nPrefix;
    p->iEnd = nRight - nSuffix;
    p->zStart = zClassAdd;
    sbsWriteText(p, pRight, SBS_NEWLINE);
    return;
  }

  /* A single chunk of text deleted from the left */
  if( nPrefix+nSuffix==nRight ){
    /* Text deleted from the left */
    sbsWriteLineno(p, lnLeft);
    p->iStart2 = p->iEnd2 = 0;
    p->iStart = nPrefix;
    p->iEnd = nLeft - nSuffix;
    p->zStart = zClassRm;
    sbsWriteText(p, pLeft, SBS_PAD);
    sbsWrite(p, " | ", 3);
    sbsWriteLineno(p, lnRight);
    p->iStart = p->iEnd = -1;
    sbsWriteText(p, pRight, SBS_NEWLINE);
    return;
  }

  /* At this point we know that there is a chunk of text that has
  ** changed between the left and the right.  Check to see if there
  ** is a large unchanged section in the middle of that changed block.
  */
  nLeftDiff = nLeft - nSuffix - nPrefix;
  nRightDiff = nRight - nSuffix - nPrefix;
  if( p->escHtml
   && nLeftDiff >= 6
   && nRightDiff >= 6
   && textLCS(&zLeft[nPrefix], nLeftDiff, &zRight[nPrefix], nRightDiff, aLCS)
  ){
    sbsWriteLineno(p, lnLeft);
    p->iStart = nPrefix;
    p->iEnd = nPrefix + aLCS[0];
    p->zStart = aLCS[2]==0 ? zClassRm : zClassChng;
    p->iStart2 = nPrefix + aLCS[1];
    p->iEnd2 = nLeft - nSuffix;
    p->zStart2 = aLCS[3]==nRightDiff ? zClassRm : zClassChng;
    if( p->iStart2==p->iEnd2 ) p->iStart2 = p->iEnd2 = 0;
    if( p->iStart==p->iEnd ){
      p->iStart = p->iStart2;
      p->iEnd = p->iEnd2;
      p->zStart = p->zStart2;
      p->iStart2 = 0;
      p->iEnd2 = 0;
    }
    if( p->iStart==p->iEnd ) p->iStart = p->iEnd = -1;
    sbsWriteText(p, pLeft, SBS_PAD);
    sbsWrite(p, " | ", 3);
    sbsWriteLineno(p, lnRight);
    p->iStart = nPrefix;
    p->iEnd = nPrefix + aLCS[2];
    p->zStart = aLCS[0]==0 ? zClassAdd : zClassChng;
    p->iStart2 = nPrefix + aLCS[3];
    p->iEnd2 = nRight - nSuffix;
    p->zStart2 = aLCS[1]==nLeftDiff ? zClassAdd : zClassChng;
    if( p->iStart2==p->iEnd2 ) p->iStart2 = p->iEnd2 = 0;
    if( p->iStart==p->iEnd ){
      p->iStart = p->iStart2;
      p->iEnd = p->iEnd2;
      p->zStart = p->zStart2;
      p->iStart2 = 0;
      p->iEnd2 = 0;
    }
    if( p->iStart==p->iEnd ) p->iStart = p->iEnd = -1; 
    sbsWriteText(p, pRight, SBS_NEWLINE);
    return;
  }

  /* If all else fails, show a single big change between left and right */
  sbsWriteLineno(p, lnLeft);
  p->iStart2 = p->iEnd2 = 0;
  p->iStart = nPrefix;
  p->iEnd = nLeft - nSuffix;
  p->zStart = zClassChng;
  sbsWriteText(p, pLeft, SBS_PAD);
  sbsWrite(p, " | ", 3);
  sbsWriteLineno(p, lnRight);
  p->iEnd = nRight - nSuffix;
  sbsWriteText(p, pRight, SBS_NEWLINE);
}

/*
** Minimum of two values
*/
static int minInt(int a, int b){ return a<b ? a : b; }

/*
** Return the number between 0 and 100 that is smaller the closer pA and
** pB match.  Return 0 for a perfect match.  Return 100 if pA and pB are
** completely different.
**
** The current algorithm is as follows:
**
** (1) Remove leading and trailing whitespace.
** (2) Truncate both strings to at most 250 characters
** (3) Find the length of the longest common subsequence
** (4) Longer common subsequences yield lower scores.
*/
static int match_dline(DLine *pA, DLine *pB){
  const char *zA;            /* Left string */
  const char *zB;            /* right string */
  int nA;                    /* Bytes in zA[] */
  int nB;                    /* Bytes in zB[] */
  int avg;                   /* Average length of A and B */
  int i, j, k;               /* Loop counters */
  int best = 0;              /* Longest match found so far */
  int score;                 /* Final score.  0..100 */
  unsigned char c;           /* Character being examined */
  unsigned char aFirst[256]; /* aFirst[X] = index in zB[] of first char X */
  unsigned char aNext[252];  /* aNext[i] = index in zB[] of next zB[i] char */

  zA = pA->z;
  zB = pB->z;
  nA = pA->h & LENGTH_MASK;
  nB = pB->h & LENGTH_MASK;
  while( nA>0 && fossil_isspace(zA[0]) ){ nA--; zA++; }
  while( nA>0 && fossil_isspace(zA[nA-1]) ){ nA--; }
  while( nB>0 && fossil_isspace(zB[0]) ){ nB--; zB++; }
  while( nB>0 && fossil_isspace(zB[nB-1]) ){ nB--; }
  if( nA>250 ) nA = 250;
  if( nB>250 ) nB = 250;
  avg = (nA+nB)/2;
  if( avg==0 ) return 0;
  if( nA==nB && memcmp(zA, zB, nA)==0 ) return 0;
  memset(aFirst, 0, sizeof(aFirst));
  zA--; zB--;   /* Make both zA[] and zB[] 1-indexed */
  for(i=nB; i>0; i--){
    c = (unsigned char)zB[i];
    aNext[i] = aFirst[c];
    aFirst[c] = i;
  }
  best = 0;
  for(i=1; i<=nA-best; i++){
    c = (unsigned char)zA[i];
    for(j=aFirst[c]; j>0 && j<nB-best; j = aNext[j]){
      int limit = minInt(nA-i, nB-j);
      for(k=1; k<=limit && zA[k+i]==zB[k+j]; k++){}
      if( k>best ) best = k;
    }
  }
  score = (best>avg) ? 0 : (avg - best)*100/avg;

#if 0
  fprintf(stderr, "A: [%.*s]\nB: [%.*s]\nbest=%d avg=%d score=%d\n",
  nA, zA+1, nB, zB+1, best, avg, score);
#endif

  /* Return the result */
  return score;
}

/*
** There is a change block in which nLeft lines of text on the left are
** converted into nRight lines of text on the right.  This routine computes
** how the lines on the left line up with the lines on the right.
**
** The return value is a buffer of unsigned characters, obtained from
** fossil_malloc().  (The caller needs to free the return value using
** fossil_free().)  Entries in the returned array have values as follows:
**
**    1.   Delete the next line of pLeft.
**    2.   The next line of pLeft changes into the next line of pRight.
**    3.   Insert the next line of pRight.
**
** The length of the returned array will be just large enough to cause
** all elements of pLeft and pRight to be consumed.
**
** Algorithm:  Wagner's minimum edit-distance algorithm, modified by
** adding a cost to each match based on how well the two rows match
** each other.  Insertion and deletion costs are 50.  Match costs
** are between 0 and 100 where 0 is a perfect match 100 is a complete
** mismatch.
*/
static unsigned char *sbsAlignment(
   DLine *aLeft, int nLeft,       /* Text on the left */
   DLine *aRight, int nRight      /* Text on the right */
){
  int i, j, k;                 /* Loop counters */
  int *a;                      /* One row of the Wagner matrix */
  int *pToFree;                /* Space that needs to be freed */
  unsigned char *aM;           /* Wagner result matrix */
  int aBuf[100];               /* Stack space for a[] if nRight not to big */

  aM = fossil_malloc( (nLeft+1)*(nRight+1) );
  if( nLeft==0 ){
    memset(aM, 3, nRight);
    return aM;
  }
  if( nRight==0 ){
    memset(aM, 1, nLeft);
    return aM;
  }
  if( nRight < (sizeof(aBuf)/sizeof(aBuf[0]))-1 ){
    pToFree = 0;
    a = aBuf;
  }else{
    a = pToFree = fossil_malloc( sizeof(a[0])*(nRight+1) );
  }

  /* Compute the best alignment */
  for(i=0; i<=nRight; i++){
    aM[i] = 3;
    a[i] = i*50;
  }
  aM[0] = 0;
  for(j=1; j<=nLeft; j++){
    int p = a[0];
    a[0] = p+50;
    aM[j*(nRight+1)] = 1;
    for(i=1; i<=nRight; i++){
      int m = a[i-1]+50;
      int d = 3;
      if( m>a[i]+50 ){
        m = a[i]+50;
        d = 1;
      }
      if( m>p ){
        int score = match_dline(&aLeft[j-1], &aRight[i-1]);
        if( (score<66 || (i<j+1 && i>j-1)) && m>p+score ){
          m = p+score;
          d = 2;
        }
      }
      p = a[i];
      a[i] = m;
      aM[j*(nRight+1)+i] = d;
    }
  }

  /* Compute the lowest-cost path back through the matrix */
  i = nRight;
  j = nLeft;
  k = (nRight+1)*(nLeft+1)-1;
  while( i+j>0 ){
    unsigned char c = aM[k--];
    if( c==2 ){
      assert( i>0 && j>0 );
      i--;
      j--;
    }else if( c==3 ){
      assert( i>0 );
      i--;
    }else{
      assert( j>0 );
      j--;
    }
    aM[k] = aM[j*(nRight+1)+i];
  }
  k++;
  i = (nRight+1)*(nLeft+1) - k;
  memmove(aM, &aM[k], i);

  /* Return the result */
  fossil_free(pToFree);
  return aM;
}

/*
** Given a diff context in which the aEdit[] array has been filled
** in, compute a side-by-side diff into pOut.
*/
static void sbsDiff(
  DContext *p,       /* The computed diff */
  Blob *pOut,        /* Write the results here */
  int nContext,      /* Number of lines of context around each change */
  int width,         /* Width of each column of output */
  int escHtml        /* True to generate HTML output */
){
  DLine *A;     /* Left side of the diff */
  DLine *B;     /* Right side of the diff */  
  int a = 0;    /* Index of next line in A[] */
  int b = 0;    /* Index of next line in B[] */
  int *R;       /* Array of COPY/DELETE/INSERT triples */
  int r;        /* Index into R[] */
  int nr;       /* Number of COPY/DELETE/INSERT triples to process */
  int mxr;      /* Maximum value for r */
  int na, nb;   /* Number of lines shown from A and B */
  int i, j;     /* Loop counters */
  int m, ma, mb;/* Number of lines to output */
  int skip;     /* Number of lines to skip */
  int nChunk = 0; /* Number of chunks of diff output seen so far */
  SbsLine s;    /* Output line buffer */



  s.zLine = fossil_malloc( 10*width + 200 );
  if( s.zLine==0 ) return;
  s.width = width;
  s.escHtml = escHtml;
  s.iStart = -1;
  s.iEnd = -1;
  A = p->aFrom;
  B = p->aTo;
  R = p->aEdit;
  mxr = p->nEdit;
  while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; }
  for(r=0; r<mxr; r += 3*nr){
    /* Figure out how many triples to show in a single block */
................................................................................
      na += R[r+nr*3];
      nb += R[r+nr*3];
    }
    for(i=1; i<nr; i++){
      na += R[r+i*3];
      nb += R[r+i*3];
    }


    /* Draw the separator between blocks */
    if( r>0 ){
      if( escHtml ){
        blob_appendf(pOut, "<span class=\"diffhr\">%.*c</span>\n",
                           width*2+16, '.');
      }else{
        blob_appendf(pOut, "%.*c\n", width*2+16, '.');
      }
    }
    nChunk++;
    if( escHtml ){
      blob_appendf(pOut, "<a name=\"chunk%d\"></a>\n", nChunk);
    }

    /* Show the initial common area */
    a += skip;
    b += skip;
    m = R[r] - skip;
    for(j=0; j<m; j++){
      s.n = 0;
      sbsWriteLineno(&s, a+j);
      s.iStart = s.iEnd = -1;
      sbsWriteText(&s, &A[a+j], SBS_PAD);
      sbsWrite(&s, "   ", 3);
      sbsWriteLineno(&s, b+j);
      sbsWriteText(&s, &B[b+j], SBS_NEWLINE);
      blob_append(pOut, s.zLine, s.n);
    }
    a += m;
    b += m;

    /* Show the differences */
    for(i=0; i<nr; i++){
      unsigned char *alignment;
      ma = R[r+i*3+1];   /* Lines on left but not on right */
      mb = R[r+i*3+2];   /* Lines on right but not on left */
      alignment = sbsAlignment(&A[a], ma, &B[b], mb);
      for(j=0; ma+mb>0; j++){
        if( alignment[j]==1 ){
          s.n = 0;
          sbsWriteLineno(&s, a);
          s.iStart = 0;
          s.zStart = "<span class=\"diffrm\">";
          s.iEnd = s.width;
          sbsWriteText(&s, &A[a], SBS_PAD);
          sbsWrite(&s, " <\n", 3);
          blob_append(pOut, s.zLine, s.n);
          assert( ma>0 );
          ma--;
          a++;
        }else if( alignment[j]==2 ){
          s.n = 0;
          sbsWriteLineChange(&s, &A[a], a, &B[b], b);
          blob_append(pOut, s.zLine, s.n);
          assert( ma>0 && mb>0 );
          ma--;
          mb--;
          a++;
          b++;
        }else{
          s.n = 0;
          sbsWriteSpace(&s, width + 7);
          sbsWrite(&s, " > ", 3);
          sbsWriteLineno(&s, b);
          s.iStart = 0;
          s.zStart = "<span class=\"diffadd\">";
          s.iEnd = s.width;
          sbsWriteText(&s, &B[b], SBS_NEWLINE);
          blob_append(pOut, s.zLine, s.n);
          assert( mb>0 );
          mb--;
          b++;
        }
      }
      fossil_free(alignment);
      if( i<nr-1 ){
        m = R[r+i*3+3];
        for(j=0; j<m; j++){
          s.n = 0;
          sbsWriteLineno(&s, a+j);
          s.iStart = s.iEnd = -1;
          sbsWriteText(&s, &A[a+j], SBS_PAD);
          sbsWrite(&s, "   ", 3);
          sbsWriteLineno(&s, b+j);
          sbsWriteText(&s, &B[b+j], SBS_NEWLINE);
          blob_append(pOut, s.zLine, s.n);
        }
        b += m;
        a += m;
      }
    }

    /* Show the final common area */
    assert( nr==i );
    m = R[r+nr*3];
    if( m>nContext ) m = nContext;
    for(j=0; j<m; j++){
      s.n = 0;
      sbsWriteLineno(&s, a+j);
      s.iStart = s.iEnd = -1;
      sbsWriteText(&s, &A[a+j], SBS_PAD);
      sbsWrite(&s, "   ", 3);
      sbsWriteLineno(&s, b+j);

      sbsWriteText(&s, &B[b+j], SBS_NEWLINE);
      blob_append(pOut, s.zLine, s.n);
    }
  }
  free(s.zLine);
}

/*
** Compute the optimal longest common subsequence (LCS) using an
** exhaustive search.  This version of the LCS is only used for
** shorter input strings since runtime is O(N*N) where N is the
** input string length.
................................................................................
  DContext *p,               /* Two files being compared */
  int iS1, int iE1,          /* Range of lines in p->aFrom[] */
  int iS2, int iE2,          /* Range of lines in p->aTo[] */
  int *piSX, int *piEX,      /* Write p->aFrom[] common segment here */
  int *piSY, int *piEY       /* Write p->aTo[] common segment here */
){
  double bestScore = -1e30;  /* Best score seen so far */
  int i, j, k;               /* Loop counters */
  int n;                     /* Loop limit */
  DLine *pA, *pB;            /* Pointers to lines */
  int iSX, iSY, iEX, iEY;    /* Current match */
  double score;              /* Current score */
  int skew;                  /* How lopsided is the match */
  int dist;                  /* Distance of match from center */
  int mid;                   /* Center of the span */
  int iSXb, iSYb, iEXb, iEYb;   /* Best match so far */
  int iSXp, iSYp, iEXp, iEYp;   /* Previous match */
................................................................................
    }
    if( j==0 ) continue;
    assert( i>=iSXb && i>=iSXp );
    if( i<iEXb && j>=iSYb && j<iEYb ) continue;
    if( i<iEXp && j>=iSYp && j<iEYp ) continue;
    iSX = i;
    iSY = j-1;
    pA = &p->aFrom[iSX-1];
    pB = &p->aTo[iSY-1];
    n = minInt(iSX-iS1, iSY-iS2);
    for(k=0; k<n && same_dline(pA,pB); k++, pA--, pB--){}
    iSX -= k;
    iSY -= k;

    iEX = i+1;
    iEY = j;

    pA = &p->aFrom[iEX];
    pB = &p->aTo[iEY];
    n = minInt(iE1-iEX, iE2-iEY);
    for(k=0; k<n && same_dline(pA,pB); k++, pA++, pB++){}
    iEX += k;
    iEY += k;

    skew = (iSX-iS1) - (iSY-iS2);
    if( skew<0 ) skew = -skew;
    dist = (iSX+iEX)/2 - mid;
    if( dist<0 ) dist = -dist;
    score = (iEX - iSX) - 0.05*skew - 0.05*dist;
    if( score>bestScore ){
      bestScore = score;
................................................................................
    *piSY = iSYb;
    *piEX = iEXb;
    *piEY = iEYb;
  }
  /* printf("LCS(%d..%d/%d..%d) = %d..%d/%d..%d\n", 
     iS1, iE1, iS2, iE2, *piSX, *piEX, *piSY, *piEY);  */
}

/*
** Expand the size of aEdit[] array to hold at least nEdit elements.
*/
static void expandEdit(DContext *p, int nEdit){
  p->aEdit = fossil_realloc(p->aEdit, nEdit*sizeof(int));
  p->nEditAlloc = nEdit;
}

/*
** Append a new COPY/DELETE/INSERT triple.
*/
static void appendTriple(DContext *p, int nCopy, int nDel, int nIns){
  /* printf("APPEND %d/%d/%d\n", nCopy, nDel, nIns); */
  if( p->nEdit>=3 ){
    if( p->aEdit[p->nEdit-1]==0 ){
      if( p->aEdit[p->nEdit-2]==0 ){
        p->aEdit[p->nEdit-3] += nCopy;
        p->aEdit[p->nEdit-2] += nDel;
        p->aEdit[p->nEdit-1] += nIns;
        return;
      }
      if( nCopy==0 ){
        p->aEdit[p->nEdit-2] += nDel;
        p->aEdit[p->nEdit-1] += nIns;
        return;
      }
    }
    if( nCopy==0 && nDel==0 ){
      p->aEdit[p->nEdit-1] += nIns;
      return;
    }
  }  
  if( p->nEdit+3>p->nEditAlloc ){
    expandEdit(p, p->nEdit*2 + 15);
    if( p->aEdit==0 ) return;
  }
  p->aEdit[p->nEdit++] = nCopy;
  p->aEdit[p->nEdit++] = nDel;
  p->aEdit[p->nEdit++] = nIns;
}

/*
** Do a single step in the difference.  Compute a sequence of
** copy/delete/insert steps that will convert lines iS1 through iE1-1 of
** the input into lines iS2 through iE2-1 of the output and write
** that sequence into the difference context.
**
................................................................................
    return;
  }

  /* Find the longest matching segment between the two sequences */
  longestCommonSequence(p, iS1, iE1, iS2, iE2, &iSX, &iEX, &iSY, &iEY);

  if( iEX>iSX ){
    /* A common segment has been found.
    ** Recursively diff either side of the matching segment */
    diff_step(p, iS1, iSX, iS2, iSY);
    if( iEX>iSX ){
      appendTriple(p, iEX - iSX, 0, 0);
    }
    diff_step(p, iEX, iE1, iEY, iE2);
  }else{
................................................................................
  expandEdit(p, p->nEdit+3);
  if( p->aEdit ){
    p->aEdit[p->nEdit++] = 0;
    p->aEdit[p->nEdit++] = 0;
    p->aEdit[p->nEdit++] = 0;
  }
}

/*
** Attempt to shift insertion or deletion blocks so that they begin and
** end on lines that are pure whitespace.  In other words, try to transform
** this:
**
**      int func1(int x){
**         return x*10;
**     +}
**     +
**     +int func2(int x){
**     +   return x*20;
**      }
**
**      int func3(int x){
**         return x/5;
**      }
**
** Into one of these:
**
**      int func1(int x){              int func1(int x){
**         return x*10;                   return x*10;
**      }                              }
**     +
**     +int func2(int x){             +int func2(int x){
**     +   return x*20;               +   return x*20;
**     +}                             +}
**                                    +
**      int func3(int x){              int func3(int x){
**         return x/5;                    return x/5;
**      }                              }
*/
static void diff_optimize(DContext *p){
  int r;       /* Index of current triple */
  int lnFrom;  /* Line number in p->aFrom */
  int lnTo;    /* Line number in p->aTo */
  int cpy, del, ins;

  lnFrom = lnTo = 0;
  for(r=0; r<p->nEdit; r += 3){
    cpy = p->aEdit[r];
    del = p->aEdit[r+1];
    ins = p->aEdit[r+2];
    lnFrom += cpy;
    lnTo += cpy;

    /* Shift insertions toward the beginning of the file */
    while( cpy>0 && del==0 && ins>0 ){
      DLine *pTop = &p->aFrom[lnFrom-1];  /* Line before start of insert */
      DLine *pBtm = &p->aTo[lnTo+ins-1];  /* Last line inserted */
      if( same_dline(pTop, pBtm)==0 ) break;
      if( LENGTH(pTop+1)+LENGTH(pBtm)<=LENGTH(pTop)+LENGTH(pBtm-1) ) break;
      lnFrom--;
      lnTo--;
      p->aEdit[r]--;
      p->aEdit[r+3]++;
      cpy--;
    }

    /* Shift insertions toward the end of the file */
    while( r+3<p->nEdit && p->aEdit[r+3]>0 && del==0 && ins>0 ){
      DLine *pTop = &p->aTo[lnTo];       /* First line inserted */
      DLine *pBtm = &p->aTo[lnTo+ins];   /* First line past end of insert */
      if( same_dline(pTop, pBtm)==0 ) break;
      if( LENGTH(pTop)+LENGTH(pBtm-1)<=LENGTH(pTop+1)+LENGTH(pBtm) ) break;
      lnFrom++;
      lnTo++;
      p->aEdit[r]++;
      p->aEdit[r+3]--;
      cpy++;
    }

    /* Shift deletions toward the beginning of the file */
    while( cpy>0 && del>0 && ins==0 ){
      DLine *pTop = &p->aFrom[lnFrom-1];     /* Line before start of delete */
      DLine *pBtm = &p->aFrom[lnFrom+del-1]; /* Last line deleted */
      if( same_dline(pTop, pBtm)==0 ) break;
      if( LENGTH(pTop+1)+LENGTH(pBtm)<=LENGTH(pTop)+LENGTH(pBtm-1) ) break;
      lnFrom--;
      lnTo--;
      p->aEdit[r]--;
      p->aEdit[r+3]++;
      cpy--;
    }

    /* Shift deletions toward the end of the file */
    while( r+3<p->nEdit && p->aEdit[r+3]>0 && del>0 && ins==0 ){
      DLine *pTop = &p->aFrom[lnFrom];     /* First line deleted */
      DLine *pBtm = &p->aFrom[lnFrom+del]; /* First line past end of delete */
      if( same_dline(pTop, pBtm)==0 ) break;
      if( LENGTH(pTop)+LENGTH(pBtm-1)<=LENGTH(pTop)+LENGTH(pBtm) ) break;
      lnFrom++;
      lnTo++;
      p->aEdit[r]++;
      p->aEdit[r+3]--;
      cpy++;
    }

    lnFrom += del;
    lnTo += ins;
  }
}

/*
** Extract the number of lines of context from diffFlags.  Supply an
** appropriate default if no context width is specified.
*/
int diff_context_lines(int diffFlags){
  int n = diffFlags & DIFF_CONTEXT_MASK;
................................................................................
  Blob *pOut,      /* Write diff here if not NULL */
  int diffFlags    /* DIFF_* flags defined above */
){
  int ignoreEolWs; /* Ignore whitespace at the end of lines */
  int nContext;    /* Amount of context to display */	
  DContext c;

  if( diffFlags & DIFF_INVERT ){
    Blob *pTemp = pA_Blob;
    pA_Blob = pB_Blob;
    pB_Blob = pTemp;
  }
  nContext = diff_context_lines(diffFlags);
  ignoreEolWs = (diffFlags & DIFF_IGNORE_EOLWS)!=0;

  /* Prepare the input files */
  memset(&c, 0, sizeof(c));
  c.aFrom = break_into_lines(blob_str(pA_Blob), blob_size(pA_Blob),
                             &c.nFrom, ignoreEolWs);
................................................................................
      blob_appendf(pOut, "cannot compute difference between binary files\n");
    }
    return 0;
  }

  /* Compute the difference */
  diff_all(&c);
  if( (diffFlags & DIFF_NOOPT)==0 ) diff_optimize(&c);

  if( pOut ){
    /* Compute a context or side-by-side diff into pOut */
    int escHtml = (diffFlags & DIFF_HTML)!=0;
    if( diffFlags & DIFF_SIDEBYSIDE ){
      int width = diff_width(diffFlags);
      sbsDiff(&c, pOut, nContext, width, escHtml);
    }else{
      int showLn = (diffFlags & DIFF_LINENO)!=0;
      contextDiff(&c, pOut, nContext, showLn, escHtml);
    }
    free(c.aFrom);
    free(c.aTo);
    free(c.aEdit);
    return 0;
  }else{
    /* If a context diff is not requested, then return the
................................................................................
    */
    free(c.aFrom);
    free(c.aTo);
    return c.aEdit;
  }
}

/*














































































































































































































** Process diff-related command-line options and return an appropriate
** "diffFlags" integer.  
**

**   --brief                Show filenames only    DIFF_BRIEF
**   --context|-c N         N lines of context.    DIFF_CONTEXT_MASK
**   --html                 Format for HTML        DIFF_HTML
**   --invert               Invert the diff        DIFF_INVERT
**   --linenum|-n           Show line numbers      DIFF_LINENO
**   --noopt                Disable optimization   DIFF_NOOPT
**   --side-by-side|-y      Side-by-side diff.     DIFF_SIDEBYSIDE
**   --width|-W N           N character lines.     DIFF_WIDTH_MASK
*/
int diff_options(void){
  int diffFlags = 0;
  const char *z;
  int f;
  if( find_option("side-by-side","y",0)!=0 ) diffFlags |= DIFF_SIDEBYSIDE;
................................................................................
    diffFlags |= f;
  }
  if( (z = find_option("width","W",1))!=0 && (f = atoi(z))>0 ){
    f *= DIFF_CONTEXT_MASK+1;
    if( f > DIFF_WIDTH_MASK ) f = DIFF_CONTEXT_MASK;
    diffFlags |= f;
  }
  if( find_option("html",0,0)!=0 ) diffFlags |= DIFF_HTML;
  if( find_option("linenum","n",0)!=0 ) diffFlags |= DIFF_LINENO;
  if( find_option("noopt",0,0)!=0 ) diffFlags |= DIFF_NOOPT;
  if( find_option("invert",0,0)!=0 ) diffFlags |= DIFF_INVERT;
  if( find_option("brief",0,0)!=0 ) diffFlags |= DIFF_BRIEF;
  return diffFlags;
}

/*
** COMMAND: test-rawdiff
*/
void test_rawdiff_cmd(void){
  Blob a, b;
  int r;
  int i;
  int *R;
  int diffFlags = diff_options();
  if( g.argc<4 ) usage("FILE1 FILE2 ...");
  blob_read_from_file(&a, g.argv[2]);
  for(i=3; i<g.argc; i++){
    if( i>3 ) fossil_print("-------------------------------\n");
    blob_read_from_file(&b, g.argv[i]);
    R = text_diff(&a, &b, 0, diffFlags);
    for(r=0; R[r] || R[r+1] || R[r+2]; r += 3){
      fossil_print(" copy %4d  delete %4d  insert %4d\n", R[r], R[r+1], R[r+2]);
    }
    /* free(R); */
    blob_reset(&b);
  }
}

/*
** COMMAND: test-udiff
**
** Print the difference between two files.  The usual diff options apply.
*/
void test_udiff_cmd(void){
................................................................................
  while( db_step(&q)==SQLITE_ROW ){
    int pid = db_column_int(&q, 0);
    const char *zUuid = db_column_text(&q, 1);
    const char *zDate = db_column_text(&q, 2);
    const char *zUser = db_column_text(&q, 3);
    if( webLabel ){
      zLabel = mprintf(
          "<a href='%s/info/%s' target='infowindow'>%.10s</a> %s %13.13s", 
          g.zTop, zUuid, zUuid, zDate, zUser
      );
    }else{
      zLabel = mprintf("%.10s %s %13.13s", zUuid, zDate, zUser);
    }
    p->nVers++;
    p->azVers = fossil_realloc(p->azVers, p->nVers*sizeof(p->azVers[0]) );
    p->azVers[p->nVers-1] = zLabel;
    content_get(pid, &step);
    annotation_step(p, &step, zLabel);
    blob_reset(&step);
................................................................................
** Output the text of a file with markings to show when each line of
** the file was last modified.
**
** Options:
**   --limit N       Only look backwards in time by N versions
**   --log           List all versions analyzed
**   --filevers      Show file version numbers rather than check-in versions
**
** See also: info, finfo, timeline
*/
void annotate_cmd(void){
  int fnid;         /* Filename ID */
  int fid;          /* File instance ID */
  int mid;          /* Manifest where file was checked in */
  int cid;          /* Checkout ID */
  Blob treename;    /* FILENAME translated to canonical form */

Changes to src/diffcmd.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
..
98
99
100
101
102
103
104





105
106
107
108
109


110
111
112
113
114
115
116
117
118
119
120
121
...
155
156
157
158
159
160
161

162
163
164
165
166
167
168
169
170
171
172
173
174
175
...
209
210
211
212
213
214
215
216

217
218
219
220
221
222
223
...
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
...
337
338
339
340
341
342
343

344
345
346
347
348
349

350
351
352
353
354
355
356
357
...
365
366
367
368
369
370
371

372
373
374
375
376
377
378
...
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
...
468
469
470
471
472
473
474

475
476
477
478

479
480
481
482
483
484
485
**
** This file contains code used to implement the "diff" command
*/
#include "config.h"
#include "diffcmd.h"
#include <assert.h>

/*
** Output the results of a diff.  Output goes to stdout for command-line
** or to the CGI/HTTP result buffer for web pages.
*/
static void diff_printf(const char *zFormat, ...){
  va_list ap;
  va_start(ap, zFormat);
  if( g.cgiOutput ){
    cgi_vprintf(zFormat, ap);
  }else{
    vprintf(zFormat, ap);
  }
  va_end(ap);
}

/*
** Print the "Index:" message that patches wants to see at the top of a diff.
*/
void diff_print_index(const char *zFile, int diffFlags){
  if( (diffFlags & DIFF_SIDEBYSIDE)==0 ){
    char *z = mprintf("Index: %s\n%.66c\n", zFile, '=');
    diff_printf("%s", z);
    fossil_free(z);
  }
}

/*
** Print the +++/--- filename lines for a diff operation.
*/
void diff_print_filenames(const char *zLeft, const char *zRight, int diffFlags){
  char *z = 0;


  if( diffFlags & DIFF_SIDEBYSIDE ){
    int w = diff_width(diffFlags);
    int n1 = strlen(zLeft);
    int x;
    if( n1>w*2 ) n1 = w*2;
    x = w*2+17 - (n1+2);
    z = mprintf("%.*c %.*s %.*c\n",
                x/2, '=', n1, zLeft, (x+1)/2, '=');
  }else{
    z = mprintf("--- %s\n+++ %s\n", zLeft, zRight);
  }
  diff_printf("%s", z);
  fossil_free(z);
}

/*
** Show the difference between two files, one in memory and one on disk.
**
** The difference is the set of edits needed to transform pFile1 into
................................................................................
      }else{
        blob_read_from_file(&file2, zFile2);
      }
      zName2 = zName;
    }

    /* Compute and output the differences */





    blob_zero(&out);
    text_diff(pFile1, &file2, &out, diffFlags);
    if( blob_size(&out) ){
      diff_print_filenames(zName, zName2, diffFlags);
      diff_printf("%s\n", blob_str(&out));


    }

    /* Release memory resources */
    blob_reset(&file2);
    blob_reset(&out);
  }else{
    int cnt = 0;
    Blob nameFile1;    /* Name of temporary file to old pFile1 content */
    Blob cmd;          /* Text of command to run */

    /* Construct a temporary file to hold pFile1 based on the name of
    ** zFile2 */
................................................................................
void diff_file_mem(
  Blob *pFile1,             /* In memory content to compare from */
  Blob *pFile2,             /* In memory content to compare to */
  const char *zName,        /* Display name of the file */
  const char *zDiffCmd,     /* Command for comparison */
  int diffFlags             /* Diff flags */
){

  if( zDiffCmd==0 ){
    Blob out;      /* Diff output text */

    blob_zero(&out);
    text_diff(pFile1, pFile2, &out, diffFlags);
    diff_print_filenames(zName, zName, diffFlags);
    diff_printf("%s\n", blob_str(&out));

    /* Release memory resources */
    blob_reset(&out);
  }else{
    Blob cmd;
    char zTemp1[300];
    char zTemp2[300];
................................................................................
){
  Blob fname;
  Blob content;
  int isLink;
  file_tree_name(zFileTreeName, &fname, 1);
  historical_version_of_file(zFrom, blob_str(&fname), &content, &isLink, 0, 0);
  if( !isLink != !file_wd_islink(zFrom) ){
    diff_printf("cannot compute difference between symlink and regular file\n");

  }else{
    diff_file(&content, zFileTreeName, zFileTreeName, zDiffCmd, diffFlags);
  }
  blob_reset(&content);
  blob_reset(&fname);
}

................................................................................
    int isNew = db_column_int(&q,3);
    int srcid = db_column_int(&q, 4);
    int isLink = db_column_int(&q, 5);
    char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
    char *zToFree = zFullName;
    int showDiff = 1;
    if( isDeleted ){
      diff_printf("DELETED  %s\n", zPathname);
      if( !asNewFile ){ showDiff = 0; zFullName = "/dev/null"; }
    }else if( file_access(zFullName, 0) ){
      diff_printf("MISSING  %s\n", zPathname);
      if( !asNewFile ){ showDiff = 0; }
    }else if( isNew ){
      diff_printf("ADDED    %s\n", zPathname);
      srcid = 0;
      if( !asNewFile ){ showDiff = 0; }
    }else if( isChnged==3 ){
      diff_printf("ADDED_BY_MERGE %s\n", zPathname);
      srcid = 0;
      if( !asNewFile ){ showDiff = 0; }
    }
    if( showDiff ){
      Blob content;
      if( !isLink != !file_wd_islink(zFullName) ){
        diff_print_index(zPathname, diffFlags);
        diff_print_filenames(zPathname, zPathname, diffFlags);
        diff_printf("cannot compute difference between symlink and regular file\n");

        continue;
      }
      if( srcid>0 ){
        content_get(srcid, &content);
      }else{
        blob_zero(&content);
      }
................................................................................
  int diffFlags,
  const char *zFileTreeName
){
  char *zName;
  Blob fname;
  Blob v1, v2;
  int isLink1, isLink2;

  file_tree_name(zFileTreeName, &fname, 1);
  zName = blob_str(&fname);
  historical_version_of_file(zFrom, zName, &v1, &isLink1, 0, 0);
  historical_version_of_file(zTo, zName, &v2, &isLink2, 0, 0);
  if( isLink1 != isLink2 ){
    diff_print_filenames(zName, zName, diffFlags);

    diff_printf("cannot compute difference between symlink and regular file\n");
  }else{
    diff_file_mem(&v1, &v2, zName, zDiffCmd, diffFlags);
  }
  blob_reset(&v1);
  blob_reset(&v2);
  blob_reset(&fname);
}
................................................................................
  struct ManifestFile *pTo,
  const char *zDiffCmd,
  int diffFlags
){
  Blob f1, f2;
  int rid;
  const char *zName =  pFrom ? pFrom->zName : pTo->zName;

  diff_print_index(zName, diffFlags);
  if( pFrom ){
    rid = uuid_to_rid(pFrom->zUuid, 0);
    content_get(rid, &f1);
  }else{
    blob_zero(&f1);
  }
................................................................................
      cmp = +1;
    }else if( pToFile==0 ){
      cmp = -1;
    }else{
      cmp = fossil_strcmp(pFromFile->zName, pToFile->zName);
    }
    if( cmp<0 ){
      diff_printf("DELETED %s\n", pFromFile->zName);
      if( asNewFlag ){
        diff_manifest_entry(pFromFile, 0, zDiffCmd, diffFlags);
      }
      pFromFile = manifest_file_next(pFrom,0);
    }else if( cmp>0 ){
      diff_printf("ADDED   %s\n", pToFile->zName);
      if( asNewFlag ){
        diff_manifest_entry(0, pToFile, zDiffCmd, diffFlags);
      }
      pToFile = manifest_file_next(pTo,0);
    }else if( fossil_strcmp(pFromFile->zUuid, pToFile->zUuid)==0 ){
      /* No changes */
      pFromFile = manifest_file_next(pFrom,0);
      pToFile = manifest_file_next(pTo,0);
    }else{

      /* diff_printf("CHANGED %s\n", pFromFile->zName); */

      diff_manifest_entry(pFromFile, pToFile, zDiffCmd, diffFlags);

      pFromFile = manifest_file_next(pFrom,0);
      pToFile = manifest_file_next(pTo,0);
    }
  }
  manifest_destroy(pFrom);
  manifest_destroy(pTo);
}
................................................................................
** the "setting" command.  If no external diff program is configured, then
** the "-i" option is a no-op.  The "-i" option converts "gdiff" into "diff".
**
** The "-N" or "--new-file" option causes the complete text of added or
** deleted files to be displayed.
**
** Options:

**   --context|-c N      Use N lines of context 
**   --from|-r VERSION   select VERSION as source for the diff
**   --new-file|-N       output complete text of added or deleted files
**   -i                  use internal diff logic

**   --to VERSION        select VERSION as target for the diff
**   --side-by-side|-y   side-by-side diff
**   --width|-W N        Width of lines in side-by-side diff 
*/
void diff_cmd(void){
  int isGDiff;               /* True for gdiff.  False for normal diff */
  int isInternDiff;          /* True for internal diff */







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




|

|









>
>
|










|







 







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




<







 







>






|







 







|
>







 







|


|


|



|








|
>







 







>






>
|







 







>







 







|





|









>
|
>
|
>







 







>


<

>







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
..
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
...
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
...
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
...
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
...
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
...
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
...
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
...
470
471
472
473
474
475
476
477
478
479

480
481
482
483
484
485
486
487
488
**
** This file contains code used to implement the "diff" command
*/
#include "config.h"
#include "diffcmd.h"
#include <assert.h>
















/*
** Print the "Index:" message that patches wants to see at the top of a diff.
*/
void diff_print_index(const char *zFile, int diffFlags){
  if( (diffFlags & (DIFF_SIDEBYSIDE|DIFF_BRIEF))==0 ){
    char *z = mprintf("Index: %s\n%.66c\n", zFile, '=');
    fossil_print("%s", z);
    fossil_free(z);
  }
}

/*
** Print the +++/--- filename lines for a diff operation.
*/
void diff_print_filenames(const char *zLeft, const char *zRight, int diffFlags){
  char *z = 0;
  if( diffFlags & DIFF_BRIEF ){
    /* no-op */
  }else if( diffFlags & DIFF_SIDEBYSIDE ){
    int w = diff_width(diffFlags);
    int n1 = strlen(zLeft);
    int x;
    if( n1>w*2 ) n1 = w*2;
    x = w*2+17 - (n1+2);
    z = mprintf("%.*c %.*s %.*c\n",
                x/2, '=', n1, zLeft, (x+1)/2, '=');
  }else{
    z = mprintf("--- %s\n+++ %s\n", zLeft, zRight);
  }
  fossil_print("%s", z);
  fossil_free(z);
}

/*
** Show the difference between two files, one in memory and one on disk.
**
** The difference is the set of edits needed to transform pFile1 into
................................................................................
      }else{
        blob_read_from_file(&file2, zFile2);
      }
      zName2 = zName;
    }

    /* Compute and output the differences */
    if( diffFlags & DIFF_BRIEF ){
      if( blob_compare(pFile1, &file2) ){
        fossil_print("CHANGED  %s\n", zName);
      }
    }else{
      blob_zero(&out);
      text_diff(pFile1, &file2, &out, diffFlags);
      if( blob_size(&out) ){
        diff_print_filenames(zName, zName2, diffFlags);
        fossil_print("%s\n", blob_str(&out));
      }
      blob_reset(&out);
    }

    /* Release memory resources */
    blob_reset(&file2);

  }else{
    int cnt = 0;
    Blob nameFile1;    /* Name of temporary file to old pFile1 content */
    Blob cmd;          /* Text of command to run */

    /* Construct a temporary file to hold pFile1 based on the name of
    ** zFile2 */
................................................................................
void diff_file_mem(
  Blob *pFile1,             /* In memory content to compare from */
  Blob *pFile2,             /* In memory content to compare to */
  const char *zName,        /* Display name of the file */
  const char *zDiffCmd,     /* Command for comparison */
  int diffFlags             /* Diff flags */
){
  if( diffFlags & DIFF_BRIEF ) return;
  if( zDiffCmd==0 ){
    Blob out;      /* Diff output text */

    blob_zero(&out);
    text_diff(pFile1, pFile2, &out, diffFlags);
    diff_print_filenames(zName, zName, diffFlags);
    fossil_print("%s\n", blob_str(&out));

    /* Release memory resources */
    blob_reset(&out);
  }else{
    Blob cmd;
    char zTemp1[300];
    char zTemp2[300];
................................................................................
){
  Blob fname;
  Blob content;
  int isLink;
  file_tree_name(zFileTreeName, &fname, 1);
  historical_version_of_file(zFrom, blob_str(&fname), &content, &isLink, 0, 0);
  if( !isLink != !file_wd_islink(zFrom) ){
    fossil_print("cannot compute difference between "
                 "symlink and regular file\n");
  }else{
    diff_file(&content, zFileTreeName, zFileTreeName, zDiffCmd, diffFlags);
  }
  blob_reset(&content);
  blob_reset(&fname);
}

................................................................................
    int isNew = db_column_int(&q,3);
    int srcid = db_column_int(&q, 4);
    int isLink = db_column_int(&q, 5);
    char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
    char *zToFree = zFullName;
    int showDiff = 1;
    if( isDeleted ){
      fossil_print("DELETED  %s\n", zPathname);
      if( !asNewFile ){ showDiff = 0; zFullName = "/dev/null"; }
    }else if( file_access(zFullName, 0) ){
      fossil_print("MISSING  %s\n", zPathname);
      if( !asNewFile ){ showDiff = 0; }
    }else if( isNew ){
      fossil_print("ADDED    %s\n", zPathname);
      srcid = 0;
      if( !asNewFile ){ showDiff = 0; }
    }else if( isChnged==3 ){
      fossil_print("ADDED_BY_MERGE %s\n", zPathname);
      srcid = 0;
      if( !asNewFile ){ showDiff = 0; }
    }
    if( showDiff ){
      Blob content;
      if( !isLink != !file_wd_islink(zFullName) ){
        diff_print_index(zPathname, diffFlags);
        diff_print_filenames(zPathname, zPathname, diffFlags);
        fossil_print("cannot compute difference between "
                     "symlink and regular file\n");
        continue;
      }
      if( srcid>0 ){
        content_get(srcid, &content);
      }else{
        blob_zero(&content);
      }
................................................................................
  int diffFlags,
  const char *zFileTreeName
){
  char *zName;
  Blob fname;
  Blob v1, v2;
  int isLink1, isLink2;
  if( diffFlags & DIFF_BRIEF ) return;
  file_tree_name(zFileTreeName, &fname, 1);
  zName = blob_str(&fname);
  historical_version_of_file(zFrom, zName, &v1, &isLink1, 0, 0);
  historical_version_of_file(zTo, zName, &v2, &isLink2, 0, 0);
  if( isLink1 != isLink2 ){
    diff_print_filenames(zName, zName, diffFlags);
    fossil_print("cannot compute difference "
                 " between symlink and regular file\n");
  }else{
    diff_file_mem(&v1, &v2, zName, zDiffCmd, diffFlags);
  }
  blob_reset(&v1);
  blob_reset(&v2);
  blob_reset(&fname);
}
................................................................................
  struct ManifestFile *pTo,
  const char *zDiffCmd,
  int diffFlags
){
  Blob f1, f2;
  int rid;
  const char *zName =  pFrom ? pFrom->zName : pTo->zName;
  if( diffFlags & DIFF_BRIEF ) return;
  diff_print_index(zName, diffFlags);
  if( pFrom ){
    rid = uuid_to_rid(pFrom->zUuid, 0);
    content_get(rid, &f1);
  }else{
    blob_zero(&f1);
  }
................................................................................
      cmp = +1;
    }else if( pToFile==0 ){
      cmp = -1;
    }else{
      cmp = fossil_strcmp(pFromFile->zName, pToFile->zName);
    }
    if( cmp<0 ){
      fossil_print("DELETED %s\n", pFromFile->zName);
      if( asNewFlag ){
        diff_manifest_entry(pFromFile, 0, zDiffCmd, diffFlags);
      }
      pFromFile = manifest_file_next(pFrom,0);
    }else if( cmp>0 ){
      fossil_print("ADDED   %s\n", pToFile->zName);
      if( asNewFlag ){
        diff_manifest_entry(0, pToFile, zDiffCmd, diffFlags);
      }
      pToFile = manifest_file_next(pTo,0);
    }else if( fossil_strcmp(pFromFile->zUuid, pToFile->zUuid)==0 ){
      /* No changes */
      pFromFile = manifest_file_next(pFrom,0);
      pToFile = manifest_file_next(pTo,0);
    }else{
      if( diffFlags & DIFF_BRIEF ){
        fossil_print("CHANGED %s\n", pFromFile->zName);
      }else{
        diff_manifest_entry(pFromFile, pToFile, zDiffCmd, diffFlags);
      }
      pFromFile = manifest_file_next(pFrom,0);
      pToFile = manifest_file_next(pTo,0);
    }
  }
  manifest_destroy(pFrom);
  manifest_destroy(pTo);
}
................................................................................
** the "setting" command.  If no external diff program is configured, then
** the "-i" option is a no-op.  The "-i" option converts "gdiff" into "diff".
**
** The "-N" or "--new-file" option causes the complete text of added or
** deleted files to be displayed.
**
** Options:
**   --brief             Show filenames only
**   --context|-c N      Use N lines of context 
**   --from|-r VERSION   select VERSION as source for the diff

**   -i                  use internal diff logic
**   --new-file|-N       output complete text of added or deleted files
**   --to VERSION        select VERSION as target for the diff
**   --side-by-side|-y   side-by-side diff
**   --width|-W N        Width of lines in side-by-side diff 
*/
void diff_cmd(void){
  int isGDiff;               /* True for gdiff.  False for normal diff */
  int isInternDiff;          /* True for internal diff */

Changes to src/file.c.

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
...
947
948
949
950
951
952
953











954
955
956
957
958
959
960
    }else{
      fossil_fatal("cannot find current working directory; %s",
                   strerror(errno));
    }
  }
#endif
}



















/*
** Compute a canonical pathname for a file or directory.
** Make the name absolute if it is relative.
** Remove redundant / characters
** Remove all /./ path elements.
** Convert /A/../ to just /
*/
void file_canonical_name(const char *zOrigName, Blob *pOut){
  if( zOrigName[0]=='/' 
#if defined(_WIN32)
      || zOrigName[0]=='\\'
      || (strlen(zOrigName)>3 && zOrigName[1]==':'
           && (zOrigName[2]=='\\' || zOrigName[2]=='/'))
#endif
  ){
    blob_set(pOut, zOrigName);
    blob_materialize(pOut);
  }else{
    char zPwd[2000];
    file_getcwd(zPwd, sizeof(zPwd)-strlen(zOrigName));
    blob_zero(pOut);
    blob_appendf(pOut, "%//%/", zPwd, zOrigName);
................................................................................
#ifdef _WIN32
  extern char *sqlite3_win32_utf8_to_mbcs(const char*);
  return sqlite3_win32_utf8_to_mbcs(zUtf8);
#else
  return (char*)zUtf8;  /* No-op on unix */
#endif  
}












/*
** Translate UTF8 to MBCS for display on the console.  Return a pointer to the
** translated text..  Call fossil_mbcs_free() to deallocate any memory
** used to store the returned pointer when done.
*/
char *fossil_utf8_to_console(const char *zUtf8){







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









|
<
<
<
<
<
<







 







>
>
>
>
>
>
>
>
>
>
>







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
...
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
    }else{
      fossil_fatal("cannot find current working directory; %s",
                   strerror(errno));
    }
  }
#endif
}

/*
** Return true if zPath is an absolute pathname.  Return false
** if it is relative.
*/
int file_is_absolute_path(const char *zPath){
  if( zPath[0]=='/'
#if defined(_WIN32)
      || zPath[0]=='\\'
      || (strlen(zPath)>3 && zPath[1]==':'
           && (zPath[2]=='\\' || zPath[2]=='/'))
#endif
  ){
    return 1;
  }else{
    return 0;
  }
}

/*
** Compute a canonical pathname for a file or directory.
** Make the name absolute if it is relative.
** Remove redundant / characters
** Remove all /./ path elements.
** Convert /A/../ to just /
*/
void file_canonical_name(const char *zOrigName, Blob *pOut){
  if( file_is_absolute_path(zOrigName) ){






    blob_set(pOut, zOrigName);
    blob_materialize(pOut);
  }else{
    char zPwd[2000];
    file_getcwd(zPwd, sizeof(zPwd)-strlen(zOrigName));
    blob_zero(pOut);
    blob_appendf(pOut, "%//%/", zPwd, zOrigName);
................................................................................
#ifdef _WIN32
  extern char *sqlite3_win32_utf8_to_mbcs(const char*);
  return sqlite3_win32_utf8_to_mbcs(zUtf8);
#else
  return (char*)zUtf8;  /* No-op on unix */
#endif  
}

/*
** Return the value of an environment variable as UTF8.
*/
char *fossil_getenv(const char *zName){
  char *zValue = getenv(zName);
#ifdef _WIN32
  if( zValue ) zValue = fossil_mbcs_to_utf8(zValue);
#endif
  return zValue;
}

/*
** Translate UTF8 to MBCS for display on the console.  Return a pointer to the
** translated text..  Call fossil_mbcs_free() to deallocate any memory
** used to store the returned pointer when done.
*/
char *fossil_utf8_to_console(const char *zUtf8){

Changes to src/finfo.c.

48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
**   -p                   select print mode
**   --revision|-r R      print the given revision (or ckout, if none is given)
**                        to stdout (only in print mode)
**   -s                   select status mode (print a status indicator for FILE)
**   --case-sensitive B   Enable or disable case-sensitive filenames.  B is a
**                        boolean: "yes", "no", "true", "false", etc.
**
** See also: descendants, info, leaves
*/
void finfo_cmd(void){
  capture_case_sensitive_option();
  db_must_be_within_tree();
  if (find_option("status","s",0)) {
    Stmt q;
    Blob line;







|







48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
**   -p                   select print mode
**   --revision|-r R      print the given revision (or ckout, if none is given)
**                        to stdout (only in print mode)
**   -s                   select status mode (print a status indicator for FILE)
**   --case-sensitive B   Enable or disable case-sensitive filenames.  B is a
**                        boolean: "yes", "no", "true", "false", etc.
**
** See also: artifact, descendants, info, leaves
*/
void finfo_cmd(void){
  capture_case_sensitive_option();
  db_must_be_within_tree();
  if (find_option("status","s",0)) {
    Stmt q;
    Blob line;

Changes to src/http.c.

172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
...
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
  */
  if( g.fHttpTrace ){
    static int traceCnt = 0;
    char *zOutFile;
    FILE *out;
    traceCnt++;
    zOutFile = mprintf("http-request-%d.txt", traceCnt);
    out = fopen(zOutFile, "w");
    if( out ){
      fwrite(blob_buffer(&hdr), 1, blob_size(&hdr), out);
      fwrite(blob_buffer(&payload), 1, blob_size(&payload), out);
      fclose(out);
    }
    free(zOutFile);
    zOutFile = mprintf("http-reply-%d.txt", traceCnt);
    out = fopen(zOutFile, "w");
    transport_log(out);
    free(zOutFile);
  }

  /*
  ** Send the request to the server.
  */
................................................................................
                          "application/x-fossil-uncompressed", -1)==0 ){
        isCompressed = 0;
      }else if( fossil_strnicmp(&zLine[14], "application/x-fossil", -1)!=0 ){
        isError = 1;
      }
    }
  }




  if( rc!=200 ){
    fossil_warning("\"location:\" missing from 302 redirect reply");
    goto write_err;
  }

  /*
  ** Extract the reply payload that follows the header
  */
  if( iLength<0 ){
    fossil_fatal("server did not reply");
    goto write_err;
  }
  blob_zero(pReply);
  blob_resize(pReply, iLength);
  iLength = transport_receive(blob_buffer(pReply), iLength);
  blob_resize(pReply, iLength);
  if( isError ){
    char *z;
    int i, j;







|







|







 







>
>
>
>








<
<
<
<







172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
...
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
  */
  if( g.fHttpTrace ){
    static int traceCnt = 0;
    char *zOutFile;
    FILE *out;
    traceCnt++;
    zOutFile = mprintf("http-request-%d.txt", traceCnt);
    out = fopen(zOutFile, "wb");
    if( out ){
      fwrite(blob_buffer(&hdr), 1, blob_size(&hdr), out);
      fwrite(blob_buffer(&payload), 1, blob_size(&payload), out);
      fclose(out);
    }
    free(zOutFile);
    zOutFile = mprintf("http-reply-%d.txt", traceCnt);
    out = fopen(zOutFile, "wb");
    transport_log(out);
    free(zOutFile);
  }

  /*
  ** Send the request to the server.
  */
................................................................................
                          "application/x-fossil-uncompressed", -1)==0 ){
        isCompressed = 0;
      }else if( fossil_strnicmp(&zLine[14], "application/x-fossil", -1)!=0 ){
        isError = 1;
      }
    }
  }
  if( iLength<0 ){
    fossil_fatal("server did not reply");
    goto write_err;
  }
  if( rc!=200 ){
    fossil_warning("\"location:\" missing from 302 redirect reply");
    goto write_err;
  }

  /*
  ** Extract the reply payload that follows the header
  */




  blob_zero(pReply);
  blob_resize(pReply, iLength);
  iLength = transport_receive(blob_buffer(pReply), iLength);
  blob_resize(pReply, iLength);
  if( isError ){
    char *z;
    int i, j;

Changes to src/info.c.

137
138
139
140
141
142
143


144
145
146
147
148
149
150
...
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
...
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
...
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
...
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
...
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
...
395
396
397
398
399
400
401
402
403

404
405
406
407
408
409
410
...
593
594
595
596
597
598
599

600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
...
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
...
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
....
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
**
** Use the "finfo" command to get information about a specific
** file in a checkout.
**
** Options:
**
**    -R|--repository FILE       Extract info from repository FILE


*/
void info_cmd(void){
  i64 fsize;
  if( g.argc==3 && (fsize = file_size(g.argv[2]))>0 && (fsize&0x1ff)==0 ){
    db_open_config(0);
    db_record_repository_filename(g.argv[2]);
    db_open_repository(g.argv[2]);
................................................................................
  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_lget("repository", ""));
      fossil_print("local-root:   %s\n", g.zLocalRoot);
    }
#if defined(_WIN32)
    if( g.zHome ){
      fossil_print("user-home:    %s\n", g.zHome);
    }
#endif
................................................................................
  }
}


/*
** Append the difference between two RIDs to the output
*/
static void append_diff(const char *zFrom, const char *zTo){
  int fromid;
  int toid;
  Blob from, to, out;
  if( zFrom ){
    fromid = uuid_to_rid(zFrom, 0);
    content_get(fromid, &from);
  }else{
................................................................................
  if( zTo ){
    toid = uuid_to_rid(zTo, 0);
    content_get(toid, &to);
  }else{
    blob_zero(&to);
  }
  blob_zero(&out);

  text_diff(&from, &to, &out, DIFF_IGNORE_EOLWS | 5);

  @ %h(blob_str(&out))
  blob_reset(&from);
  blob_reset(&to);
  blob_reset(&out);  
}


/*
** Write the difference between two RIDs to the output
*/
static void generate_sbsdiff(const char *zFrom, const char *zTo){
  int fromid;
  int toid;
  Blob from, to;
  if( zFrom ){
    fromid = uuid_to_rid(zFrom, 0);
    content_get(fromid, &from);

  }else{
    blob_zero(&from);




  }
  if( zTo ){
    toid = uuid_to_rid(zTo, 0);
    content_get(toid, &to);
  }else{
    blob_zero(&to);
  }
  @ <table class="sbsdiff">
  @ <tr><th colspan="2" class="diffhdr">Old (%S(zFrom))</th><th/>
  @ <th colspan="2" class="diffhdr">New (%S(zTo))</th></tr>
  html_sbsdiff(&from, &to, 5, 1);
  @ </table>
  blob_reset(&from);
  blob_reset(&to);

}


/*
** Write a line of web-page output that shows changes that have occurred 
** to a file between two check-ins.
*/
static void append_file_change_line(
  const char *zName,    /* Name of the file that has changed */
  const char *zOld,     /* blob.uuid before change.  NULL for added files */
  const char *zNew,     /* blob.uuid after change.  NULL for deletes */
  const char *zOldName, /* Prior name.  NULL if no name change. */
  int showDiff,         /* Show edit diffs if true */
  int sideBySide,       /* Show diffs side-by-side */
  int mperm             /* executable or symlink permission for zNew */
){
  if( !g.perm.History ){
    if( zNew==0 ){
      @ <p>Deleted %h(zName)</p>
    }else if( zOld==0 ){
      @ <p>Added %h(zName)</p>
................................................................................
      @ <p>Name change from %h(zOldName) to %h(zName)
    }else if( fossil_strcmp(zNew, zOld)==0 ){
      @ <p>Execute permission %s(( mperm==PERM_EXE )?"set":"cleared")
      @  for %h(zName)</p>
    }else{
      @ <p>Changes to %h(zName)</p>
    }
    if( showDiff ){
      if( sideBySide ){
        generate_sbsdiff(zOld, zNew);
      }else{
        @ <blockquote><pre>
        append_diff(zOld, zNew);
        @ </pre></blockquote>
      }
    }
  }else{
    if( zOld && zNew ){
      if( fossil_strcmp(zOld, zNew)!=0 ){
        @ <p>Modified <a href="%s(g.zTop)/finfo?name=%T(zName)">%h(zName)</a>
        @ from <a href="%s(g.zTop)/artifact/%s(zOld)">[%S(zOld)]</a>
        @ to <a href="%s(g.zTop)/artifact/%s(zNew)">[%S(zNew)].</a>
................................................................................
    }else if( zOld ){
      @ <p>Deleted <a href="%s(g.zTop)/finfo?name=%T(zName)">%h(zName)</a>
      @ version <a href="%s(g.zTop)/artifact/%s(zOld)">[%S(zOld)]</a>
    }else{
      @ <p>Added <a href="%s(g.zTop)/finfo?name=%T(zName)">%h(zName)</a>
      @ version <a href="%s(g.zTop)/artifact/%s(zNew)">[%S(zNew)]</a>
    }
    if( showDiff ){
      if( sideBySide ){
        generate_sbsdiff(zOld, zNew);
      }else{
        @ <blockquote><pre>
        append_diff(zOld, zNew);
        @ </pre></blockquote>
      }
    }else if( zOld && zNew && fossil_strcmp(zOld,zNew)!=0 ){
      @ &nbsp;&nbsp;
      @ <a href="%s(g.zTop)/fdiff?v1=%S(zOld)&amp;v2=%S(zNew)">[diff]</a>
    }
    @ </p>
  }
}


































/*
** WEBPAGE: vinfo
** WEBPAGE: ci
** URL:  /ci?name=RID|ARTIFACTID
**
................................................................................
** shown, without diffs.  This behavior is inverted if the
** "show-version-diffs" setting is turned on.
*/
void ci_page(void){
  Stmt q;
  int rid;
  int isLeaf;
  int showDiff;
  int sideBySide;

  const char *zName;   /* Name of the checkin to be displayed */
  const char *zUuid;   /* UUID of zName */
  const char *zParent; /* UUID of the parent checkin (if any) */

  login_check_credentials();
  if( !g.perm.Read ){ login_needed(); return; }
  zName = P("name");
................................................................................
       "       (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"
       " ORDER BY name /*sort*/",
       rid
    );

    while( db_step(&q)==SQLITE_ROW ){
      const char *zName = db_column_text(&q,0);
      int mperm = db_column_int(&q, 1);
      const char *zOld = db_column_text(&q,2);
      const char *zNew = db_column_text(&q,3);
      const char *zOldName = db_column_text(&q, 4);
      append_file_change_line(zName, zOld, zNew, zOldName, showDiff,
            sideBySide, mperm);
    }
    db_finalize(&q);
  }
  style_footer();
}

/*
................................................................................
**
** Show all differences between two checkins.  
*/
void vdiff_page(void){
  int ridFrom, ridTo;
  int showDetail = 0;
  int sideBySide = 0;

  Manifest *pFrom, *pTo;
  ManifestFile *pFileFrom, *pFileTo;

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

  pFrom = vdiff_parse_manifest("from", &ridFrom);
  if( pFrom==0 ) return;
  pTo = vdiff_parse_manifest("to", &ridTo);
  if( pTo==0 ) return;
  showDetail = atoi(PD("detail","0"));
  sideBySide = atoi(PD("sbs","1"));


  if( !sideBySide ){
    style_submenu_element("Side-by-side Diff", "sbsdiff",
                          "%s/vdiff?from=%T&to=%T&detail=%d&sbs=1",
                          g.zTop, P("from"), P("to"), showDetail);
  }else{
    style_submenu_element("Unified Diff", "udiff",
                          "%s/vdiff?from=%T&to=%T&detail=%d&sbs=0",
................................................................................
  checkin_description(ridTo);
  @ </blockquote><hr /><p>

  manifest_file_rewind(pFrom);
  pFileFrom = manifest_file_next(pFrom, 0);
  manifest_file_rewind(pTo);
  pFileTo = manifest_file_next(pTo, 0);

  while( pFileFrom || pFileTo ){
    int cmp;
    if( pFileFrom==0 ){
      cmp = +1;
    }else if( pFileTo==0 ){
      cmp = -1;
    }else{
      cmp = fossil_strcmp(pFileFrom->zName, pFileTo->zName);
    }
    if( cmp<0 ){
      append_file_change_line(pFileFrom->zName, 
                              pFileFrom->zUuid, 0, 0, 0, 0, 0);
      pFileFrom = manifest_file_next(pFrom, 0);
    }else if( cmp>0 ){
      append_file_change_line(pFileTo->zName, 
                              0, pFileTo->zUuid, 0, 0, 0,
                              manifest_file_mperm(pFileTo));
      pFileTo = manifest_file_next(pTo, 0);
    }else if( fossil_strcmp(pFileFrom->zUuid, pFileTo->zUuid)==0 ){
      /* No changes */
      pFileFrom = manifest_file_next(pFrom, 0);
      pFileTo = manifest_file_next(pTo, 0);
    }else{
      append_file_change_line(pFileFrom->zName, 
                              pFileFrom->zUuid,
                              pFileTo->zUuid, 0, showDetail, sideBySide,
                              manifest_file_mperm(pFileTo));
      pFileFrom = manifest_file_next(pFrom, 0);
      pFileTo = manifest_file_next(pTo, 0);
    }
  }
  manifest_destroy(pFrom);
  manifest_destroy(pTo);
................................................................................
void diff_page(void){
  int v1, v2;
  int isPatch;
  int sideBySide;
  Blob c1, c2, diff, *pOut;
  char *zV1;
  char *zV2;



  login_check_credentials();
  if( !g.perm.Read ){ login_needed(); return; }
  v1 = name_to_rid_www("v1");
  v2 = name_to_rid_www("v2");
  if( v1==0 || v2==0 ) fossil_redirect_home();
  sideBySide = atoi(PD("sbs","1"));
  zV1 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v1);
  zV2 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v2);
  isPatch = P("patch")!=0;
  if( isPatch ){
    pOut = cgi_output_blob();
    cgi_set_content_type("text/plain");

  }else{
    blob_zero(&diff);
    pOut = &diff;






  }
  if( !sideBySide || isPatch ){

    content_get(v1, &c1);
    content_get(v2, &c2);
    text_diff(&c1, &c2, pOut, 4 | 0);
    blob_reset(&c1);
    blob_reset(&c2);
  }
  if( !isPatch ){
    style_header("Diff");
    style_submenu_element("Patch", "Patch", "%s/fdiff?v1=%T&v2=%T&patch",
                          g.zTop, P("v1"), P("v2"));
    if( !sideBySide ){
      style_submenu_element("Side-by-side Diff", "sbsdiff",
                            "%s/fdiff?v1=%T&v2=%T&sbs=1",
................................................................................
                            g.zTop, P("v1"), P("v2"));
    }else{
      style_submenu_element("Unified Diff", "udiff",
                            "%s/fdiff?v1=%T&v2=%T&sbs=0",
                            g.zTop, P("v1"), P("v2"));
    }






    @ <h2>Differences From
    @ Artifact <a href="%s(g.zTop)/artifact/%S(zV1)">[%S(zV1)]</a>:</h2>
    object_description(v1, 0, 0);

    @ <h2>To Artifact <a href="%s(g.zTop)/artifact/%S(zV2)">[%S(zV2)]</a>:</h2>
    object_description(v2, 0, 0);

    @ <hr />
    if( sideBySide ){
      generate_sbsdiff(zV1, zV2);
    }else{
      @ <blockquote><pre>

      @ %h(blob_str(&diff))
      @ </pre></blockquote>
    }

    blob_reset(&diff);
    style_footer();
  }
}

/*
** WEBPAGE: raw







>
>







 







|







 







|







 







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

<
>
>
>
>

<
<
<
<
<
<
<
<
<
<
<


>












|
<







 







|
|
<
<
<
|
|
<







 







|
|
<
<
<
|
|
<







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







 







|
|
>







 







>






|
<







 







>











<

>
>







 







>











|



|









|







 







>
>













>



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







 







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

<
<
<
<
>
|
<
<
>







137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
...
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
...
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
...
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
...
310
311
312
313
314
315
316
317
318



319
320

321
322
323
324
325
326
327
...
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
...
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
...
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613

614
615
616
617
618
619
620
...
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
...
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
....
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
**
** Use the "finfo" command to get information about a specific
** file in a checkout.
**
** Options:
**
**    -R|--repository FILE       Extract info from repository FILE
**
** See also: annotate, artifact, finfo, timeline
*/
void info_cmd(void){
  i64 fsize;
  if( g.argc==3 && (fsize = file_size(g.argv[2]))>0 && (fsize&0x1ff)==0 ){
    db_open_config(0);
    db_record_repository_filename(g.argv[2]);
    db_open_repository(g.argv[2]);
................................................................................
  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());
      fossil_print("local-root:   %s\n", g.zLocalRoot);
    }
#if defined(_WIN32)
    if( g.zHome ){
      fossil_print("user-home:    %s\n", g.zHome);
    }
#endif
................................................................................
  }
}


/*
** Append the difference between two RIDs to the output
*/
static void append_diff(const char *zFrom, const char *zTo, int diffFlags){
  int fromid;
  int toid;
  Blob from, to, out;
  if( zFrom ){
    fromid = uuid_to_rid(zFrom, 0);
    content_get(fromid, &from);
  }else{
................................................................................
  if( zTo ){
    toid = uuid_to_rid(zTo, 0);
    content_get(toid, &to);
  }else{
    blob_zero(&to);
  }
  blob_zero(&out);
  if( diffFlags & DIFF_SIDEBYSIDE ){
    text_diff(&from, &to, &out, diffFlags | DIFF_HTML);
    @ <div class="sbsdiff">
    @ %s(blob_str(&out))
















    @ </div>
  }else{

    text_diff(&from, &to, &out, diffFlags | DIFF_LINENO | DIFF_HTML);
    @ <div class="udiff">
    @ %s(blob_str(&out))
    @ </div>
  }











  blob_reset(&from);
  blob_reset(&to);
  blob_reset(&out);  
}


/*
** Write a line of web-page output that shows changes that have occurred 
** to a file between two check-ins.
*/
static void append_file_change_line(
  const char *zName,    /* Name of the file that has changed */
  const char *zOld,     /* blob.uuid before change.  NULL for added files */
  const char *zNew,     /* blob.uuid after change.  NULL for deletes */
  const char *zOldName, /* Prior name.  NULL if no name change. */
  int diffFlags,        /* Flags for text_diff().  Zero to omit diffs */

  int mperm             /* executable or symlink permission for zNew */
){
  if( !g.perm.History ){
    if( zNew==0 ){
      @ <p>Deleted %h(zName)</p>
    }else if( zOld==0 ){
      @ <p>Added %h(zName)</p>
................................................................................
      @ <p>Name change from %h(zOldName) to %h(zName)
    }else if( fossil_strcmp(zNew, zOld)==0 ){
      @ <p>Execute permission %s(( mperm==PERM_EXE )?"set":"cleared")
      @  for %h(zName)</p>
    }else{
      @ <p>Changes to %h(zName)</p>
    }
    if( diffFlags ){
      @ <pre style="white-space:pre;">



      append_diff(zOld, zNew, diffFlags);
      @ </pre>

    }
  }else{
    if( zOld && zNew ){
      if( fossil_strcmp(zOld, zNew)!=0 ){
        @ <p>Modified <a href="%s(g.zTop)/finfo?name=%T(zName)">%h(zName)</a>
        @ from <a href="%s(g.zTop)/artifact/%s(zOld)">[%S(zOld)]</a>
        @ to <a href="%s(g.zTop)/artifact/%s(zNew)">[%S(zNew)].</a>
................................................................................
    }else if( zOld ){
      @ <p>Deleted <a href="%s(g.zTop)/finfo?name=%T(zName)">%h(zName)</a>
      @ version <a href="%s(g.zTop)/artifact/%s(zOld)">[%S(zOld)]</a>
    }else{
      @ <p>Added <a href="%s(g.zTop)/finfo?name=%T(zName)">%h(zName)</a>
      @ version <a href="%s(g.zTop)/artifact/%s(zNew)">[%S(zNew)]</a>
    }
    if( diffFlags ){
      @ <pre style="white-space:pre;">



      append_diff(zOld, zNew, diffFlags);
      @ </pre>

    }else if( zOld && zNew && fossil_strcmp(zOld,zNew)!=0 ){
      @ &nbsp;&nbsp;
      @ <a href="%s(g.zTop)/fdiff?v1=%S(zOld)&amp;v2=%S(zNew)">[diff]</a>
    }
    @ </p>
  }
}

/*
** Construct an appropriate diffFlag for text_diff() based on query
** parameters and the to boolean arguments.
*/
int construct_diff_flags(int showDiff, int sideBySide){
  int diffFlags;
  if( showDiff==0 ){
    diffFlags = 0;  /* Zero means do not show any diff */
  }else{
    int x;
    if( sideBySide ){
      diffFlags = DIFF_SIDEBYSIDE | DIFF_IGNORE_EOLWS;

      /* "dw" query parameter determines width of each column */
      x = atoi(PD("dw","80"))*(DIFF_CONTEXT_MASK+1);
      if( x<0 || x>DIFF_WIDTH_MASK ) x = DIFF_WIDTH_MASK;
      diffFlags += x;
    }else{
      diffFlags = DIFF_INLINE | DIFF_IGNORE_EOLWS;
    }

    /* "dc" query parameter determines lines of context */
    x = atoi(PD("dc","7"));
    if( x<0 || x>DIFF_CONTEXT_MASK ) x = DIFF_CONTEXT_MASK;
    diffFlags += x;

    /* The "noopt" parameter disables diff optimization */
    if( PD("noopt",0)!=0 ) diffFlags |= DIFF_NOOPT;
  }
  return diffFlags;
}


/*
** WEBPAGE: vinfo
** WEBPAGE: ci
** URL:  /ci?name=RID|ARTIFACTID
**
................................................................................
** shown, without diffs.  This behavior is inverted if the
** "show-version-diffs" setting is turned on.
*/
void ci_page(void){
  Stmt q;
  int rid;
  int isLeaf;
  int showDiff;        /* True to show diffs */
  int sideBySide;      /* True for side-by-side diffs */
  int diffFlags;       /* Flag parameter for text_diff() */
  const char *zName;   /* Name of the checkin to be displayed */
  const char *zUuid;   /* UUID of zName */
  const char *zParent; /* UUID of the parent checkin (if any) */

  login_check_credentials();
  if( !g.perm.Read ){ login_needed(); return; }
  zName = P("name");
................................................................................
       "       (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"
       " ORDER BY name /*sort*/",
       rid
    );
    diffFlags = construct_diff_flags(showDiff, sideBySide);
    while( db_step(&q)==SQLITE_ROW ){
      const char *zName = db_column_text(&q,0);
      int mperm = db_column_int(&q, 1);
      const char *zOld = db_column_text(&q,2);
      const char *zNew = db_column_text(&q,3);
      const char *zOldName = db_column_text(&q, 4);
      append_file_change_line(zName, zOld, zNew, zOldName, diffFlags, mperm);

    }
    db_finalize(&q);
  }
  style_footer();
}

/*
................................................................................
**
** Show all differences between two checkins.  
*/
void vdiff_page(void){
  int ridFrom, ridTo;
  int showDetail = 0;
  int sideBySide = 0;
  int diffFlags = 0;
  Manifest *pFrom, *pTo;
  ManifestFile *pFileFrom, *pFileTo;

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

  pFrom = vdiff_parse_manifest("from", &ridFrom);
  if( pFrom==0 ) return;
  pTo = vdiff_parse_manifest("to", &ridTo);
  if( pTo==0 ) return;

  sideBySide = atoi(PD("sbs","1"));
  showDetail = atoi(PD("detail","0"));
  if( !showDetail && sideBySide ) showDetail = 1;
  if( !sideBySide ){
    style_submenu_element("Side-by-side Diff", "sbsdiff",
                          "%s/vdiff?from=%T&to=%T&detail=%d&sbs=1",
                          g.zTop, P("from"), P("to"), showDetail);
  }else{
    style_submenu_element("Unified Diff", "udiff",
                          "%s/vdiff?from=%T&to=%T&detail=%d&sbs=0",
................................................................................
  checkin_description(ridTo);
  @ </blockquote><hr /><p>

  manifest_file_rewind(pFrom);
  pFileFrom = manifest_file_next(pFrom, 0);
  manifest_file_rewind(pTo);
  pFileTo = manifest_file_next(pTo, 0);
  diffFlags = construct_diff_flags(showDetail, sideBySide);
  while( pFileFrom || pFileTo ){
    int cmp;
    if( pFileFrom==0 ){
      cmp = +1;
    }else if( pFileTo==0 ){
      cmp = -1;
    }else{
      cmp = fossil_strcmp(pFileFrom->zName, pFileTo->zName);
    }
    if( cmp<0 ){
      append_file_change_line(pFileFrom->zName, 
                              pFileFrom->zUuid, 0, 0, 0, 0);
      pFileFrom = manifest_file_next(pFrom, 0);
    }else if( cmp>0 ){
      append_file_change_line(pFileTo->zName, 
                              0, pFileTo->zUuid, 0, 0,
                              manifest_file_mperm(pFileTo));
      pFileTo = manifest_file_next(pTo, 0);
    }else if( fossil_strcmp(pFileFrom->zUuid, pFileTo->zUuid)==0 ){
      /* No changes */
      pFileFrom = manifest_file_next(pFrom, 0);
      pFileTo = manifest_file_next(pTo, 0);
    }else{
      append_file_change_line(pFileFrom->zName, 
                              pFileFrom->zUuid,
                              pFileTo->zUuid, 0, diffFlags,
                              manifest_file_mperm(pFileTo));
      pFileFrom = manifest_file_next(pFrom, 0);
      pFileTo = manifest_file_next(pTo, 0);
    }
  }
  manifest_destroy(pFrom);
  manifest_destroy(pTo);
................................................................................
void diff_page(void){
  int v1, v2;
  int isPatch;
  int sideBySide;
  Blob c1, c2, diff, *pOut;
  char *zV1;
  char *zV2;
  int diffFlags;
  const char *zStyle = "sbsdiff";

  login_check_credentials();
  if( !g.perm.Read ){ login_needed(); return; }
  v1 = name_to_rid_www("v1");
  v2 = name_to_rid_www("v2");
  if( v1==0 || v2==0 ) fossil_redirect_home();
  sideBySide = atoi(PD("sbs","1"));
  zV1 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v1);
  zV2 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v2);
  isPatch = P("patch")!=0;
  if( isPatch ){
    pOut = cgi_output_blob();
    cgi_set_content_type("text/plain");
    diffFlags = 4;
  }else{
    blob_zero(&diff);
    pOut = &diff;
    diffFlags = construct_diff_flags(1, sideBySide);
    if( sideBySide ){
      zStyle = "sbsdiff";
    }else{
      diffFlags |= DIFF_LINENO;
      zStyle = "udiff";
    }

  }
  content_get(v1, &c1);
  content_get(v2, &c2);
  text_diff(&c1, &c2, pOut, diffFlags | DIFF_HTML );
  blob_reset(&c1);
  blob_reset(&c2);

  if( !isPatch ){
    style_header("Diff");
    style_submenu_element("Patch", "Patch", "%s/fdiff?v1=%T&v2=%T&patch",
                          g.zTop, P("v1"), P("v2"));
    if( !sideBySide ){
      style_submenu_element("Side-by-side Diff", "sbsdiff",
                            "%s/fdiff?v1=%T&v2=%T&sbs=1",
................................................................................
                            g.zTop, P("v1"), P("v2"));
    }else{
      style_submenu_element("Unified Diff", "udiff",
                            "%s/fdiff?v1=%T&v2=%T&sbs=0",
                            g.zTop, P("v1"), P("v2"));
    }

    if( P("smhdr")!=0 ){
      @ <h2>Differences From Artifact
      @ <a href="%s(g.zTop)/artifact/%S(zV1)">[%S(zV1)]</a> To
      @ <a href="%s(g.zTop)/artifact/%S(zV2)">[%S(zV2)]</a>.</h2>
    }else{
      @ <h2>Differences From
      @ Artifact <a href="%s(g.zTop)/artifact/%S(zV1)">[%S(zV1)]</a>:</h2>
      object_description(v1, 0, 0);
      @ <h2>To Artifact
      @ <a href="%s(g.zTop)/artifact/%S(zV2)">[%S(zV2)]</a>:</h2>
      object_description(v2, 0, 0);
    }
    @ <hr />




    @ <div class="%s(zStyle)">
    @ %s(blob_str(&diff))


    @ </div>
    blob_reset(&diff);
    style_footer();
  }
}

/*
** WEBPAGE: raw

Changes to src/json.c.

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
..
93
94
95
96
97
98
99
100
101
102
103
104
105
106


107
108
109
110
111
112
113
...
171
172
173
174
175
176
177

178
179
180
181
182
183
184
...
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
...
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
...
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
...
520
521
522
523
524
525
526

527
528


529
530
531
532
533
534
535
...
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
...
579
580
581
582
583
584
585



586
587
588
589
590
591
592
593
594
595
596
...
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
...
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
...
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
....
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
....
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
....
1174
1175
1176
1177
1178
1179
1180







1181
1182
1183
1184
1185
1186
1187
....
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
....
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
....
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
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505

1506
1507
1508
1509
1510
1511
1512
1513
....
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
....
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
....
1755
1756
1757
1758
1759
1760
1761



1762
1763
1764
1765
1766
1767
1768
....
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784



1785
1786
1787
1788
1789
1790
1791
....
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
....
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903


1904
1905
1906
1907
1908
1909
1910
....
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
2028
2029
2030
2031
....
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
....
2199
2200
2201
2202
2203
2204
2205




2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216

2217
2218

2219
2220
2221
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
2259
2260




2261
2262
2263
2264
2265
2266
2267
2268
2269
2270



2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288



2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310

2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336




2337
2338
2339


2340
2341








2342

2343

2344

2345
2346


2347
2348
2349
2350
2351
2352

2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
....
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414


2415
2416
2417
2418
2419




2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
  "payload" /* payload */,
  "requestId" /*requestId*/,
  "resultCode" /*resultCode*/,
  "resultText" /*resultText*/,
  "timestamp" /*timestamp*/
};

/*
** Internal helpers to manipulate a byte array as a bitset. The B
** argument must be-a array at least (BIT/8+1) bytes long.
** The BIT argument is the bit number to query/set/clear/toggle.
*/
#define BITSET_BYTEFOR(B,BIT) ((B)[ BIT / 8 ])
#define BITSET_SET(B,BIT) ((BITSET_BYTEFOR(B,BIT) |= (0x01 << (BIT%8))),0x01)
#define BITSET_UNSET(B,BIT) ((BITSET_BYTEFOR(B,BIT) &= ~(0x01 << (BIT%8))),0x00)
#define BITSET_GET(B,BIT) ((BITSET_BYTEFOR(B,BIT) & (0x01 << (BIT%8))) ? 0x01 : 0x00)
#define BITSET_TOGGLE(B,BIT) (BITSET_GET(B,BIT) ? (BITSET_UNSET(B,BIT)) : (BITSET_SET(B,BIT)))


/* Timer code taken from sqlite3's shell.c, modified slightly.
   FIXME: move the timer into the fossil core API so that we can
   start the timer early on in the app init phase. Right now we're
   just timing the json ops themselves.
*/
#if !defined(_WIN32) && !defined(WIN32) && !defined(__OS2__) && !defined(__RTP__) && !defined(_WRS_KERNEL)
................................................................................

/*
** Print the timing results.
*/
static double endTimer(void){
  struct rusage sEnd;
  getrusage(RUSAGE_SELF, &sEnd);
  return timeDiff(&sBegin.ru_utime, &sEnd.ru_utime)
    + timeDiff(&sBegin.ru_stime, &sEnd.ru_stime);
#if 0
  printf("CPU Time: user %f sys %f\n",
         timeDiff(&sBegin.ru_utime, &sEnd.ru_utime),
         timeDiff(&sBegin.ru_stime, &sEnd.ru_stime));
#endif


}

#define BEGIN_TIMER beginTimer()
#define END_TIMER endTimer()
#define HAS_TIMER 1

#elif (defined(_WIN32) || defined(WIN32))
................................................................................
static double endTimer(void){
  if(getProcessTimesAddr){
    FILETIME ftCreation, ftExit, ftKernelEnd, ftUserEnd;
    getProcessTimesAddr(hProcess, &ftCreation, &ftExit, &ftKernelEnd, &ftUserEnd);
    return timeDiff(&ftUserBegin, &ftUserEnd) +
      timeDiff(&ftKernelBegin, &ftKernelEnd);
  }

}

#define BEGIN_TIMER beginTimer()
#define END_TIMER endTimer()
#define HAS_TIMER hasTimer()

#else
................................................................................
static char const * json_err_cstr( int errCode ){
  switch( errCode ){
    case 0: return "Success";
#define C(X,V) case FSL_JSON_E_ ## X: return V

    C(GENERIC,"Generic error");
    C(INVALID_REQUEST,"Invalid request");
    C(UNKNOWN_COMMAND,"Unknown Command");
    C(UNKNOWN,"Unknown error");
    C(TIMEOUT,"Timeout reached");
    C(ASSERT,"Assertion failed");
    C(ALLOC,"Resource allocation failed");
    C(NYI,"Not yet implemented");
    C(PANIC,"x");
    C(MANIFEST_READ_FAILED,"Reading artifact manifest failed");
................................................................................
  }else{
    char const * cv = PD(zKey,NULL);
    if(!cv && !g.isHTTP){
      /* reminder to self: in CLI mode i'd like to try
         find_option(zKey,NULL,XYZ) here, but we don't have a sane
         default for the XYZ param here.
      */
      cv = getenv(zKey);
    }
    if(cv){/*transform it to JSON for later use.*/
      /* use sscanf() to figure out if it's an int,
         and transform it to JSON int if it is.

         FIXME: use strtol(), since it has more accurate
         error handling.
................................................................................
}


/*
** Wrapper around json_getenv() which tries to evaluate a payload/env
** value as a boolean. Uses mostly the same logic as
** json_getenv_int(), with the addition that string values which
** either start with a digit 1..9 or the letters [tT] are considered
** to be true. If this function cannot find a matching key/value then
** dflt is returned. e.g. if it finds the key but the value is-a
** Object then dftl is returned.
**
** If an entry is found, this function guarantees that it will return
** either 0 or 1, as opposed to "0 or non-zero", so that clients can
** pass a different value as dflt. Thus they can use, e.g. -1 to know
................................................................................
  }else if( cson_value_is_number(v) ){
    return cson_value_get_integer(v) ? 1 : 0;
  }else if( cson_value_is_string(v) ){
    char const * sv = cson_string_cstr(cson_value_get_string(v));
    if(!*sv || ('0'==*sv)){
      return 0;
    }else{

      return (('t'==*sv) || ('T'==*sv)
              || (('1'<=*sv) && ('9'>=*sv)))


        ? 1 : 0;
    }
  }else if( cson_value_is_bool(v) ){
    return cson_value_get_bool(v) ? 1 : 0;
  }else if( cson_value_is_null(v) ){
    return 0;
  }else{
................................................................................
}

/*
** An extended form of find_option() which tries to look up a combo
** GET/POST/CLI argument.
**
** zKey must be the GET/POST parameter key. zCLILong must be the "long
** form" CLI flag (NULL means to use zKey). zCLIShort may be NULL or
** the "short form" CLI flag (if NULL, no short form is used).
**
** If argPos is >=0 and no other match is found,
** json_command_arg(argPos) is also checked.
**
** On error (no match found) NULL is returned.
**
................................................................................
  }
  if(!rc && (argPos>=0)){
    rc = json_command_arg((unsigned char)argPos);
  }
  return rc;
}




char const * json_find_option_cstr(char const * zKey,
                                   char const * zCLILong,
                                   char const * zCLIShort){
  return json_find_option_cstr2(zKey, zCLIShort, zCLIShort, -1);
}

/*
** The boolean equivalent of json_find_option_cstr().
** If the option is not found, dftl is returned.
*/
char json_find_option_bool(char const * zKey,
................................................................................
  if((-1==rc) && fossil_has_json()){
    rc = json_getenv_bool(zKey,-1);
  }
  return (-1==rc) ? dflt : rc;
}

/*
** The integer equivalent of json_find_option_cstr().
** If the option is not found, dftl is returned.
*/
int json_find_option_int(char const * zKey,
                         char const * zCLILong,
                         char const * zCLIShort,
                         int dflt ){
  enum { Magic = -947 };
  int rc = Magic;
  if(!g.isHTTP){
    /* FIXME: use strtol() for better error/dflt handling. */
    char const * opt = find_option(zCLILong ? zCLILong : zKey,
                                   zCLIShort, 1);
    if(NULL!=opt){
      rc = atoi(opt);
................................................................................
                       char separator,
                       char doDeHttp,
                       cson_array * target ){
  char const * p = zStr /* current byte */;
  char const * head  /* current start-of-token */;
  unsigned int len = 0   /* current token's length */;
  int rc = 0   /* return code (number of added elements)*/;
  char skipWs = fossil_isspace(separator) ? 0 : 1;
  assert( zStr && target );
  while( fossil_isspace(*p) ){
    ++p;
  }
  head = p;
  for( ; ; ++p){
    if( !*p || (separator == *p) ){
................................................................................
/*
** Wrapper around json_string_split(), taking the same first 3
** parameters as this function, but returns the results as a JSON
** Array (if splitting produced tokens) or NULL (if splitting failed
** in any way or produced no tokens).
**
** The returned value is owned by the caller. If not NULL then it
** _will_ have a JSON type of Array or Null.
*/
cson_value * json_string_split2( char const * zStr,
                                 char separator,
                                 char doDeHttp ){
  cson_value * v = cson_value_new_array();
  cson_array * a = cson_value_get_array(v);
  int rc = json_string_split( zStr, separator, doDeHttp, a );
................................................................................
** before they do any work.
**
** This must only be called once, or an assertion may be triggered.
*/
static void json_mode_bootstrap(){
  static char once = 0  /* guard against multiple runs */;
  char const * zPath = P("PATH_INFO");
  cson_value * pathSplit = NULL;
  assert( (0==once) && "json_mode_bootstrap() called too many times!");
  if( once ){
    return;
  }else{
    once = 1;
  }
  g.json.isJsonMode = 1;
................................................................................
  }
  if(!g.isHTTP){
    g.json.errorDetailParanoia = 0 /*disable error code dumb-down for CLI mode*/;
  }

  {/* set up JSON output formatting options. */
    int indent = -1;
    char const * indentStr = NULL;
    indent = json_find_option_int("indent",NULL,"I",-1);
    g.json.outOpt.indentation = (0>indent)
      ? (g.isHTTP ? 0 : 1)
      : (unsigned char)indent;
    g.json.outOpt.addNewline = g.isHTTP
      ? 0
      : (g.json.jsonp ? 0 : 1);
................................................................................
  if( g.isHTTP ){
    json_auth_token()/* will copy our auth token, if any, to fossil's
                        core, which we need before we call
                        login_check_credentials(). */;
    login_check_credentials()/* populates g.perm */;
  }
  else{







    db_find_and_open_repository(OPEN_ANY_SCHEMA,0);
  }
}

/*
** Returns the ndx'th item in the "command path", where index 0 is the
** position of the "json" part of the path. Returns NULL if ndx is out
................................................................................
    return code;
  }
}

/*
** Convenience routine which converts a Julian time value into a Unix
** Epoch timestamp. Requires the db, so this cannot be used before the
** repo is opened (will trigger a fatal error in db_xxx()).

*/
cson_value * json_julian_to_timestamp(double j){
  return cson_value_new_integer((cson_int_t)
           db_int64(0,"SELECT cast(strftime('%%s',%lf) as int)",j)
                                );
}

/*
** Returns a timestamp value.
*/
cson_int_t json_timestamp(){
  return (cson_int_t)time(0);
}

/*
** Returns a new JSON value (owned by the caller) representing
** a timestamp. If timeVal is < 0 then time(0) is used to fetch
** the time, else timeVal is used as-is

*/
cson_value * json_new_timestamp(cson_int_t timeVal){
  return cson_value_new_integer((timeVal<0) ? (cson_int_t)time(0) : timeVal);
}

/*
** Internal helper for json_create_response(). Appends the first
................................................................................
*/
static cson_value * json_response_command_path(){
  if(!g.json.cmd.a){
    return NULL;
  }else{
    cson_value * rc = NULL;
    Blob path = empty_blob;
    char const * part;
    unsigned int aLen = g.json.dispatchDepth+1; /*cson_array_length_get(g.json.cmd.a);*/
    unsigned int i = 1;
    for( ; i < aLen; ++i ){
      char const * part = cson_string_cstr(cson_value_get_string(cson_array_get(g.json.cmd.a, i)));
      if(!part){
        fossil_warning("Iterating further than expected in %s.",
                       __FILE__);
................................................................................
/*
** Creates a new Fossil/JSON response envelope skeleton.  It is owned
** by the caller, who must eventually free it using cson_value_free(),
** or add it to a cson container to transfer ownership. Returns NULL
** on error.
**
** If payload is not NULL and resultCode is 0 then it is set as the
** "payload" property of the returned object.  If resultCode is

** non-zero and payload is not NULL then this function calls
** cson_value_free(payload) and does not insert the payload into the
** response. In either case, onwership of payload is transfered to (or
** shared with, if the caller holds a reference) this function.
**
** pMsg is an optional message string property (resultText) of the
** response. If resultCode is non-0 and pMsg is NULL then
** json_err_cstr() is used to get the error string. The caller may
** provide his own or may use an empty string to suppress the
** resultText property.
**
*/
cson_value * json_create_response( int resultCode,
                                   char const * pMsg,
                                   cson_value * payload){
  cson_value * v = NULL;
  cson_value * tmp = NULL;
  cson_object * o = NULL;
  int rc;
  resultCode = json_dumbdown_rc(resultCode);
  o = cson_new_object();
  v = cson_object_value(o);
  if( ! o ) return NULL;
#define SET(K) if(!tmp) goto cleanup; \
  rc = cson_object_set( o, K, tmp ); \
  if(rc) do{\
    cson_value_free(tmp); \
    tmp = NULL; \
    goto cleanup; \
  }while(0)


  tmp = cson_value_new_string(MANIFEST_UUID,strlen(MANIFEST_UUID));
  SET("fossil");

  tmp = json_new_timestamp(-1);
  SET(FossilJsonKeys.timestamp);

  if( 0 != resultCode ){
    if( ! pMsg ){
................................................................................
** the cgi_xxx() family of functions, this function inherits any
** compression which fossil does for its output.
**
** If alsoOutput is true AND g.isHTTP then cgi_reply() is called to
** flush the output (and headers). Generally only do this if you are
** about to call exit().
**
** !g.isHTTP then alsoOutput is ignored and all output is sent to
** stdout immediately.
**
** For generating the resultText property: if msg is not NULL then it
** is used as-is. If it is NULL then g.zErrMsg is checked, and if that
** is NULL then json_err_cstr(code) is used.
*/
void json_err( int code, char const * msg, char alsoOutput ){
................................................................................
    if(!a){
      a = cson_new_array();
      assert(NULL!=a);
    }
    if(!colNames){
      colNamesV = cson_sqlite3_column_names(pStmt->pStmt);
      assert(NULL != colNamesV);
      cson_value_add_reference(colNamesV);
      colNames = cson_value_get_array(colNamesV);
      assert(NULL != colNames);
    }      
    row = cson_sqlite3_row_to_object2(pStmt->pStmt, colNames);
    if(!row && !warnMsg){
      warnMsg = "Could not convert at least one result row to JSON.";
      continue;
................................................................................
** Executes the given SQL and runs it through
** json_stmt_to_array_of_obj(), returning the result of that
** function. If resetBlob is true then blob_reset(pSql) is called
** after preparing the query.
**
** pTgt has the same semantics as described for
** json_stmt_to_array_of_obj().



*/
cson_value * json_sql_to_array_of_obj(Blob * pSql, cson_array * pTgt,
                                      char resetBlob){
  Stmt q = empty_Stmt;
  cson_value * pay = NULL;
  assert( blob_size(pSql) > 0 );
  db_prepare(&q, "%s", blob_str(pSql));
................................................................................
  db_finalize(&q);
  return pay;

}

/*
** If the given COMMIT rid has any tags associated with it, this
** function returns a JSON Array containing the tag names, else it
** returns NULL.
**
** See info_tags_of_checkin() for more details (this is simply a JSON
** wrapper for that function).



*/
cson_value * json_tags_for_checkin_rid(int rid, char propagatingOnly){
  cson_value * v = NULL;
  char * tags = info_tags_of_checkin(rid, propagatingOnly);
  if(tags){
    if(*tags){
      v = json_string_split2(tags,',',0);
................................................................................
    cson_array * list = cson_value_get_array(listV);
    cson_value * objV = NULL;
    cson_object * obj = NULL;
    cson_string * kRC;
    cson_string * kSymbol;
    cson_string * kNumber;
    cson_string * kDesc;
    int rc = cson_array_reserve( list, 35 );
    if(rc){
        assert( 0 && "Allocation error.");
        exit(1);
    }
    kRC = cson_new_string("resultCode",10);
    kSymbol = cson_new_string("cSymbol",7);
    kNumber = cson_new_string("number",6);
    kDesc = cson_new_string("description",11);
#define C(K) objV = cson_value_new_object(); obj = cson_value_get_object(objV); \
    cson_object_set_s(obj, kRC, json_new_string(json_rc_cstr(FSL_JSON_E_##K)) ); \
    cson_object_set_s(obj, kSymbol, json_new_string("FSL_JSON_E_"#K) );             \
................................................................................
  jobj = cson_value_get_object(jval);
#define FSET(X,K) cson_object_set( jobj, K, cson_value_new_string(X,strlen(X)))
  FSET(MANIFEST_UUID,"manifestUuid");
  FSET(MANIFEST_VERSION,"manifestVersion");
  FSET(MANIFEST_DATE,"manifestDate");
  FSET(MANIFEST_YEAR,"manifestYear");
  FSET(RELEASE_VERSION,"releaseVersion");
#undef FSET
  cson_object_set( jobj, "releaseVersionNumber",
                   cson_value_new_integer(RELEASE_VERSION_NUMBER) );
  cson_object_set( jobj, "resultCodeParanoiaLevel",
                   cson_value_new_integer(g.json.errorDetailParanoia) );


  return jval;
}


/*
** Returns the current user's capabilities string as a String value.
** Returned value is owned by the caller, and will only be NULL if
................................................................................
  const char *zDb;
  enum { BufLen = 1000 };
  char zBuf[BufLen];
  cson_value * jv = NULL;
  cson_object * jo = NULL;
  cson_value * jv2 = NULL;
  cson_object * jo2 = NULL;

  if( !g.perm.Read ){
    json_set_err(FSL_JSON_E_DENIED,
                 "Requires 'o' permissions.");
    return NULL;
  }
  full = json_find_option_bool("full",NULL,"f",0);
#define SETBUF(O,K) cson_object_set(O, K, cson_value_new_string(zBuf, strlen(zBuf)));

  jv = cson_value_new_object();
  jo = cson_value_get_object(jv);

  sqlite3_snprintf(BufLen, zBuf, db_get("project-name",""));
  SETBUF(jo, "projectName");
  /* FIXME: don't include project-description until we ensure that
     zBuf will always be big enough. We "should" replace zBuf
     with a blob for this purpose.
  */


  fsize = file_size(g.zRepositoryName);
  cson_object_set(jo, "repositorySize", cson_value_new_integer((cson_int_t)fsize));

  if(full){
    n = db_int(0, "SELECT count(*) FROM blob");
    m = db_int(0, "SELECT count(*) FROM delta");
    cson_object_set(jo, "blobCount", cson_value_new_integer((cson_int_t)n));
................................................................................
    if((zPages+1)->name){
      blob_append(pOut, ", ",2);
    }
  }
  return i;
}


























cson_value * json_page_dispatch_helper(JsonPageDef const * pages){
  JsonPageDef const * def;
  char const * cmd = json_command_arg(1+g.json.dispatchDepth);
  assert( NULL != pages );
  if( ! cmd ){
    Blob cmdNames = empty_blob;
    json_pagedefs_to_string(pages, &cmdNames);
    json_set_err(FSL_JSON_E_MISSING_ARGS,
                 "No subcommand specified. Try one of (%s).",
                 blob_str(&cmdNames));
    blob_reset(&cmdNames);

    return NULL;
  }
  def = json_handler_for_name( cmd, pages );
  if(!def){
    g.json.resultCode = FSL_JSON_E_UNKNOWN_COMMAND;

    return NULL;
  }
  else{
    ++g.json.dispatchDepth;
    return (*def->func)();
  }
}
................................................................................
cson_value * json_page_query();
/* Impl in json_report.c. */
cson_value * json_page_report();
/* Impl in json_tag.c. */
cson_value * json_page_tag();
/* Impl in json_user.c. */
cson_value * json_page_user();





/*
** Mapping of names to JSON pages/commands.  Each name is a subpath of
** /json (in CGI mode) or a subcommand of the json command in CLI mode
*/
static const JsonPageDef JsonPageDefs[] = {
/* please keep alphabetically sorted (case-insensitive) for maintenance reasons. */
{"anonymousPassword", json_page_anon_password, 0},
{"artifact", json_page_artifact, 0},
{"branch", json_page_branch,0},
{"cap", json_page_cap, 0},

{"diff", json_page_diff, 0},
{"dir", json_page_nyi, 0},

{"g", json_page_g, 0},
{"HAI",json_page_version,0},
{"login",json_page_login,0},
{"logout",json_page_logout,0},
{"query",json_page_query,0},
{"rebuild",json_page_rebuild,0},
{"report", json_page_report, 0},
{"resultCodes", json_page_resultCodes,0},
{"stat",json_page_stat,0},
{"tag", json_page_tag,0},
{"ticket", json_page_nyi,0},
{"timeline", json_page_timeline,0},
{"user",json_page_user,0},
{"version",json_page_version,0},
{"whoami",json_page_whoami,0},
{"wiki",json_page_wiki,0},
/* Last entry MUST have a NULL name. */
{NULL,NULL,0}
};


/*

** Mapping of /json/ticket/XXX commands/paths to callbacks.




*/
static const JsonPageDef JsonPageDefs_Ticket[] = {
{"get", json_page_nyi, 0},
{"list", json_page_nyi, 0},
{"save", json_page_nyi, 1},
{"create", json_page_nyi, 1},
/* Last entry MUST have a NULL name. */
{NULL,NULL,0}
};













/*
** Mapping of /json/artifact/XXX commands/paths to callbacks.
*/
static const JsonPageDef JsonPageDefs_Artifact[] = {
{"vinfo", json_page_nyi, 0},
{"finfo", json_page_nyi, 0},
/* Last entry MUST have a NULL name. */
{NULL,NULL,0}
};





/*
** Mapping of /json/tag/XXX commands/paths to callbacks.
*/
static const JsonPageDef JsonPageDefs_Tag[] = {
{"list", json_page_nyi, 0},
{"create", json_page_nyi, 1},
/* Last entry MUST have a NULL name. */
{NULL,NULL,0}
};





#ifdef FOSSIL_ENABLE_JSON /* dupe ifdef needed for mkindex */
/*
** WEBPAGE: json
**
** Pages under /json/... must be entered into JsonPageDefs.
** This function dispatches them, and is the HTTP equivalent of
** json_cmd_top().
*/
void json_page_top(void){
  int rc = FSL_JSON_E_UNKNOWN_COMMAND;
  char const * cmd;
  cson_value * payload = NULL;
  JsonPageDef const * pageDef = NULL;
  BEGIN_TIMER;
  json_mode_bootstrap();
  cmd = json_command_arg(1);



  if(!cmd || !*cmd){
    goto usage;
  }
  /*cgi_printf("{\"cmd\":\"%s\"}\n",cmd); return;*/
  pageDef = json_handler_for_name(cmd,&JsonPageDefs[0]);
  if( ! pageDef ){
    json_err( FSL_JSON_E_UNKNOWN_COMMAND, NULL, 0 );
    return;
  }else if( pageDef->runMode < 0 /*CLI only*/){
    rc = FSL_JSON_E_WRONG_MODE;
  }else{
    rc = 0;
    g.json.dispatchDepth = 1;
    payload = (*pageDef->func)();
  }
  if( g.json.resultCode ){
    cson_value_free(payload);
    json_err(g.json.resultCode, NULL, 0);
  }else{
    cson_value * root = json_create_response(rc, NULL, payload);
    json_send_response(root);
    cson_value_free(root);

  }

  return;
  usage:
  {
    Blob cmdNames = empty_blob;
    blob_init(&cmdNames,
              "No command (sub-path) specified. Try one of: ",
              -1);
    json_pagedefs_to_string(&JsonPageDefs[0], &cmdNames);
    json_err(FSL_JSON_E_MISSING_ARGS,
             blob_str(&cmdNames), 0);
    blob_reset(&cmdNames);
  }

}
#endif /* FOSSIL_ENABLE_JSON */

#ifdef FOSSIL_ENABLE_JSON /* dupe ifdef needed for mkindex */
/*
** This function dispatches json commands and is the CLI equivalent of
** json_page_top().
**
** COMMAND: json
**
** Usage: %fossil json SUBCOMMAND




**
** The commands include:
**


**   branch
**   cap








**   stat

**   timeline

**   version (alias: HAI)

**   wiki
**


**
** TODOs:
**
**   tag
**   ticket
**   ...

**
*/
void json_cmd_top(void){
  char const * cmd = NULL;
  int rc = FSL_JSON_E_UNKNOWN_COMMAND;
  cson_value * payload = NULL;
  JsonPageDef const * pageDef;
  BEGIN_TIMER;
  memset( &g.perm, 0xff, sizeof(g.perm) )
    /* In CLI mode fossil does not use permissions
       and they all default to false. We enable them
       here because (A) fossil doesn't use them in local
       mode but (B) having them set gives us one less
       difference in the CLI/CGI/Server-mode JSON
................................................................................
    */
    ;
  json_main_bootstrap();
  json_mode_bootstrap();
  if( 2 > cson_array_length_get(g.json.cmd.a) ){
    goto usage;
  }
  db_find_and_open_repository(0, 0);
#if 0
  json_warn(FSL_JSON_W_ROW_TO_JSON_FAILED, "Just testing.");
  json_warn(FSL_JSON_W_ROW_TO_JSON_FAILED, "Just testing again.");
#endif
  cmd = json_command_arg(1);
  if( !cmd || !*cmd ){
    goto usage;
  }
  pageDef = json_handler_for_name(cmd,&JsonPageDefs[0]);
  if( ! pageDef ){
    json_err( FSL_JSON_E_UNKNOWN_COMMAND, NULL, 1 );
    return;
  }else if( pageDef->runMode > 0 /*HTTP only*/){
    rc = FSL_JSON_E_WRONG_MODE;
  }else{
    rc = 0;
    g.json.dispatchDepth = 1;
    payload = (*pageDef->func)();
  }
  if( g.json.resultCode ){
    cson_value_free(payload);
    json_err(g.json.resultCode, NULL, 1);
  }else{
    payload = json_create_response(rc, NULL, payload);
    json_send_response(payload);
    cson_value_free( payload );
    if((0 != rc) && !g.isHTTP){
      /* FIXME: we need a way of passing this error back
         up to the routine which called this callback.
         e.g. add g.errCode.
      */
      fossil_exit(1);
    }
  }
  return;
  usage:
  {
    Blob cmdNames = empty_blob;
    blob_init(&cmdNames,


              "No subcommand specified. Try one of: ", -1);
    json_pagedefs_to_string(&JsonPageDefs[0], &cmdNames);
    json_err(FSL_JSON_E_MISSING_ARGS,
             blob_str(&cmdNames), 1);
    blob_reset(&cmdNames);




    fossil_exit(1);
  }
}
#endif /* FOSSIL_ENABLE_JSON */

#undef BITSET_BYTEFOR
#undef BITSET_SET
#undef BITSET_UNSET
#undef BITSET_GET
#undef BITSET_TOGGLE
#endif /* FOSSIL_ENABLE_JSON */







<
<
<
<
<
<
<
<
<
<
<







 







<
<





>
>







 







>







 







|







 







|







 







|







 







>
|
<
>
>







 







|







 







>
>
>



|







 







|






|







 







<







 







|







 







<







 







<







 







>
>
>
>
>
>
>







 







|
>













>



|
>







 







<







 







|
>












|
|
|




|











>
|







 







|







 







|







 







>
>
>







 







|
|



>
>
>







 







|
<
<
<
<







 







<




>
>







 







>











|
|
|
|
|
<
>
>







 







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






|
<
<
|
<
<
>




|
>







 







>
>
>
>











>

|
>










|









<

>
|
>
>
>
>

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










<
|
<
<


|
>
>
>
|
<
<
<
<
<
<

<
<
<
<
<
<

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








|
>
>
>
>



>
>


>
>
>
>
>
>
>
>

>

>

>


>
>

<
<
<
<
<
>




|
<
<







 







<








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



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



|

<
<
<
<
<

50
51
52
53
54
55
56











57
58
59
60
61
62
63
..
82
83
84
85
86
87
88


89
90
91
92
93
94
95
96
97
98
99
100
101
102
...
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
...
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
...
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
...
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
...
510
511
512
513
514
515
516
517
518

519
520
521
522
523
524
525
526
527
...
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
...
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
...
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
...
913
914
915
916
917
918
919

920
921
922
923
924
925
926
...
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
....
1015
1016
1017
1018
1019
1020
1021

1022
1023
1024
1025
1026
1027
1028
....
1150
1151
1152
1153
1154
1155
1156

1157
1158
1159
1160
1161
1162
1163
....
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
....
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
....
1336
1337
1338
1339
1340
1341
1342

1343
1344
1345
1346
1347
1348
1349
....
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
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
....
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
....
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
....
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
....
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
....
1826
1827
1828
1829
1830
1831
1832
1833




1834
1835
1836
1837
1838
1839
1840
....
1897
1898
1899
1900
1901
1902
1903

1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
....
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030

2031
2032
2033
2034
2035
2036
2037
2038
2039
....
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
....
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
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274

2275
2276
2277
2278
2279
2280
2281
2282




2283
2284
2285

2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298









2299
2300
2301
2302
2303






2304


2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318

2319


2320
2321
2322
2323
2324
2325
2326






2327






2328







2329
2330















2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370





2371
2372
2373
2374
2375
2376


2377
2378
2379
2380
2381
2382
2383
....
2385
2386
2387
2388
2389
2390
2391

2392
2393
2394
2395
2396
2397
2398
2399
2400

















2401
2402
2403
2404
2405
2406
2407

2408
2409
2410


2411
2412
2413




2414
2415
2416
2417
2418
2419
2420
2421
2422





2423
  "payload" /* payload */,
  "requestId" /*requestId*/,
  "resultCode" /*resultCode*/,
  "resultText" /*resultText*/,
  "timestamp" /*timestamp*/
};













/* Timer code taken from sqlite3's shell.c, modified slightly.
   FIXME: move the timer into the fossil core API so that we can
   start the timer early on in the app init phase. Right now we're
   just timing the json ops themselves.
*/
#if !defined(_WIN32) && !defined(WIN32) && !defined(__OS2__) && !defined(__RTP__) && !defined(_WRS_KERNEL)
................................................................................

/*
** Print the timing results.
*/
static double endTimer(void){
  struct rusage sEnd;
  getrusage(RUSAGE_SELF, &sEnd);


#if 0
  printf("CPU Time: user %f sys %f\n",
         timeDiff(&sBegin.ru_utime, &sEnd.ru_utime),
         timeDiff(&sBegin.ru_stime, &sEnd.ru_stime));
#endif
  return timeDiff(&sBegin.ru_utime, &sEnd.ru_utime)
    + timeDiff(&sBegin.ru_stime, &sEnd.ru_stime);
}

#define BEGIN_TIMER beginTimer()
#define END_TIMER endTimer()
#define HAS_TIMER 1

#elif (defined(_WIN32) || defined(WIN32))
................................................................................
static double endTimer(void){
  if(getProcessTimesAddr){
    FILETIME ftCreation, ftExit, ftKernelEnd, ftUserEnd;
    getProcessTimesAddr(hProcess, &ftCreation, &ftExit, &ftKernelEnd, &ftUserEnd);
    return timeDiff(&ftUserBegin, &ftUserEnd) +
      timeDiff(&ftKernelBegin, &ftKernelEnd);
  }
  return 0.0;
}

#define BEGIN_TIMER beginTimer()
#define END_TIMER endTimer()
#define HAS_TIMER hasTimer()

#else
................................................................................
static char const * json_err_cstr( int errCode ){
  switch( errCode ){
    case 0: return "Success";
#define C(X,V) case FSL_JSON_E_ ## X: return V

    C(GENERIC,"Generic error");
    C(INVALID_REQUEST,"Invalid request");
    C(UNKNOWN_COMMAND,"Unknown command or subcommand");
    C(UNKNOWN,"Unknown error");
    C(TIMEOUT,"Timeout reached");
    C(ASSERT,"Assertion failed");
    C(ALLOC,"Resource allocation failed");
    C(NYI,"Not yet implemented");
    C(PANIC,"x");
    C(MANIFEST_READ_FAILED,"Reading artifact manifest failed");
................................................................................
  }else{
    char const * cv = PD(zKey,NULL);
    if(!cv && !g.isHTTP){
      /* reminder to self: in CLI mode i'd like to try
         find_option(zKey,NULL,XYZ) here, but we don't have a sane
         default for the XYZ param here.
      */
      cv = fossil_getenv(zKey);
    }
    if(cv){/*transform it to JSON for later use.*/
      /* use sscanf() to figure out if it's an int,
         and transform it to JSON int if it is.

         FIXME: use strtol(), since it has more accurate
         error handling.
................................................................................
}


/*
** Wrapper around json_getenv() which tries to evaluate a payload/env
** value as a boolean. Uses mostly the same logic as
** json_getenv_int(), with the addition that string values which
** either start with a digit 1..9 or the letters [tTyY] are considered
** to be true. If this function cannot find a matching key/value then
** dflt is returned. e.g. if it finds the key but the value is-a
** Object then dftl is returned.
**
** If an entry is found, this function guarantees that it will return
** either 0 or 1, as opposed to "0 or non-zero", so that clients can
** pass a different value as dflt. Thus they can use, e.g. -1 to know
................................................................................
  }else if( cson_value_is_number(v) ){
    return cson_value_get_integer(v) ? 1 : 0;
  }else if( cson_value_is_string(v) ){
    char const * sv = cson_string_cstr(cson_value_get_string(v));
    if(!*sv || ('0'==*sv)){
      return 0;
    }else{
      return ((('1'<=*sv) && ('9'>=*sv))
              || ('t'==*sv) || ('T'==*sv)

              || ('y'==*sv) || ('Y'==*sv)
              )
        ? 1 : 0;
    }
  }else if( cson_value_is_bool(v) ){
    return cson_value_get_bool(v) ? 1 : 0;
  }else if( cson_value_is_null(v) ){
    return 0;
  }else{
................................................................................
}

/*
** An extended form of find_option() which tries to look up a combo
** GET/POST/CLI argument.
**
** zKey must be the GET/POST parameter key. zCLILong must be the "long
s** form" CLI flag (NULL means to use zKey). zCLIShort may be NULL or
** the "short form" CLI flag (if NULL, no short form is used).
**
** If argPos is >=0 and no other match is found,
** json_command_arg(argPos) is also checked.
**
** On error (no match found) NULL is returned.
**
................................................................................
  }
  if(!rc && (argPos>=0)){
    rc = json_command_arg((unsigned char)argPos);
  }
  return rc;
}

/*
** Short-hand form of json_find_option_cstr2(zKey,zCLILong,zCLIShort,-1).
*/
char const * json_find_option_cstr(char const * zKey,
                                   char const * zCLILong,
                                   char const * zCLIShort){
  return json_find_option_cstr2(zKey, zCLILong, zCLIShort, -1);
}

/*
** The boolean equivalent of json_find_option_cstr().
** If the option is not found, dftl is returned.
*/
char json_find_option_bool(char const * zKey,
................................................................................
  if((-1==rc) && fossil_has_json()){
    rc = json_getenv_bool(zKey,-1);
  }
  return (-1==rc) ? dflt : rc;
}

/*
** The integer equivalent of json_find_option_cstr2().
** If the option is not found, dftl is returned.
*/
int json_find_option_int(char const * zKey,
                         char const * zCLILong,
                         char const * zCLIShort,
                         int dflt ){
  enum { Magic = -1947854832 };
  int rc = Magic;
  if(!g.isHTTP){
    /* FIXME: use strtol() for better error/dflt handling. */
    char const * opt = find_option(zCLILong ? zCLILong : zKey,
                                   zCLIShort, 1);
    if(NULL!=opt){
      rc = atoi(opt);
................................................................................
                       char separator,
                       char doDeHttp,
                       cson_array * target ){
  char const * p = zStr /* current byte */;
  char const * head  /* current start-of-token */;
  unsigned int len = 0   /* current token's length */;
  int rc = 0   /* return code (number of added elements)*/;

  assert( zStr && target );
  while( fossil_isspace(*p) ){
    ++p;
  }
  head = p;
  for( ; ; ++p){
    if( !*p || (separator == *p) ){
................................................................................
/*
** Wrapper around json_string_split(), taking the same first 3
** parameters as this function, but returns the results as a JSON
** Array (if splitting produced tokens) or NULL (if splitting failed
** in any way or produced no tokens).
**
** The returned value is owned by the caller. If not NULL then it
** _will_ have a JSON type of Array.
*/
cson_value * json_string_split2( char const * zStr,
                                 char separator,
                                 char doDeHttp ){
  cson_value * v = cson_value_new_array();
  cson_array * a = cson_value_get_array(v);
  int rc = json_string_split( zStr, separator, doDeHttp, a );
................................................................................
** before they do any work.
**
** This must only be called once, or an assertion may be triggered.
*/
static void json_mode_bootstrap(){
  static char once = 0  /* guard against multiple runs */;
  char const * zPath = P("PATH_INFO");

  assert( (0==once) && "json_mode_bootstrap() called too many times!");
  if( once ){
    return;
  }else{
    once = 1;
  }
  g.json.isJsonMode = 1;
................................................................................
  }
  if(!g.isHTTP){
    g.json.errorDetailParanoia = 0 /*disable error code dumb-down for CLI mode*/;
  }

  {/* set up JSON output formatting options. */
    int indent = -1;

    indent = json_find_option_int("indent",NULL,"I",-1);
    g.json.outOpt.indentation = (0>indent)
      ? (g.isHTTP ? 0 : 1)
      : (unsigned char)indent;
    g.json.outOpt.addNewline = g.isHTTP
      ? 0
      : (g.json.jsonp ? 0 : 1);
................................................................................
  if( g.isHTTP ){
    json_auth_token()/* will copy our auth token, if any, to fossil's
                        core, which we need before we call
                        login_check_credentials(). */;
    login_check_credentials()/* populates g.perm */;
  }
  else{
    /* FIXME: we need an option which allows us to skip this. At least
       one known command (/json/version) does not need an opened
       repo. The problem here is we cannot know which functions need
       it from here (because command dispatching hasn't yet happened)
       and all other commands rely on the repo being opened before
       they are called. A textbook example of lack of foresight :/.
     */
    db_find_and_open_repository(OPEN_ANY_SCHEMA,0);
  }
}

/*
** Returns the ndx'th item in the "command path", where index 0 is the
** position of the "json" part of the path. Returns NULL if ndx is out
................................................................................
    return code;
  }
}

/*
** Convenience routine which converts a Julian time value into a Unix
** Epoch timestamp. Requires the db, so this cannot be used before the
** repo is opened (will trigger a fatal error in db_xxx()). The returned
** value is owned by the caller.
*/
cson_value * json_julian_to_timestamp(double j){
  return cson_value_new_integer((cson_int_t)
           db_int64(0,"SELECT cast(strftime('%%s',%lf) as int)",j)
                                );
}

/*
** Returns a timestamp value.
*/
cson_int_t json_timestamp(){
  return (cson_int_t)time(0);
}

/*
** Returns a new JSON value (owned by the caller) representing
** a timestamp. If timeVal is < 0 then time(0) is used to fetch
** the time, else timeVal is used as-is. The returned value is
** owned by the caller.
*/
cson_value * json_new_timestamp(cson_int_t timeVal){
  return cson_value_new_integer((timeVal<0) ? (cson_int_t)time(0) : timeVal);
}

/*
** Internal helper for json_create_response(). Appends the first
................................................................................
*/
static cson_value * json_response_command_path(){
  if(!g.json.cmd.a){
    return NULL;
  }else{
    cson_value * rc = NULL;
    Blob path = empty_blob;

    unsigned int aLen = g.json.dispatchDepth+1; /*cson_array_length_get(g.json.cmd.a);*/
    unsigned int i = 1;
    for( ; i < aLen; ++i ){
      char const * part = cson_string_cstr(cson_value_get_string(cson_array_get(g.json.cmd.a, i)));
      if(!part){
        fossil_warning("Iterating further than expected in %s.",
                       __FILE__);
................................................................................
/*
** Creates a new Fossil/JSON response envelope skeleton.  It is owned
** by the caller, who must eventually free it using cson_value_free(),
** or add it to a cson container to transfer ownership. Returns NULL
** on error.
**
** If payload is not NULL and resultCode is 0 then it is set as the
** "payload" property of the returned object.  If resultCode is 0 then
** it defaults to g.json.resultCode. If resultCode is (or defaults to)
** non-zero and payload is not NULL then this function calls
** cson_value_free(payload) and does not insert the payload into the
** response. In either case, onwership of payload is transfered to (or
** shared with, if the caller holds a reference) this function.
**
** pMsg is an optional message string property (resultText) of the
** response. If resultCode is non-0 and pMsg is NULL then
** json_err_cstr() is used to get the error string. The caller may
** provide his own or may use an empty string to suppress the
** resultText property.
**
*/
static cson_value * json_create_response( int resultCode,
                                          char const * pMsg,
                                          cson_value * payload){
  cson_value * v = NULL;
  cson_value * tmp = NULL;
  cson_object * o = NULL;
  int rc;
  resultCode = json_dumbdown_rc(resultCode ? resultCode : g.json.resultCode);
  o = cson_new_object();
  v = cson_object_value(o);
  if( ! o ) return NULL;
#define SET(K) if(!tmp) goto cleanup; \
  rc = cson_object_set( o, K, tmp ); \
  if(rc) do{\
    cson_value_free(tmp); \
    tmp = NULL; \
    goto cleanup; \
  }while(0)

  
  tmp = json_new_string(MANIFEST_UUID);
  SET("fossil");

  tmp = json_new_timestamp(-1);
  SET(FossilJsonKeys.timestamp);

  if( 0 != resultCode ){
    if( ! pMsg ){
................................................................................
** the cgi_xxx() family of functions, this function inherits any
** compression which fossil does for its output.
**
** If alsoOutput is true AND g.isHTTP then cgi_reply() is called to
** flush the output (and headers). Generally only do this if you are
** about to call exit().
**
** If !g.isHTTP then alsoOutput is ignored and all output is sent to
** stdout immediately.
**
** For generating the resultText property: if msg is not NULL then it
** is used as-is. If it is NULL then g.zErrMsg is checked, and if that
** is NULL then json_err_cstr(code) is used.
*/
void json_err( int code, char const * msg, char alsoOutput ){
................................................................................
    if(!a){
      a = cson_new_array();
      assert(NULL!=a);
    }
    if(!colNames){
      colNamesV = cson_sqlite3_column_names(pStmt->pStmt);
      assert(NULL != colNamesV);
      cson_value_add_reference(colNamesV)/*avoids an ownership problem*/;
      colNames = cson_value_get_array(colNamesV);
      assert(NULL != colNames);
    }      
    row = cson_sqlite3_row_to_object2(pStmt->pStmt, colNames);
    if(!row && !warnMsg){
      warnMsg = "Could not convert at least one result row to JSON.";
      continue;
................................................................................
** Executes the given SQL and runs it through
** json_stmt_to_array_of_obj(), returning the result of that
** function. If resetBlob is true then blob_reset(pSql) is called
** after preparing the query.
**
** pTgt has the same semantics as described for
** json_stmt_to_array_of_obj().
**
** FIXME: change this to take a (char const *) instead of a blob,
** to simplify the trivial use-cases (which don't need a Blob).
*/
cson_value * json_sql_to_array_of_obj(Blob * pSql, cson_array * pTgt,
                                      char resetBlob){
  Stmt q = empty_Stmt;
  cson_value * pay = NULL;
  assert( blob_size(pSql) > 0 );
  db_prepare(&q, "%s", blob_str(pSql));
................................................................................
  db_finalize(&q);
  return pay;

}

/*
** If the given COMMIT rid has any tags associated with it, this
** function returns a JSON Array containing the tag names (owned by
** the caller), else it returns NULL.
**
** See info_tags_of_checkin() for more details (this is simply a JSON
** wrapper for that function).
**
** If there are no tags then this function returns NULL, not an empty
** Array.
*/
cson_value * json_tags_for_checkin_rid(int rid, char propagatingOnly){
  cson_value * v = NULL;
  char * tags = info_tags_of_checkin(rid, propagatingOnly);
  if(tags){
    if(*tags){
      v = json_string_split2(tags,',',0);
................................................................................
    cson_array * list = cson_value_get_array(listV);
    cson_value * objV = NULL;
    cson_object * obj = NULL;
    cson_string * kRC;
    cson_string * kSymbol;
    cson_string * kNumber;
    cson_string * kDesc;
    cson_array_reserve( list, 35 );




    kRC = cson_new_string("resultCode",10);
    kSymbol = cson_new_string("cSymbol",7);
    kNumber = cson_new_string("number",6);
    kDesc = cson_new_string("description",11);
#define C(K) objV = cson_value_new_object(); obj = cson_value_get_object(objV); \
    cson_object_set_s(obj, kRC, json_new_string(json_rc_cstr(FSL_JSON_E_##K)) ); \
    cson_object_set_s(obj, kSymbol, json_new_string("FSL_JSON_E_"#K) );             \
................................................................................
  jobj = cson_value_get_object(jval);
#define FSET(X,K) cson_object_set( jobj, K, cson_value_new_string(X,strlen(X)))
  FSET(MANIFEST_UUID,"manifestUuid");
  FSET(MANIFEST_VERSION,"manifestVersion");
  FSET(MANIFEST_DATE,"manifestDate");
  FSET(MANIFEST_YEAR,"manifestYear");
  FSET(RELEASE_VERSION,"releaseVersion");

  cson_object_set( jobj, "releaseVersionNumber",
                   cson_value_new_integer(RELEASE_VERSION_NUMBER) );
  cson_object_set( jobj, "resultCodeParanoiaLevel",
                   cson_value_new_integer(g.json.errorDetailParanoia) );
  FSET(FOSSIL_JSON_API_VERSION, "jsonApiVersion" );
#undef FSET
  return jval;
}


/*
** Returns the current user's capabilities string as a String value.
** Returned value is owned by the caller, and will only be NULL if
................................................................................
  const char *zDb;
  enum { BufLen = 1000 };
  char zBuf[BufLen];
  cson_value * jv = NULL;
  cson_object * jo = NULL;
  cson_value * jv2 = NULL;
  cson_object * jo2 = NULL;
  char * zTmp = NULL;
  if( !g.perm.Read ){
    json_set_err(FSL_JSON_E_DENIED,
                 "Requires 'o' permissions.");
    return NULL;
  }
  full = json_find_option_bool("full",NULL,"f",0);
#define SETBUF(O,K) cson_object_set(O, K, cson_value_new_string(zBuf, strlen(zBuf)));

  jv = cson_value_new_object();
  jo = cson_value_get_object(jv);

  zTmp = db_get("project-name",NULL);
  cson_object_set(jo, "projectName", json_new_string(zTmp));
  free(zTmp);
  zTmp = db_get("project-description",NULL);
  cson_object_set(jo, "projectDescription", json_new_string(zTmp));

  free(zTmp);
  zTmp = NULL;
  fsize = file_size(g.zRepositoryName);
  cson_object_set(jo, "repositorySize", cson_value_new_integer((cson_int_t)fsize));

  if(full){
    n = db_int(0, "SELECT count(*) FROM blob");
    m = db_int(0, "SELECT count(*) FROM delta");
    cson_object_set(jo, "blobCount", cson_value_new_integer((cson_int_t)n));
................................................................................
    if((zPages+1)->name){
      blob_append(pOut, ", ",2);
    }
  }
  return i;
}

/*
** Creates an error message using zErrPrefix and the given array of
** JSON command definitions, and sets the g.json error state to
** reflect FSL_JSON_E_MISSING_ARGS. If zErrPrefix is NULL then
** some default is used (e.g. "Try one of: "). If it is "" then
** no prefix is used.
**
** The intention is to provide the user (via the response.resultText)
** a list of available commands/subcommands.
**
*/
void json_dispatch_missing_args_err( JsonPageDef const * pCommands,
                                     char const * zErrPrefix ){
  Blob cmdNames = empty_blob;
  blob_init(&cmdNames,NULL,0);
  if( !zErrPrefix ) {
    zErrPrefix = "Try one of: ";
  }
  blob_append( &cmdNames, zErrPrefix, strlen(zErrPrefix) );
  json_pagedefs_to_string(pCommands, &cmdNames);
  json_set_err(FSL_JSON_E_MISSING_ARGS, "%s",
               blob_str(&cmdNames));
  blob_reset(&cmdNames);
}

cson_value * json_page_dispatch_helper(JsonPageDef const * pages){
  JsonPageDef const * def;
  char const * cmd = json_command_arg(1+g.json.dispatchDepth);
  assert( NULL != pages );
  if( ! cmd ){
    json_dispatch_missing_args_err(pages,


                                   "No subcommand specified. "


                                   "Try one of: ");
    return NULL;
  }
  def = json_handler_for_name( cmd, pages );
  if(!def){
    json_set_err(FSL_JSON_E_UNKNOWN_COMMAND,
                 "Unknown subcommand: %s", cmd);
    return NULL;
  }
  else{
    ++g.json.dispatchDepth;
    return (*def->func)();
  }
}
................................................................................
cson_value * json_page_query();
/* Impl in json_report.c. */
cson_value * json_page_report();
/* Impl in json_tag.c. */
cson_value * json_page_tag();
/* Impl in json_user.c. */
cson_value * json_page_user();
/* Impl in json_config.c. */
cson_value * json_page_config();
/* Impl in json_finfo.c. */
cson_value * json_page_finfo();

/*
** Mapping of names to JSON pages/commands.  Each name is a subpath of
** /json (in CGI mode) or a subcommand of the json command in CLI mode
*/
static const JsonPageDef JsonPageDefs[] = {
/* please keep alphabetically sorted (case-insensitive) for maintenance reasons. */
{"anonymousPassword", json_page_anon_password, 0},
{"artifact", json_page_artifact, 0},
{"branch", json_page_branch,0},
{"cap", json_page_cap, 0},
{"config", json_page_config, 0 },
{"diff", json_page_diff, 0},
/*{"dir", json_page_nyi, 0},*/
{"finfo", json_page_finfo, 0},
{"g", json_page_g, 0},
{"HAI",json_page_version,0},
{"login",json_page_login,0},
{"logout",json_page_logout,0},
{"query",json_page_query,0},
{"rebuild",json_page_rebuild,0},
{"report", json_page_report, 0},
{"resultCodes", json_page_resultCodes,0},
{"stat",json_page_stat,0},
{"tag", json_page_tag,0},
/*{"ticket", json_page_nyi,0},*/
{"timeline", json_page_timeline,0},
{"user",json_page_user,0},
{"version",json_page_version,0},
{"whoami",json_page_whoami,0},
{"wiki",json_page_wiki,0},
/* Last entry MUST have a NULL name. */
{NULL,NULL,0}
};


/*
** Internal helper for json_cmd_top() and json_page_top().
**
** Searches JsonPageDefs for a command with the given name. If found,
** it is used to generate and output a JSON response. If not found, it
** generates a JSON-style error response. Returns 0 on success, non-0
** on error. On error it will set g.json's error state.
*/




static int json_dispatch_root_command( char const * zCommand ){
  int rc = 0;
  cson_value * payload = NULL;

  JsonPageDef const * pageDef = NULL;
  pageDef = json_handler_for_name(zCommand,&JsonPageDefs[0]);
  if( ! pageDef ){
    rc = FSL_JSON_E_UNKNOWN_COMMAND;
    json_set_err( rc, "Unknown command: %s", zCommand );
  }else if( pageDef->runMode < 0 /*CLI only*/){
    rc = FSL_JSON_E_WRONG_MODE;
  }else if( (g.isHTTP && (pageDef->runMode < 0 /*CLI only*/))
            ||
            (!g.isHTTP && (pageDef->runMode > 0 /*HTTP only*/))
            ){
    rc = FSL_JSON_E_WRONG_MODE;
  }









  else{
    rc = 0;
    g.json.dispatchDepth = 1;
    payload = (*pageDef->func)();
  }






  payload = json_create_response(rc, NULL, payload);


  json_send_response(payload);
  cson_value_free(payload);
  return rc;
}

#ifdef FOSSIL_ENABLE_JSON /* dupe ifdef needed for mkindex */
/*
** WEBPAGE: json
**
** Pages under /json/... must be entered into JsonPageDefs.
** This function dispatches them, and is the HTTP equivalent of
** json_cmd_top().
*/
void json_page_top(void){

  char const * zCommand;


  BEGIN_TIMER;
  json_mode_bootstrap();
  zCommand = json_command_arg(1);
  if(!zCommand || !*zCommand){
    json_dispatch_missing_args_err( JsonPageDefs,
                                    "No command (sub-path) specified."
                                    " Try one of: ");






    return;






  }







  json_dispatch_root_command( zCommand );
}















#endif /* FOSSIL_ENABLE_JSON for mkindex */

#ifdef FOSSIL_ENABLE_JSON /* dupe ifdef needed for mkindex */
/*
** This function dispatches json commands and is the CLI equivalent of
** json_page_top().
**
** COMMAND: json
**
** Usage: %fossil json SUBCOMMAND ?OPTIONS?
**
** In CLI mode, the -R REPO common option is supported. Due to limitations
** in the argument dispatching code, any -FLAGS must come after the final
** sub- (or subsub-) command.
**
** The commands include:
**
**   anonymousPassord
**   artifact
**   branch
**   cap
**   diff
**   g
**   login
**   logout
**   query
**   rebuild
**   report
**   resultCodes
**   stat
**   tag
**   timeline
**   user
**   version (alias: HAI)
**   whoami
**   wiki
**
** Run '%fossil json' without any subcommand to see the full list (but be
** aware that some listed might not yet be implemented).
**





** PS: the notable TODO-commands include: config, dir, finfo, ticket
**
*/
void json_cmd_top(void){
  char const * cmd = NULL;
  int rc = 0;


  BEGIN_TIMER;
  memset( &g.perm, 0xff, sizeof(g.perm) )
    /* In CLI mode fossil does not use permissions
       and they all default to false. We enable them
       here because (A) fossil doesn't use them in local
       mode but (B) having them set gives us one less
       difference in the CLI/CGI/Server-mode JSON
................................................................................
    */
    ;
  json_main_bootstrap();
  json_mode_bootstrap();
  if( 2 > cson_array_length_get(g.json.cmd.a) ){
    goto usage;
  }

#if 0
  json_warn(FSL_JSON_W_ROW_TO_JSON_FAILED, "Just testing.");
  json_warn(FSL_JSON_W_ROW_TO_JSON_FAILED, "Just testing again.");
#endif
  cmd = json_command_arg(1);
  if( !cmd || !*cmd ){
    goto usage;
  }
  rc = json_dispatch_root_command( cmd );

















  if(0 != rc){
    /* FIXME: we need a way of passing this error back
       up to the routine which called this callback.
       e.g. add g.errCode.
    */
    fossil_exit(1);
  }

  return;
  usage:
  {


    cson_value * payload;
    json_dispatch_missing_args_err( JsonPageDefs,
                                    "No subcommand specified."




                                    " Try one of: ");
    payload = json_create_response(0, NULL, NULL);
    json_send_response(payload);
    cson_value_free(payload);
    fossil_exit(1);
  }
}
#endif /* FOSSIL_ENABLE_JSON for mkindex */






#endif /* FOSSIL_ENABLE_JSON */

Changes to src/json_artifact.c.

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
...
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
...
222
223
224
225
226
227
228




229
230
231
232
233
234
235
236
...
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
  /**
     JSON construction callback. Creates the contents for the
     payload.artifact property of /json/artifact responses.
  */
  artifact_f func;
} ArtifactDispatchEntry;


























/*
** Generates an artifact Object for the given rid,
** which must refer to a Checkin.
**
** Returned value is NULL or an Object owned by the caller.
*/
cson_value * json_artifact_for_ci( int rid, char showFiles ){
  char * zParent = NULL;
  cson_value * v = NULL;
  Stmt q;
  static cson_value * eventTypeLabel = NULL;
  if(!eventTypeLabel){
    eventTypeLabel = json_new_string("checkin");
    json_gc_add("$EVENT_TYPE_LABEL(commit)", eventTypeLabel);
  }
  zParent = db_text(0,
    "SELECT uuid FROM plink, blob"
    " WHERE plink.cid=%d AND blob.rid=plink.pid AND plink.isprim",
    rid
  );

  db_prepare(&q, 
             "SELECT uuid, "
             " cast(strftime('%%s',mtime) as int), "

             " user, "
             " comment,"
             " strftime('%%s',omtime)"
             " FROM blob, event"
             " WHERE blob.rid=%d"
             "   AND event.objid=%d",
             rid, rid
             );
  if( db_step(&q)==SQLITE_ROW ){
    cson_object * o;
    cson_value * tmpV = NULL;
    const char *zUuid = db_column_text(&q, 0);
    char * zTmp;
    const char *zUser;
    const char *zComment;
    char * zEUser, * zEComment;
    int mtime, omtime;
    v = cson_value_new_object();
    o = cson_value_get_object(v);
#define SET(K,V) cson_object_set(o,(K), (V))
    SET("type", eventTypeLabel );
    SET("uuid",json_new_string(zUuid));
    SET("isLeaf", cson_value_new_bool(is_a_leaf(rid)));








    zUser = db_column_text(&q,2);
    zEUser = db_text(0,
                   "SELECT value FROM tagxref WHERE tagid=%d AND rid=%d",
                   TAG_USER, rid);
    if(zEUser){
      SET("user", json_new_string(zEUser));
      if(0!=strcmp(zEUser,zUser)){
        SET("originUser",json_new_string(zUser));
      }
      free(zEUser);
    }else{
      SET("user",json_new_string(zUser));
    }

    zComment = db_column_text(&q,3);
    zEComment = db_text(0, 
                   "SELECT value FROM tagxref WHERE tagid=%d AND rid=%d",
                   TAG_COMMENT, rid);
    if(zEComment){
      SET("comment",json_new_string(zEComment));
      if(0 != strcmp(zEComment,zComment)){
        SET("originComment", json_new_string(zComment));
      }
      free(zEComment);
    }else{
      SET("comment",json_new_string(zComment));
    }

    mtime = db_column_int(&q,1);
    SET("mtime",json_new_int(mtime));
    omtime = db_column_int(&q,4);
    if(omtime && (omtime!=mtime)){
      SET("originTime",json_new_int(omtime));
    }

    if(zParent){
      SET("parentUuid", json_new_string(zParent));
    }

    tmpV = json_tags_for_checkin_rid(rid,0);
    if(tmpV){
      SET("tags",tmpV);
    }

    if( showFiles ){
      cson_value * fileList = json_get_changed_files(rid);
      if(fileList){
        SET("files",fileList);
      }
    }


#undef SET
  }
  free(zParent);
  db_finalize(&q);
  return v;
}

/*
** Very incomplete/incorrect impl of /json/artifact/TICKET_ID.
*/
................................................................................
  return cson_object_value(pay);
}

/*
** Sub-impl of /json/artifact for checkins.
*/
static cson_value * json_artifact_ci( int rid ){
  if(! g.perm.Read ){
    g.json.resultCode = FSL_JSON_E_DENIED;
    return NULL;
  }else{
    return json_artifact_for_ci(rid, 1);
  }
}

/*
................................................................................

cson_value * json_artifact_wiki(int rid){
  if( ! g.perm.RdWiki ){
    json_set_err(FSL_JSON_E_DENIED,
                 "Requires 'j' privileges.");
    return NULL;
  }else{




    return json_get_wiki_page_by_rid(rid, 0);
  }
}

cson_value * json_artifact_file(int rid){
  cson_object * pay = NULL;
  const char *zMime;
  Blob content = empty_blob;
................................................................................
  char const * zType = NULL;
  char const * zUuid = NULL;
  cson_value * entry = NULL;
  Blob uuid = empty_blob;
  int rc;
  int rid = 0;
  ArtifactDispatchEntry const * dispatcher = &ArtifactDispatchList[0];
  zName = json_find_option_cstr2("uuid", NULL, NULL, 2);
  if(!zName || !*zName) {
    json_set_err(FSL_JSON_E_MISSING_ARGS,
                 "Missing 'uuid' argument.");
    return NULL;
  }

  if( validate16(zName, strlen(zName)) ){
    if( db_exists("SELECT 1 FROM ticket WHERE tkt_uuid GLOB '%q*'", zName) ){
      zType = "ticket";
      goto handle_entry;







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








<

|





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






<










>
>
>
>
>
>
>
>
|













|













|
|
|
<
<
<
<
<
<








|
|
|



<


<







 







|
|







 







>
>
>
>
|







 







|


|







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
...
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
...
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
...
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
  /**
     JSON construction callback. Creates the contents for the
     payload.artifact property of /json/artifact responses.
  */
  artifact_f func;
} ArtifactDispatchEntry;


/*
** Generates a JSON Array reference holding the parent UUIDs (as strings).
** If it finds no matches then it returns NULL (OOM is a fatal error).
**
** Returned value is NULL or an Array owned by the caller.
*/
cson_value * json_parent_uuids_for_ci( int rid ){
  Stmt q = empty_Stmt;
  cson_array * pParents = NULL;
  db_prepare( &q,
              "SELECT uuid FROM plink, blob"
              " WHERE plink.cid=%d AND blob.rid=plink.pid"
              " ORDER BY plink.isprim DESC",
              rid );
  while( SQLITE_ROW==db_step(&q) ){
    if(!pParents) {
      pParents = cson_new_array();
    }
    cson_array_append( pParents, cson_sqlite3_column_to_value( q.pStmt, 0 ) );
  }
  db_finalize(&q);
  return cson_array_value(pParents);
}

/*
** Generates an artifact Object for the given rid,
** which must refer to a Checkin.
**
** Returned value is NULL or an Object owned by the caller.
*/
cson_value * json_artifact_for_ci( int rid, char showFiles ){

  cson_value * v = NULL;
  Stmt q = empty_Stmt;
  static cson_value * eventTypeLabel = NULL;
  if(!eventTypeLabel){
    eventTypeLabel = json_new_string("checkin");
    json_gc_add("$EVENT_TYPE_LABEL(commit)", eventTypeLabel);
  }





  
  db_prepare(&q,
             "SELECT b.uuid, "
             " cast(strftime('%%s',e.mtime) as int), "
             " strftime('%%s',e.omtime),"
             " e.user, "
             " e.comment"

             " FROM blob b, event e"
             " WHERE b.rid=%d"
             "   AND e.objid=%d",
             rid, rid
             );
  if( db_step(&q)==SQLITE_ROW ){
    cson_object * o;
    cson_value * tmpV = NULL;
    const char *zUuid = db_column_text(&q, 0);

    const char *zUser;
    const char *zComment;
    char * zEUser, * zEComment;
    int mtime, omtime;
    v = cson_value_new_object();
    o = cson_value_get_object(v);
#define SET(K,V) cson_object_set(o,(K), (V))
    SET("type", eventTypeLabel );
    SET("uuid",json_new_string(zUuid));
    SET("isLeaf", cson_value_new_bool(is_a_leaf(rid)));

    mtime = db_column_int(&q,1);
    SET("mtime",json_new_int(mtime));
    omtime = db_column_int(&q,2);
    if(omtime && (omtime!=mtime)){
      SET("originTime",json_new_int(omtime));
    }

    zUser = db_column_text(&q,3);
    zEUser = db_text(0,
                   "SELECT value FROM tagxref WHERE tagid=%d AND rid=%d",
                   TAG_USER, rid);
    if(zEUser){
      SET("user", json_new_string(zEUser));
      if(0!=strcmp(zEUser,zUser)){
        SET("originUser",json_new_string(zUser));
      }
      free(zEUser);
    }else{
      SET("user",json_new_string(zUser));
    }

    zComment = db_column_text(&q,4);
    zEComment = db_text(0, 
                   "SELECT value FROM tagxref WHERE tagid=%d AND rid=%d",
                   TAG_COMMENT, rid);
    if(zEComment){
      SET("comment",json_new_string(zEComment));
      if(0 != strcmp(zEComment,zComment)){
        SET("originComment", json_new_string(zComment));
      }
      free(zEComment);
    }else{
      SET("comment",json_new_string(zComment));
    }

    tmpV = json_parent_uuids_for_ci(rid);
    if(tmpV){
      SET("parents", tmpV);






    }

    tmpV = json_tags_for_checkin_rid(rid,0);
    if(tmpV){
      SET("tags",tmpV);
    }

    if( showFiles ){
      tmpV = json_get_changed_files(rid);
      if(tmpV){
        SET("files",tmpV);
      }
    }


#undef SET
  }

  db_finalize(&q);
  return v;
}

/*
** Very incomplete/incorrect impl of /json/artifact/TICKET_ID.
*/
................................................................................
  return cson_object_value(pay);
}

/*
** Sub-impl of /json/artifact for checkins.
*/
static cson_value * json_artifact_ci( int rid ){
  if(!g.perm.Read){
    json_set_err( FSL_JSON_E_DENIED, "Viewing checkins requires 'o' privileges." );
    return NULL;
  }else{
    return json_artifact_for_ci(rid, 1);
  }
}

/*
................................................................................

cson_value * json_artifact_wiki(int rid){
  if( ! g.perm.RdWiki ){
    json_set_err(FSL_JSON_E_DENIED,
                 "Requires 'j' privileges.");
    return NULL;
  }else{
    char contentFormat = json_wiki_get_content_format_flag(-9);
    if(-9 == contentFormat){
      contentFormat = json_artifact_include_content_flag() ? -1 : 0;
    }
    return json_get_wiki_page_by_rid(rid, contentFormat);
  }
}

cson_value * json_artifact_file(int rid){
  cson_object * pay = NULL;
  const char *zMime;
  Blob content = empty_blob;
................................................................................
  char const * zType = NULL;
  char const * zUuid = NULL;
  cson_value * entry = NULL;
  Blob uuid = empty_blob;
  int rc;
  int rid = 0;
  ArtifactDispatchEntry const * dispatcher = &ArtifactDispatchList[0];
  zName = json_find_option_cstr2("name", NULL, NULL, 2);
  if(!zName || !*zName) {
    json_set_err(FSL_JSON_E_MISSING_ARGS,
                 "Missing 'name' argument.");
    return NULL;
  }

  if( validate16(zName, strlen(zName)) ){
    if( db_exists("SELECT 1 FROM ticket WHERE tkt_uuid GLOB '%q*'", zName) ){
      zType = "ticket";
      goto handle_entry;

Added src/json_config.c.



























































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
#ifdef FOSSIL_ENABLE_JSON
/*
** Copyright (c) 2011 D. Richard Hipp
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the Simplified BSD License (also
** known as the "2-Clause License" or "FreeBSD License".)
**
** This program is distributed in the hope that it will be useful,
** but without any warranty; without even the implied warranty of
** merchantability or fitness for a particular purpose.
**
** Author contact information:
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*/
#include "VERSION.h"
#include "config.h"
#include "json_config.h"

#if INTERFACE
#include "json_detail.h"
#endif

static cson_value * json_config_get();
static cson_value * json_config_save();

/*
** Mapping of /json/config/XXX commands/paths to callbacks.
*/
static const JsonPageDef JsonPageDefs_Config[] = {
{"get", json_config_get, 0},
{"save", json_config_save, 0},
/* Last entry MUST have a NULL name. */
{NULL,NULL,0}
};


/*
** Implements the /json/config family of pages/commands.
**
*/
cson_value * json_page_config(){
  return json_page_dispatch_helper(&JsonPageDefs_Config[0]);
}


/*
** JSON-internal mapping of config options to config groups.  This is
** mostly a copy of the config options in configure.c, but that data
** is private and cannot be re-used directly here.
*/
static const struct JsonConfigProperty {
  char const * name;
  int groupMask;
} JsonConfigProperties[] = {
{ "css",                    CONFIGSET_SKIN },
{ "header",                 CONFIGSET_SKIN },
{ "footer",                 CONFIGSET_SKIN },
{ "index-page",             CONFIGSET_SKIN },
{ "timeline-block-markup",  CONFIGSET_SKIN },
{ "timeline-max-comment",   CONFIGSET_SKIN },

{ "project-name",           CONFIGSET_PROJ },
{ "project-description",    CONFIGSET_PROJ },
{ "manifest",               CONFIGSET_PROJ },
{ "ignore-glob",            CONFIGSET_PROJ },
{ "crnl-glob",              CONFIGSET_PROJ },
{ "empty-dirs",             CONFIGSET_PROJ },
{ "allow-symlinks",         CONFIGSET_PROJ },

{ "ticket-table",           CONFIGSET_TKT  },
{ "ticket-common",          CONFIGSET_TKT  },
{ "ticket-change",          CONFIGSET_TKT  },
{ "ticket-newpage",         CONFIGSET_TKT  },
{ "ticket-viewpage",        CONFIGSET_TKT  },
{ "ticket-editpage",        CONFIGSET_TKT  },
{ "ticket-reportlist",      CONFIGSET_TKT  },
{ "ticket-report-template", CONFIGSET_TKT  },
{ "ticket-key-template",    CONFIGSET_TKT  },
{ "ticket-title-expr",      CONFIGSET_TKT  },
{ "ticket-closed-expr",     CONFIGSET_TKT  },

{NULL, 0}
};


/*
** Impl of /json/config/get. Requires setup rights.
**
*/
static cson_value * json_config_get(){
  cson_object * pay = NULL;
  Stmt q = empty_Stmt;
  Blob sql = empty_blob;
  char const * zName = NULL;
  int confMask = 0;
  char optSkinBackups = 0;
  unsigned int i;
  if(!g.perm.Setup){
    json_set_err(FSL_JSON_E_DENIED, "Requires 's' permissions.");
    return NULL;
  }

  i = g.json.dispatchDepth + 1;
  zName = json_command_arg(i);
  for( ; zName; zName = json_command_arg(++i) ){
    if(0==(strcmp("all", zName))){
      confMask = CONFIGSET_ALL;
    }else if(0==(strcmp("project", zName))){
      confMask |= CONFIGSET_PROJ;
    }else if(0==(strcmp("skin", zName))){
      confMask |= CONFIGSET_SKIN;
    }else if(0==(strcmp("ticket", zName))){
      confMask |= CONFIGSET_TKT;
    }else if(0==(strcmp("skin-backup", zName))){
      optSkinBackups = 1;
    }else{
      json_set_err( FSL_JSON_E_INVALID_ARGS,
                    "Unknown config area: %s", zName);
      return NULL;
    }
  }

  if(!confMask && !optSkinBackups){
    json_set_err(FSL_JSON_E_MISSING_ARGS, "No configuration area(s) selected.");
  }
  blob_append(&sql,
              "SELECT name, value"
              " FROM config "
              " WHERE 0 ", -1);
  {
    const struct JsonConfigProperty * prop = &JsonConfigProperties[0];
    blob_append(&sql," OR name IN (",-1);
    for( i = 0; prop->name; ++prop ){
      if(prop->groupMask & confMask){
        if( i++ ){
          blob_append(&sql,",",1);
        }
        blob_appendf(&sql, "%Q", prop->name);
      }
    }
    blob_append(&sql,") ", -1);
  }


  if( optSkinBackups ){
    blob_append(&sql, " OR name GLOB 'skin:*'", -1);
  }
  blob_append(&sql," ORDER BY name", -1);
  db_prepare(&q, blob_str(&sql));
  blob_reset(&sql);
  pay = cson_new_object();
  while( (SQLITE_ROW==db_step(&q)) ){
    cson_object_set(pay,
                    db_column_text(&q,0),
                    json_new_string(db_column_text(&q,1)));
  }
  db_finalize(&q);
  return cson_object_value(pay);
}

/*
** Impl of /json/config/save.
**
** TODOs:
*/
static cson_value * json_config_save(){
  json_set_err(FSL_JSON_E_NYI, NULL);
  return NULL;
}
#endif /* FOSSIL_ENABLE_JSON */

Changes to src/json_detail.h.

15
16
17
18
19
20
21









22
23
24
25
26
27
28
..
31
32
33
34
35
36
37




38
39
40
41
42
43
44
** Author contact information:
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*/

#include "cson_amalgamation.h"









/*
** Impl details for the JSON API which need to be shared
** across multiple C files.
*/

/*
** The "official" list of Fossil/JSON error codes.  Their values might
................................................................................
**
** Values must be in the range 1000..9999 for error codes and 1..999
** for warning codes.
**
** Numbers evenly dividable by 100 are "categories", and error codes
** for a given category have their high bits set to the category
** value.




**
*/
enum FossilJsonCodes {
FSL_JSON_W_START = 0,
FSL_JSON_W_UNKNOWN /*+1*/,
FSL_JSON_W_ROW_TO_JSON_FAILED /*+2*/,
FSL_JSON_W_COL_TO_JSON_FAILED /*+3*/,







>
>
>
>
>
>
>
>
>







 







>
>
>
>







15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
..
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
** Author contact information:
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*/

#include "cson_amalgamation.h"

/**
   FOSSIL_JSON_API_VERSION holds the date (YYYYMMDD) of the latest
   "significant" change to the JSON API (a change in an interface
   or new functionality). It is sent as part of the /json/version
   request. We could arguably add it to each response.
*/
#define FOSSIL_JSON_API_VERSION "20120409"

/*
** Impl details for the JSON API which need to be shared
** across multiple C files.
*/

/*
** The "official" list of Fossil/JSON error codes.  Their values might
................................................................................
**
** Values must be in the range 1000..9999 for error codes and 1..999
** for warning codes.
**
** Numbers evenly dividable by 100 are "categories", and error codes
** for a given category have their high bits set to the category
** value.
**
** Maintenance reminder: when entries are added to this list, update
** the code in json_page_resultCodes() and json_err_cstr() (both in
** json.c)!
**
*/
enum FossilJsonCodes {
FSL_JSON_W_START = 0,
FSL_JSON_W_UNKNOWN /*+1*/,
FSL_JSON_W_ROW_TO_JSON_FAILED /*+2*/,
FSL_JSON_W_COL_TO_JSON_FAILED /*+3*/,

Changes to src/json_diff.c.

35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
..
57
58
59
60
61
62
63
64
65

66
67
68
69
70
71
72
cson_value * json_generate_diff(const char *zFrom, const char *zTo,
                                int nContext, char fSbs){
  int fromid;
  int toid;
  int outLen;
  Blob from = empty_blob, to = empty_blob, out = empty_blob;
  cson_value * rc = NULL;
  char const * zType = "ci";
  int flags = (DIFF_CONTEXT_MASK & nContext)
      | (fSbs ? DIFF_SIDEBYSIDE : 0);
  fromid = name_to_typed_rid(zFrom, "*");
  if(fromid<=0){
      json_set_err(FSL_JSON_E_UNRESOLVED_UUID,
                   "Could not resolve 'from' ID.");
      return NULL;
................................................................................
  content_get(fromid, &from);
  content_get(toid, &to);
  blob_zero(&out);
  text_diff(&from, &to, &out, flags);
  blob_reset(&from);
  blob_reset(&to);
  outLen = blob_size(&out);
  if(outLen>0){
    rc = cson_value_new_string(blob_buffer(&out), blob_size(&out));

  }
  blob_reset(&out);
  return rc;
}

/*
** Implementation of the /json/diff page.







<







 







|
|
>







35
36
37
38
39
40
41

42
43
44
45
46
47
48
..
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
cson_value * json_generate_diff(const char *zFrom, const char *zTo,
                                int nContext, char fSbs){
  int fromid;
  int toid;
  int outLen;
  Blob from = empty_blob, to = empty_blob, out = empty_blob;
  cson_value * rc = NULL;

  int flags = (DIFF_CONTEXT_MASK & nContext)
      | (fSbs ? DIFF_SIDEBYSIDE : 0);
  fromid = name_to_typed_rid(zFrom, "*");
  if(fromid<=0){
      json_set_err(FSL_JSON_E_UNRESOLVED_UUID,
                   "Could not resolve 'from' ID.");
      return NULL;
................................................................................
  content_get(fromid, &from);
  content_get(toid, &to);
  blob_zero(&out);
  text_diff(&from, &to, &out, flags);
  blob_reset(&from);
  blob_reset(&to);
  outLen = blob_size(&out);
  if(outLen>=0){
    rc = cson_value_new_string(blob_buffer(&out),
                               (unsigned int)blob_size(&out));
  }
  blob_reset(&out);
  return rc;
}

/*
** Implementation of the /json/diff page.

Added src/json_finfo.c.





































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
#ifdef FOSSIL_ENABLE_JSON
/*
** Copyright (c) 2011 D. Richard Hipp
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the Simplified BSD License (also
** known as the "2-Clause License" or "FreeBSD License".)
**
** This program is distributed in the hope that it will be useful,
** but without any warranty; without even the implied warranty of
** merchantability or fitness for a particular purpose.
**
** Author contact information:
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*/
#include "VERSION.h"
#include "config.h"
#include "json_finfo.h"

#if INTERFACE
#include "json_detail.h"
#endif

/*
** Implements the /json/finfo page/command.
**
*/
cson_value * json_page_finfo(){
  cson_object * pay = NULL;
  cson_array * checkins = NULL;
  char const * zFilename = NULL;
  Blob sql = empty_blob;
  Stmt q = empty_Stmt;
  char const * zAfter = NULL;
  char const * zBefore = NULL;
  int limit = -1;
  int currentRow = 0;
  if(!g.perm.Read){
    json_set_err(FSL_JSON_E_DENIED,"Requires 'o' privileges.");
    return NULL;
  }
  json_warn( FSL_JSON_W_UNKNOWN, "Achtung: the output of the finfo command is up for change.");
  zFilename = json_find_option_cstr2("name",NULL,NULL,
                                 g.json.dispatchDepth+1);

  if(!zFilename){
    json_set_err(FSL_JSON_E_MISSING_ARGS, "Missing 'name' parameter.");
    return NULL;
  }
  zBefore = json_find_option_cstr("before",NULL,"b");
  zAfter = json_find_option_cstr("after",NULL,"a");
  limit = json_find_option_int("limit",NULL,"n", -1);

  blob_appendf(&sql, 
        "SELECT b.uuid,"
        "   ci.uuid,"
        "   (SELECT uuid FROM blob WHERE rid=mlink.fid),"  /* Current file uuid */
        "   cast(strftime('%%s',event.mtime) AS INTEGER),"
        "   coalesce(event.euser, event.user),"
        "   coalesce(event.ecomment, event.comment),"
#if 1
        " (SELECT uuid FROM blob WHERE rid=mlink.pid),"  /* Parent file uuid */
#endif
        "   event.bgcolor,"
        " 1"
        "  FROM mlink, blob b, event, blob ci, filename"
        " WHERE filename.name=%Q %s"
        "   AND mlink.fnid=filename.fnid"
        "   AND b.rid=mlink.fid"
        "   AND event.objid=mlink.mid"
        "   AND event.objid=ci.rid",
        zFilename, filename_collation()
               );
  if( zAfter ){
    blob_appendf(&sql, " AND event.mtime>=julianday('%q')", zAfter);
  }else if( zBefore ){
    blob_appendf(&sql, " AND event.mtime<=julianday('%q')", zBefore);
  }
  blob_appendf(&sql," ORDER BY event.mtime DESC /*sort*/");
  db_prepare(&q, "%s", blob_str(&sql)/*extra %s to avoid double-expanding
                                       SQL escapes*/);
  blob_reset(&sql);

  pay = cson_new_object();
  cson_object_set(pay, "name", json_new_string(zFilename));
  if( limit > 0 ){
    cson_object_set(pay, "limit", json_new_int(limit));
  }
  checkins = cson_new_array();
  cson_object_set(pay, "checkins", cson_array_value(checkins));
  while( db_step(&q)==SQLITE_ROW ){
    cson_object * row = cson_new_object();
    cson_array_append( checkins, cson_object_value(row) );
    cson_object_set(row, "checkin", json_new_string( db_column_text(&q,1) ));
    cson_object_set(row, "artifact", json_new_string( db_column_text(&q,2) ));
    /*cson_object_set(row, "parentArtifact", json_new_string( db_column_text(&q,6) ));*/
    cson_object_set(row, "mtime", json_new_int( db_column_int(&q,3) ));
    cson_object_set(row, "user", json_new_string( db_column_text(&q,4) ));
    cson_object_set(row, "comment", json_new_string( db_column_text(&q,5) ));
    /*cson_object_set(row, "bgColor", json_new_string( db_column_text(&q,7) ));*/
    if( (0 < limit) && (++currentRow >= limit) ){
      break;
    }
  }
  db_finalize(&q);

  return cson_object_value(pay);
}



#endif /* FOSSIL_ENABLE_JSON */

Changes to src/json_report.c.

92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
    json_set_err(FSL_JSON_E_DENIED,
                 "Requires 't' privileges.");
    return NULL;
  }
  nReport = json_report_get_number(3);
  if(nReport <=0){
    json_set_err(FSL_JSON_E_MISSING_ARGS,
                 "Missing or invalid 'number' (-n) parameter.");
    return NULL;
  }

  db_prepare(&q,"SELECT rn AS report,"
             " owner AS owner,"
             " title AS title,"
             " cast(strftime('%%s',mtime) as int) as mtime,"







|







92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
    json_set_err(FSL_JSON_E_DENIED,
                 "Requires 't' privileges.");
    return NULL;
  }
  nReport = json_report_get_number(3);
  if(nReport <=0){
    json_set_err(FSL_JSON_E_MISSING_ARGS,
                 "Missing or invalid 'report' (-r) parameter.");
    return NULL;
  }

  db_prepare(&q,"SELECT rn AS report,"
             " owner AS owner,"
             " title AS title,"
             " cast(strftime('%%s',mtime) as int) as mtime,"

Changes to src/json_timeline.c.

33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
...
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
...
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
...
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
...
351
352
353
354
355
356
357

358
359
360
361
362
363
364
...
376
377
378
379
380
381
382




383
384
385
386
387
388
389
...
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
...
427
428
429
430
431
432
433
434
435
436

437
438
439
440
441
442
443
444
445
446
447
...
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
...
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
...
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
...
566
567
568
569
570
571
572
573
574
575
576

577
578
579
580
581
582
583
static const JsonPageDef JsonPageDefs_Timeline[] = {
/* the short forms are only enabled in CLI mode, to avoid
   that we end up with HTTP clients using 3 different names
   for the same requests.
*/
{"branch", json_timeline_branch, 0},
{"checkin", json_timeline_ci, 0},
{"ci", json_timeline_ci, -1},
{"t", json_timeline_ticket, -1},
{"ticket", json_timeline_ticket, 0},
{"w", json_timeline_wiki, -1},
{"wiki", json_timeline_wiki, 0},
/* Last entry MUST have a NULL name. */
{NULL,NULL,0}
};


/*
................................................................................
**
** pSql is the target blob to append the query [subset]
** to.
**
** Returns a positive value if it modifies pSql, 0 if it
** does not. It returns a negative value if the tag
** provided to the request was not found (pSql is not modified
** in that case.
**
** If payload is not NULL then on success its "tag" or "branch"
** property is set to the tag/branch name found in the request.
**
** Only one of "tag" or "branch" modes will work at a time, and if
** both are specified, which one takes precedence is unspecified.
*/
................................................................................
/*
** Tries to figure out a timeline query length limit base on
** environment parameters. If it can it returns that value,
** else it returns some statically defined default value.
**
** Never returns a negative value. 0 means no limit.
*/
static int json_timeline_limit(){
  static const int defaultLimit = 20;
  int limit = -1;
  if(!g.isHTTP){/* CLI mode */
    char const * arg = find_option("limit","n",1);
    if(arg && *arg){
      limit = atoi(arg);
    }
  }
................................................................................
  blob_append(pSql, "INSERT OR IGNORE INTO json_timeline ", -1);
  blob_append(pSql, json_timeline_query(), -1 );
  blob_appendf(pSql, " AND event.type IN(%Q) ", zEventType);
  if( json_timeline_add_tag_branch_clause(pSql, pPayload) < 0 ){
    return FSL_JSON_E_INVALID_ARGS;
  }
  json_timeline_add_time_clause(pSql);
  limit = json_timeline_limit();
  if(limit>=0){
    blob_appendf(pSql,"LIMIT %d ",limit);
  }
  if(pPayload){
    cson_object_set(pPayload, "limit", json_new_int(limit));
  }
  return 0;
}
................................................................................
  return rowsV;
}

static cson_value * json_timeline_branch(){
  cson_value * pay = NULL;
  Blob sql = empty_blob;
  Stmt q = empty_Stmt;

  if(!g.perm.Read){
    json_set_err(FSL_JSON_E_DENIED,
                 "Requires 'o' permissions.");
    return NULL;
  }
  json_timeline_temp_table();
  blob_append(&sql,
................................................................................

  blob_appendf(&sql,
               " AND event.type='ci'"
               " AND blob.rid IN (SELECT rid FROM tagxref"
               "  WHERE tagtype>0 AND tagid=%d AND srcid!=0)"
               " ORDER BY event.mtime DESC",
               TAG_BRANCH);




  db_prepare(&q,"%s", blob_str(&sql));
  blob_reset(&sql);
  pay = json_stmt_to_array_of_obj(&q, NULL);
  db_finalize(&q);
  assert(NULL != pay);
  if(pay){
    /* get the array-form tags of each record. */
................................................................................
    cson_value_add_reference( cson_string_value(isLeaf) );
    cson_array * ar = cson_value_get_array(pay);
    unsigned int i = 0;
    unsigned int len = cson_array_length_get(ar);
    for( ; i < len; ++i ){
      cson_object * row = cson_value_get_object(cson_array_get(ar,i));
      int rid = cson_value_get_integer(cson_object_get(row,"rid"));
      if(row>0) {
        cson_object_set_s(row, tags, json_tags_for_checkin_rid(rid,0));
        cson_object_set_s(row, isLeaf, json_value_to_bool(cson_object_get(row,"isLeaf")));
      }
    }
    cson_value_free( cson_string_value(tags) );
    cson_value_free( cson_string_value(isLeaf) );
  }
   
  goto end;
  error:
  assert( 0 != g.json.resultCode );
  cson_value_free(pay);

  end:
  return pay;
}

/*
** Implementation of /json/timeline/ci.
**
** Still a few TODOs (like figuring out how to structure
................................................................................
  cson_value * tmp = NULL;
  cson_value * listV = NULL;
  cson_array * list = NULL;
  int check = 0;
  char showFiles = -1/*magic number*/;
  Stmt q = empty_Stmt;
  char warnRowToJsonFailed = 0;
  char warnStringToArrayFailed = 0;
  Blob sql = empty_blob;
  if( !g.perm.Read ){

    /* IMO this falls more under the category of g.perm.History, but
       i'm following the original timeline impl here.
    */
    json_set_err( FSL_JSON_E_DENIED, "Checkin timeline requires 'o' access." );
    return NULL;
  }
  showFiles = json_find_option_bool("files",NULL,"f",0);
  payV = cson_value_new_object();
  pay = cson_value_get_object(payV);
  check = json_timeline_setup_sql( "ci", &sql, pay );
  if(check){
................................................................................
  tmp = cson_value_new_string(blob_buffer(&sql),strlen(blob_buffer(&sql)));
  SET("timelineSql");
#endif
  db_multi_exec(blob_buffer(&sql));
  blob_reset(&sql);
  db_prepare(&q, "SELECT "
             " rid AS rid"
#if 0
             " uuid AS uuid,"
             " mtime AS timestamp,"
#  if 0
             " timestampString AS timestampString,"
#  endif
             " comment AS comment, "
             " user AS user,"
             " isLeaf AS isLeaf," /*FIXME: convert to JSON bool */
             " bgColor AS bgColor," /* why always null? */
             " eventType AS eventType"
#  if 0
             " tags AS tags"
             /*tagId is always null?*/
             " tagId AS tagId"
#  endif
#endif
             " FROM json_timeline"
             " ORDER BY rowid");
  listV = cson_value_new_array();
  list = cson_value_get_array(listV);
  tmp = listV;
  SET("timeline");
  while( (SQLITE_ROW == db_step(&q) )){
................................................................................
** Implementation of /json/timeline/wiki.
**
*/
cson_value * json_timeline_wiki(){
  /* This code is 95% the same as json_timeline_ci(), by the way. */
  cson_value * payV = NULL;
  cson_object * pay = NULL;
  cson_value * tmp = NULL;
  cson_array * list = NULL;
  int check = 0;
  Stmt q = empty_Stmt;
  Blob sql = empty_blob;
  if( !g.perm.RdWiki && !g.perm.Read ){
    json_set_err( FSL_JSON_E_DENIED, "Wiki timeline requires 'o' or 'j' access.");
    return NULL;
................................................................................
  pay = cson_value_get_object(payV);
  check = json_timeline_setup_sql( "w", &sql, pay );
  if(check){
    json_set_err(check, "Query initialization failed.");
    goto error;
  }

#define SET(K) if(0!=(check=cson_object_set(pay,K,tmp))){ \
    json_set_err((cson_rc.AllocError==check)        \
                 ? FSL_JSON_E_ALLOC : FSL_JSON_E_UNKNOWN,       \
                 "Object property insertion failed."); \
    goto error;\
  } (void)0
#if 0
  /* only for testing! */
  tmp = cson_value_new_string(blob_buffer(&sql),strlen(blob_buffer(&sql)));
  SET("timelineSql");
#endif
  db_multi_exec(blob_buffer(&sql));
  blob_reset(&sql);
................................................................................
                                a JSON array*/
             " tagId AS tagId,"
#endif
             " FROM json_timeline"
             " ORDER BY rowid",
             -1);
  list = cson_new_array();
  tmp = cson_array_value(list);
  SET("timeline");
  json_stmt_to_array_of_obj(&q, list);
#undef SET

  goto ok;
  error:
  assert( 0 != g.json.resultCode );
  cson_value_free(payV);
  payV = NULL;
  ok:
  db_finalize(&q);







<
<

<







 







|







 







|
<







 







|
|







 







>







 







>
>
>
>







 







|
|
|
<




<
<
<
<
<
<
<







 







<

|
>
|
<

|







 







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







 







<







 







<
<
<
<
<
<







 







<
<

<
>







33
34
35
36
37
38
39


40

41
42
43
44
45
46
47
...
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
...
228
229
230
231
232
233
234
235

236
237
238
239
240
241
242
...
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
...
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
...
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
...
394
395
396
397
398
399
400
401
402
403

404
405
406
407







408
409
410
411
412
413
414
...
420
421
422
423
424
425
426

427
428
429
430

431
432
433
434
435
436
437
438
439
...
452
453
454
455
456
457
458

















459
460
461
462
463
464
465
...
492
493
494
495
496
497
498

499
500
501
502
503
504
505
...
508
509
510
511
512
513
514






515
516
517
518
519
520
521
...
534
535
536
537
538
539
540


541

542
543
544
545
546
547
548
549
static const JsonPageDef JsonPageDefs_Timeline[] = {
/* the short forms are only enabled in CLI mode, to avoid
   that we end up with HTTP clients using 3 different names
   for the same requests.
*/
{"branch", json_timeline_branch, 0},
{"checkin", json_timeline_ci, 0},


{"ticket", json_timeline_ticket, 0},

{"wiki", json_timeline_wiki, 0},
/* Last entry MUST have a NULL name. */
{NULL,NULL,0}
};


/*
................................................................................
**
** pSql is the target blob to append the query [subset]
** to.
**
** Returns a positive value if it modifies pSql, 0 if it
** does not. It returns a negative value if the tag
** provided to the request was not found (pSql is not modified
** in that case).
**
** If payload is not NULL then on success its "tag" or "branch"
** property is set to the tag/branch name found in the request.
**
** Only one of "tag" or "branch" modes will work at a time, and if
** both are specified, which one takes precedence is unspecified.
*/
................................................................................
/*
** Tries to figure out a timeline query length limit base on
** environment parameters. If it can it returns that value,
** else it returns some statically defined default value.
**
** Never returns a negative value. 0 means no limit.
*/
static int json_timeline_limit(int defaultLimit){

  int limit = -1;
  if(!g.isHTTP){/* CLI mode */
    char const * arg = find_option("limit","n",1);
    if(arg && *arg){
      limit = atoi(arg);
    }
  }
................................................................................
  blob_append(pSql, "INSERT OR IGNORE INTO json_timeline ", -1);
  blob_append(pSql, json_timeline_query(), -1 );
  blob_appendf(pSql, " AND event.type IN(%Q) ", zEventType);
  if( json_timeline_add_tag_branch_clause(pSql, pPayload) < 0 ){
    return FSL_JSON_E_INVALID_ARGS;
  }
  json_timeline_add_time_clause(pSql);
  limit = json_timeline_limit(20);
  if(limit>0){
    blob_appendf(pSql,"LIMIT %d ",limit);
  }
  if(pPayload){
    cson_object_set(pPayload, "limit", json_new_int(limit));
  }
  return 0;
}
................................................................................
  return rowsV;
}

static cson_value * json_timeline_branch(){
  cson_value * pay = NULL;
  Blob sql = empty_blob;
  Stmt q = empty_Stmt;
  int limit = 0;
  if(!g.perm.Read){
    json_set_err(FSL_JSON_E_DENIED,
                 "Requires 'o' permissions.");
    return NULL;
  }
  json_timeline_temp_table();
  blob_append(&sql,
................................................................................

  blob_appendf(&sql,
               " AND event.type='ci'"
               " AND blob.rid IN (SELECT rid FROM tagxref"
               "  WHERE tagtype>0 AND tagid=%d AND srcid!=0)"
               " ORDER BY event.mtime DESC",
               TAG_BRANCH);
  limit = json_timeline_limit(20);
  if(limit>0){
    blob_appendf(&sql," LIMIT %d ",limit);
  }
  db_prepare(&q,"%s", blob_str(&sql));
  blob_reset(&sql);
  pay = json_stmt_to_array_of_obj(&q, NULL);
  db_finalize(&q);
  assert(NULL != pay);
  if(pay){
    /* get the array-form tags of each record. */
................................................................................
    cson_value_add_reference( cson_string_value(isLeaf) );
    cson_array * ar = cson_value_get_array(pay);
    unsigned int i = 0;
    unsigned int len = cson_array_length_get(ar);
    for( ; i < len; ++i ){
      cson_object * row = cson_value_get_object(cson_array_get(ar,i));
      int rid = cson_value_get_integer(cson_object_get(row,"rid"));
      assert( rid > 0 );
      cson_object_set_s(row, tags, json_tags_for_checkin_rid(rid,0));
      cson_object_set_s(row, isLeaf, json_value_to_bool(cson_object_get(row,"isLeaf")));

    }
    cson_value_free( cson_string_value(tags) );
    cson_value_free( cson_string_value(isLeaf) );
  }







  return pay;
}

/*
** Implementation of /json/timeline/ci.
**
** Still a few TODOs (like figuring out how to structure
................................................................................
  cson_value * tmp = NULL;
  cson_value * listV = NULL;
  cson_array * list = NULL;
  int check = 0;
  char showFiles = -1/*magic number*/;
  Stmt q = empty_Stmt;
  char warnRowToJsonFailed = 0;

  Blob sql = empty_blob;
  if( !g.perm.History ){
    /* Reminder to self: HTML impl requires 'o' (Read)
       rights.

    */
    json_set_err( FSL_JSON_E_DENIED, "Checkin timeline requires 'h' access." );
    return NULL;
  }
  showFiles = json_find_option_bool("files",NULL,"f",0);
  payV = cson_value_new_object();
  pay = cson_value_get_object(payV);
  check = json_timeline_setup_sql( "ci", &sql, pay );
  if(check){
................................................................................
  tmp = cson_value_new_string(blob_buffer(&sql),strlen(blob_buffer(&sql)));
  SET("timelineSql");
#endif
  db_multi_exec(blob_buffer(&sql));
  blob_reset(&sql);
  db_prepare(&q, "SELECT "
             " rid AS rid"

















             " FROM json_timeline"
             " ORDER BY rowid");
  listV = cson_value_new_array();
  list = cson_value_get_array(listV);
  tmp = listV;
  SET("timeline");
  while( (SQLITE_ROW == db_step(&q) )){
................................................................................
** Implementation of /json/timeline/wiki.
**
*/
cson_value * json_timeline_wiki(){
  /* This code is 95% the same as json_timeline_ci(), by the way. */
  cson_value * payV = NULL;
  cson_object * pay = NULL;

  cson_array * list = NULL;
  int check = 0;
  Stmt q = empty_Stmt;
  Blob sql = empty_blob;
  if( !g.perm.RdWiki && !g.perm.Read ){
    json_set_err( FSL_JSON_E_DENIED, "Wiki timeline requires 'o' or 'j' access.");
    return NULL;
................................................................................
  pay = cson_value_get_object(payV);
  check = json_timeline_setup_sql( "w", &sql, pay );
  if(check){
    json_set_err(check, "Query initialization failed.");
    goto error;
  }







#if 0
  /* only for testing! */
  tmp = cson_value_new_string(blob_buffer(&sql),strlen(blob_buffer(&sql)));
  SET("timelineSql");
#endif
  db_multi_exec(blob_buffer(&sql));
  blob_reset(&sql);
................................................................................
                                a JSON array*/
             " tagId AS tagId,"
#endif
             " FROM json_timeline"
             " ORDER BY rowid",
             -1);
  list = cson_new_array();


  json_stmt_to_array_of_obj(&q, list);

  cson_object_set(pay, "timeline", cson_array_value(list));
  goto ok;
  error:
  assert( 0 != g.json.resultCode );
  cson_value_free(payV);
  payV = NULL;
  ok:
  db_finalize(&q);

Changes to src/json_user.c.

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
...
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
...
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
...
286
287
288
289
290
291
292
293

294

295
296
297
298
299







300
301
302
303
304
305
306
...
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
**
** On error g.json's error state is set one of the FSL_JSON_E_xxx
** values from FossilJsonCodes is returned.
**
** On success the db record for the given user is updated.
**
** Requires either Admin, Setup, or Password access. Non-admin/setup
** users can only change their own information.
**
** TODOs:
**
** - Admin non-Setup users cannot change the information for Setup
** users.
**
*/
int json_user_update_from_json( cson_object * pUser ){
#define CSTR(X) cson_string_cstr(cson_value_get_string( cson_object_get(pUser, X ) ))
  char const * zName = CSTR("name");
  char const * zNameNew = zName;
  char * zNameFree = NULL;
................................................................................
  char const * zInfo = CSTR("info");
  char const * zCap = CSTR("capabilities");
  char const * zPW = CSTR("password");
  cson_value const * forceLogout = cson_object_get(pUser, "forceLogout");
  int gotFields = 0;
#undef CSTR
  cson_int_t uid = cson_value_get_integer( cson_object_get(pUser, "uid") );


  Blob sql = empty_blob;
  Stmt q = empty_Stmt;

  if(!g.perm.Admin && !g.perm.Setup && !g.perm.Password){
    return json_set_err( FSL_JSON_E_DENIED,
                         "Password change requires 'a', 's', "
                         "or 'p' permissions.");
................................................................................
    }
    zName = zNameFree;
  }else if(-1==uid){
    /* try to create a new user */
    if(!g.perm.Admin && !g.perm.Setup){
      return json_set_err(FSL_JSON_E_DENIED,
                          "Requires 'a' or 's' privileges.");
    } else if(!zName || !*zName){
      return json_set_err(FSL_JSON_E_MISSING_ARGS,
                          "No name specified for new user.");
    }else if( db_exists("SELECT 1 FROM user WHERE login=%Q", zName) ){
      return json_set_err(FSL_JSON_E_RESOURCE_ALREADY_EXISTS,
                          "User %s already exists.", zName);
    }else{
      Stmt ins = empty_Stmt;
................................................................................
  }

  /* Maintenance note: all error-returns from here on out should go
     via 'goto error' in order to clean up.
  */
  
  if(uid != g.userUid){
    /*
      TODO: do not allow an admin user to modify a setup user
      unless the admin is also a setup user. setup.c uses
      that logic. There is a corner case for a NEW Setup user
      which the admin is just installing. Hmm.      
    */
    if(!g.perm.Admin && !g.perm.Setup){
      json_set_err(FSL_JSON_E_DENIED,
                   "Changing another user's data requires "
                   "'a' or 's' privileges.");
    }
  }



  














  blob_append(&sql, "UPDATE USER SET",-1 );
  blob_append(&sql, " mtime=cast(strftime('%s') AS INTEGER)", -1);

  if((uid>0) && zNameNew){
    /* Check for name change... */
    if( (!g.perm.Admin && !g.perm.Setup)
        && zNameNew && (zName != zNameNew)
        && (0!=strcmp(zNameNew,zName))){
................................................................................
    ++gotFields;
  }

  if( zCap ){
    blob_appendf(&sql, ", cap=%Q", zCap);
    ++gotFields;
  }


  if( zPW ){

    char * zPWHash = NULL;
    ++gotFields;
    zPWHash = sha1_shared_secret(zPW, zNameNew ? zNameNew : zName, NULL);
    blob_appendf(&sql, ", pw=%Q", zPWHash);
    free(zPWHash);







  }

  if( zInfo ){
    blob_appendf(&sql, ", info=%Q", zInfo);
    ++gotFields;
  }

................................................................................
  
  if(!gotFields){
    json_set_err( FSL_JSON_E_MISSING_ARGS,
                  "Required user data are missing.");
    goto error;
  }
  assert(uid>0);

  blob_appendf(&sql, " WHERE uid=%d", uid);
  free( zNameFree );



#if 0
  puts(blob_str(&sql));
  cson_output_FILE( cson_object_value(pUser), stdout, NULL );
#endif
  db_prepare(&q, "%s", blob_str(&sql));
  blob_reset(&sql);
  db_exec(&q);
  db_finalize(&q);


























  return 0;

  error:
  assert(0 != g.json.resultCode);
  free(zNameFree);
  blob_reset(&sql);
  return g.json.resultCode;
}


/*
** Impl of /json/user/save.
**
** TODOs:
**
** - Return something useful in the payload (at least the id of the
** modified/created user).
*/
static cson_value * json_user_save(){
  /* try to get user info from GET/CLI args and construct
     a JSON form of it... */
  cson_object * u = cson_new_object();
  char const * str = NULL;
  char b = -1;







|
|
|
<
<
<







 







>
>







 







|







 







<
<
<
<
<
<






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







 







<
>

>





>
>
>
>
>
>
>







 







>

<
>
>
>





<


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












<
<
<
<
<







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
...
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
...
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
...
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
...
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
**
** On error g.json's error state is set one of the FSL_JSON_E_xxx
** values from FossilJsonCodes is returned.
**
** On success the db record for the given user is updated.
**
** Requires either Admin, Setup, or Password access. Non-admin/setup
** users can only change their own information. Non-setup users may
** not modify the 's' permission. Admin users without setup
** permissions may not edit any other user who has the 's' permission.



**
*/
int json_user_update_from_json( cson_object * pUser ){
#define CSTR(X) cson_string_cstr(cson_value_get_string( cson_object_get(pUser, X ) ))
  char const * zName = CSTR("name");
  char const * zNameNew = zName;
  char * zNameFree = NULL;
................................................................................
  char const * zInfo = CSTR("info");
  char const * zCap = CSTR("capabilities");
  char const * zPW = CSTR("password");
  cson_value const * forceLogout = cson_object_get(pUser, "forceLogout");
  int gotFields = 0;
#undef CSTR
  cson_int_t uid = cson_value_get_integer( cson_object_get(pUser, "uid") );
  char const tgtHasSetup = zCap && (NULL!=strchr(zCap, 's'));
  char tgtHadSetup = 0;
  Blob sql = empty_blob;
  Stmt q = empty_Stmt;

  if(!g.perm.Admin && !g.perm.Setup && !g.perm.Password){
    return json_set_err( FSL_JSON_E_DENIED,
                         "Password change requires 'a', 's', "
                         "or 'p' permissions.");
................................................................................
    }
    zName = zNameFree;
  }else if(-1==uid){
    /* try to create a new user */
    if(!g.perm.Admin && !g.perm.Setup){
      return json_set_err(FSL_JSON_E_DENIED,
                          "Requires 'a' or 's' privileges.");
    }else if(!zName || !*zName){
      return json_set_err(FSL_JSON_E_MISSING_ARGS,
                          "No name specified for new user.");
    }else if( db_exists("SELECT 1 FROM user WHERE login=%Q", zName) ){
      return json_set_err(FSL_JSON_E_RESOURCE_ALREADY_EXISTS,
                          "User %s already exists.", zName);
    }else{
      Stmt ins = empty_Stmt;
................................................................................
  }

  /* Maintenance note: all error-returns from here on out should go
     via 'goto error' in order to clean up.
  */
  
  if(uid != g.userUid){






    if(!g.perm.Admin && !g.perm.Setup){
      json_set_err(FSL_JSON_E_DENIED,
                   "Changing another user's data requires "
                   "'a' or 's' privileges.");
    }
  }
  /* check if the target uid currently has setup rights. */
  tgtHadSetup = db_int(0,"SELECT 1 FROM user where uid=%d"
                       " AND cap GLOB '*s*'", uid);

  if((tgtHasSetup || tgtHadSetup) && !g.perm.Setup){
    /*
      Do not allow a non-setup user to set or remove setup
      privileges. setup.c uses similar logic.
    */
    return json_set_err(FSL_JSON_E_DENIED,
                        "Modifying 's' users/privileges requires "
                        "'s' privileges.");
  }
  /*
    Potential todo: do not allow a setup user to remove 's' from
    himself, to avoid locking himself out?
  */

  blob_append(&sql, "UPDATE user SET",-1 );
  blob_append(&sql, " mtime=cast(strftime('%s') AS INTEGER)", -1);

  if((uid>0) && zNameNew){
    /* Check for name change... */
    if( (!g.perm.Admin && !g.perm.Setup)
        && zNameNew && (zName != zNameNew)
        && (0!=strcmp(zNameNew,zName))){
................................................................................
    ++gotFields;
  }

  if( zCap ){
    blob_appendf(&sql, ", cap=%Q", zCap);
    ++gotFields;
  }

#define TRY_LOGIN_GROUP 0 /* login group support is not yet implemented. */
  if( zPW ){
#if !TRY_LOGIN_GROUP
    char * zPWHash = NULL;
    ++gotFields;
    zPWHash = sha1_shared_secret(zPW, zNameNew ? zNameNew : zName, NULL);
    blob_appendf(&sql, ", pw=%Q", zPWHash);
    free(zPWHash);
#else
    ++gotFields;
    blob_appendf(&sql, ", pw=coalesce(shared_secret(%Q,%Q,"
                 "(SELECT value FROM config WHERE name='project-code')))",
                 zPW, zNameNew ? zNameNew : zName);
    /* shared_secret() func is undefined? */
#endif
  }

  if( zInfo ){
    blob_appendf(&sql, ", info=%Q", zInfo);
    ++gotFields;
  }

................................................................................
  
  if(!gotFields){
    json_set_err( FSL_JSON_E_MISSING_ARGS,
                  "Required user data are missing.");
    goto error;
  }
  assert(uid>0);
#if !TRY_LOGIN_GROUP
  blob_appendf(&sql, " WHERE uid=%d", uid);

#else /* need name for login group support :/ */
  blob_appendf(&sql, " WHERE login=%Q", zName);
#endif
#if 0
  puts(blob_str(&sql));
  cson_output_FILE( cson_object_value(pUser), stdout, NULL );
#endif
  db_prepare(&q, "%s", blob_str(&sql));

  db_exec(&q);
  db_finalize(&q);
#if TRY_LOGIN_GROUP
  if( zPW || forceLogout ){
    Blob groupSql = empty_blob;
    char * zErr = NULL;
    blob_appendf(&groupSql,
      "INSERT INTO user(login)"
      "  SELECT %Q WHERE NOT EXISTS(SELECT 1 FROM user WHERE login=%Q);",
      zName, zName
    );
    blob_append(&groupSql, blob_str(&sql), blob_size(&sql));
    login_group_sql(blob_str(&groupSql), NULL, NULL, &zErr);
    blob_reset(&groupSql);
    if( zErr ){
      json_set_err( FSL_JSON_E_UNKNOWN,
                    "Repo-group update at least partially failed: %s",
                    zErr);
      free(zErr);
      goto error;
    }
  }
#endif /* TRY_LOGIN_GROUP */

#undef TRY_LOGIN_GROUP

  free( zNameFree );
  blob_reset(&sql);
  return 0;

  error:
  assert(0 != g.json.resultCode);
  free(zNameFree);
  blob_reset(&sql);
  return g.json.resultCode;
}


/*
** Impl of /json/user/save.





*/
static cson_value * json_user_save(){
  /* try to get user info from GET/CLI args and construct
     a JSON form of it... */
  cson_object * u = cson_new_object();
  char const * str = NULL;
  char b = -1;

Changes to src/json_wiki.c.

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
...
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
...
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
...
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
...
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
...
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
...
360
361
362
363
364
365
366








































































































367
#include "json_detail.h"
#endif

static cson_value * json_wiki_create();
static cson_value * json_wiki_get();
static cson_value * json_wiki_list();
static cson_value * json_wiki_save();

/*
** Mapping of /json/wiki/XXX commands/paths to callbacks.
*/
static const JsonPageDef JsonPageDefs_Wiki[] = {
{"create", json_wiki_create, 1},

{"get", json_wiki_get, 0},
{"list", json_wiki_list, 0},
{"save", json_wiki_save, 1},
{"timeline", json_timeline_wiki,0},
/* Last entry MUST have a NULL name. */
{NULL,NULL,0}
};


/*
................................................................................
** Implements the /json/wiki family of pages/commands.
**
*/
cson_value * json_page_wiki(){
  return json_page_dispatch_helper(&JsonPageDefs_Wiki[0]);
}


/*
** Loads the given wiki page and creates a JSON object representation
** of it. If the page is not found then NULL is returned. If doParse
** is true then the page content is HTML-ized using fossil's
** conventional wiki format, else it is not parsed.
**
** The returned value, if not NULL, is-a JSON Object owned by the
** caller.
*/
cson_value * json_get_wiki_page_by_name(char const * zPageName, char doParse){
  int rid;
  Manifest *pWiki = 0;
  char const * zBody = NULL;
  char const * zFormat = NULL;
  char * zUuid = NULL;
  Stmt q;
  db_prepare(&q,
             "SELECT x.rid, b.uuid FROM tag t, tagxref x, blob b"
             " WHERE x.tagid=t.tagid AND t.tagname='wiki-%q' "
             " AND b.rid=x.rid"
             " ORDER BY x.mtime DESC LIMIT 1",
             zPageName 
             );
  if( (SQLITE_ROW != db_step(&q)) ){
    db_finalize(&q);
    return NULL;
  }
  rid = db_column_int(&q,0);
  zUuid = db_column_malloc(&q,1);
  db_finalize(&q);
  if( (pWiki = manifest_get(rid, CFTYPE_WIKI))!=0 ){
    zBody = pWiki->zWiki;
  }

  {
    unsigned int len;
    cson_object * pay = cson_new_object();
    cson_object_set(pay,"name",json_new_string(zPageName));
    cson_object_set(pay,"uuid",json_new_string(zUuid));
    free(zUuid);
    zUuid = NULL;





    /*cson_object_set(pay,"rid",json_new_int((cson_int_t)rid));*/
    cson_object_set(pay,"lastSavedBy",json_new_string(pWiki->zUser));
    cson_object_set(pay,FossilJsonKeys.timestamp, json_julian_to_timestamp(pWiki->rDate));


    cson_object_set(pay,"contentFormat",json_new_string(zFormat));
    if( doParse ){




      Blob content = empty_blob;
      Blob raw = empty_blob;

      blob_append(&raw,zBody,-1);
      wiki_convert(&raw,&content,0);
      len = strlen(zBody);
      len = (unsigned int)blob_size(&content);

      cson_object_set(pay,"contentLength",json_new_int((cson_int_t)len));
      cson_object_set(pay,"content",
                      cson_value_new_string(blob_buffer(&content),len));
      blob_reset(&content);
      blob_reset(&raw);
    }else{

      len = zBody ? strlen(zBody) : 0;
      cson_object_set(pay,"contentLength",json_new_int((cson_int_t)len));
      cson_object_set(pay,"content",cson_value_new_string(zBody,len));
    }



    /*TODO: add 'T' (tag) fields*/
    /*TODO: add the 'A' card (file attachment) entries?*/
    manifest_destroy(pWiki);
    return cson_object_value(pay);
  }






















}


/*
** Searches for a wiki page with the given rid. If found it behaves
** like json_get_wiki_page_by_name(pageName, doParse), else it returns
** NULL.
*/
cson_value * json_get_wiki_page_by_rid(int rid, char doParse){
  char * zPageName = NULL;
  cson_value * rc = NULL;
  zPageName = db_text(NULL,
                      "SELECT substr(t.tagname,6) AS name "
                      " FROM tag t, tagxref x, blob b "
                      " WHERE b.rid=%d "
                      " AND t.tagname GLOB 'wiki-*'"
                      " AND x.tagid=t.tagid AND b.rid=x.rid ",
                      rid);
  if( zPageName ){
    rc = json_get_wiki_page_by_name(zPageName, doParse);
    free(zPageName);
  }
  return rc;








}

/*
** Implementation of /json/wiki/get.
**
*/
static cson_value * json_wiki_get(){
  int rid;
  Manifest *pWiki = 0;
  char const * zBody = NULL;
  char const * zPageName;
  char const * zFormat = NULL;
  char * zUuid = NULL;
  Stmt q;


  if( !g.perm.RdWiki && !g.perm.Read ){
    json_set_err(FSL_JSON_E_DENIED,
                 "Requires 'o' or 'j' access.");
    return NULL;
  }
  zPageName = json_find_option_cstr("name",NULL,"n")
      /* Damn... fossil automatically sets name to the PATH
................................................................................
  }
  if( !zPageName && cson_value_is_string(g.json.reqPayload.v) ){
      zPageName = cson_string_cstr(cson_value_get_string(g.json.reqPayload.v));
  }
  if(!zPageName){
    zPageName = json_command_arg(g.json.dispatchDepth+1);
  }



  if(!zPageName||!*zPageName){
    json_set_err(FSL_JSON_E_MISSING_ARGS,
                 "'name' argument is missing.");

    return NULL;
  }

  zFormat = json_find_option_cstr("format",NULL,"f");
  if(!zFormat || !*zFormat){
    zFormat = "raw";



  }
  if( 'r' != *zFormat ){
    zFormat = "html";















  }
  return json_get_wiki_page_by_name(zPageName, 'h'==*zFormat);

}

/*
** Internal impl of /wiki/save and /wiki/create. If createMode is 0
** and the page already exists then a
** FSL_JSON_E_RESOURCE_ALREADY_EXISTS error is triggered.  If
** createMode is false then the FSL_JSON_E_RESOURCE_NOT_FOUND is
................................................................................
** Note that the error triggered when createMode==0 and no such page
** exists is rather arbitrary - we could just as well create the entry
** here if it doesn't already exist. With that, save/create would
** become one operation. That said, i expect there are people who
** would categorize such behaviour as "being too clever" or "doing too
** much automatically" (and i would likely agree with them).
**
** If allowCreateIfExists is true then this function will allow a new
** page to be created even if createMode is false.
*/
static cson_value * json_wiki_create_or_save(char createMode,
                                             char allowCreateIfExists){
  Blob content = empty_blob;
  cson_value * nameV;

  cson_value * contentV;
  cson_value * emptyContent = NULL;
  cson_value * payV = NULL;
  cson_object * pay = NULL;
  cson_string const * jstr = NULL;
  char const * zContent;
  char const * zBody = NULL;
  char const * zPageName;
  unsigned int contentLen = 0;
  int rid;
  if( (createMode && !g.perm.NewWiki)
      || (!createMode && !g.perm.WrWiki)){
    json_set_err(FSL_JSON_E_DENIED,
                 "Requires '%c' permissions.",
                 (createMode ? 'f' : 'k'));
................................................................................
  if(rid){
    if(createMode){
      json_set_err(FSL_JSON_E_RESOURCE_ALREADY_EXISTS,
                   "Wiki page '%s' already exists.",
                   zPageName);
      goto error;
    }
  }else if(!allowCreateIfExists){
    json_set_err(FSL_JSON_E_RESOURCE_NOT_FOUND,
                 "Wiki page '%s' not found.",
                 zPageName);
    goto error;
  }

  contentV = json_req_payload_get("content");
  if( !contentV ){
    if( createMode || (!rid && allowCreateIfExists) ){
      contentV = emptyContent = cson_value_new_string("",0);
    }else{
      json_set_err(FSL_JSON_E_MISSING_ARGS,
                   "'content' parameter is missing.");
      goto error;
    }
  }
................................................................................
  jstr = cson_value_get_string(contentV);
  contentLen = (int)cson_string_length_bytes(jstr);
  if(contentLen){
    blob_append(&content, cson_string_cstr(jstr),contentLen);
  }
  wiki_cmd_commit(zPageName, 0==rid, &content);
  blob_reset(&content);

  payV = cson_value_new_object();
  pay = cson_value_get_object(payV);
  cson_object_set( pay, "name", nameV );
  cson_object_set( pay, FossilJsonKeys.timestamp,
                   json_new_timestamp(-1) );



  goto ok;
  error:
  assert( 0 != g.json.resultCode );
  cson_value_free(payV);
  payV = NULL;
  ok:
  if( emptyContent ){
    /* We have some potentially tricky memory ownership
       here, which is why we handle emptyContent separately.

       This is, in fact, overkill because cson_value_new_string("",0)
       actually returns a shared singleton instance (i.e. doesn't
................................................................................
/*
** Implementation of /json/wiki/list.
*/
static cson_value * json_wiki_list(){
  cson_value * listV = NULL;
  cson_array * list = NULL;
  Stmt q;


  if( !g.perm.RdWiki && !g.perm.Read ){
    json_set_err(FSL_JSON_E_DENIED,
                 "Requires 'j' or 'o' permissions.");
    return NULL;
  }
  db_prepare(&q,"SELECT"
             " substr(tagname,6) as name"
             " FROM tag WHERE tagname GLOB 'wiki-*'"
             " ORDER BY lower(name)");
  listV = cson_value_new_array();
  list = cson_value_get_array(listV);
  while( SQLITE_ROW == db_step(&q) ){





    cson_value * v = cson_sqlite3_column_to_value(q.pStmt,0);

    if(!v){
      json_set_err(FSL_JSON_E_UNKNOWN,
                   "Could not convert wiki name column to JSON.");
      goto error;
    }else if( 0 != cson_array_append( list, v ) ){
      cson_value_free(v);
      json_set_err(FSL_JSON_E_ALLOC,"Could not append wiki page name to array.")
................................................................................
  assert(0 != g.json.resultCode);
  cson_value_free(listV);
  listV = NULL;
  end:
  db_finalize(&q);
  return listV;
}








































































































#endif /* FOSSIL_ENABLE_JSON */







|




|
>


|







 







|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|



>
>
>
>
>


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




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




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







<
<
<


<
<
>
>







 







>
>
>
|

<
>



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







 







|



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







 







|








|







 







|
|
|
|
|
|
|
>
>



|
<







 







>
>












>
>
>
>
>
|
>







 







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

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
...
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
...
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
...
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
...
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
...
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
...
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
#include "json_detail.h"
#endif

static cson_value * json_wiki_create();
static cson_value * json_wiki_get();
static cson_value * json_wiki_list();
static cson_value * json_wiki_save();
static cson_value * json_wiki_diff();
/*
** Mapping of /json/wiki/XXX commands/paths to callbacks.
*/
static const JsonPageDef JsonPageDefs_Wiki[] = {
{"create", json_wiki_create, 0},
{"diff", json_wiki_diff, 0},
{"get", json_wiki_get, 0},
{"list", json_wiki_list, 0},
{"save", json_wiki_save, 0},
{"timeline", json_timeline_wiki,0},
/* Last entry MUST have a NULL name. */
{NULL,NULL,0}
};


/*
................................................................................
** Implements the /json/wiki family of pages/commands.
**
*/
cson_value * json_page_wiki(){
  return json_page_dispatch_helper(&JsonPageDefs_Wiki[0]);
}

char * json_wiki_get_uuid_for_rid( int rid )
{
  return db_text(NULL,
             "SELECT b.uuid FROM tag t, tagxref x, blob b"
             " WHERE x.tagid=t.tagid AND t.tagname GLOB 'wiki-*' "
             " AND b.rid=x.rid AND b.rid=%d"
             " ORDER BY x.mtime DESC LIMIT 1",
             rid
             );
}

/*
** Tries to load a wiki page from the given rid creates a JSON object
** representation of it. If the page is not found then NULL is
** returned. If contentFormat is positive then the page content
** is HTML-ized using fossil's conventional wiki format, if it is
** negative then no parsing is performed, if it is 0 then the content
** is not returned in the response. If contentFormat is 0 then the
** contentSize reflects the number of bytes, not characters, stored in
** the page.
**
** The returned value, if not NULL, is-a JSON Object owned by the
** caller. If it returns NULL then it may set g.json's error state.
*/
cson_value * json_get_wiki_page_by_rid(int rid, char contentFormat){
  Manifest * pWiki = NULL;
  if( NULL == (pWiki = manifest_get(rid, CFTYPE_WIKI)) ){
    json_set_err( FSL_JSON_E_UNKNOWN,
                  "Error reading wiki page from manifest (rid=%d).",
                  rid );
    return NULL;
  }else{
    /*char const * zFormat = NULL;*/
    unsigned int len = 0;
    cson_object * pay = cson_new_object();
    char const * zBody = pWiki->zWiki;
    char const * zFormat = NULL;
    char * zUuid = json_wiki_get_uuid_for_rid(rid);
    cson_object_set(pay,"name",json_new_string(pWiki->zWikiTitle));
    cson_object_set(pay,"uuid",json_new_string(zUuid));
    free(zUuid);
    zUuid = NULL;
    if( pWiki->nParent > 0 ){
      cson_object_set( pay, "parent", json_new_string(pWiki->azParent[0]) )
        /* Reminder: wiki pages do not branch and have only one parent
           (except for the initial version, which has no parents). */;
    }
    /*cson_object_set(pay,"rid",json_new_int((cson_int_t)rid));*/
    cson_object_set(pay,"lastSavedBy",json_new_string(pWiki->zUser));
    cson_object_set(pay,FossilJsonKeys.timestamp,
                    json_julian_to_timestamp(pWiki->rDate));
    if(0 == contentFormat){
      cson_object_set(pay,"contentLength",

                      json_new_int((cson_int_t)(zBody?strlen(zBody):0)));
    }else{
      if( contentFormat>0 ){/*HTML-ize it*/
        zFormat = "html";
        Blob content = empty_blob;
        Blob raw = empty_blob;
        if(zBody && *zBody){
          blob_append(&raw,zBody,-1);
          wiki_convert(&raw,&content,0);

          len = (unsigned int)blob_size(&content);
        }
        cson_object_set(pay,"contentLength",json_new_int((cson_int_t)len));
        cson_object_set(pay,"content",
                        cson_value_new_string(blob_buffer(&content),len));
        blob_reset(&content);
        blob_reset(&raw);
      }else{/*raw format*/
        zFormat = "raw";
        len = zBody ? strlen(zBody) : 0;
        cson_object_set(pay,"contentLength",json_new_int((cson_int_t)len));
        cson_object_set(pay,"content",cson_value_new_string(zBody,len));
      }
      cson_object_set(pay,"contentFormat",json_new_string(zFormat));

    }
    /*TODO: add 'T' (tag) fields*/
    /*TODO: add the 'A' card (file attachment) entries?*/
    manifest_destroy(pWiki);
    return cson_object_value(pay);
  }  
}

/*
** Searches for the latest version of a wiki page with the given
** name. If found it behaves like json_get_wiki_page_by_rid(theRid,
** contentFormat), else it returns NULL.
*/
cson_value * json_get_wiki_page_by_name(char const * zPageName, char contentFormat){
  int rid;
  rid = db_int(0,
               "SELECT x.rid FROM tag t, tagxref x, blob b"
               " WHERE x.tagid=t.tagid AND t.tagname='wiki-%q' "
               " AND b.rid=x.rid"
               " ORDER BY x.mtime DESC LIMIT 1",
               zPageName 
             );
  if( 0==rid ){
    json_set_err( FSL_JSON_E_RESOURCE_NOT_FOUND, "Wiki page not found: %s",
                  zPageName );
    return NULL;
  }
  return json_get_wiki_page_by_rid(rid, contentFormat);
}


/*
** Searches json_find_option_ctr("format",NULL,"f") for a flag.
** If not found it returns defaultValue else it returns a value
** depending on the first character of the format option:
**
** [h]tml = 1
** [n]one = 0
** [r]aw = -1
**
** The return value is intended for use with
** json_get_wiki_page_by_rid() and friends.
*/
char json_wiki_get_content_format_flag( char defaultValue ){
  char contentFormat = defaultValue;
  char const * zFormat = json_find_option_cstr("format",NULL,"f");
  if( !zFormat || !*zFormat ){
    return contentFormat;
  }
  else if('r'==*zFormat){
    contentFormat = -1;
  }
  else if('h'==*zFormat){
    contentFormat = 1;
  }
  else if('n'==*zFormat){
    contentFormat = 0;
  }
  return contentFormat;
}

/*
** Implementation of /json/wiki/get.
**
*/
static cson_value * json_wiki_get(){



  char const * zPageName;
  char const * zFormat = NULL;


  char const * zSymName = NULL;
  char contentFormat = -1;
  if( !g.perm.RdWiki && !g.perm.Read ){
    json_set_err(FSL_JSON_E_DENIED,
                 "Requires 'o' or 'j' access.");
    return NULL;
  }
  zPageName = json_find_option_cstr("name",NULL,"n")
      /* Damn... fossil automatically sets name to the PATH
................................................................................
  }
  if( !zPageName && cson_value_is_string(g.json.reqPayload.v) ){
      zPageName = cson_string_cstr(cson_value_get_string(g.json.reqPayload.v));
  }
  if(!zPageName){
    zPageName = json_command_arg(g.json.dispatchDepth+1);
  }

  zSymName = json_find_option_cstr("uuid",NULL,"u");
  
  if((!zPageName||!*zPageName) && (!zSymName || !*zSymName)){
    json_set_err(FSL_JSON_E_MISSING_ARGS,

                 "At least one of the 'name' or 'uuid' arguments must be provided.");
    return NULL;
  }




  /* TODO: see if we have a page named zPageName. If not, try to resolve
     zPageName as a UUID.
  */
  


  contentFormat = json_wiki_get_content_format_flag(contentFormat);
  if(!zSymName || !*zSymName){
    return json_get_wiki_page_by_name(zPageName, contentFormat);
  }else{
    int rid = symbolic_name_to_rid( zSymName ? zSymName : zPageName, "w" );
    if(rid<0){
      json_set_err(FSL_JSON_E_AMBIGUOUS_UUID,
                   "UUID [%s] is ambiguious.", zSymName);
      return NULL;
    }else if(rid==0){
      json_set_err(FSL_JSON_E_RESOURCE_NOT_FOUND,
                   "UUID [%s] does not resolve to a wiki page.", zSymName);
      return NULL;
    }else{
      return json_get_wiki_page_by_rid(rid, contentFormat);
    }

  }
}

/*
** Internal impl of /wiki/save and /wiki/create. If createMode is 0
** and the page already exists then a
** FSL_JSON_E_RESOURCE_ALREADY_EXISTS error is triggered.  If
** createMode is false then the FSL_JSON_E_RESOURCE_NOT_FOUND is
................................................................................
** Note that the error triggered when createMode==0 and no such page
** exists is rather arbitrary - we could just as well create the entry
** here if it doesn't already exist. With that, save/create would
** become one operation. That said, i expect there are people who
** would categorize such behaviour as "being too clever" or "doing too
** much automatically" (and i would likely agree with them).
**
** If allowCreateIfNotExists is true then this function will allow a new
** page to be created even if createMode is false.
*/
static cson_value * json_wiki_create_or_save(char createMode,
                                             char allowCreateIfNotExists){
  Blob content = empty_blob;  /* wiki  page content */
  cson_value * nameV;         /* wiki page name */
  char const * zPageName;     /* cstr form of page name */
  cson_value * contentV;      /* passed-in content */
  cson_value * emptyContent = NULL;  /* placeholder for empty content. */
  cson_value * payV = NULL;   /* payload/return value */

  cson_string const * jstr = NULL;  /* temp for cson_value-to-cson_string conversions. */



  unsigned int contentLen = 0;
  int rid;
  if( (createMode && !g.perm.NewWiki)
      || (!createMode && !g.perm.WrWiki)){
    json_set_err(FSL_JSON_E_DENIED,
                 "Requires '%c' permissions.",
                 (createMode ? 'f' : 'k'));
................................................................................
  if(rid){
    if(createMode){
      json_set_err(FSL_JSON_E_RESOURCE_ALREADY_EXISTS,
                   "Wiki page '%s' already exists.",
                   zPageName);
      goto error;
    }
  }else if(!createMode && !allowCreateIfNotExists){
    json_set_err(FSL_JSON_E_RESOURCE_NOT_FOUND,
                 "Wiki page '%s' not found.",
                 zPageName);
    goto error;
  }

  contentV = json_req_payload_get("content");
  if( !contentV ){
    if( createMode || (!rid && allowCreateIfNotExists) ){
      contentV = emptyContent = cson_value_new_string("",0);
    }else{
      json_set_err(FSL_JSON_E_MISSING_ARGS,
                   "'content' parameter is missing.");
      goto error;
    }
  }
................................................................................
  jstr = cson_value_get_string(contentV);
  contentLen = (int)cson_string_length_bytes(jstr);
  if(contentLen){
    blob_append(&content, cson_string_cstr(jstr),contentLen);
  }
  wiki_cmd_commit(zPageName, 0==rid, &content);
  blob_reset(&content);
  /*
    Our return value here has a race condition: if this operation
    is called concurrently for the same wiki page via two requests,
    payV could reflect the results of the other save operation.
  */
  payV = json_get_wiki_page_by_name(
           cson_string_cstr(
             cson_value_get_string(nameV)),
             0);
  goto ok;
  error:
  assert( 0 != g.json.resultCode );
  assert( NULL == payV );

  ok:
  if( emptyContent ){
    /* We have some potentially tricky memory ownership
       here, which is why we handle emptyContent separately.

       This is, in fact, overkill because cson_value_new_string("",0)
       actually returns a shared singleton instance (i.e. doesn't
................................................................................
/*
** Implementation of /json/wiki/list.
*/
static cson_value * json_wiki_list(){
  cson_value * listV = NULL;
  cson_array * list = NULL;
  Stmt q;
  char const verbose = json_find_option_bool("verbose",NULL,"v",0);

  if( !g.perm.RdWiki && !g.perm.Read ){
    json_set_err(FSL_JSON_E_DENIED,
                 "Requires 'j' or 'o' permissions.");
    return NULL;
  }
  db_prepare(&q,"SELECT"
             " substr(tagname,6) as name"
             " FROM tag WHERE tagname GLOB 'wiki-*'"
             " ORDER BY lower(name)");
  listV = cson_value_new_array();
  list = cson_value_get_array(listV);
  while( SQLITE_ROW == db_step(&q) ){
    cson_value * v;
    if( verbose ){
      char const * name = db_column_text(&q,0);
      v = json_get_wiki_page_by_name(name,0);
    }else{
      v = cson_sqlite3_column_to_value(q.pStmt,0);
    }
    if(!v){
      json_set_err(FSL_JSON_E_UNKNOWN,
                   "Could not convert wiki name column to JSON.");
      goto error;
    }else if( 0 != cson_array_append( list, v ) ){
      cson_value_free(v);
      json_set_err(FSL_JSON_E_ALLOC,"Could not append wiki page name to array.")
................................................................................
  assert(0 != g.json.resultCode);
  cson_value_free(listV);
  listV = NULL;
  end:
  db_finalize(&q);
  return listV;
}

static cson_value * json_wiki_diff(){
  char const * zV1 = NULL;
  char const * zV2 = NULL;
  char const * zContent = NULL;
  cson_object * pay = NULL;
  int argPos = g.json.dispatchDepth;
  int r1 = 0, r2 = 0;
  Manifest * pW1 = NULL, *pW2 = NULL;
  Blob w1 = empty_blob, w2 = empty_blob, d = empty_blob;
  char const * zErrTag = NULL;
  int diffFlags;
  char * zUuid = NULL;
  if( !g.perm.History ){
    json_set_err(FSL_JSON_E_DENIED,
                 "Requires 'h' permissions.");
    return NULL;
  }

  
  zV1 = json_find_option_cstr2( "v1",NULL, NULL, ++argPos );
  zV2 = json_find_option_cstr2( "v2",NULL, NULL, ++argPos );
  if(!zV1 || !*zV1 || !zV2 || !*zV2) {
    json_set_err(FSL_JSON_E_INVALID_ARGS,
                 "Requires both 'v1' and 'v2' arguments.");
    return NULL;
  }
  
  r1 = symbolic_name_to_rid( zV1, "w" );
  zErrTag = zV1;
  if(r1<0){
    goto ambiguous;
  }else if(0==r1){
    goto invalid;
  }

  r2 = symbolic_name_to_rid( zV2, "w" );
  zErrTag = zV2;
  if(r2<0){
    goto ambiguous;
  }else if(0==r2){
    goto invalid;
  }

  zErrTag = zV1;
  pW1 = manifest_get(r1, CFTYPE_WIKI);
  if( pW1==0 ) {
    goto manifest;
  }
  zErrTag = zV2;
  pW2 = manifest_get(r2, CFTYPE_WIKI);
  if( pW2==0 ) {
    goto manifest;
  }

  blob_init(&w1, pW1->zWiki, -1);
  blob_zero(&w2);
  blob_init(&w2, pW2->zWiki, -1);
  blob_zero(&d);
  diffFlags = DIFF_IGNORE_EOLWS | DIFF_INLINE;
  text_diff(&w2, &w1, &d, diffFlags);
  blob_reset(&w1);
  blob_reset(&w2);

  pay = cson_new_object();
  
  zUuid = json_wiki_get_uuid_for_rid( pW1->rid );
  cson_object_set(pay, "v1", json_new_string(zUuid) );
  free(zUuid);
  zUuid = json_wiki_get_uuid_for_rid( pW2->rid );
  cson_object_set(pay, "v2", json_new_string(zUuid) );
  free(zUuid);
  zUuid = NULL;

  manifest_destroy(pW1);
  manifest_destroy(pW2);

  cson_object_set(pay, "diff",
                  cson_value_new_string( blob_str(&d),
                                         (unsigned int)blob_size(&d)));
  
  return cson_object_value(pay);

  manifest:
  json_set_err(FSL_JSON_E_UNKNOWN,
               "Could not load wiki manifest for UUID [%s].",
               zErrTag);
  goto end;

  ambiguous:
  json_set_err(FSL_JSON_E_AMBIGUOUS_UUID,
               "UUID [%s] is ambiguous.", zErrTag);
  goto end;

  invalid:
  json_set_err(FSL_JSON_E_RESOURCE_NOT_FOUND,
               "UUID [%s] not found.", zErrTag);
  goto end;

  end:
  cson_free_object(pay);
  return NULL;
}

#endif /* FOSSIL_ENABLE_JSON */

Changes to src/main.c.

439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
....
1202
1203
1204
1205
1206
1207
1208

1209
1210
1211
1212
1213
1214
1215
....
1368
1369
1370
1371
1372
1373
1374


1375
1376
1377
1378
1379
1380
1381
....
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
....
1556
1557
1558
1559
1560
1561
1562
1563

1564
1565



1566
1567
1568
1569






1570
1571
1572

1573
1574
1575
1576
1577
1578
1579
....
1604
1605
1606
1607
1608
1609
1610
1611


1612
1613
1614
1615
1616
1617
1618
....
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
....
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
....
1670
1671
1672
1673
1674
1675
1676








1677
1678
1679
1680
1681
1682
1683
  g.json.outOpt.addNewline = 1;
  g.json.outOpt.indentation = 1 /* in CGI/server mode this can be configured */;
#endif /* FOSSIL_ENABLE_JSON */
  expand_args_option();
  argc = g.argc;
  argv = g.argv;
  for(i=0; i<argc; i++) g.argv[i] = fossil_mbcs_to_utf8(argv[i]);
  if( getenv("GATEWAY_INTERFACE")!=0 && !find_option("nocgi", 0, 0)){
    zCmdName = "cgi";
    g.isHTTP = 1;
  }else if( argc<2 ){
    fossil_print(
       "Usage: %s COMMAND ...\n"
       "   or: %s help           -- for a list of common commands\n"
       "   or: %s help COMMMAND  -- for help with the named command\n"
................................................................................
          i++;
          continue;
        }
        zRepo[j] = '.';
      }

      if( szFile<1024 ){

        if( zNotFound ){
          cgi_redirect(zNotFound);
        }else{
#ifdef FOSSIL_ENABLE_JSON
          if(g.json.isJsonMode){
            json_err(FSL_JSON_E_RESOURCE_NOT_FOUND,NULL,1);
            return;
................................................................................
**
**      #!/usr/bin/fossil
**      repository: /home/somebody/project.db
**
** The second line defines the name of the repository.  After locating
** the repository, fossil will generate a webpage on stdout based on
** the values of standard CGI environment variables.


*/
void cmd_cgi(void){
  const char *zFile;
  const char *zNotFound = 0;
  char **azRedirect = 0;             /* List of repositories to redirect to */
  int nRedirect = 0;                 /* Number of entries in azRedirect */
  Blob config, line, key, value, value2;
................................................................................
**
**        fossil http REPOSITORY INFILE OUTFILE IPADDR
**
** The argv==6 form is used by the win32 server only.
**
** COMMAND: http*
**
** Usage: %fossil http REPOSITORY [--notfound URL] [--host HOSTNAME] [--https]
**
** Handle a single HTTP request appearing on stdin.  The resulting webpage
** is delivered on stdout.  This method is used to launch an HTTP request
** handler from inetd, for example.  The argument is the name of the 
** repository.
**
** If REPOSITORY is a directory that contains one or more respositories
................................................................................
** with names of the form "*.fossil" then the first element of the URL
** pathname selects among the various repositories.  If the pathname does
** not select a valid repository and the --notfound option is available,
** then the server redirects (HTTP code 302) to the URL of --notfound.
**
** The --host option can be used to specify the hostname for the server.
** The --https option indicates that the request came from HTTPS rather
** than HTTP.

**
** Other options:



**
**    --localauth      Password signin is not required if this is true and
**                     the input comes from 127.0.0.1 and the "localauth"
**                     setting is not disabled.






**
**    --nossl          SSL connections are not available so do not
**                     redirect from http: to https:.

*/
void cmd_http(void){
  const char *zIpAddr;
  const char *zNotFound;
  const char *zHost;
  zNotFound = find_option("notfound", 0, 1);
  g.useLocalauth = find_option("localauth", 0, 0)!=0;
................................................................................
/*
** Note that the following command is used by ssh:// processing.
**
** COMMAND: test-http
** Works like the http command but gives setup permission to all users.
*/
void cmd_test_http(void){
  login_set_capabilities("s", 0);


  g.httpIn = stdin;
  g.httpOut = stdout;
  find_server_repository(0);
  g.cgiOutput = 1;
  g.fullHttpReply = 1;
  cgi_handle_http_request(0);
  process_one_web_page(0);
................................................................................
#if !defined(_WIN32)
#if !defined(__DARWIN__) && !defined(__APPLE__)
/*
** Search for an executable on the PATH environment variable.
** Return true (1) if found and false (0) if not found.
*/
static int binaryOnPath(const char *zBinary){
  const char *zPath = getenv("PATH");
  char *zFull;
  int i;
  int bExists;
  while( zPath && zPath[0] ){
    while( zPath[0]==':' ) zPath++;
    for(i=0; zPath[i] && zPath[i]!=':'; i++){}
    zFull = mprintf("%.*s/%s", i, zPath, zBinary);
................................................................................
#endif
#endif

/*
** COMMAND: server*
** COMMAND: ui
**
** Usage: %fossil server ?-P|--port TCPPORT? -?-R|--root ROOT? ?REPOSITORY?
**    Or: %fossil ui ?-P|--port TCPPORT? -?-R|--root ROOT? ?REPOSITORY?
**
** Open a socket and begin listening and responding to HTTP requests on
** TCP port 8080, or on any other TCP port defined by the -P or
** --port option.  The optional argument is the name of the repository.
** The repository argument may be omitted if the working directory is
** within an open checkout.
**
................................................................................
** various repositories.
**
** By default, the "ui" command provides full administrative access without
** having to log in.  This can be disabled by setting turning off the
** "localauth" setting.  Automatic login for the "server" command is available
** if the --localauth option is present and the "localauth" setting is off
** and the connection is from localhost.








*/
void cmd_webserver(void){
  int iPort, mxPort;        /* Range of TCP ports allowed */
  const char *zPort;        /* Value of the --port option */
  char *zBrowser;           /* Name of web browser program */
  char *zBrowserCmd = 0;    /* Command to launch the web browser */
  int isUiCmd;              /* True if command is "ui", not "server' */







|







 







>







 







>
>







 







|







 







|
>

<
>
>
>

<
<
<
>
>
>
>
>
>

<
<
>







 







|
>
>







 







|







 







|
|







 







>
>
>
>
>
>
>
>







439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
....
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
....
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
....
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
....
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568

1569
1570
1571
1572



1573
1574
1575
1576
1577
1578
1579


1580
1581
1582
1583
1584
1585
1586
1587
....
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
....
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
....
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
....
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
  g.json.outOpt.addNewline = 1;
  g.json.outOpt.indentation = 1 /* in CGI/server mode this can be configured */;
#endif /* FOSSIL_ENABLE_JSON */
  expand_args_option();
  argc = g.argc;
  argv = g.argv;
  for(i=0; i<argc; i++) g.argv[i] = fossil_mbcs_to_utf8(argv[i]);
  if( fossil_getenv("GATEWAY_INTERFACE")!=0 && !find_option("nocgi", 0, 0)){
    zCmdName = "cgi";
    g.isHTTP = 1;
  }else if( argc<2 ){
    fossil_print(
       "Usage: %s COMMAND ...\n"
       "   or: %s help           -- for a list of common commands\n"
       "   or: %s help COMMMAND  -- for help with the named command\n"
................................................................................
          i++;
          continue;
        }
        zRepo[j] = '.';
      }

      if( szFile<1024 ){
        set_base_url();
        if( zNotFound ){
          cgi_redirect(zNotFound);
        }else{
#ifdef FOSSIL_ENABLE_JSON
          if(g.json.isJsonMode){
            json_err(FSL_JSON_E_RESOURCE_NOT_FOUND,NULL,1);
            return;
................................................................................
**
**      #!/usr/bin/fossil
**      repository: /home/somebody/project.db
**
** The second line defines the name of the repository.  After locating
** the repository, fossil will generate a webpage on stdout based on
** the values of standard CGI environment variables.
**
** See also: http, server, winsrv
*/
void cmd_cgi(void){
  const char *zFile;
  const char *zNotFound = 0;
  char **azRedirect = 0;             /* List of repositories to redirect to */
  int nRedirect = 0;                 /* Number of entries in azRedirect */
  Blob config, line, key, value, value2;
................................................................................
**
**        fossil http REPOSITORY INFILE OUTFILE IPADDR
**
** The argv==6 form is used by the win32 server only.
**
** COMMAND: http*
**
** Usage: %fossil http REPOSITORY ?OPTIONS?
**
** Handle a single HTTP request appearing on stdin.  The resulting webpage
** is delivered on stdout.  This method is used to launch an HTTP request
** handler from inetd, for example.  The argument is the name of the 
** repository.
**
** If REPOSITORY is a directory that contains one or more respositories
................................................................................
** with names of the form "*.fossil" then the first element of the URL
** pathname selects among the various repositories.  If the pathname does
** not select a valid repository and the --notfound option is available,
** then the server redirects (HTTP code 302) to the URL of --notfound.
**
** The --host option can be used to specify the hostname for the server.
** The --https option indicates that the request came from HTTPS rather
** than HTTP. If --nossl is given, then SSL connections will not be available,
** thus also no redirecting from http: to https: will take place.
**

** If the --localauth option is given, then automatic login is performed
** for requests coming from localhost, if the "localauth" setting is not
** enabled.
**



** Options:
**   --localauth    enable automatic login for local connections
**   --host NAME    specify hostname of the server
**   --https        signal a request coming in via https
**   --nossl        signal that no SSL connections are available
**   --notfound URL use URL as "HTTP 404, object not found" page.
**


** See also: cgi, server, winsrv
*/
void cmd_http(void){
  const char *zIpAddr;
  const char *zNotFound;
  const char *zHost;
  zNotFound = find_option("notfound", 0, 1);
  g.useLocalauth = find_option("localauth", 0, 0)!=0;
................................................................................
/*
** Note that the following command is used by ssh:// processing.
**
** COMMAND: test-http
** Works like the http command but gives setup permission to all users.
*/
void cmd_test_http(void){
  login_set_capabilities("sx", 0);
  g.useLocalauth = 1;
  cgi_set_parameter("REMOTE_ADDR", "127.0.0.1");
  g.httpIn = stdin;
  g.httpOut = stdout;
  find_server_repository(0);
  g.cgiOutput = 1;
  g.fullHttpReply = 1;
  cgi_handle_http_request(0);
  process_one_web_page(0);
................................................................................
#if !defined(_WIN32)
#if !defined(__DARWIN__) && !defined(__APPLE__)
/*
** Search for an executable on the PATH environment variable.
** Return true (1) if found and false (0) if not found.
*/
static int binaryOnPath(const char *zBinary){
  const char *zPath = fossil_getenv("PATH");
  char *zFull;
  int i;
  int bExists;
  while( zPath && zPath[0] ){
    while( zPath[0]==':' ) zPath++;
    for(i=0; zPath[i] && zPath[i]!=':'; i++){}
    zFull = mprintf("%.*s/%s", i, zPath, zBinary);
................................................................................
#endif
#endif

/*
** COMMAND: server*
** COMMAND: ui
**
** Usage: %fossil server ?OPTIONS? ?REPOSITORY?
**    Or: %fossil ui ?OPTIONS? ?REPOSITORY?
**
** Open a socket and begin listening and responding to HTTP requests on
** TCP port 8080, or on any other TCP port defined by the -P or
** --port option.  The optional argument is the name of the repository.
** The repository argument may be omitted if the working directory is
** within an open checkout.
**
................................................................................
** various repositories.
**
** By default, the "ui" command provides full administrative access without
** having to log in.  This can be disabled by setting turning off the
** "localauth" setting.  Automatic login for the "server" command is available
** if the --localauth option is present and the "localauth" setting is off
** and the connection is from localhost.
** Options:
**   --localauth         enable automatic login for requests from localhost
**   -P|--port TCPPORT   listen to request on port TCPPORT
**   -R|--root ROOT      map fossil at virtual directory ROOT in reverse 
**                       proxying
**   --th-trace          trace TH1 execution (for debugging purposes)
**
** See also: cgi, http, winsrv
*/
void cmd_webserver(void){
  int iPort, mxPort;        /* Range of TCP ports allowed */
  const char *zPort;        /* Value of the --port option */
  char *zBrowser;           /* Name of web browser program */
  char *zBrowserCmd = 0;    /* Command to launch the web browser */
  int isUiCmd;              /* True if command is "ui", not "server' */

Changes to src/main.mk.

1




2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
..
48
49
50
51
52
53
54

55

56
57
58
59
60
61
62
..
99
100
101
102
103
104
105

106
107
108
109
110
111
112
...
143
144
145
146
147
148
149

150

151
152
153
154
155
156
157
...
194
195
196
197
198
199
200

201
202
203
204
205
206
207
...
238
239
240
241
242
243
244

245

246
247
248
249
250
251
252
...
289
290
291
292
293
294
295

296
297
298
299
300
301
302
...
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
...
332
333
334
335
336
337
338



339
340
341
342
343
344
345
346
347
...
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
...
646
647
648
649
650
651
652







653
654
655
656
657
658
659







660
661
662
663
664
665
666
....
1003
1004
1005
1006
1007
1008
1009







1010
1011
1012
1013
1014
1015
1016
# DO NOT EDIT




#
# This file is automatically generated.  Instead of editing this
# file, edit "makemake.tcl" then run "tclsh makemake.tcl"
# to regenerate this file.
#
# This file is included by primary Makefile.
#

XTCC = $(TCC) $(CFLAGS) -I. -I$(SRCDIR)


SRC = \
  $(SRCDIR)/add.c \
  $(SRCDIR)/allrepo.c \
  $(SRCDIR)/attach.c \
  $(SRCDIR)/bag.c \
................................................................................
  $(SRCDIR)/http_ssl.c \
  $(SRCDIR)/http_transport.c \
  $(SRCDIR)/import.c \
  $(SRCDIR)/info.c \
  $(SRCDIR)/json.c \
  $(SRCDIR)/json_artifact.c \
  $(SRCDIR)/json_branch.c \

  $(SRCDIR)/json_diff.c \

  $(SRCDIR)/json_login.c \
  $(SRCDIR)/json_query.c \
  $(SRCDIR)/json_report.c \
  $(SRCDIR)/json_tag.c \
  $(SRCDIR)/json_timeline.c \
  $(SRCDIR)/json_user.c \
  $(SRCDIR)/json_wiki.c \
................................................................................
  $(SRCDIR)/user.c \
  $(SRCDIR)/verify.c \
  $(SRCDIR)/vfile.c \
  $(SRCDIR)/wiki.c \
  $(SRCDIR)/wikiformat.c \
  $(SRCDIR)/winhttp.c \
  $(SRCDIR)/xfer.c \

  $(SRCDIR)/zip.c

TRANS_SRC = \
  $(OBJDIR)/add_.c \
  $(OBJDIR)/allrepo_.c \
  $(OBJDIR)/attach_.c \
  $(OBJDIR)/bag_.c \
................................................................................
  $(OBJDIR)/http_ssl_.c \
  $(OBJDIR)/http_transport_.c \
  $(OBJDIR)/import_.c \
  $(OBJDIR)/info_.c \
  $(OBJDIR)/json_.c \
  $(OBJDIR)/json_artifact_.c \
  $(OBJDIR)/json_branch_.c \

  $(OBJDIR)/json_diff_.c \

  $(OBJDIR)/json_login_.c \
  $(OBJDIR)/json_query_.c \
  $(OBJDIR)/json_report_.c \
  $(OBJDIR)/json_tag_.c \
  $(OBJDIR)/json_timeline_.c \
  $(OBJDIR)/json_user_.c \
  $(OBJDIR)/json_wiki_.c \
................................................................................
  $(OBJDIR)/user_.c \
  $(OBJDIR)/verify_.c \
  $(OBJDIR)/vfile_.c \
  $(OBJDIR)/wiki_.c \
  $(OBJDIR)/wikiformat_.c \
  $(OBJDIR)/winhttp_.c \
  $(OBJDIR)/xfer_.c \

  $(OBJDIR)/zip_.c

OBJ = \
 $(OBJDIR)/add.o \
 $(OBJDIR)/allrepo.o \
 $(OBJDIR)/attach.o \
 $(OBJDIR)/bag.o \
................................................................................
 $(OBJDIR)/http_ssl.o \
 $(OBJDIR)/http_transport.o \
 $(OBJDIR)/import.o \
 $(OBJDIR)/info.o \
 $(OBJDIR)/json.o \
 $(OBJDIR)/json_artifact.o \
 $(OBJDIR)/json_branch.o \

 $(OBJDIR)/json_diff.o \

 $(OBJDIR)/json_login.o \
 $(OBJDIR)/json_query.o \
 $(OBJDIR)/json_report.o \
 $(OBJDIR)/json_tag.o \
 $(OBJDIR)/json_timeline.o \
 $(OBJDIR)/json_user.o \
 $(OBJDIR)/json_wiki.o \
................................................................................
 $(OBJDIR)/user.o \
 $(OBJDIR)/verify.o \
 $(OBJDIR)/vfile.o \
 $(OBJDIR)/wiki.o \
 $(OBJDIR)/wikiformat.o \
 $(OBJDIR)/winhttp.o \
 $(OBJDIR)/xfer.o \

 $(OBJDIR)/zip.o

APPNAME = fossil$(E)



all:	$(OBJDIR) $(APPNAME)
................................................................................

$(OBJDIR)/mkindex:	$(SRCDIR)/mkindex.c
	$(BCC) -o $(OBJDIR)/mkindex $(SRCDIR)/mkindex.c

$(OBJDIR)/mkversion:	$(SRCDIR)/mkversion.c
	$(BCC) -o $(OBJDIR)/mkversion $(SRCDIR)/mkversion.c

# WARNING. DANGER. Running the testsuite modifies the repository the
# build is done from, i.e. the checkout belongs to. Do not sync/push
# the repository after running the tests.
test:	$(OBJDIR) $(APPNAME)
	$(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME)

$(OBJDIR)/VERSION.h:	$(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION $(OBJDIR)/mkversion
	$(OBJDIR)/mkversion $(SRCDIR)/../manifest.uuid  $(SRCDIR)/../manifest  $(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h
................................................................................
# to 1. If it is set to 1, then there is no need to build or link
# the sqlite3.o object. Instead, the system sqlite will be linked
# using -lsqlite3.
SQLITE3_OBJ.1 = 
SQLITE3_OBJ.0 = $(OBJDIR)/sqlite3.o
SQLITE3_OBJ.  = $(SQLITE3_OBJ.0)




TCL_OBJ.1 =
TCL_OBJ.0 = $(OBJDIR)/th_tcl.o
TCL_OBJ. = $(TCL_OBJ.0)

EXTRAOBJ =  $(SQLITE3_OBJ.$(USE_SYSTEM_SQLITE))  $(OBJDIR)/shell.o  $(OBJDIR)/th.o  $(OBJDIR)/th_lang.o  $(TCL_OBJ.$(FOSSIL_ENABLE_TCL))  $(OBJDIR)/cson_amalgamation.o

$(APPNAME):	$(OBJDIR)/headers $(OBJ) $(EXTRAOBJ)
	$(TCC) -o $(APPNAME) $(OBJ) $(EXTRAOBJ) $(LIB)

................................................................................
clean:	
	rm -rf $(OBJDIR)/* $(APPNAME)


$(OBJDIR)/page_index.h: $(TRANS_SRC) $(OBJDIR)/mkindex
	$(OBJDIR)/mkindex $(TRANS_SRC) >$@
$(OBJDIR)/headers:	$(OBJDIR)/page_index.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)/blob_.c:$(OBJDIR)/blob.h $(OBJDIR)/branch_.c:$(OBJDIR)/branch.h $(OBJDIR)/browse_.c:$(OBJDIR)/browse.h $(OBJDIR)/captcha_.c:$(OBJDIR)/captcha.h $(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h $(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h $(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h $(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h $(OBJDIR)/clone_.c:$(OBJDIR)/clone.h $(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h $(OBJDIR)/configure_.c:$(OBJDIR)/configure.h $(OBJDIR)/content_.c:$(OBJDIR)/content.h $(OBJDIR)/db_.c:$(OBJDIR)/db.h $(OBJDIR)/delta_.c:$(OBJDIR)/delta.h $(OBJDIR)/deltacmd_.c:$(OBJDIR)/deltacmd.h $(OBJDIR)/descendants_.c:$(OBJDIR)/descendants.h $(OBJDIR)/diff_.c:$(OBJDIR)/diff.h $(OBJDIR)/diffcmd_.c:$(OBJDIR)/diffcmd.h $(OBJDIR)/doc_.c:$(OBJDIR)/doc.h $(OBJDIR)/encode_.c:$(OBJDIR)/encode.h $(OBJDIR)/event_.c:$(OBJDIR)/event.h $(OBJDIR)/export_.c:$(OBJDIR)/export.h $(OBJDIR)/file_.c:$(OBJDIR)/file.h $(OBJDIR)/finfo_.c:$(OBJDIR)/finfo.h $(OBJDIR)/glob_.c:$(OBJDIR)/glob.h $(OBJDIR)/graph_.c:$(OBJDIR)/graph.h $(OBJDIR)/gzip_.c:$(OBJDIR)/gzip.h $(OBJDIR)/http_.c:$(OBJDIR)/http.h $(OBJDIR)/http_socket_.c:$(OBJDIR)/http_socket.h $(OBJDIR)/http_ssl_.c:$(OBJDIR)/http_ssl.h $(OBJDIR)/http_transport_.c:$(OBJDIR)/http_transport.h $(OBJDIR)/import_.c:$(OBJDIR)/import.h $(OBJDIR)/info_.c:$(OBJDIR)/info.h $(OBJDIR)/json_.c:$(OBJDIR)/json.h $(OBJDIR)/json_artifact_.c:$(OBJDIR)/json_artifact.h $(OBJDIR)/json_branch_.c:$(OBJDIR)/json_branch.h $(OBJDIR)/json_diff_.c:$(OBJDIR)/json_diff.h $(OBJDIR)/json_login_.c:$(OBJDIR)/json_login.h $(OBJDIR)/json_query_.c:$(OBJDIR)/json_query.h $(OBJDIR)/json_report_.c:$(OBJDIR)/json_report.h $(OBJDIR)/json_tag_.c:$(OBJDIR)/json_tag.h $(OBJDIR)/json_timeline_.c:$(OBJDIR)/json_timeline.h $(OBJDIR)/json_user_.c:$(OBJDIR)/json_user.h $(OBJDIR)/json_wiki_.c:$(OBJDIR)/json_wiki.h $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h $(OBJDIR)/login_.c:$(OBJDIR)/login.h $(OBJDIR)/main_.c:$(OBJDIR)/main.h $(OBJDIR)/manifest_.c:$(OBJDIR)/manifest.h $(OBJDIR)/md5_.c:$(OBJDIR)/md5.h $(OBJDIR)/merge_.c:$(OBJDIR)/merge.h $(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h $(OBJDIR)/name_.c:$(OBJDIR)/name.h $(OBJDIR)/path_.c:$(OBJDIR)/path.h $(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h $(OBJDIR)/popen_.c:$(OBJDIR)/popen.h $(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h $(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h $(OBJDIR)/report_.c:$(OBJDIR)/report.h $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h $(OBJDIR)/search_.c:$(OBJDIR)/search.h $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h $(OBJDIR)/sha1_.c:$(OBJDIR)/sha1.h $(OBJDIR)/shun_.c:$(OBJDIR)/shun.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)/tktsetup_.c:$(OBJDIR)/tktsetup.h $(OBJDIR)/undo_.c:$(OBJDIR)/undo.h $(OBJDIR)/update_.c:$(OBJDIR)/update.h $(OBJDIR)/url_.c:$(OBJDIR)/url.h $(OBJDIR)/user_.c:$(OBJDIR)/user.h $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h $(OBJDIR)/xfer_.c:$(OBJDIR)/xfer.h $(OBJDIR)/zip_.c:$(OBJDIR)/zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h $(OBJDIR)/VERSION.h
	touch $(OBJDIR)/headers
$(OBJDIR)/headers: Makefile
$(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h
Makefile:
$(OBJDIR)/add_.c:	$(SRCDIR)/add.c $(OBJDIR)/translate
	$(OBJDIR)/translate $(SRCDIR)/add.c >$(OBJDIR)/add_.c

$(OBJDIR)/add.o:	$(OBJDIR)/add_.c $(OBJDIR)/add.h  $(SRCDIR)/config.h
	$(XTCC) -o $(OBJDIR)/add.o -c $(OBJDIR)/add_.c

................................................................................
$(OBJDIR)/json_branch_.c:	$(SRCDIR)/json_branch.c $(OBJDIR)/translate
	$(OBJDIR)/translate $(SRCDIR)/json_branch.c >$(OBJDIR)/json_branch_.c

$(OBJDIR)/json_branch.o:	$(OBJDIR)/json_branch_.c $(OBJDIR)/json_branch.h  $(SRCDIR)/config.h
	$(XTCC) -o $(OBJDIR)/json_branch.o -c $(OBJDIR)/json_branch_.c

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







$(OBJDIR)/json_diff_.c:	$(SRCDIR)/json_diff.c $(OBJDIR)/translate
	$(OBJDIR)/translate $(SRCDIR)/json_diff.c >$(OBJDIR)/json_diff_.c

$(OBJDIR)/json_diff.o:	$(OBJDIR)/json_diff_.c $(OBJDIR)/json_diff.h  $(SRCDIR)/config.h
	$(XTCC) -o $(OBJDIR)/json_diff.o -c $(OBJDIR)/json_diff_.c

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







$(OBJDIR)/json_login_.c:	$(SRCDIR)/json_login.c $(OBJDIR)/translate
	$(OBJDIR)/translate $(SRCDIR)/json_login.c >$(OBJDIR)/json_login_.c

$(OBJDIR)/json_login.o:	$(OBJDIR)/json_login_.c $(OBJDIR)/json_login.h  $(SRCDIR)/config.h
	$(XTCC) -o $(OBJDIR)/json_login.o -c $(OBJDIR)/json_login_.c

$(OBJDIR)/json_login.h:	$(OBJDIR)/headers
................................................................................
$(OBJDIR)/xfer_.c:	$(SRCDIR)/xfer.c $(OBJDIR)/translate
	$(OBJDIR)/translate $(SRCDIR)/xfer.c >$(OBJDIR)/xfer_.c

$(OBJDIR)/xfer.o:	$(OBJDIR)/xfer_.c $(OBJDIR)/xfer.h  $(SRCDIR)/config.h
	$(XTCC) -o $(OBJDIR)/xfer.o -c $(OBJDIR)/xfer_.c

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







$(OBJDIR)/zip_.c:	$(SRCDIR)/zip.c $(OBJDIR)/translate
	$(OBJDIR)/translate $(SRCDIR)/zip.c >$(OBJDIR)/zip_.c

$(OBJDIR)/zip.o:	$(OBJDIR)/zip_.c $(OBJDIR)/zip.h  $(SRCDIR)/config.h
	$(XTCC) -o $(OBJDIR)/zip.o -c $(OBJDIR)/zip_.c

$(OBJDIR)/zip.h:	$(OBJDIR)/headers
<
>
>
>
>








|







 







>

>







 







>







 







>

>







 







>







 







>

>







 







>







 







|







 







>
>
>
|
|







 







|


|







 







>
>
>
>
>
>
>







>
>
>
>
>
>
>







 







>
>
>
>
>
>
>








1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
..
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
...
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
...
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
...
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
...
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
...
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
...
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
...
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
...
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
...
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
....
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052

#
##############################################################################
# WARNING: DO NOT EDIT, AUTOMATICALLY GENERATED FILE (SEE "src/makemake.tcl")
##############################################################################
#
# This file is automatically generated.  Instead of editing this
# file, edit "makemake.tcl" then run "tclsh makemake.tcl"
# to regenerate this file.
#
# This file is included by primary Makefile.
#

XTCC = $(TCC) $(CFLAGS) -I. -I$(SRCDIR) -I$(OBJDIR)


SRC = \
  $(SRCDIR)/add.c \
  $(SRCDIR)/allrepo.c \
  $(SRCDIR)/attach.c \
  $(SRCDIR)/bag.c \
................................................................................
  $(SRCDIR)/http_ssl.c \
  $(SRCDIR)/http_transport.c \
  $(SRCDIR)/import.c \
  $(SRCDIR)/info.c \
  $(SRCDIR)/json.c \
  $(SRCDIR)/json_artifact.c \
  $(SRCDIR)/json_branch.c \
  $(SRCDIR)/json_config.c \
  $(SRCDIR)/json_diff.c \
  $(SRCDIR)/json_finfo.c \
  $(SRCDIR)/json_login.c \
  $(SRCDIR)/json_query.c \
  $(SRCDIR)/json_report.c \
  $(SRCDIR)/json_tag.c \
  $(SRCDIR)/json_timeline.c \
  $(SRCDIR)/json_user.c \
  $(SRCDIR)/json_wiki.c \
................................................................................
  $(SRCDIR)/user.c \
  $(SRCDIR)/verify.c \
  $(SRCDIR)/vfile.c \
  $(SRCDIR)/wiki.c \
  $(SRCDIR)/wikiformat.c \
  $(SRCDIR)/winhttp.c \
  $(SRCDIR)/xfer.c \
  $(SRCDIR)/xfersetup.c \
  $(SRCDIR)/zip.c

TRANS_SRC = \
  $(OBJDIR)/add_.c \
  $(OBJDIR)/allrepo_.c \
  $(OBJDIR)/attach_.c \
  $(OBJDIR)/bag_.c \
................................................................................
  $(OBJDIR)/http_ssl_.c \
  $(OBJDIR)/http_transport_.c \
  $(OBJDIR)/import_.c \
  $(OBJDIR)/info_.c \
  $(OBJDIR)/json_.c \
  $(OBJDIR)/json_artifact_.c \
  $(OBJDIR)/json_branch_.c \
  $(OBJDIR)/json_config_.c \
  $(OBJDIR)/json_diff_.c \
  $(OBJDIR)/json_finfo_.c \
  $(OBJDIR)/json_login_.c \
  $(OBJDIR)/json_query_.c \
  $(OBJDIR)/json_report_.c \
  $(OBJDIR)/json_tag_.c \
  $(OBJDIR)/json_timeline_.c \
  $(OBJDIR)/json_user_.c \
  $(OBJDIR)/json_wiki_.c \
................................................................................
  $(OBJDIR)/user_.c \
  $(OBJDIR)/verify_.c \
  $(OBJDIR)/vfile_.c \
  $(OBJDIR)/wiki_.c \
  $(OBJDIR)/wikiformat_.c \
  $(OBJDIR)/winhttp_.c \
  $(OBJDIR)/xfer_.c \
  $(OBJDIR)/xfersetup_.c \
  $(OBJDIR)/zip_.c

OBJ = \
 $(OBJDIR)/add.o \
 $(OBJDIR)/allrepo.o \
 $(OBJDIR)/attach.o \
 $(OBJDIR)/bag.o \
................................................................................
 $(OBJDIR)/http_ssl.o \
 $(OBJDIR)/http_transport.o \
 $(OBJDIR)/import.o \
 $(OBJDIR)/info.o \
 $(OBJDIR)/json.o \
 $(OBJDIR)/json_artifact.o \
 $(OBJDIR)/json_branch.o \
 $(OBJDIR)/json_config.o \
 $(OBJDIR)/json_diff.o \
 $(OBJDIR)/json_finfo.o \
 $(OBJDIR)/json_login.o \
 $(OBJDIR)/json_query.o \
 $(OBJDIR)/json_report.o \
 $(OBJDIR)/json_tag.o \
 $(OBJDIR)/json_timeline.o \
 $(OBJDIR)/json_user.o \
 $(OBJDIR)/json_wiki.o \
................................................................................
 $(OBJDIR)/user.o \
 $(OBJDIR)/verify.o \
 $(OBJDIR)/vfile.o \
 $(OBJDIR)/wiki.o \
 $(OBJDIR)/wikiformat.o \
 $(OBJDIR)/winhttp.o \
 $(OBJDIR)/xfer.o \
 $(OBJDIR)/xfersetup.o \
 $(OBJDIR)/zip.o

APPNAME = fossil$(E)



all:	$(OBJDIR) $(APPNAME)
................................................................................

$(OBJDIR)/mkindex:	$(SRCDIR)/mkindex.c
	$(BCC) -o $(OBJDIR)/mkindex $(SRCDIR)/mkindex.c

$(OBJDIR)/mkversion:	$(SRCDIR)/mkversion.c
	$(BCC) -o $(OBJDIR)/mkversion $(SRCDIR)/mkversion.c

# WARNING. DANGER. Running the test suite modifies the repository the
# build is done from, i.e. the checkout belongs to. Do not sync/push
# the repository after running the tests.
test:	$(OBJDIR) $(APPNAME)
	$(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME)

$(OBJDIR)/VERSION.h:	$(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION $(OBJDIR)/mkversion
	$(OBJDIR)/mkversion $(SRCDIR)/../manifest.uuid  $(SRCDIR)/../manifest  $(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h
................................................................................
# to 1. If it is set to 1, then there is no need to build or link
# the sqlite3.o object. Instead, the system sqlite will be linked
# using -lsqlite3.
SQLITE3_OBJ.1 = 
SQLITE3_OBJ.0 = $(OBJDIR)/sqlite3.o
SQLITE3_OBJ.  = $(SQLITE3_OBJ.0)

# The FOSSIL_ENABLE_TCL variable may be undefined, set to 0, or set to 1.
# If it is set to 1, then we need to build the Tcl integration code and
# link to the Tcl library.
TCL_OBJ.0 = 
TCL_OBJ.1 = $(OBJDIR)/th_tcl.o
TCL_OBJ. = $(TCL_OBJ.0)

EXTRAOBJ =  $(SQLITE3_OBJ.$(USE_SYSTEM_SQLITE))  $(OBJDIR)/shell.o  $(OBJDIR)/th.o  $(OBJDIR)/th_lang.o  $(TCL_OBJ.$(FOSSIL_ENABLE_TCL))  $(OBJDIR)/cson_amalgamation.o

$(APPNAME):	$(OBJDIR)/headers $(OBJ) $(EXTRAOBJ)
	$(TCC) -o $(APPNAME) $(OBJ) $(EXTRAOBJ) $(LIB)

................................................................................
clean:	
	rm -rf $(OBJDIR)/* $(APPNAME)


$(OBJDIR)/page_index.h: $(TRANS_SRC) $(OBJDIR)/mkindex
	$(OBJDIR)/mkindex $(TRANS_SRC) >$@
$(OBJDIR)/headers:	$(OBJDIR)/page_index.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)/blob_.c:$(OBJDIR)/blob.h $(OBJDIR)/branch_.c:$(OBJDIR)/branch.h $(OBJDIR)/browse_.c:$(OBJDIR)/browse.h $(OBJDIR)/captcha_.c:$(OBJDIR)/captcha.h $(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h $(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h $(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h $(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h $(OBJDIR)/clone_.c:$(OBJDIR)/clone.h $(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h $(OBJDIR)/configure_.c:$(OBJDIR)/configure.h $(OBJDIR)/content_.c:$(OBJDIR)/content.h $(OBJDIR)/db_.c:$(OBJDIR)/db.h $(OBJDIR)/delta_.c:$(OBJDIR)/delta.h $(OBJDIR)/deltacmd_.c:$(OBJDIR)/deltacmd.h $(OBJDIR)/descendants_.c:$(OBJDIR)/descendants.h $(OBJDIR)/diff_.c:$(OBJDIR)/diff.h $(OBJDIR)/diffcmd_.c:$(OBJDIR)/diffcmd.h $(OBJDIR)/doc_.c:$(OBJDIR)/doc.h $(OBJDIR)/encode_.c:$(OBJDIR)/encode.h $(OBJDIR)/event_.c:$(OBJDIR)/event.h $(OBJDIR)/export_.c:$(OBJDIR)/export.h $(OBJDIR)/file_.c:$(OBJDIR)/file.h $(OBJDIR)/finfo_.c:$(OBJDIR)/finfo.h $(OBJDIR)/glob_.c:$(OBJDIR)/glob.h $(OBJDIR)/graph_.c:$(OBJDIR)/graph.h $(OBJDIR)/gzip_.c:$(OBJDIR)/gzip.h $(OBJDIR)/http_.c:$(OBJDIR)/http.h $(OBJDIR)/http_socket_.c:$(OBJDIR)/http_socket.h $(OBJDIR)/http_ssl_.c:$(OBJDIR)/http_ssl.h $(OBJDIR)/http_transport_.c:$(OBJDIR)/http_transport.h $(OBJDIR)/import_.c:$(OBJDIR)/import.h $(OBJDIR)/info_.c:$(OBJDIR)/info.h $(OBJDIR)/json_.c:$(OBJDIR)/json.h $(OBJDIR)/json_artifact_.c:$(OBJDIR)/json_artifact.h $(OBJDIR)/json_branch_.c:$(OBJDIR)/json_branch.h $(OBJDIR)/json_config_.c:$(OBJDIR)/json_config.h $(OBJDIR)/json_diff_.c:$(OBJDIR)/json_diff.h $(OBJDIR)/json_finfo_.c:$(OBJDIR)/json_finfo.h $(OBJDIR)/json_login_.c:$(OBJDIR)/json_login.h $(OBJDIR)/json_query_.c:$(OBJDIR)/json_query.h $(OBJDIR)/json_report_.c:$(OBJDIR)/json_report.h $(OBJDIR)/json_tag_.c:$(OBJDIR)/json_tag.h $(OBJDIR)/json_timeline_.c:$(OBJDIR)/json_timeline.h $(OBJDIR)/json_user_.c:$(OBJDIR)/json_user.h $(OBJDIR)/json_wiki_.c:$(OBJDIR)/json_wiki.h $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h $(OBJDIR)/login_.c:$(OBJDIR)/login.h $(OBJDIR)/main_.c:$(OBJDIR)/main.h $(OBJDIR)/manifest_.c:$(OBJDIR)/manifest.h $(OBJDIR)/md5_.c:$(OBJDIR)/md5.h $(OBJDIR)/merge_.c:$(OBJDIR)/merge.h $(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h $(OBJDIR)/name_.c:$(OBJDIR)/name.h $(OBJDIR)/path_.c:$(OBJDIR)/path.h $(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h $(OBJDIR)/popen_.c:$(OBJDIR)/popen.h $(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h $(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h $(OBJDIR)/report_.c:$(OBJDIR)/report.h $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h $(OBJDIR)/search_.c:$(OBJDIR)/search.h $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h $(OBJDIR)/sha1_.c:$(OBJDIR)/sha1.h $(OBJDIR)/shun_.c:$(OBJDIR)/shun.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)/tktsetup_.c:$(OBJDIR)/tktsetup.h $(OBJDIR)/undo_.c:$(OBJDIR)/undo.h $(OBJDIR)/update_.c:$(OBJDIR)/update.h $(OBJDIR)/url_.c:$(OBJDIR)/url.h $(OBJDIR)/user_.c:$(OBJDIR)/user.h $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h $(OBJDIR)/xfer_.c:$(OBJDIR)/xfer.h $(OBJDIR)/xfersetup_.c:$(OBJDIR)/xfersetup.h $(OBJDIR)/zip_.c:$(OBJDIR)/zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h $(OBJDIR)/VERSION.h
	touch $(OBJDIR)/headers
$(OBJDIR)/headers: Makefile
$(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_config.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_finfo.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h
Makefile:
$(OBJDIR)/add_.c:	$(SRCDIR)/add.c $(OBJDIR)/translate
	$(OBJDIR)/translate $(SRCDIR)/add.c >$(OBJDIR)/add_.c

$(OBJDIR)/add.o:	$(OBJDIR)/add_.c $(OBJDIR)/add.h  $(SRCDIR)/config.h
	$(XTCC) -o $(OBJDIR)/add.o -c $(OBJDIR)/add_.c

................................................................................
$(OBJDIR)/json_branch_.c:	$(SRCDIR)/json_branch.c $(OBJDIR)/translate
	$(OBJDIR)/translate $(SRCDIR)/json_branch.c >$(OBJDIR)/json_branch_.c

$(OBJDIR)/json_branch.o:	$(OBJDIR)/json_branch_.c $(OBJDIR)/json_branch.h  $(SRCDIR)/config.h
	$(XTCC) -o $(OBJDIR)/json_branch.o -c $(OBJDIR)/json_branch_.c

$(OBJDIR)/json_branch.h:	$(OBJDIR)/headers
$(OBJDIR)/json_config_.c:	$(SRCDIR)/json_config.c $(OBJDIR)/translate
	$(OBJDIR)/translate $(SRCDIR)/json_config.c >$(OBJDIR)/json_config_.c

$(OBJDIR)/json_config.o:	$(OBJDIR)/json_config_.c $(OBJDIR)/json_config.h  $(SRCDIR)/config.h
	$(XTCC) -o $(OBJDIR)/json_config.o -c $(OBJDIR)/json_config_.c

$(OBJDIR)/json_config.h:	$(OBJDIR)/headers
$(OBJDIR)/json_diff_.c:	$(SRCDIR)/json_diff.c $(OBJDIR)/translate
	$(OBJDIR)/translate $(SRCDIR)/json_diff.c >$(OBJDIR)/json_diff_.c

$(OBJDIR)/json_diff.o:	$(OBJDIR)/json_diff_.c $(OBJDIR)/json_diff.h  $(SRCDIR)/config.h
	$(XTCC) -o $(OBJDIR)/json_diff.o -c $(OBJDIR)/json_diff_.c

$(OBJDIR)/json_diff.h:	$(OBJDIR)/headers
$(OBJDIR)/json_finfo_.c:	$(SRCDIR)/json_finfo.c $(OBJDIR)/translate
	$(OBJDIR)/translate $(SRCDIR)/json_finfo.c >$(OBJDIR)/json_finfo_.c

$(OBJDIR)/json_finfo.o:	$(OBJDIR)/json_finfo_.c $(OBJDIR)/json_finfo.h  $(SRCDIR)/config.h
	$(XTCC) -o $(OBJDIR)/json_finfo.o -c $(OBJDIR)/json_finfo_.c

$(OBJDIR)/json_finfo.h:	$(OBJDIR)/headers
$(OBJDIR)/json_login_.c:	$(SRCDIR)/json_login.c $(OBJDIR)/translate
	$(OBJDIR)/translate $(SRCDIR)/json_login.c >$(OBJDIR)/json_login_.c

$(OBJDIR)/json_login.o:	$(OBJDIR)/json_login_.c $(OBJDIR)/json_login.h  $(SRCDIR)/config.h
	$(XTCC) -o $(OBJDIR)/json_login.o -c $(OBJDIR)/json_login_.c

$(OBJDIR)/json_login.h:	$(OBJDIR)/headers
................................................................................
$(OBJDIR)/xfer_.c:	$(SRCDIR)/xfer.c $(OBJDIR)/translate
	$(OBJDIR)/translate $(SRCDIR)/xfer.c >$(OBJDIR)/xfer_.c

$(OBJDIR)/xfer.o:	$(OBJDIR)/xfer_.c $(OBJDIR)/xfer.h  $(SRCDIR)/config.h
	$(XTCC) -o $(OBJDIR)/xfer.o -c $(OBJDIR)/xfer_.c

$(OBJDIR)/xfer.h:	$(OBJDIR)/headers
$(OBJDIR)/xfersetup_.c:	$(SRCDIR)/xfersetup.c $(OBJDIR)/translate
	$(OBJDIR)/translate $(SRCDIR)/xfersetup.c >$(OBJDIR)/xfersetup_.c

$(OBJDIR)/xfersetup.o:	$(OBJDIR)/xfersetup_.c $(OBJDIR)/xfersetup.h  $(SRCDIR)/config.h
	$(XTCC) -o $(OBJDIR)/xfersetup.o -c $(OBJDIR)/xfersetup_.c

$(OBJDIR)/xfersetup.h:	$(OBJDIR)/headers
$(OBJDIR)/zip_.c:	$(SRCDIR)/zip.c $(OBJDIR)/translate
	$(OBJDIR)/translate $(SRCDIR)/zip.c >$(OBJDIR)/zip_.c

$(OBJDIR)/zip.o:	$(OBJDIR)/zip_.c $(OBJDIR)/zip.h  $(SRCDIR)/config.h
	$(XTCC) -o $(OBJDIR)/zip.o -c $(OBJDIR)/zip_.c

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

Changes to src/makemake.tcl.

54
55
56
57
58
59
60

61

62
63
64
65
66
67
68
...
105
106
107
108
109
110
111

112
113
114
115
116
117
118
...
137
138
139
140
141
142
143
144



145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
...
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
...
207
208
209
210
211
212
213



214
215
216
217
218
219
220
221
222
...
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
...
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
...
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
...
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
...
629
630
631
632
633
634
635

636

637
638
639
640
641
642
643
...
666
667
668
669
670
671
672
673



674
675
676
677

678
679
680
681
682
683
684
...
782
783
784
785
786
787
788

789

790
791
792
793
794
795
796
...
819
820
821
822
823
824
825
826



827
828
829
830
831
832
833
834
835
836
  http_socket
  http_transport
  import
  info
  json
  json_artifact
  json_branch

  json_diff

  json_login
  json_query
  json_report
  json_tag
  json_timeline
  json_user
  json_wiki
................................................................................
  user
  verify
  vfile
  wiki
  wikiformat
  winhttp
  xfer

  zip
  http_ssl
}

# Name of the final application
#
set name fossil
................................................................................
##############################################################################
# Start by generating the "main.mk" makefile used for all unix systems.
#
puts "building main.mk"
set output_file [open main.mk w]
fconfigure $output_file -translation binary

writeln {# DO NOT EDIT



#
# This file is automatically generated.  Instead of editing this
# file, edit "makemake.tcl" then run "tclsh makemake.tcl"
# to regenerate this file.
#
# This file is included by primary Makefile.
#

XTCC = $(TCC) $(CFLAGS) -I. -I$(SRCDIR)

}
writeln -nonewline "SRC ="
foreach s [lsort $src] {
  writeln -nonewline " \\\n  \$(SRCDIR)/$s.c"
}
writeln "\n"
................................................................................

$(OBJDIR)/mkindex:	$(SRCDIR)/mkindex.c
	$(BCC) -o $(OBJDIR)/mkindex $(SRCDIR)/mkindex.c

$(OBJDIR)/mkversion:	$(SRCDIR)/mkversion.c
	$(BCC) -o $(OBJDIR)/mkversion $(SRCDIR)/mkversion.c

# WARNING. DANGER. Running the testsuite modifies the repository the
# build is done from, i.e. the checkout belongs to. Do not sync/push
# the repository after running the tests.
test:	$(OBJDIR) $(APPNAME)
	$(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME)

$(OBJDIR)/VERSION.h:	$(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION $(OBJDIR)/mkversion
	$(OBJDIR)/mkversion $(SRCDIR)/../manifest.uuid \
................................................................................
# to 1. If it is set to 1, then there is no need to build or link
# the sqlite3.o object. Instead, the system sqlite will be linked
# using -lsqlite3.
SQLITE3_OBJ.1 = 
SQLITE3_OBJ.0 = $(OBJDIR)/sqlite3.o
SQLITE3_OBJ.  = $(SQLITE3_OBJ.0)




TCL_OBJ.1 =
TCL_OBJ.0 = $(OBJDIR)/th_tcl.o
TCL_OBJ. = $(TCL_OBJ.0)

EXTRAOBJ = \
  $(SQLITE3_OBJ.$(USE_SYSTEM_SQLITE)) \
  $(OBJDIR)/shell.o \
  $(OBJDIR)/th.o \
  $(OBJDIR)/th_lang.o \
................................................................................
append mhargs " \$(OBJDIR)/VERSION.h"
writeln "\$(OBJDIR)/page_index.h: \$(TRANS_SRC) \$(OBJDIR)/mkindex"
writeln "\t\$(OBJDIR)/mkindex \$(TRANS_SRC) >$@"
writeln "\$(OBJDIR)/headers:\t\$(OBJDIR)/page_index.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_diff.o \$(OBJDIR)/json_login.o \$(OBJDIR)/json_query.o \$(OBJDIR)/json_report.o \$(OBJDIR)/json_tag.o \$(OBJDIR)/json_timeline.o \$(OBJDIR)/json_user.o \$(OBJDIR)/json_wiki.o : \$(SRCDIR)/json_detail.h"
writeln "Makefile:"
set extra_h(main) \$(OBJDIR)/page_index.h

foreach s [lsort $src] {
  writeln "\$(OBJDIR)/${s}_.c:\t\$(SRCDIR)/$s.c \$(OBJDIR)/translate"
  writeln "\t\$(OBJDIR)/translate \$(SRCDIR)/$s.c >\$(OBJDIR)/${s}_.c\n"
  writeln "\$(OBJDIR)/$s.o:\t\$(OBJDIR)/${s}_.c \$(OBJDIR)/$s.h $extra_h($s) \$(SRCDIR)/config.h"
................................................................................
#
puts "building ../win/Makefile.mingw"
set output_file [open ../win/Makefile.mingw w]
fconfigure $output_file -translation binary

writeln {#!/usr/bin/make
#








# This is a makefile for us on windows using mingw.
#
#### The toplevel directory of the source tree.  Fossil can be built
#    in a directory that is separate from the source tree.  Just change
#    the following to point from the build directory to the src/ folder.
#
SRCDIR = src

#### The directory into which object code files should be written.
#
#
OBJDIR = wbld

#### C Compiler and options for use in building executables that
#    will run on the platform that is doing the build.  This is used
#    to compile code-generator programs as part of the build process.
#    See TCC below for the C compiler for building the finished binary.
#
BCC = gcc





#### Enable HTTPS support via OpenSSL (links to libssl and libcrypto)
#
# FOSSIL_ENABLE_SSL=1

#### The directory in which the zlib compression library is installed.

#

#
ZLIBDIR = /programs/gnuwin32


















































#### C Compile and options for use in building executables that 
#    will run on the target platform.  This is usually the same
#    as BCC, unless you are cross-compiling.  This C compiler builds
#    the finished binary for fossil.  The BCC compiler above is used
#    for building intermediate code-generator tools.
#
TCC = gcc -Os -Wall -L$(ZLIBDIR)/lib -I$(ZLIBDIR)/include

# With HTTPS support
ifdef FOSSIL_ENABLE_SSL















TCC += -static -DFOSSIL_ENABLE_SSL=1










endif

#### Extra arguments for linking the finished binary.  Fossil needs
#    to link against the Z-Lib compression library.  There are no
#    other dependencies.  We sometimes add the -static option here
#    so that we can build a static executable that will run in a
#    chroot jail.
#
#LIB = -lz -lws2_32
# OpenSSL:


ifdef FOSSIL_ENABLE_SSL
LIB += -lssl -lcrypto -lgdi32
endif












LIB += -lmingwex -lz -lws2_32


#### Tcl shell for use in running the fossil testsuite.  This is only
#    used for testing.  If you do not run
#
TCLSH = tclsh

#### Nullsoft installer makensis location
#
MAKENSIS = "c:\Program Files\NSIS\makensis.exe"

#### Include a configuration file that can override any one of these settings.
#
-include config.w32

# STOP HERE
# You should not need to change anything below this line
................................................................................

$(OBJDIR)/mkindex:	$(SRCDIR)/mkindex.c
	$(BCC) -o $(OBJDIR)/mkindex $(SRCDIR)/mkindex.c

$(VERSION): $(SRCDIR)/mkversion.c
	$(BCC) -o $(OBJDIR)/version $(SRCDIR)/mkversion.c

# WARNING. DANGER. Running the testsuite modifies the repository the
# build is done from, i.e. the checkout belongs to. Do not sync/push
# the repository after running the tests.
test:	$(APPNAME)
	$(TCLSH) test/tester.tcl $(APPNAME)

$(OBJDIR)/VERSION.h:	$(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(VERSION)
	$(VERSION) $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h

EXTRAOBJ = \
  $(OBJDIR)/sqlite3.o \
  $(OBJDIR)/shell.o \
  $(OBJDIR)/th.o \
  $(OBJDIR)/th_lang.o \
  $(OBJDIR)/cson_amalgamation.o





$(APPNAME):	$(OBJDIR)/headers $(OBJ) $(EXTRAOBJ) $(OBJDIR)/icon.o
	$(TCC) -o $(APPNAME) $(OBJ) $(EXTRAOBJ) $(LIB) $(OBJDIR)/icon.o

# This rule prevents make from using its default rules to try build
# an executable named "manifest" out of the file named "manifest.c"
#
$(SRCDIR)/../manifest:	
	# noop

# Requires msys to be installed in addition to the mingw, for the "rm"
# command.  "del" will not work here because it is not a separate command
# but a MSDOS-shell builtin.
#
clean:	
	rm -rf $(OBJDIR) $(APPNAME)

setup: $(OBJDIR) $(APPNAME)
	$(MAKENSIS) ./fossil.nsi

}

................................................................................
writeln "\$(OBJDIR)/sqlite3.o:\t\$(SRCDIR)/sqlite3.c"
set opt $SQLITE_OPTIONS
writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/sqlite3.c -o \$(OBJDIR)/sqlite3.o\n"

set opt {}
writeln "\$(OBJDIR)/cson_amalgamation.o:\t\$(SRCDIR)/cson_amalgamation.c"
writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/cson_amalgamation.c -o \$(OBJDIR)/cson_amalgamation.o -DCSON_FOSSIL_MODE\n"
writeln "\$(OBJDIR)/json.o \$(OBJDIR)/json_artifact.o \$(OBJDIR)/json_branch.o \$(OBJDIR)/json_diff.o \$(OBJDIR)/json_login.o \$(OBJDIR)/json_query.o \$(OBJDIR)/json_report.o \$(OBJDIR)/json_tag.o \$(OBJDIR)/json_timeline.o \$(OBJDIR)/json_user.o \$(OBJDIR)/json_wiki.o : \$(SRCDIR)/json_detail.h"

writeln "\$(OBJDIR)/shell.o:\t\$(SRCDIR)/shell.c \$(SRCDIR)/sqlite3.h"
set opt {-Dmain=sqlite3_shell}
append opt " -DSQLITE_OMIT_LOAD_EXTENSION=1"
writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/shell.c -o \$(OBJDIR)/shell.o\n"

writeln "\$(OBJDIR)/th.o:\t\$(SRCDIR)/th.c"
writeln "\t\$(XTCC) -I\$(SRCDIR) -c \$(SRCDIR)/th.c -o \$(OBJDIR)/th.o\n"

writeln "\$(OBJDIR)/th_lang.o:\t\$(SRCDIR)/th_lang.c"
writeln "\t\$(XTCC) -I\$(SRCDIR) -c \$(SRCDIR)/th_lang.c -o \$(OBJDIR)/th_lang.o\n"







close $output_file
#
# End of the main.mk output
##############################################################################
##############################################################################
##############################################################################
# Begin win/Makefile.dmc
#
puts "building ../win/Makefile.dmc"
set output_file [open ../win/Makefile.dmc w]
fconfigure $output_file -translation binary

writeln {# DO NOT EDIT



#
# This file is automatically generated.  Instead of editing this
# file, edit "makemake.tcl" then run "tclsh src/makemake.tcl"
# to regenerate this file.

B      = ..
SRCDIR = $B\src
OBJDIR = .
O      = .obj
E      = .exe


................................................................................

realclean:
	-del $(APPNAME) translate$E mkindex$E makeheaders$E mkversion$E

$(OBJDIR)\json$O : $(SRCDIR)\json_detail.h
$(OBJDIR)\json_artifact$O : $(SRCDIR)\json_detail.h
$(OBJDIR)\json_branch$O : $(SRCDIR)\json_detail.h

$(OBJDIR)\json_diff$O : $(SRCDIR)\json_detail.h

$(OBJDIR)\json_login$O : $(SRCDIR)\json_detail.h
$(OBJDIR)\json_query$O : $(SRCDIR)\json_detail.h
$(OBJDIR)\json_report$O : $(SRCDIR)\json_detail.h
$(OBJDIR)\json_tag$O : $(SRCDIR)\json_detail.h
$(OBJDIR)\json_timeline$O : $(SRCDIR)\json_detail.h
$(OBJDIR)\json_user$O : $(SRCDIR)\json_detail.h
$(OBJDIR)\json_wiki$O : $(SRCDIR)\json_detail.h
................................................................................
##############################################################################
# Begin win/Makefile.msc
#
puts "building ../win/Makefile.msc"
set output_file [open ../win/Makefile.msc w]
fconfigure $output_file -translation binary

writeln {# DO NOT EDIT



#
# This file is automatically generated.  Instead of editing this
# file, edit "makemake.tcl" then run "tclsh src/makemake.tcl"
# to regenerate this file.

B      = ..
SRCDIR = $B\src
OBJDIR = .
OX     = .
O      = .obj
E      = .exe

................................................................................

realclean:
	-del $(APPNAME) translate$E mkindex$E makeheaders$E mkversion$E

$(OBJDIR)\json$O : $(SRCDIR)\json_detail.h
$(OBJDIR)\json_artifact$O : $(SRCDIR)\json_detail.h
$(OBJDIR)\json_branch$O : $(SRCDIR)\json_detail.h

$(OBJDIR)\json_diff$O : $(SRCDIR)\json_detail.h

$(OBJDIR)\json_login$O : $(SRCDIR)\json_detail.h
$(OBJDIR)\json_query$O : $(SRCDIR)\json_detail.h
$(OBJDIR)\json_report$O : $(SRCDIR)\json_detail.h
$(OBJDIR)\json_tag$O : $(SRCDIR)\json_detail.h
$(OBJDIR)\json_timeline$O : $(SRCDIR)\json_detail.h
$(OBJDIR)\json_user$O : $(SRCDIR)\json_detail.h
$(OBJDIR)\json_wiki$O : $(SRCDIR)\json_detail.h
................................................................................
##############################################################################
# Begin win/Makefile.PellesCGMake
#
puts "building ../win/Makefile.PellesCGMake"
set output_file [open ../win/Makefile.PellesCGMake w]
fconfigure $output_file -translation binary

writeln {# DO NOT EDIT



#
# This file is automatically generated.  Instead of editing this
# file, edit "makemake.tcl" then run "tclsh src/makemake.tcl"
# to regenerate this file.
#
# HowTo
# -----
#
# This is a Makefile to compile fossil with PellesC from
#  http://www.smorgasbordet.com/pellesc/index.htm







>

>







 







>







 







|
>
>
>








|







 







|







 







>
>
>
|
|







 







|







 







>
>
>
>
>
>
>
>
|








<










>
>
>
>


|

<
>

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





|



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




|



|
|
>
>



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

|
|



|

|







 







|


|
|










>
>
>
>







|


|



|







 







|












>
>
>
>
>













|
>
>
>


|

>







 







>

>







 







|
>
>
>


|

>







 







>

>







 







|
>
>
>


|







54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
...
107
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
154
155
156
157
158
159
160
161
162
163
164
165
166
...
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
...
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
...
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
...
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
...
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
...
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
...
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
...
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
...
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
...
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
  http_socket
  http_transport
  import
  info
  json
  json_artifact
  json_branch
  json_config
  json_diff
  json_finfo
  json_login
  json_query
  json_report
  json_tag
  json_timeline
  json_user
  json_wiki
................................................................................
  user
  verify
  vfile
  wiki
  wikiformat
  winhttp
  xfer
  xfersetup
  zip
  http_ssl
}

# Name of the final application
#
set name fossil
................................................................................
##############################################################################
# Start by generating the "main.mk" makefile used for all unix systems.
#
puts "building main.mk"
set output_file [open main.mk w]
fconfigure $output_file -translation binary

writeln {#
##############################################################################
# WARNING: DO NOT EDIT, AUTOMATICALLY GENERATED FILE (SEE "src/makemake.tcl")
##############################################################################
#
# This file is automatically generated.  Instead of editing this
# file, edit "makemake.tcl" then run "tclsh makemake.tcl"
# to regenerate this file.
#
# This file is included by primary Makefile.
#

XTCC = $(TCC) $(CFLAGS) -I. -I$(SRCDIR) -I$(OBJDIR)

}
writeln -nonewline "SRC ="
foreach s [lsort $src] {
  writeln -nonewline " \\\n  \$(SRCDIR)/$s.c"
}
writeln "\n"
................................................................................

$(OBJDIR)/mkindex:	$(SRCDIR)/mkindex.c
	$(BCC) -o $(OBJDIR)/mkindex $(SRCDIR)/mkindex.c

$(OBJDIR)/mkversion:	$(SRCDIR)/mkversion.c
	$(BCC) -o $(OBJDIR)/mkversion $(SRCDIR)/mkversion.c

# WARNING. DANGER. Running the test suite modifies the repository the
# build is done from, i.e. the checkout belongs to. Do not sync/push
# the repository after running the tests.
test:	$(OBJDIR) $(APPNAME)
	$(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME)

$(OBJDIR)/VERSION.h:	$(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION $(OBJDIR)/mkversion
	$(OBJDIR)/mkversion $(SRCDIR)/../manifest.uuid \
................................................................................
# to 1. If it is set to 1, then there is no need to build or link
# the sqlite3.o object. Instead, the system sqlite will be linked
# using -lsqlite3.
SQLITE3_OBJ.1 = 
SQLITE3_OBJ.0 = $(OBJDIR)/sqlite3.o
SQLITE3_OBJ.  = $(SQLITE3_OBJ.0)

# The FOSSIL_ENABLE_TCL variable may be undefined, set to 0, or set to 1.
# If it is set to 1, then we need to build the Tcl integration code and
# link to the Tcl library.
TCL_OBJ.0 = 
TCL_OBJ.1 = $(OBJDIR)/th_tcl.o
TCL_OBJ. = $(TCL_OBJ.0)

EXTRAOBJ = \
  $(SQLITE3_OBJ.$(USE_SYSTEM_SQLITE)) \
  $(OBJDIR)/shell.o \
  $(OBJDIR)/th.o \
  $(OBJDIR)/th_lang.o \
................................................................................
append mhargs " \$(OBJDIR)/VERSION.h"
writeln "\$(OBJDIR)/page_index.h: \$(TRANS_SRC) \$(OBJDIR)/mkindex"
writeln "\t\$(OBJDIR)/mkindex \$(TRANS_SRC) >$@"
writeln "\$(OBJDIR)/headers:\t\$(OBJDIR)/page_index.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_finfo.o \$(OBJDIR)/json_login.o \$(OBJDIR)/json_query.o \$(OBJDIR)/json_report.o \$(OBJDIR)/json_tag.o \$(OBJDIR)/json_timeline.o \$(OBJDIR)/json_user.o \$(OBJDIR)/json_wiki.o : \$(SRCDIR)/json_detail.h"
writeln "Makefile:"
set extra_h(main) \$(OBJDIR)/page_index.h

foreach s [lsort $src] {
  writeln "\$(OBJDIR)/${s}_.c:\t\$(SRCDIR)/$s.c \$(OBJDIR)/translate"
  writeln "\t\$(OBJDIR)/translate \$(SRCDIR)/$s.c >\$(OBJDIR)/${s}_.c\n"
  writeln "\$(OBJDIR)/$s.o:\t\$(OBJDIR)/${s}_.c \$(OBJDIR)/$s.h $extra_h($s) \$(SRCDIR)/config.h"
................................................................................
#
puts "building ../win/Makefile.mingw"
set output_file [open ../win/Makefile.mingw w]
fconfigure $output_file -translation binary

writeln {#!/usr/bin/make
#
##############################################################################
# WARNING: DO NOT EDIT, AUTOMATICALLY GENERATED FILE (SEE "src/makemake.tcl")
##############################################################################
#
# This file is automatically generated.  Instead of editing this
# file, edit "makemake.tcl" then run "tclsh makemake.tcl"
# to regenerate this file.
#
# This is a makefile for us on windows using MinGW.
#
#### The toplevel directory of the source tree.  Fossil can be built
#    in a directory that is separate from the source tree.  Just change
#    the following to point from the build directory to the src/ folder.
#
SRCDIR = src

#### The directory into which object code files should be written.

#
OBJDIR = wbld

#### C Compiler and options for use in building executables that
#    will run on the platform that is doing the build.  This is used
#    to compile code-generator programs as part of the build process.
#    See TCC below for the C compiler for building the finished binary.
#
BCC = gcc

#### Enable JSON (http://www.json.org) support using "cson"
#
# FOSSIL_ENABLE_JSON = 1

#### Enable HTTPS support via OpenSSL (links to libssl and libcrypto)
#
# FOSSIL_ENABLE_SSL = 1


#### Enable scripting support via Tcl/Tk
#
# FOSSIL_ENABLE_TCL = 1


#### Use the Tcl source directory instead of the install directory?
#    This is useful when Tcl has been compiled statically with MinGW.
#
FOSSIL_TCL_SOURCE = 1

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

#### 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)/../openssl-1.0.0g/include
OPENSSLLIBDIR = $(SRCDIR)/../openssl-1.0.0g

#### 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
#    here is to use the Sysinternals junction tool to create a hard
#    link between a "tcl-8.x" sub-directory of the Fossil source code
#    directory and the target Tcl directory.  This removes the need to
#    hard-code the necessary paths in this Makefile.
#
TCLDIR = $(SRCDIR)/../tcl-8.6

#### The Tcl source code directory.  This defaults to the same value as
#    TCLDIR macro (above), which may not be correct.  This value will
#    only be used if the FOSSIL_TCL_SOURCE macro is defined.
#
TCLSRCDIR = $(TCLDIR)

#### The Tcl include and library directories.  These values will only be
#    used if the FOSSIL_TCL_SOURCE macro is not defined.
#
TCLINCDIR = $(TCLDIR)/include
TCLLIBDIR = $(TCLDIR)/lib

#### Tcl: Which Tcl library do we want to use (8.4, 8.5, 8.6, etc)?
#
LIBTCL = -ltcl86

#### C Compile and options for use in building executables that
#    will run on the target platform.  This is usually the same
#    as BCC, unless you are cross-compiling.  This C compiler builds
#    the finished binary for fossil.  The BCC compiler above is used
#    for building intermediate code-generator tools.
#
TCC = gcc -Os -Wall -L$(ZLIBDIR) -I$(ZINCDIR)

# With HTTPS support
ifdef FOSSIL_ENABLE_SSL
TCC += -Dpqueue_insert=pqueue_insert_fossil
TCC += -L$(OPENSSLLIBDIR) -I$(OPENSSLINCDIR)
endif

# With Tcl support
ifdef FOSSIL_ENABLE_TCL
ifdef FOSSIL_TCL_SOURCE
TCC += -L$(TCLSRCDIR)/win -I$(TCLSRCDIR)/generic -I$(TCLSRCDIR)/win
else
TCC += -L$(TCLLIBDIR) -I$(TCLINCDIR)
endif
endif

# With HTTPS support
ifdef FOSSIL_ENABLE_SSL
TCC += -DFOSSIL_ENABLE_SSL=1
endif

# With Tcl support (statically linked)
ifdef FOSSIL_ENABLE_TCL
TCC += -DFOSSIL_ENABLE_TCL=1 -DSTATIC_BUILD
endif

# With JSON support
ifdef FOSSIL_ENABLE_JSON
TCC += -DFOSSIL_ENABLE_JSON=1
endif

#### Extra arguments for linking the finished binary.  Fossil needs
#    to link against the Z-Lib compression library.  There are no
#    other mandatory dependencies.  We add the -static option here
#    so that we can build a static executable that will run in a
#    chroot jail.
#
LIB = -static
LIB += -lmingwex -lz

# OpenSSL: Add the necessary libaries required, if enabled.
ifdef FOSSIL_ENABLE_SSL
LIB += -lssl -lcrypto -lgdi32
endif

# Tcl: Add the necessary libaries required, if enabled.
ifdef FOSSIL_ENABLE_TCL
LIB += $(LIBTCL)
endif

#### These libraries MUST appear in the same order as they do for Tcl
#    or linking with it will not work (exact reason unknown).
#
ifdef FOSSIL_ENABLE_TCL
LIB += -lnetapi32 -lkernel32 -luser32 -ladvapi32 -lws2_32
else
LIB += -lws2_32
endif

#### Tcl shell for use in running the fossil test suite.  This is only
#    used for testing.
#
TCLSH = tclsh

#### Nullsoft installer MakeNSIS location
#
MAKENSIS = "$(ProgramFiles)\NSIS\MakeNSIS.exe"

#### Include a configuration file that can override any one of these settings.
#
-include config.w32

# STOP HERE
# You should not need to change anything below this line
................................................................................

$(OBJDIR)/mkindex:	$(SRCDIR)/mkindex.c
	$(BCC) -o $(OBJDIR)/mkindex $(SRCDIR)/mkindex.c

$(VERSION): $(SRCDIR)/mkversion.c
	$(BCC) -o $(OBJDIR)/version $(SRCDIR)/mkversion.c

# WARNING. DANGER. Running the test suite modifies the repository the
# build is done from, i.e. the checkout belongs to. Do not sync/push
# the repository after running the tests.
test:	$(OBJDIR) $(APPNAME)
	$(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME)

$(OBJDIR)/VERSION.h:	$(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(VERSION)
	$(VERSION) $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h

EXTRAOBJ = \
  $(OBJDIR)/sqlite3.o \
  $(OBJDIR)/shell.o \
  $(OBJDIR)/th.o \
  $(OBJDIR)/th_lang.o \
  $(OBJDIR)/cson_amalgamation.o

ifdef FOSSIL_ENABLE_TCL
EXTRAOBJ +=  $(OBJDIR)/th_tcl.o
endif

$(APPNAME):	$(OBJDIR)/headers $(OBJ) $(EXTRAOBJ) $(OBJDIR)/icon.o
	$(TCC) -o $(APPNAME) $(OBJ) $(EXTRAOBJ) $(LIB) $(OBJDIR)/icon.o

# This rule prevents make from using its default rules to try build
# an executable named "manifest" out of the file named "manifest.c"
#
$(SRCDIR)/../manifest:
	# noop

# Requires MSYS to be installed in addition to the MinGW, for the "rm"
# command.  "del" will not work here because it is not a separate command
# but a MSDOS-shell builtin.
#
clean:
	rm -rf $(OBJDIR) $(APPNAME)

setup: $(OBJDIR) $(APPNAME)
	$(MAKENSIS) ./fossil.nsi

}

................................................................................
writeln "\$(OBJDIR)/sqlite3.o:\t\$(SRCDIR)/sqlite3.c"
set opt $SQLITE_OPTIONS
writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/sqlite3.c -o \$(OBJDIR)/sqlite3.o\n"

set opt {}
writeln "\$(OBJDIR)/cson_amalgamation.o:\t\$(SRCDIR)/cson_amalgamation.c"
writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/cson_amalgamation.c -o \$(OBJDIR)/cson_amalgamation.o -DCSON_FOSSIL_MODE\n"
writeln "\$(OBJDIR)/json.o \$(OBJDIR)/json_artifact.o \$(OBJDIR)/json_branch.o \$(OBJDIR)/json_config.o \$(OBJDIR)/json_diff.o \$(OBJDIR)/jsos_finfo.o \$(OBJDIR)/json_login.o \$(OBJDIR)/json_query.o \$(OBJDIR)/json_report.o \$(OBJDIR)/json_tag.o \$(OBJDIR)/json_timeline.o \$(OBJDIR)/json_user.o \$(OBJDIR)/json_wiki.o : \$(SRCDIR)/json_detail.h\n"

writeln "\$(OBJDIR)/shell.o:\t\$(SRCDIR)/shell.c \$(SRCDIR)/sqlite3.h"
set opt {-Dmain=sqlite3_shell}
append opt " -DSQLITE_OMIT_LOAD_EXTENSION=1"
writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/shell.c -o \$(OBJDIR)/shell.o\n"

writeln "\$(OBJDIR)/th.o:\t\$(SRCDIR)/th.c"
writeln "\t\$(XTCC) -I\$(SRCDIR) -c \$(SRCDIR)/th.c -o \$(OBJDIR)/th.o\n"

writeln "\$(OBJDIR)/th_lang.o:\t\$(SRCDIR)/th_lang.c"
writeln "\t\$(XTCC) -I\$(SRCDIR) -c \$(SRCDIR)/th_lang.c -o \$(OBJDIR)/th_lang.o\n"

writeln {ifdef FOSSIL_ENABLE_TCL
$(OBJDIR)/th_tcl.o:	$(SRCDIR)/th_tcl.c
	$(XTCC) -I$(SRCDIR) -c $(SRCDIR)/th_tcl.c -o $(OBJDIR)/th_tcl.o
endif
}

close $output_file
#
# End of the main.mk output
##############################################################################
##############################################################################
##############################################################################
# Begin win/Makefile.dmc
#
puts "building ../win/Makefile.dmc"
set output_file [open ../win/Makefile.dmc w]
fconfigure $output_file -translation binary

writeln {#
##############################################################################
# WARNING: DO NOT EDIT, AUTOMATICALLY GENERATED FILE (SEE "src/makemake.tcl")
##############################################################################
#
# This file is automatically generated.  Instead of editing this
# file, edit "makemake.tcl" then run "tclsh makemake.tcl"
# to regenerate this file.
#
B      = ..
SRCDIR = $B\src
OBJDIR = .
O      = .obj
E      = .exe


................................................................................

realclean:
	-del $(APPNAME) translate$E mkindex$E makeheaders$E mkversion$E

$(OBJDIR)\json$O : $(SRCDIR)\json_detail.h
$(OBJDIR)\json_artifact$O : $(SRCDIR)\json_detail.h
$(OBJDIR)\json_branch$O : $(SRCDIR)\json_detail.h
$(OBJDIR)\json_config$O : $(SRCDIR)\json_detail.h
$(OBJDIR)\json_diff$O : $(SRCDIR)\json_detail.h
$(OBJDIR)\json_finfo$O : $(SRCDIR)\json_detail.h
$(OBJDIR)\json_login$O : $(SRCDIR)\json_detail.h
$(OBJDIR)\json_query$O : $(SRCDIR)\json_detail.h
$(OBJDIR)\json_report$O : $(SRCDIR)\json_detail.h
$(OBJDIR)\json_tag$O : $(SRCDIR)\json_detail.h
$(OBJDIR)\json_timeline$O : $(SRCDIR)\json_detail.h
$(OBJDIR)\json_user$O : $(SRCDIR)\json_detail.h
$(OBJDIR)\json_wiki$O : $(SRCDIR)\json_detail.h
................................................................................
##############################################################################
# Begin win/Makefile.msc
#
puts "building ../win/Makefile.msc"
set output_file [open ../win/Makefile.msc w]
fconfigure $output_file -translation binary

writeln {#
##############################################################################
# WARNING: DO NOT EDIT, AUTOMATICALLY GENERATED FILE (SEE "src/makemake.tcl")
##############################################################################
#
# This file is automatically generated.  Instead of editing this
# file, edit "makemake.tcl" then run "tclsh makemake.tcl"
# to regenerate this file.
#
B      = ..
SRCDIR = $B\src
OBJDIR = .
OX     = .
O      = .obj
E      = .exe

................................................................................

realclean:
	-del $(APPNAME) translate$E mkindex$E makeheaders$E mkversion$E

$(OBJDIR)\json$O : $(SRCDIR)\json_detail.h
$(OBJDIR)\json_artifact$O : $(SRCDIR)\json_detail.h
$(OBJDIR)\json_branch$O : $(SRCDIR)\json_detail.h
$(OBJDIR)\json_config$O : $(SRCDIR)\json_detail.h
$(OBJDIR)\json_diff$O : $(SRCDIR)\json_detail.h
$(OBJDIR)\json_finfo$O : $(SRCDIR)\json_detail.h
$(OBJDIR)\json_login$O : $(SRCDIR)\json_detail.h
$(OBJDIR)\json_query$O : $(SRCDIR)\json_detail.h
$(OBJDIR)\json_report$O : $(SRCDIR)\json_detail.h
$(OBJDIR)\json_tag$O : $(SRCDIR)\json_detail.h
$(OBJDIR)\json_timeline$O : $(SRCDIR)\json_detail.h
$(OBJDIR)\json_user$O : $(SRCDIR)\json_detail.h
$(OBJDIR)\json_wiki$O : $(SRCDIR)\json_detail.h
................................................................................
##############################################################################
# Begin win/Makefile.PellesCGMake
#
puts "building ../win/Makefile.PellesCGMake"
set output_file [open ../win/Makefile.PellesCGMake w]
fconfigure $output_file -translation binary

writeln {#
##############################################################################
# WARNING: DO NOT EDIT, AUTOMATICALLY GENERATED FILE (SEE "src/makemake.tcl")
##############################################################################
#
# This file is automatically generated.  Instead of editing this
# file, edit "makemake.tcl" then run "tclsh makemake.tcl"
# to regenerate this file.
#
# HowTo
# -----
#
# This is a Makefile to compile fossil with PellesC from
#  http://www.smorgasbordet.com/pellesc/index.htm

Changes to src/manifest.c.

1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
....
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
    }
  }
  if( p->zBaseline==0 ) return 0;
  fetch_baseline(p, 1);
  pBase = p->pBaseline;
  if( pBase==0 ) return 0;
  for(i=0; i<pBase->nFile; i++){
    if( fossil_stricmp(zName, p->aFile[i].zName)==0 ){
      return &p->aFile[i];
    }
  }
  return 0;
}

/*
** Add mlink table entries associated with manifest cid, pChild.  The
................................................................................
  }
  if( p->type==CFTYPE_CONTROL ){
    Blob comment;
    int i;
    const char *zName;
    const char *zValue;
    const char *zUuid;

    blob_zero(&comment);
    for(i=0; i<p->nTag; i++){
      zUuid = p->aTag[i].zUuid;
      if( i==0 || fossil_strcmp(zUuid, p->aTag[i-1].zUuid)!=0 ){
        if( i>0 ) blob_append(&comment, " ", 1);
        blob_appendf(&comment, "Tag changes on [/timeline?dp=%S&n=4 | %S]:",

           zUuid, zUuid);

      }
      zName = p->aTag[i].zName;
      zValue = p->aTag[i].zValue;


































      if( zName[0]=='-' ){
        blob_appendf(&comment, " Cancel");
      }else if( zName[0]=='+' ){
        blob_appendf(&comment, " Add");
      }else{
        blob_appendf(&comment, " Add propagating");
      }
      if( memcmp(&zName[1], "sym-",4)==0 ){
        blob_appendf(&comment, " symbolic tag \"%h\".", &zName[5]);
      }else if( fossil_strcmp(&zName[1], "comment")!=0 && zValue && zValue[0] ){
        blob_appendf(&comment, " %h=%h.", &zName[1], zValue);
      }else{
        blob_appendf(&comment, " %h.", &zName[1]);
      }
    }


    db_multi_exec(
      "REPLACE INTO event(type,mtime,objid,user,comment)"
      "VALUES('g',%.17g,%d,%Q,%Q)",
      p->rDate, rid, p->zUser, blob_str(&comment)
    );
    blob_reset(&comment);
  }







|
|







 







>





|
>

>



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







1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
....
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
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927


1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
    }
  }
  if( p->zBaseline==0 ) return 0;
  fetch_baseline(p, 1);
  pBase = p->pBaseline;
  if( pBase==0 ) return 0;
  for(i=0; i<pBase->nFile; i++){
    if( fossil_stricmp(zName, pBase->aFile[i].zName)==0 ){
      return &pBase->aFile[i];
    }
  }
  return 0;
}

/*
** Add mlink table entries associated with manifest cid, pChild.  The
................................................................................
  }
  if( p->type==CFTYPE_CONTROL ){
    Blob comment;
    int i;
    const char *zName;
    const char *zValue;
    const char *zUuid;
    int branchMove = 0;
    blob_zero(&comment);
    for(i=0; i<p->nTag; i++){
      zUuid = p->aTag[i].zUuid;
      if( i==0 || fossil_strcmp(zUuid, p->aTag[i-1].zUuid)!=0 ){
        if( i>0 ) blob_append(&comment, " ", 1);
        blob_appendf(&comment,
           "Edit &#91;[/info/%S | %S]&#93;:",
           zUuid, zUuid);
        branchMove = 0;
      }
      zName = p->aTag[i].zName;
      zValue = p->aTag[i].zValue;
      if( strcmp(zName, "*branch")==0 ){
        blob_appendf(&comment,
           " Move to branch [/timeline?r=%h&nd&dp=%S | %h].",
           zValue, zUuid, zValue);
        branchMove = 1;
      }else if( strcmp(zName, "*bgcolor")==0 ){
        blob_appendf(&comment,
           " Change branch background color to \"%h\".", zValue);
      }else if( strcmp(zName, "+bgcolor")==0 ){
        blob_appendf(&comment,
           " Change background color to \"%h\".", zValue);
      }else if( strcmp(zName, "-bgcolor")==0 ){
        blob_appendf(&comment, " Cancel background color.");
      }else if( strcmp(zName, "+comment")==0 ){
        blob_appendf(&comment, " Edit check-in comment.");
      }else if( strcmp(zName, "+user")==0 ){
        blob_appendf(&comment, " Change user to \"%h\".", zValue);
      }else if( strcmp(zName, "+date")==0 ){
        blob_appendf(&comment, " Timestamp %h.", zValue);
      }else if( memcmp(zName, "-sym-",5)==0 ){
        if( !branchMove ) blob_appendf(&comment, " Cancel tag %h.", &zName[5]);
      }else if( memcmp(zName, "*sym-",5)==0 ){
        if( !branchMove ){
          blob_appendf(&comment, " Add propagating tag \"%h\".", &zName[5]);
        }
      }else if( memcmp(zName, "+sym-",5)==0 ){
        blob_appendf(&comment, " Add tag \"%h\".", &zName[5]);
      }else if( memcmp(zName, "-sym-",5)==0 ){
        blob_appendf(&comment, " Cancel tag \"%h\".", &zName[5]);
      }else if( strcmp(zName, "+closed")==0 ){
        blob_appendf(&comment, " Marked \"Closed\".");
      }else if( strcmp(zName, "-closed")==0 ){
        blob_appendf(&comment, " Removed the \"Closed\" mark.");
      }else {
        if( zName[0]=='-' ){
          blob_appendf(&comment, " Cancel \"%h\"", &zName[1]);
        }else if( zName[0]=='+' ){
          blob_appendf(&comment, " Add \"%h\"", &zName[1]);
        }else{
          blob_appendf(&comment, " Add propagating \"%h\"", &zName[1]);
        }


        if( zValue && zValue[0] ){
          blob_appendf(&comment, " with value \"%h\".", zValue);
        }else{
          blob_appendf(&comment, ".");
        }
      }
    }
    /*blob_appendf(&comment, " &#91;[/info/%S | details]&#93;");*/
    db_multi_exec(
      "REPLACE INTO event(type,mtime,objid,user,comment)"
      "VALUES('g',%.17g,%d,%Q,%Q)",
      p->rDate, rid, p->zUser, blob_str(&comment)
    );
    blob_reset(&comment);
  }

Changes to src/merge.c.

18
19
20
21
22
23
24

































25
26
27
28
29
30
31
...
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
...
142
143
144
145
146
147
148




149
150
151
152
153
154
155
...
516
517
518
519
520
521
522
523
524










525
526
527
528
** This file contains code used to merge two or more branches into
** a single tree.
*/
#include "config.h"
#include "merge.h"
#include <assert.h>



































/*
** COMMAND: merge
**
** Usage: %fossil merge ?OPTIONS? VERSION
**
** The argument VERSION is a version that should be merged into the
................................................................................
    pid = name_to_typed_rid(zPivot, "ci");
    if( pid==0 || !is_a_version(pid) ){
      fossil_fatal("not a version: %s", zPivot);
    }
    if( pickFlag ){
      fossil_fatal("incompatible options: --cherrypick & --baseline");
    }
    /* pickFlag = 1;  // Using --baseline is really like doing a cherrypick */
  }else if( pickFlag || backoutFlag ){
    pid = db_int(0, "SELECT pid FROM plink WHERE cid=%d AND isprim", mid);
    if( pid<=0 ){
      fossil_fatal("cannot find an ancestor for %s", g.argv[2]);
    }
  }else{
    pivot_set_primary(mid);
................................................................................
    int t = pid;
    pid = mid;
    mid = t;
  }
  if( !is_a_version(pid) ){
    fossil_fatal("not a version: record #%d", pid);
  }




  vfile_check_signature(vid, 1, 0);
  db_begin_transaction();
  if( !nochangeFlag ) undo_begin();
  load_vfile_from_rid(mid);
  load_vfile_from_rid(pid);
  if( debugFlag ){
    char *z;
................................................................................
    }
  }

  /*
  ** Clean up the mid and pid VFILE entries.  Then commit the changes.
  */
  db_multi_exec("DELETE FROM vfile WHERE vid!=%d", vid);
  if( !pickFlag ){
    db_multi_exec("INSERT OR IGNORE INTO vmerge(id,merge) VALUES(0,%d)", mid);










  }
  undo_finish();
  db_end_transaction(nochangeFlag);
}







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







 







<







 







>
>
>
>







 







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




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
...
147
148
149
150
151
152
153

154
155
156
157
158
159
160
...
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
...
552
553
554
555
556
557
558

559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
** This file contains code used to merge two or more branches into
** a single tree.
*/
#include "config.h"
#include "merge.h"
#include <assert.h>

/*
** Print information about a particular check-in.
*/
void print_checkin_description(int rid, int indent, const char *zLabel){
  Stmt q;
  db_prepare(&q,
     "SELECT datetime(mtime,'localtime'),"
     "       coalesce(euser,user), coalesce(ecomment,comment),"
     "       (SELECT uuid FROM blob WHERE rid=%d),"
     "       (SELECT group_concat(substr(tagname,5), ', ') FROM tag, tagxref"
     "         WHERE tagname GLOB 'sym-*' AND tag.tagid=tagxref.tagid"
     "           AND tagxref.rid=%d AND tagxref.tagtype>0)"
     "  FROM event WHERE objid=%d", rid, rid, rid);
  if( db_step(&q)==SQLITE_ROW ){
    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, indent, 78);
    fossil_free(zCom);
  }
  db_finalize(&q);
}


/*
** COMMAND: merge
**
** Usage: %fossil merge ?OPTIONS? VERSION
**
** The argument VERSION is a version that should be merged into the
................................................................................
    pid = name_to_typed_rid(zPivot, "ci");
    if( pid==0 || !is_a_version(pid) ){
      fossil_fatal("not a version: %s", zPivot);
    }
    if( pickFlag ){
      fossil_fatal("incompatible options: --cherrypick & --baseline");
    }

  }else if( pickFlag || backoutFlag ){
    pid = db_int(0, "SELECT pid FROM plink WHERE cid=%d AND isprim", mid);
    if( pid<=0 ){
      fossil_fatal("cannot find an ancestor for %s", g.argv[2]);
    }
  }else{
    pivot_set_primary(mid);
................................................................................
    int t = pid;
    pid = mid;
    mid = t;
  }
  if( !is_a_version(pid) ){
    fossil_fatal("not a version: record #%d", pid);
  }
  if( detailFlag ){
    print_checkin_description(mid, 12, "merge-from:");
    print_checkin_description(pid, 12, "baseline:");
  }
  vfile_check_signature(vid, 1, 0);
  db_begin_transaction();
  if( !nochangeFlag ) undo_begin();
  load_vfile_from_rid(mid);
  load_vfile_from_rid(pid);
  if( debugFlag ){
    char *z;
................................................................................
    }
  }

  /*
  ** Clean up the mid and pid VFILE entries.  Then commit the changes.
  */
  db_multi_exec("DELETE FROM vfile WHERE vid!=%d", vid);

  db_multi_exec("INSERT OR IGNORE INTO vmerge(id,merge) VALUES(%d,%d)",
                pickFlag ? -1 : (backoutFlag ? -2 : 0), mid);
  if( pickFlag ){
    /* For a cherry-pick merge, make the default check-in comment the same
    ** as the check-in comment on the check-in that is being merged in. */
    db_multi_exec(
       "REPLACE INTO vvar(name,value)"
       " SELECT 'ci-comment', coalesce(ecomment,comment) FROM event"
       "  WHERE type='ci' AND objid=%d",
       mid
    );
  }
  undo_finish();
  db_end_transaction(nochangeFlag);
}

Changes to src/merge3.c.

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
...
432
433
434
435
436
437
438


439
440
441
442
443
444
445
  Blob *pPivot,       /* Common ancestor (older) */
  const char *zV1,    /* Name of file for version merging into (mine) */
  Blob *pV2,          /* Version merging from (yours) */
  Blob *pOut          /* Output written here */
){
  Blob v1;            /* Content of zV1 */
  int rc;             /* Return code of subroutines and this routine */




  blob_read_from_file(&v1, zV1);
  rc = blob_merge(pPivot, &v1, pV2, pOut);
  if( rc>0 ){
    char *zPivot;   /* Name of the pivot file */
    char *zOrig;    /* Name of the original content file */
    char *zOther;   /* Name of the merge file */
    const char *zGMerge;   /* Name of the gmerge command */

    zPivot = file_newname(zV1, "baseline", 1);
    blob_write_to_file(pPivot, zPivot);
    zOrig = file_newname(zV1, "original", 1);
    blob_write_to_file(&v1, zOrig);
    zOther = file_newname(zV1, "merge", 1);
    blob_write_to_file(pV2, zOther);




    zGMerge = db_get("gmerge-command", 0);
    if( zGMerge && zGMerge[0] ){
      char *zOut;     /* Temporary output file */
      char *zCmd;     /* Command to invoke */
      const char *azSubst[8];  /* Strings to be substituted */

      zOut = file_newname(zV1, "output", 1);
................................................................................
        file_delete(zOrig);
        file_delete(zOther);
        file_delete(zOut);
      }
      fossil_free(zCmd);
      fossil_free(zOut);
    }


    fossil_free(zPivot);
    fossil_free(zOrig);
    fossil_free(zOther);
  }
  blob_reset(&v1);
  return rc;
}







>
>
>



|
<
<
<








>
>
>
>







 







>
>







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
...
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
  Blob *pPivot,       /* Common ancestor (older) */
  const char *zV1,    /* Name of file for version merging into (mine) */
  Blob *pV2,          /* Version merging from (yours) */
  Blob *pOut          /* Output written here */
){
  Blob v1;            /* Content of zV1 */
  int rc;             /* Return code of subroutines and this routine */
  char *zPivot;       /* Name of the pivot file */
  char *zOrig;        /* Name of the original content file */
  char *zOther;       /* Name of the merge file */

  blob_read_from_file(&v1, zV1);
  rc = blob_merge(pPivot, &v1, pV2, pOut);
  if( rc!=0 ){



    const char *zGMerge;   /* Name of the gmerge command */

    zPivot = file_newname(zV1, "baseline", 1);
    blob_write_to_file(pPivot, zPivot);
    zOrig = file_newname(zV1, "original", 1);
    blob_write_to_file(&v1, zOrig);
    zOther = file_newname(zV1, "merge", 1);
    blob_write_to_file(pV2, zOther);
  }
  if( rc>0 ){
    const char *zGMerge;   /* Name of the gmerge command */

    zGMerge = db_get("gmerge-command", 0);
    if( zGMerge && zGMerge[0] ){
      char *zOut;     /* Temporary output file */
      char *zCmd;     /* Command to invoke */
      const char *azSubst[8];  /* Strings to be substituted */

      zOut = file_newname(zV1, "output", 1);
................................................................................
        file_delete(zOrig);
        file_delete(zOther);
        file_delete(zOut);
      }
      fossil_free(zCmd);
      fossil_free(zOut);
    }
  }
  if( rc!=0 ){
    fossil_free(zPivot);
    fossil_free(zOrig);
    fossil_free(zOther);
  }
  blob_reset(&v1);
  return rc;
}

Changes to src/name.c.

67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
...
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
** match any known object.  Or return -1 if the name is ambiguious.
**
** The zType parameter specifies the type of artifact: ci, t, w, e, g. 
** If zType is NULL or "" or "*" then any type of artifact will serve.
** zType is "ci" in most use cases since we are usually searching for
** a check-in.
*/
static int symbolic_name_to_rid(const char *zTag, const char *zType){
  int vid;
  int rid = 0;
  int nTag;
  int i;

  if( zType==0 || zType[0]==0 ) zType = "*";
  if( zTag==0 || zTag[0]==0 ) return 0;
................................................................................
  rid = symbolic_name_to_rid(zName, 0);
  if( rid<0 ){
    fossil_print("Ambiguous artifact name prefix: %s\n", zName);
  }else if( rid==0 ){
    fossil_print("Unknown artifact: %s\n", zName);
  }else{
    Stmt q;

    db_prepare(&q, "SELECT uuid, size, datetime(mtime, 'localtime'), ipaddr"



                   "  FROM blob, rcvfrom"
                   " WHERE rid=%d"
                   "   AND rcvfrom.rcvid=blob.rcvid",
                   rid);
    if( db_step(&q)==SQLITE_ROW ){

      if( fExtra ){
        fossil_print("artifact: %s (%d)\n", db_column_text(&q,0), rid);
        fossil_print("size:     %d bytes\n", db_column_int(&q,1));
        fossil_print("received: %s from %s\n",
           db_column_text(&q, 2),
           db_column_text(&q, 3));
      }else{
        fossil_print("artifact: %s\n", db_column_text(&q,0));
        fossil_print("size:     %d bytes\n", db_column_int(&q,1));
      }



    }
    db_finalize(&q);
    db_prepare(&q,
       "SELECT type, datetime(mtime,'localtime'),"
       "       coalesce(euser,user), coalesce(ecomment,comment)"
       "  FROM event WHERE objid=%d", rid);
    if( db_step(&q)==SQLITE_ROW ){







|







 







>
|
>
>
>
|
|
|
|

>










>
>
>







67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
...
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
** match any known object.  Or return -1 if the name is ambiguious.
**
** The zType parameter specifies the type of artifact: ci, t, w, e, g. 
** If zType is NULL or "" or "*" then any type of artifact will serve.
** zType is "ci" in most use cases since we are usually searching for
** a check-in.
*/
int symbolic_name_to_rid(const char *zTag, const char *zType){
  int vid;
  int rid = 0;
  int nTag;
  int i;

  if( zType==0 || zType[0]==0 ) zType = "*";
  if( zTag==0 || zTag[0]==0 ) return 0;
................................................................................
  rid = symbolic_name_to_rid(zName, 0);
  if( rid<0 ){
    fossil_print("Ambiguous artifact name prefix: %s\n", zName);
  }else if( rid==0 ){
    fossil_print("Unknown artifact: %s\n", zName);
  }else{
    Stmt q;
    db_prepare(&q,
       "SELECT uuid, size, datetime(mtime, 'localtime'), ipaddr,"
       "       (SELECT group_concat(substr(tagname,5), ', ') FROM tag, tagxref"
       "         WHERE tagname GLOB 'sym-*' AND tag.tagid=tagxref.tagid"
       "           AND tagxref.rid=blob.rid AND tagxref.tagtype>0)"
       "  FROM blob, rcvfrom"
       " WHERE rid=%d"
       "   AND rcvfrom.rcvid=blob.rcvid",
       rid);
    if( db_step(&q)==SQLITE_ROW ){
      const char *zTagList = db_column_text(&q, 4);
      if( fExtra ){
        fossil_print("artifact: %s (%d)\n", db_column_text(&q,0), rid);
        fossil_print("size:     %d bytes\n", db_column_int(&q,1));
        fossil_print("received: %s from %s\n",
           db_column_text(&q, 2),
           db_column_text(&q, 3));
      }else{
        fossil_print("artifact: %s\n", db_column_text(&q,0));
        fossil_print("size:     %d bytes\n", db_column_int(&q,1));
      }
      if( zTagList && zTagList[0] ){
        fossil_print("tags:     %s\n", zTagList);
      }
    }
    db_finalize(&q);
    db_prepare(&q,
       "SELECT type, datetime(mtime,'localtime'),"
       "       coalesce(euser,user), coalesce(ecomment,comment)"
       "  FROM event WHERE objid=%d", rid);
    if( db_step(&q)==SQLITE_ROW ){

Changes to src/path.c.

131
132
133
134
135
136
137




138
139
140
141
142
143
144
145

  path_reset();
  path.pStart = path_new_node(iFrom, 0, 0);
  if( iTo==iFrom ){
    path.pEnd = path.pStart;
    return path.pStart;
  }




  if( oneWayOnly ){
    db_prepare(&s, 
        "SELECT cid, 1 FROM plink WHERE pid=:pid "
    );
  }else if( directOnly ){
    db_prepare(&s, 
        "SELECT cid, 1 FROM plink WHERE pid=:pid AND isprim "
        "UNION ALL "







>
>
>
>
|







131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149

  path_reset();
  path.pStart = path_new_node(iFrom, 0, 0);
  if( iTo==iFrom ){
    path.pEnd = path.pStart;
    return path.pStart;
  }
  if( oneWayOnly && directOnly ){
    db_prepare(&s, 
        "SELECT cid, 1 FROM plink WHERE pid=:pid AND isprim"
    );
  }else if( oneWayOnly ){
    db_prepare(&s, 
        "SELECT cid, 1 FROM plink WHERE pid=:pid "
    );
  }else if( directOnly ){
    db_prepare(&s, 
        "SELECT cid, 1 FROM plink WHERE pid=:pid AND isprim "
        "UNION ALL "

Changes to src/printf.c.

820
821
822
823
824
825
826

827
828
829
830
831
832
833
  assert( toStdErr==0 || toStdErr==1 );
  if( istty[toStdErr] ) z = zToFree = fossil_utf8_to_console(z);
  fwrite(z, 1, strlen(z), toStdErr ? stderr : stdout);
  free(zToFree);
#else
  fwrite(z, 1, strlen(z), toStdErr ? stderr : stdout);
#endif

}

/*
** Write output for user consumption.  If g.cgiOutput is enabled, then
** send the output as part of the CGI reply.  If g.cgiOutput is false,
** then write on standard output.
*/







>







820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
  assert( toStdErr==0 || toStdErr==1 );
  if( istty[toStdErr] ) z = zToFree = fossil_utf8_to_console(z);
  fwrite(z, 1, strlen(z), toStdErr ? stderr : stdout);
  free(zToFree);
#else
  fwrite(z, 1, strlen(z), toStdErr ? stderr : stdout);
#endif
  fflush(toStdErr ? stderr : stdout);
}

/*
** Write output for user consumption.  If g.cgiOutput is enabled, then
** send the output as part of the CGI reply.  If g.cgiOutput is false,
** then write on standard output.
*/

Changes to src/rebuild.c.

422
423
424
425
426
427
428

429
430
431
432
433
434
435
...
483
484
485
486
487
488
489




















490
491
492
493
494
495
496
...
549
550
551
552
553
554
555

556
557
558
559
560
561
562
...
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
...
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
...
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
  }
  if( doClustering ) create_cluster();
  if( ttyOutput && !g.fQuiet && totalSize>0 ){
    processCnt += incrSize;
    percent_complete((processCnt*1000)/totalSize);
  }
  if(!g.fQuiet && ttyOutput ){

    fossil_print("\n");
  }
  return errCnt;
}

/*
** Attempt to convert more full-text blobs into delta-blobs for
................................................................................
      previd = rid;
    }
  }
  db_finalize(&q);

  db_end_transaction(0);
}





















/*
** COMMAND: rebuild
**
** Usage: %fossil rebuild ?REPOSITORY? ?OPTIONS?
**
** Reconstruct the named repository database from the core
................................................................................
    }
    db_close(1);
    db_open_repository(g.zRepositoryName);
  }
  db_begin_transaction();
  ttyOutput = 1;
  errCnt = rebuild_db(randomizeFlag, 1, doClustering);

  db_multi_exec(
    "REPLACE INTO config(name,value,mtime) VALUES('content-schema','%s',now());"
    "REPLACE INTO config(name,value,mtime) VALUES('aux-schema','%s',now());",
    CONTENT_SCHEMA, AUX_SCHEMA
  );
  if( errCnt && !forceFlag ){
    fossil_print(
................................................................................
**
** By default, only passwords are removed.  However, if the --verily option
** is added, then private branches, concealed email addresses, IP
** addresses of correspondents, and similar privacy-sensitive fields
** are also purged.  If the --private option is used, then only private
** branches are removed and all other information is left intact.
**
** This command permanently deletes the scrubbed information.  The effects
** of this command are irreversible.  Use with caution.
**
** The user is prompted to confirm the scrub unless the --force option
** is used.
**
** Options:
**   --force     do not prompt for confirmation
**   --private   only private branches are removed from the repository
................................................................................
    if( blob_str(&ans)[0]!='y' ){
      fossil_exit(1);
    }
  }
  db_begin_transaction();
  if( privateOnly || bVerily ){
    bNeedRebuild = db_exists("SELECT 1 FROM private");
    db_multi_exec(
      "DELETE FROM blob WHERE rid IN private;"
      "DELETE FROM delta WHERE rid IN private;"
      "DELETE FROM private;"
    );
  }
  if( !privateOnly ){
    db_multi_exec(
      "UPDATE user SET pw='';"
      "DELETE FROM config WHERE name GLOB 'last-sync-*';"
      "DELETE FROM config WHERE name GLOB 'peer-*';"
      "DELETE FROM config WHERE name GLOB 'login-group-*';"
................................................................................
  db_initial_setup(0, 0, 1);

  fossil_print("Reading files from directory \"%s\"...\n", g.argv[3]);
  recon_read_dir(g.argv[3]);
  fossil_print("\nBuilding the Fossil repository...\n");

  rebuild_db(0, 1, 1);

  /* Reconstruct the private table.  The private table contains the rid
  ** of every manifest that is tagged with "private" and every file that
  ** is not used by a manifest that is not private.
  */
  db_multi_exec(
    "CREATE TEMP TABLE private_ckin(rid INTEGER PRIMARY KEY);"
    "INSERT INTO private_ckin "
        " SELECT rid FROM tagxref WHERE tagid=%d AND tagtype>0;"
    "INSERT OR IGNORE INTO private"
        " SELECT fid FROM mlink"
        " EXCEPT SELECT fid FROM mlink WHERE mid NOT IN private_ckin;"
    "INSERT OR IGNORE INTO private SELECT rid FROM private_ckin;"
    "DROP TABLE private_ckin;"
  );


  /* Skip the verify_before_commit() step on a reconstruct.  Most artifacts
  ** will have been changed and verification therefore takes a really, really
  ** long time.
  */
  verify_cancel();
  







>







 







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







 







>







 







|
|







 







|
<
<
<
<







 







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







422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
...
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
...
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
...
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
...
791
792
793
794
795
796
797
798




799
800
801
802
803
804
805
...
901
902
903
904
905
906
907















908
909
910
911
912
913
914
915
  }
  if( doClustering ) create_cluster();
  if( ttyOutput && !g.fQuiet && totalSize>0 ){
    processCnt += incrSize;
    percent_complete((processCnt*1000)/totalSize);
  }
  if(!g.fQuiet && ttyOutput ){
    percent_complete(1000);
    fossil_print("\n");
  }
  return errCnt;
}

/*
** Attempt to convert more full-text blobs into delta-blobs for
................................................................................
      previd = rid;
    }
  }
  db_finalize(&q);

  db_end_transaction(0);
}


/* Reconstruct the private table.  The private table contains the rid
** of every manifest that is tagged with "private" and every file that
** is not used by a manifest that is not private.
*/
static void reconstruct_private_table(void){
  db_multi_exec(
    "CREATE TEMP TABLE private_ckin(rid INTEGER PRIMARY KEY);"
    "INSERT INTO private_ckin "
        " SELECT rid FROM tagxref WHERE tagid=%d AND tagtype>0;"
    "INSERT OR IGNORE INTO private"
        " SELECT fid FROM mlink"
        " EXCEPT SELECT fid FROM mlink WHERE mid NOT IN private_ckin;"
    "INSERT OR IGNORE INTO private SELECT rid FROM private_ckin;"
    "DROP TABLE private_ckin;", TAG_PRIVATE
  );
  fix_private_blob_dependencies(0);
}


/*
** COMMAND: rebuild
**
** Usage: %fossil rebuild ?REPOSITORY? ?OPTIONS?
**
** Reconstruct the named repository database from the core
................................................................................
    }
    db_close(1);
    db_open_repository(g.zRepositoryName);
  }
  db_begin_transaction();
  ttyOutput = 1;
  errCnt = rebuild_db(randomizeFlag, 1, doClustering);
  reconstruct_private_table();
  db_multi_exec(
    "REPLACE INTO config(name,value,mtime) VALUES('content-schema','%s',now());"
    "REPLACE INTO config(name,value,mtime) VALUES('aux-schema','%s',now());",
    CONTENT_SCHEMA, AUX_SCHEMA
  );
  if( errCnt && !forceFlag ){
    fossil_print(
................................................................................
**
** By default, only passwords are removed.  However, if the --verily option
** is added, then private branches, concealed email addresses, IP
** addresses of correspondents, and similar privacy-sensitive fields
** are also purged.  If the --private option is used, then only private
** branches are removed and all other information is left intact.
**
** This command permanently deletes the scrubbed information. THE EFFECTS
** OF THIS COMMAND ARE IRREVERSIBLE. USE WITH CAUTION!
**
** The user is prompted to confirm the scrub unless the --force option
** is used.
**
** Options:
**   --force     do not prompt for confirmation
**   --private   only private branches are removed from the repository
................................................................................
    if( blob_str(&ans)[0]!='y' ){
      fossil_exit(1);
    }
  }
  db_begin_transaction();
  if( privateOnly || bVerily ){
    bNeedRebuild = db_exists("SELECT 1 FROM private");
    delete_private_content();




  }
  if( !privateOnly ){
    db_multi_exec(
      "UPDATE user SET pw='';"
      "DELETE FROM config WHERE name GLOB 'last-sync-*';"
      "DELETE FROM config WHERE name GLOB 'peer-*';"
      "DELETE FROM config WHERE name GLOB 'login-group-*';"
................................................................................
  db_initial_setup(0, 0, 1);

  fossil_print("Reading files from directory \"%s\"...\n", g.argv[3]);
  recon_read_dir(g.argv[3]);
  fossil_print("\nBuilding the Fossil repository...\n");

  rebuild_db(0, 1, 1);















  reconstruct_private_table();

  /* Skip the verify_before_commit() step on a reconstruct.  Most artifacts
  ** will have been changed and verification therefore takes a really, really
  ** long time.
  */
  verify_cancel();
  

Changes to src/report.c.

17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
....
1139
1140
1141
1142
1143
1144
1145
1146
**  
** Code to generate the ticket listings
*/
#include "config.h"
#include <time.h>
#include "report.h"
#include <assert.h>
#ifdef FOSSIL_ENABLE_JSON
#  include "cson_amalgamation.h"
#endif

/* Forward references to static routines */
static void report_format_hints(void);

/*
** WEBPAGE: /reportlist
*/
................................................................................
  report_restrict_sql(&zErr1);
  sqlite3_exec_readonly(g.db, zSql, output_separated_file, &count, &zErr2);
  report_unrestrict_sql();
  if( zFilter ){
    free(zSql);
  }
}








<
<
<







 







<
17
18
19
20
21
22
23



24
25
26
27
28
29
30
....
1136
1137
1138
1139
1140
1141
1142

**  
** Code to generate the ticket listings
*/
#include "config.h"
#include <time.h>
#include "report.h"
#include <assert.h>




/* Forward references to static routines */
static void report_format_hints(void);

/*
** WEBPAGE: /reportlist
*/
................................................................................
  report_restrict_sql(&zErr1);
  sqlite3_exec_readonly(g.db, zSql, output_separated_file, &count, &zErr2);
  report_unrestrict_sql();
  if( zFilter ){
    free(zSql);
  }
}

Changes to src/schema.c.

472
473
474
475
476
477
478
479

480
481
482
483
484
485
486
487
@   UNIQUE(pathname,vid)
@ );
@
@ -- This table holds a record of uncommitted merges in the local
@ -- file tree.  If a VFILE entry with id has merged with another
@ -- record, there is an entry in this table with (id,merge) where
@ -- merge is the RECORD table entry that the file merged against.
@ -- An id of 0 here means the version record itself.

@
@ CREATE TABLE vmerge(
@   id INTEGER REFERENCES vfile,      -- VFILE entry that has been merged
@   merge INTEGER,                    -- Merged with this record
@   UNIQUE(id, merge)
@ );
@   
;







|
>








472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
@   UNIQUE(pathname,vid)
@ );
@
@ -- This table holds a record of uncommitted merges in the local
@ -- file tree.  If a VFILE entry with id has merged with another
@ -- record, there is an entry in this table with (id,merge) where
@ -- merge is the RECORD table entry that the file merged against.
@ -- An id of 0 here means the version record itself.  When id==(-1)
@ -- that is a cherrypick merge and id==(-2) is a backout merge.
@
@ CREATE TABLE vmerge(
@   id INTEGER REFERENCES vfile,      -- VFILE entry that has been merged
@   merge INTEGER,                    -- Merged with this record
@   UNIQUE(id, merge)
@ );
@   
;

Changes to src/setup.c.

71
72
73
74
75
76
77


78
79
80
81
82
83
84
  setup_menu_entry("Timeline", "setup_timeline",
    "Timeline display preferences");
  setup_menu_entry("Login-Group", "setup_login_group",
    "Manage single sign-on between this repository and others"
    " on the same server");
  setup_menu_entry("Tickets", "tktsetup",
    "Configure the trouble-ticketing system for this repository");


  setup_menu_entry("Skins", "setup_skin",
    "Select from a menu of prepackaged \"skins\" for the web interface");
  setup_menu_entry("CSS", "setup_editcss",
    "Edit the Cascading Style Sheet used by all pages of this repository");
  setup_menu_entry("Header", "setup_header",
    "Edit HTML text inserted at the top of every page");
  setup_menu_entry("Footer", "setup_footer",







>
>







71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
  setup_menu_entry("Timeline", "setup_timeline",
    "Timeline display preferences");
  setup_menu_entry("Login-Group", "setup_login_group",
    "Manage single sign-on between this repository and others"
    " on the same server");
  setup_menu_entry("Tickets", "tktsetup",
    "Configure the trouble-ticketing system for this repository");
  setup_menu_entry("Transfers", "xfersetup",
    "Configure the transfer system for this repository");
  setup_menu_entry("Skins", "setup_skin",
    "Select from a menu of prepackaged \"skins\" for the web interface");
  setup_menu_entry("CSS", "setup_editcss",
    "Edit the Cascading Style Sheet used by all pages of this repository");
  setup_menu_entry("Header", "setup_header",
    "Edit HTML text inserted at the top of every page");
  setup_menu_entry("Footer", "setup_footer",

Changes to src/shell.c.

53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
...
330
331
332
333
334
335
336
337
338
339
340

341
342
343
344
345
346
347
...
357
358
359
360
361
362
363
364



365
366
367
368
369
370
371
372
...
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
...
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
...
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
....
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
1293
1294
1295
1296
1297
1298
1299
1300
....
1765
1766
1767
1768
1769
1770
1771
1772
1773

1774
1775
1776


1777
1778
1779
1780
1781
1782
1783
1784
....
1790
1791
1792
1793
1794
1795
1796








1797
1798
1799
1800
1801
1802
1803
....
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
....
2747
2748
2749
2750
2751
2752
2753
2754
2755



2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
....
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
....
2879
2880
2881
2882
2883
2884
2885
2886

2887
2888
2889
2890
2891
2892
2893
2894
2895

2896
2897
2898
2899
2900
2901
2902
....
2923
2924
2925
2926
2927
2928
2929
2930
2931


















2932
2933
2934
2935
2936
2937
2938
# include <editline/editline.h>
#endif
#if defined(HAVE_READLINE) && HAVE_READLINE==1
# include <readline/readline.h>
# include <readline/history.h>
#endif
#if !defined(HAVE_EDITLINE) && (!defined(HAVE_READLINE) || HAVE_READLINE!=1)
# define readline(p) local_getline(p,stdin)
# define add_history(X)
# define read_history(X)
# define write_history(X)
# define stifle_history(X)
#endif

#if defined(_WIN32) || defined(WIN32)
................................................................................
** the text in memory obtained from malloc() and returns a pointer
** to the text.  NULL is returned at end of file, or if malloc()
** fails.
**
** The interface is like "readline" but no command-line editing
** is done.
*/
static char *local_getline(char *zPrompt, FILE *in){
  char *zLine;
  int nLine;
  int n;


  if( zPrompt && *zPrompt ){
    printf("%s",zPrompt);
    fflush(stdout);
  }
  nLine = 100;
  zLine = malloc( nLine );
................................................................................
      if( n==0 ){
        free(zLine);
        return 0;
      }
      zLine[n] = 0;
      break;
    }
    while( zLine[n] ){ n++; }



    if( n>0 && zLine[n-1]=='\n' ){
      n--;
      if( n>0 && zLine[n-1]=='\r' ) n--;
      zLine[n] = 0;
      break;
    }
  }
  zLine = realloc( zLine, n+1 );
................................................................................
** zPrior is a string of prior text retrieved.  If not the empty
** string, then issue a continuation prompt.
*/
static char *one_input_line(const char *zPrior, FILE *in){
  char *zPrompt;
  char *zResult;
  if( in!=0 ){
    return local_getline(0, in);
  }
  if( zPrior && zPrior[0] ){
    zPrompt = continuePrompt;
  }else{
    zPrompt = mainPrompt;
  }
  zResult = readline(zPrompt);
................................................................................
  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 using ANSI-C rules.  Numbers
** appear outside of quotes.
*/
static void output_csv(struct callback_data *p, const char *z, int bSep){
  FILE *out = p->out;
  if( z==0 ){
    fprintf(out,"%s",p->nullvalue);
  }else{
    int i;
................................................................................
  }

  return zIn;
}


/*
** Execute a query statement that has a single result column.  Print
** that result column on a line by itself with a semicolon terminator.

**
** This is used, for example, to show the schema of the database by
** querying the SQLITE_MASTER table.



*/
static int run_table_dump_query(
  struct callback_data *p, /* Query context */
  const char *zSelect,     /* SELECT statement to extract content */
  const char *zFirstRow    /* Print before first row, if not NULL */
){
  sqlite3_stmt *pSelect;
  int rc;



  rc = sqlite3_prepare(p->db, zSelect, -1, &pSelect, 0);
  if( rc!=SQLITE_OK || !pSelect ){
    fprintf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, sqlite3_errmsg(p->db));
    p->nErr++;
    return rc;
  }
  rc = sqlite3_step(pSelect);

  while( rc==SQLITE_ROW ){
    if( zFirstRow ){
      fprintf(p->out, "%s", zFirstRow);
      zFirstRow = 0;
    }
    fprintf(p->out, "%s;\n", sqlite3_column_text(pSelect, 0));











    rc = sqlite3_step(pSelect);
  }
  rc = sqlite3_finalize(pSelect);
  if( rc!=SQLITE_OK ){
    fprintf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, sqlite3_errmsg(p->db));
    p->nErr++;
  }
................................................................................

  if( strcmp(zType, "table")==0 ){
    sqlite3_stmt *pTableInfo = 0;
    char *zSelect = 0;
    char *zTableInfo = 0;
    char *zTmp = 0;
    int nRow = 0;

   
    zTableInfo = appendText(zTableInfo, "PRAGMA table_info(", 0);
    zTableInfo = appendText(zTableInfo, zTable, '"');
    zTableInfo = appendText(zTableInfo, ");", 0);

    rc = sqlite3_prepare(p->db, zTableInfo, -1, &pTableInfo, 0);
    free(zTableInfo);
    if( rc!=SQLITE_OK || !pTableInfo ){
      return 1;
    }

    zSelect = appendText(zSelect, "SELECT 'INSERT INTO ' || ", 0);





    zTmp = appendText(zTmp, zTable, '"');
    if( zTmp ){
      zSelect = appendText(zSelect, zTmp, '\'');
    }
    zSelect = appendText(zSelect, " || ' VALUES(' || ", 0);
    rc = sqlite3_step(pTableInfo);
    while( rc==SQLITE_ROW ){
      const char *zText = (const char *)sqlite3_column_text(pTableInfo, 1);
      zSelect = appendText(zSelect, "quote(", 0);
      zSelect = appendText(zSelect, zText, '"');
      rc = sqlite3_step(pTableInfo);
      if( rc==SQLITE_ROW ){
        zSelect = appendText(zSelect, ") || ',' || ", 0);
      }else{
        zSelect = appendText(zSelect, ") ", 0);
      }
      nRow++;
    }
    rc = sqlite3_finalize(pTableInfo);
    if( rc!=SQLITE_OK || nRow==0 ){
................................................................................
      fprintf(stderr, "Error: out of memory\n");
      fclose(in);
      sqlite3_finalize(pStmt);
      return 1;
    }
    sqlite3_exec(p->db, "BEGIN", 0, 0, 0);
    zCommit = "COMMIT";
    while( (zLine = local_getline(0, in))!=0 ){
      char *z;

      lineno++;
      azCol[0] = zLine;
      for(i=0, z=zLine; *z && *z!='\n' && *z!='\r'; z++){


        if( *z==p->separator[0] && strncmp(z, p->separator, nSep)==0 ){
          *z = 0;
          i++;
          if( i<nCol ){
            azCol[i] = &z[nSep];
            z += nSep-1;
          }
        }
................................................................................
                zFile, lineno, nCol, i+1);
        zCommit = "ROLLBACK";
        free(zLine);
        rc = 1;
        break; /* from while */
      }
      for(i=0; i<nCol; i++){








        sqlite3_bind_text(pStmt, i+1, azCol[i], -1, SQLITE_STATIC);
      }
      sqlite3_step(pStmt);
      rc = sqlite3_reset(pStmt);
      free(zLine);
      if( rc!=SQLITE_OK ){
        fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db));
................................................................................
  return rc;
}

/*
** Show available command line options
*/
static const char zOptions[] = 
  "   -help                show this message\n"
  "   -init filename       read/process named file\n"
  "   -echo                print commands before execution\n"
  "   -[no]header          turn headers on or off\n"
  "   -bail                stop after hitting an error\n"
  "   -interactive         force interactive I/O\n"
  "   -batch               force batch I/O\n"
  "   -column              set output mode to 'column'\n"

  "   -csv                 set output mode to 'csv'\n"




  "   -html                set output mode to HTML\n"

  "   -line                set output mode to 'line'\n"
  "   -list                set output mode to 'list'\n"




  "   -separator 'x'       set output field separator (|)\n"
  "   -stats               print memory stats before each finalize\n"
  "   -nullvalue 'text'    set text string for NULL values\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
#ifdef SQLITE_ENABLE_MULTIPLEX
  "   -multiplex           enable the multiplexor VFS\n"
#endif
;
static void usage(int showDetail){
  fprintf(stderr,
      "Usage: %s [OPTIONS] FILENAME [SQL]\n"  
      "FILENAME is the name of an SQLite database. A new database is created\n"
      "if the file does not previously exist.\n", Argv0);
  if( showDetail ){
................................................................................
  ** the size of the alternative malloc heap,
  ** and the first command to execute.
  */
  for(i=1; i<argc-1; i++){
    char *z;
    if( argv[i][0]!='-' ) break;
    z = argv[i];
    if( z[0]=='-' && z[1]=='-' ) z++;
    if( strcmp(argv[i],"-separator")==0 || strcmp(argv[i],"-nullvalue")==0 ){



      i++;
    }else if( strcmp(argv[i],"-init")==0 ){
      i++;
      zInitFile = argv[i];
    /* Need to check for batch mode here to so we can avoid printing
    ** informational messages (like from process_sqliterc) before 
    ** we do the actual processing of arguments later in a second pass.
    */
    }else if( strcmp(argv[i],"-batch")==0 ){
      stdin_is_interactive = 0;
    }else if( strcmp(argv[i],"-heap")==0 ){
#if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5)
      int j, c;
      const char *zSize;
      sqlite3_int64 szHeap;

      zSize = argv[++i];
      szHeap = atoi(zSize);
................................................................................
        if( c=='K' ){ szHeap *= 1000; break; }
        if( c=='G' ){ szHeap *= 1000000000; break; }
      }
      if( szHeap>0x7fff0000 ) szHeap = 0x7fff0000;
      sqlite3_config(SQLITE_CONFIG_HEAP, malloc((int)szHeap), (int)szHeap, 64);
#endif
#ifdef SQLITE_ENABLE_VFSTRACE
    }else if( strcmp(argv[i],"-vfstrace")==0 ){
      extern int vfstrace_register(
         const char *zTraceName,
         const char *zOldVfsName,
         int (*xOut)(const char*,void*),
         void *pOutArg,
         int makeDefault
      );
      vfstrace_register("trace",0,(int(*)(const char*,void*))fputs,stderr,1);
#endif
#ifdef SQLITE_ENABLE_MULTIPLEX
    }else if( strcmp(argv[i],"-multiplex")==0 ){
      extern int sqlite3_multiple_initialize(const char*,int);
      sqlite3_multiplex_initialize(0, 1);
#endif
    }else if( strcmp(argv[i],"-vfs")==0 ){
      sqlite3_vfs *pVfs = sqlite3_vfs_find(argv[++i]);
      if( pVfs ){
        sqlite3_vfs_register(pVfs, 1);
      }else{
        fprintf(stderr, "no such VFS: \"%s\"\n", argv[i]);
        exit(1);
      }
................................................................................
      data.mode = MODE_Column;
    }else if( strcmp(z,"-csv")==0 ){
      data.mode = MODE_Csv;
      memcpy(data.separator,",",2);
    }else if( strcmp(z,"-separator")==0 ){
      i++;
      if(i>=argc){
        fprintf(stderr,"%s: Error: missing argument for option: %s\n", Argv0, z);

        fprintf(stderr,"Use -help for a list of options.\n");
        return 1;
      }
      sqlite3_snprintf(sizeof(data.separator), data.separator,
                       "%.*s",(int)sizeof(data.separator)-1,argv[i]);
    }else if( strcmp(z,"-nullvalue")==0 ){
      i++;
      if(i>=argc){
        fprintf(stderr,"%s: Error: missing argument for option: %s\n", Argv0, z);

        fprintf(stderr,"Use -help for a list of options.\n");
        return 1;
      }
      sqlite3_snprintf(sizeof(data.nullvalue), data.nullvalue,
                       "%.*s",(int)sizeof(data.nullvalue)-1,argv[i]);
    }else if( strcmp(z,"-header")==0 ){
      data.showHeader = 1;
................................................................................
    }else if( strcmp(z,"-vfstrace")==0 ){
      i++;
#endif
#ifdef SQLITE_ENABLE_MULTIPLEX
    }else if( strcmp(z,"-multiplex")==0 ){
      i++;
#endif
    }else if( strcmp(z,"-help")==0 || strcmp(z, "--help")==0 ){
      usage(1);


















    }else{
      fprintf(stderr,"%s: Error: unknown option: %s\n", Argv0, z);
      fprintf(stderr,"Use -help for a list of options.\n");
      return 1;
    }
  }








|







 







|



>







 







|
>
>
>
|







 







|







 







|
<







 







|
|
>

<
|
>
>
>








>
>
>







>





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







 







>












>
>
>
>
>
|











|







 







|
|
>


|
>
>
|







 







>
>
>
>
>
>
>
>







 







<
<
<
<

<


>

>
>
>
>

>


>
>
>
>


<





<
<
<







 







|
|
>
>
>

|






|

|







 







|










|



|







 







|
>








|
>







 







|

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







53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
...
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
...
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
...
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
...
614
615
616
617
618
619
620
621

622
623
624
625
626
627
628
...
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
....
1283
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
....
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
....
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
....
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
....
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
....
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
....
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
....
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
# include <editline/editline.h>
#endif
#if defined(HAVE_READLINE) && HAVE_READLINE==1
# include <readline/readline.h>
# include <readline/history.h>
#endif
#if !defined(HAVE_EDITLINE) && (!defined(HAVE_READLINE) || HAVE_READLINE!=1)
# define readline(p) local_getline(p,stdin,0)
# define add_history(X)
# define read_history(X)
# define write_history(X)
# define stifle_history(X)
#endif

#if defined(_WIN32) || defined(WIN32)
................................................................................
** the text in memory obtained from malloc() and returns a pointer
** to the text.  NULL is returned at end of file, or if malloc()
** fails.
**
** The interface is like "readline" but no command-line editing
** is done.
*/
static char *local_getline(char *zPrompt, FILE *in, int csvFlag){
  char *zLine;
  int nLine;
  int n;
  int inQuote = 0;

  if( zPrompt && *zPrompt ){
    printf("%s",zPrompt);
    fflush(stdout);
  }
  nLine = 100;
  zLine = malloc( nLine );
................................................................................
      if( n==0 ){
        free(zLine);
        return 0;
      }
      zLine[n] = 0;
      break;
    }
    while( zLine[n] ){
      if( zLine[n]=='"' ) inQuote = !inQuote;
      n++;
    }
    if( n>0 && zLine[n-1]=='\n' && (!inQuote || !csvFlag) ){
      n--;
      if( n>0 && zLine[n-1]=='\r' ) n--;
      zLine[n] = 0;
      break;
    }
  }
  zLine = realloc( zLine, n+1 );
................................................................................
** zPrior is a string of prior text retrieved.  If not the empty
** string, then issue a continuation prompt.
*/
static char *one_input_line(const char *zPrior, FILE *in){
  char *zPrompt;
  char *zResult;
  if( in!=0 ){
    return local_getline(0, in, 0);
  }
  if( zPrior && zPrior[0] ){
    zPrompt = continuePrompt;
  }else{
    zPrompt = mainPrompt;
  }
  zResult = readline(zPrompt);
................................................................................
  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.

*/
static void output_csv(struct callback_data *p, const char *z, int bSep){
  FILE *out = p->out;
  if( z==0 ){
    fprintf(out,"%s",p->nullvalue);
  }else{
    int i;
................................................................................
  }

  return zIn;
}


/*
** Execute a query statement that will generate SQL output.  Print
** the result columns, comma-separated, on a line and then add a
** semicolon terminator to the end of that line.
**

** If the number of columns is 1 and that column contains text "--"
** then write the semicolon on a separate line.  That way, if a 
** "--" comment occurs at the end of the statement, the comment
** won't consume the semicolon terminator.
*/
static int run_table_dump_query(
  struct callback_data *p, /* Query context */
  const char *zSelect,     /* SELECT statement to extract content */
  const char *zFirstRow    /* Print before first row, if not NULL */
){
  sqlite3_stmt *pSelect;
  int rc;
  int nResult;
  int i;
  const char *z;
  rc = sqlite3_prepare(p->db, zSelect, -1, &pSelect, 0);
  if( rc!=SQLITE_OK || !pSelect ){
    fprintf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, sqlite3_errmsg(p->db));
    p->nErr++;
    return rc;
  }
  rc = sqlite3_step(pSelect);
  nResult = sqlite3_column_count(pSelect);
  while( rc==SQLITE_ROW ){
    if( zFirstRow ){
      fprintf(p->out, "%s", zFirstRow);
      zFirstRow = 0;
    }
    z = (const char*)sqlite3_column_text(pSelect, 0);
    fprintf(p->out, "%s", z);
    for(i=1; i<nResult; i++){ 
      fprintf(p->out, ",%s", sqlite3_column_text(pSelect, i));
    }
    if( z==0 ) z = "";
    while( z[0] && (z[0]!='-' || z[1]!='-') ) z++;
    if( z[0] ){
      fprintf(p->out, "\n;\n");
    }else{
      fprintf(p->out, ";\n");
    }    
    rc = sqlite3_step(pSelect);
  }
  rc = sqlite3_finalize(pSelect);
  if( rc!=SQLITE_OK ){
    fprintf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, sqlite3_errmsg(p->db));
    p->nErr++;
  }
................................................................................

  if( strcmp(zType, "table")==0 ){
    sqlite3_stmt *pTableInfo = 0;
    char *zSelect = 0;
    char *zTableInfo = 0;
    char *zTmp = 0;
    int nRow = 0;
    int kk;
   
    zTableInfo = appendText(zTableInfo, "PRAGMA table_info(", 0);
    zTableInfo = appendText(zTableInfo, zTable, '"');
    zTableInfo = appendText(zTableInfo, ");", 0);

    rc = sqlite3_prepare(p->db, zTableInfo, -1, &pTableInfo, 0);
    free(zTableInfo);
    if( rc!=SQLITE_OK || !pTableInfo ){
      return 1;
    }

    zSelect = appendText(zSelect, "SELECT 'INSERT INTO ' || ", 0);
    if( !isalpha(zTable[0]) ){
      kk = 0;
    }else{
      for(kk=1; isalnum(zTable[kk]); kk++){}
    }
    zTmp = appendText(zTmp, zTable, zTable[kk] ? '"' : 0);
    if( zTmp ){
      zSelect = appendText(zSelect, zTmp, '\'');
    }
    zSelect = appendText(zSelect, " || ' VALUES(' || ", 0);
    rc = sqlite3_step(pTableInfo);
    while( rc==SQLITE_ROW ){
      const char *zText = (const char *)sqlite3_column_text(pTableInfo, 1);
      zSelect = appendText(zSelect, "quote(", 0);
      zSelect = appendText(zSelect, zText, '"');
      rc = sqlite3_step(pTableInfo);
      if( rc==SQLITE_ROW ){
        zSelect = appendText(zSelect, "), ", 0);
      }else{
        zSelect = appendText(zSelect, ") ", 0);
      }
      nRow++;
    }
    rc = sqlite3_finalize(pTableInfo);
    if( rc!=SQLITE_OK || nRow==0 ){
................................................................................
      fprintf(stderr, "Error: out of memory\n");
      fclose(in);
      sqlite3_finalize(pStmt);
      return 1;
    }
    sqlite3_exec(p->db, "BEGIN", 0, 0, 0);
    zCommit = "COMMIT";
    while( (zLine = local_getline(0, in, 1))!=0 ){
      char *z, c;
      int inQuote = 0;
      lineno++;
      azCol[0] = zLine;
      for(i=0, z=zLine; (c = *z)!=0; z++){
        if( c=='"' ) inQuote = !inQuote;
        if( c=='\n' ) lineno++;
        if( !inQuote && c==p->separator[0] && strncmp(z,p->separator,nSep)==0 ){
          *z = 0;
          i++;
          if( i<nCol ){
            azCol[i] = &z[nSep];
            z += nSep-1;
          }
        }
................................................................................
                zFile, lineno, nCol, i+1);
        zCommit = "ROLLBACK";
        free(zLine);
        rc = 1;
        break; /* from while */
      }
      for(i=0; i<nCol; i++){
        if( azCol[i][0]=='"' ){
          int k;
          for(z=azCol[i], j=1, k=0; z[j]; j++){
            if( z[j]=='"' ){ j++; if( z[j]==0 ) break; }
            z[k++] = z[j];
          }
          z[k] = 0;
        }
        sqlite3_bind_text(pStmt, i+1, azCol[i], -1, SQLITE_STATIC);
      }
      sqlite3_step(pStmt);
      rc = sqlite3_reset(pStmt);
      free(zLine);
      if( rc!=SQLITE_OK ){
        fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db));
................................................................................
  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"
  "   -[no]header          turn headers on or off\n"
  "   -help                show this message\n"
  "   -html                set output mode to HTML\n"
  "   -interactive         force interactive I/O\n"
  "   -line                set output mode to 'line'\n"
  "   -list                set output mode to 'list'\n"
#ifdef SQLITE_ENABLE_MULTIPLEX
  "   -multiplex           enable the multiplexor VFS\n"
#endif
  "   -nullvalue 'text'    set text string for NULL values\n"
  "   -separator 'x'       set output field separator (|)\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



;
static void usage(int showDetail){
  fprintf(stderr,
      "Usage: %s [OPTIONS] FILENAME [SQL]\n"  
      "FILENAME is the name of an SQLite database. A new database is created\n"
      "if the file does not previously exist.\n", Argv0);
  if( showDetail ){
................................................................................
  ** the size of the alternative malloc heap,
  ** and the first command to execute.
  */
  for(i=1; i<argc-1; i++){
    char *z;
    if( argv[i][0]!='-' ) break;
    z = argv[i];
    if( z[1]=='-' ) z++;
    if( strcmp(z,"-separator")==0
     || strcmp(z,"-nullvalue")==0
     || strcmp(z,"-cmd")==0
    ){
      i++;
    }else if( strcmp(z,"-init")==0 ){
      i++;
      zInitFile = argv[i];
    /* Need to check for batch mode here to so we can avoid printing
    ** informational messages (like from process_sqliterc) before 
    ** we do the actual processing of arguments later in a second pass.
    */
    }else if( strcmp(z,"-batch")==0 ){
      stdin_is_interactive = 0;
    }else if( strcmp(z,"-heap")==0 ){
#if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5)
      int j, c;
      const char *zSize;
      sqlite3_int64 szHeap;

      zSize = argv[++i];
      szHeap = atoi(zSize);
................................................................................
        if( c=='K' ){ szHeap *= 1000; break; }
        if( c=='G' ){ szHeap *= 1000000000; break; }
      }
      if( szHeap>0x7fff0000 ) szHeap = 0x7fff0000;
      sqlite3_config(SQLITE_CONFIG_HEAP, malloc((int)szHeap), (int)szHeap, 64);
#endif
#ifdef SQLITE_ENABLE_VFSTRACE
    }else if( strcmp(z,"-vfstrace")==0 ){
      extern int vfstrace_register(
         const char *zTraceName,
         const char *zOldVfsName,
         int (*xOut)(const char*,void*),
         void *pOutArg,
         int makeDefault
      );
      vfstrace_register("trace",0,(int(*)(const char*,void*))fputs,stderr,1);
#endif
#ifdef SQLITE_ENABLE_MULTIPLEX
    }else if( strcmp(z,"-multiplex")==0 ){
      extern int sqlite3_multiple_initialize(const char*,int);
      sqlite3_multiplex_initialize(0, 1);
#endif
    }else if( strcmp(z,"-vfs")==0 ){
      sqlite3_vfs *pVfs = sqlite3_vfs_find(argv[++i]);
      if( pVfs ){
        sqlite3_vfs_register(pVfs, 1);
      }else{
        fprintf(stderr, "no such VFS: \"%s\"\n", argv[i]);
        exit(1);
      }
................................................................................
      data.mode = MODE_Column;
    }else if( strcmp(z,"-csv")==0 ){
      data.mode = MODE_Csv;
      memcpy(data.separator,",",2);
    }else if( strcmp(z,"-separator")==0 ){
      i++;
      if(i>=argc){
        fprintf(stderr,"%s: Error: missing argument for option: %s\n",
                        Argv0, z);
        fprintf(stderr,"Use -help for a list of options.\n");
        return 1;
      }
      sqlite3_snprintf(sizeof(data.separator), data.separator,
                       "%.*s",(int)sizeof(data.separator)-1,argv[i]);
    }else if( strcmp(z,"-nullvalue")==0 ){
      i++;
      if(i>=argc){
        fprintf(stderr,"%s: Error: missing argument for option: %s\n",
                        Argv0, z);
        fprintf(stderr,"Use -help for a list of options.\n");
        return 1;
      }
      sqlite3_snprintf(sizeof(data.nullvalue), data.nullvalue,
                       "%.*s",(int)sizeof(data.nullvalue)-1,argv[i]);
    }else if( strcmp(z,"-header")==0 ){
      data.showHeader = 1;
................................................................................
    }else if( strcmp(z,"-vfstrace")==0 ){
      i++;
#endif
#ifdef SQLITE_ENABLE_MULTIPLEX
    }else if( strcmp(z,"-multiplex")==0 ){
      i++;
#endif
    }else if( strcmp(z,"-help")==0 ){
      usage(1);
    }else if( strcmp(z,"-cmd")==0 ){
      if( i==argc-1 ) break;
      i++;
      z = argv[i];
      if( z[0]=='.' ){
        rc = do_meta_command(z, &data);
        if( rc && bail_on_error ) return rc;
      }else{
        open_db(&data);
        rc = shell_exec(data.db, z, shell_callback, &data, &zErrMsg);
        if( zErrMsg!=0 ){
          fprintf(stderr,"Error: %s\n", zErrMsg);
          if( bail_on_error ) return rc!=0 ? rc : 1;
        }else if( rc!=0 ){
          fprintf(stderr,"Error: unable to process SQL \"%s\"\n", z);
          if( bail_on_error ) return rc;
        }
      }
    }else{
      fprintf(stderr,"%s: Error: unknown option: %s\n", Argv0, z);
      fprintf(stderr,"Use -help for a list of options.\n");
      return 1;
    }
  }

Changes to src/skins.c.

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
...
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
...
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
....
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
@ }
@ 
@ /* The label/value pairs on (for example) the vinfo page */
@ table.label-value th {
@   vertical-align: top;
@   text-align: right;
@   padding: 0.2ex 2ex;
@ }
@
@ /* Side-by-side diff */
@ table.sbsdiff {
@   background-color: white;
@   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;
@ }
@
@ table.sbsdiff th.diffhdr {
@   border-bottom: dotted;
@   border-width: 1px;
@ }
@
@ table.sbsdiff tr td {
@   white-space: pre;
@   padding-left: 3px;
@   padding-right: 3px;
@   margin: 0px;
@ }
@
@ table.sbsdiff tr td.lineno {
@   text-align: right;
@ }
@
@ table.sbsdiff tr td.meta {
@   color: white;
@   background-color: rgb(20, 20, 20);
@   text-align: center;
@ }
@
@ table.sbsdiff tr td.added {
@   background-color: rgb(230, 230, 230);
@ }
@
@ table.sbsdiff tr td.removed {
@   background-color: rgb(200, 200, 200);
@ }
@
@ table.sbsdiff tr td.changed {
@   background-color: rgb(220, 220, 220);
@ }');
@ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
@ <head>
@ <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?blackwhite" type="text/css"
................................................................................
@ }
@ 
@ /* The label/value pairs on (for example) the ci page */
@ table.label-value th {
@   vertical-align: top;
@   text-align: right;
@   padding: 0.2ex 2ex;
@ }
@
@ /* Side-by-side diff */
@ table.sbsdiff {
@   background-color: #ffffc5;
@   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;
@ }
@
@ table.sbsdiff th.diffhdr {
@   border-bottom: dotted;
@   border-width: 1px;
@ }
@
@ table.sbsdiff tr td {
@   white-space: pre;
@   padding-left: 3px;
@   padding-right: 3px;
@   margin: 0px;
@ }
@
@ table.sbsdiff tr td.lineno {
@   text-align: right;
@ }
@
@ table.sbsdiff tr td.meta {
@   background-color: #a09048;
@   text-align: center;
@ }
@
@ table.sbsdiff tr td.added {
@   background-color: rgb(210, 210, 100);
@ }
@
@ table.sbsdiff tr td.removed {
@   background-color: rgb(190, 200, 110);
@ }
@
@ table.sbsdiff tr td.changed {
@   background-color: rgb(200, 210, 120);
@ }');
@ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
@ <head>
@ <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?tan" type="text/css"
................................................................................
@ }
@ 
@ /* The label/value pairs on (for example) the ci page */
@ table.label-value th {
@   vertical-align: top;
@   text-align: right;
@   padding: 0.2ex 2ex;
@ }
@
@ /* Side-by-side diff */
@ table.sbsdiff {
@   background-color: white;
@   font-family: fixed, Dejavu Sans Mono, Monaco, Lucida Console, monospace;
@   font-size: 6pt;
@   border-collapse:collapse;
@   white-space: pre;
@   width: 98%;
@   border: 1px #000 dashed;
@ }
@
@ table.sbsdiff th.diffhdr {
@   border-bottom: dotted;
@   border-width: 1px;
@ }
@
@ table.sbsdiff tr td {
@   white-space: pre;
@   padding-left: 3px;
@   padding-right: 3px;
@   margin: 0px;
@ }
@
@ table.sbsdiff tr td.lineno {
@   text-align: right;
@ }
@
@ table.sbsdiff tr td.meta {
@   color: white;
@   background-color: black;
@   text-align: center;
@ }
@
@ table.sbsdiff tr td.added {
@   background-color: white;
@ }
@
@ table.sbsdiff tr td.removed {
@   background-color: white;
@   text-decoration: line-through;
@ }
@
@ table.sbsdiff tr td.changed {
@   background-color: white;
@ }');
@ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
@ <head>
@ <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?black2" type="text/css"
................................................................................
@ 
@ table.report tr td {
@   padding: 3px 5px;
@ }
@ 
@ textarea {
@   font-size: 1em;
@ }
@
@ /* Side-by-side diff */
@ table.sbsdiff {
@   background-color: white;
@   font-family: Dejavu Sans Mono, Monaco, Lucida Console, monospace;
@   font-size: 6pt;
@   border-collapse:collapse;
@   width: 98%;
@   border: 1px #000 dashed;
@   margin-left: auto;
@   margin-right: auto;
@ }
@
@ table.sbsdiff th.diffhdr {
@   border-bottom: dotted;
@   border-width: 1px;
@ }
@
@ table.sbsdiff tr td {
@   padding-left: 3px;
@   padding-right: 3px;
@   margin: 0px;
@   vertical-align: top;
@   white-space: pre-wrap;
@ }
@
@ table.sbsdiff tr td.lineno {
@   text-align: right;
@   /* border-bottom: 1px solid rgb(220, 220, 220); */
@ }
@
@ table.sbsdiff tr td.srcline {
@   /* max-width: 400px; */
@   /* Note: May partially hide long lines without whitespaces */
@   /* overflow: hidden; */
@   /* border-bottom: 1px solid rgb(220, 220, 220); */
@ }
@
@ table.sbsdiff tr td.meta {
@   background-color: rgb(170, 160, 255);
@   padding-top: 0.25em;
@   padding-bottom: 0.25em;
@   text-align: center;
@   -moz-border-radius: 5px;
@   -moz-border-radius: 5px;
@   -webkit-border-radius: 5px;
@   -webkit-border-radius: 5px;
@   -border-radius: 5px;
@   -border-radius: 5px;
@   border-radius: 5px;
@   border-radius: 5px;
@ }
@
@ table.sbsdiff tr td.added {
@   background-color: rgb(180, 250, 180);
@   /* border-bottom: 1px solid rgb(160, 230, 160); */
@ }
@
@ table.sbsdiff tr td.removed {
@   background-color: rgb(250, 130, 130);
@   /* border-bottom: 1px solid rgb(230, 110, 110); */
@ }
@
@ table.sbsdiff tr td.changed {
@   background-color: rgb(210, 210, 200);
@   /* border-bottom: 1px solid rgb(190, 190, 180); */
@ }');
@ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
@ <head>
@ <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?black2" type="text/css"







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







 







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







 







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







 







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







151
152
153
154
155
156
157













































158
159
160
161
162
163
164
...
353
354
355
356
357
358
359












































360
361
362
363
364
365
366
...
589
590
591
592
593
594
595














































596
597
598
599
600
601
602
...
887
888
889
890
891
892
893



































































894
895
896
897
898
899
900
@ }
@ 
@ /* 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>
@ <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?blackwhite" type="text/css"
................................................................................
@ }
@ 
@ /* 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>
@ <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?tan" type="text/css"
................................................................................
@ }
@ 
@ /* 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>
@ <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?black2" type="text/css"
................................................................................
@ 
@ table.report tr td {
@   padding: 3px 5px;
@ }
@ 
@ textarea {
@   font-size: 1em;



































































@ }');
@ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
@ <head>
@ <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?black2" type="text/css"

Changes to src/sqlcmd.c.

73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
  pOut[2] = nIn>>8 & 0xff;
  pOut[3] = nIn & 0xff;
  compress(&pOut[4], &nOut, pIn, nIn);
  sqlite3_result_blob(context, pOut, nOut+4, sqlite3_free);
}

/*
** Implementation of the "uncontent(X)" SQL function.  The argument X
** is a blob which was obtained from compress(Y).  The output will be
** the value Y.
*/
static void sqlcmd_decompress(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv







|







73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
  pOut[2] = nIn>>8 & 0xff;
  pOut[3] = nIn & 0xff;
  compress(&pOut[4], &nOut, pIn, nIn);
  sqlite3_result_blob(context, pOut, nOut+4, sqlite3_free);
}

/*
** Implementation of the "decompress(X)" SQL function.  The argument X
** is a blob which was obtained from compress(Y).  The output will be
** the value Y.
*/
static void sqlcmd_decompress(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv

Changes to src/sqlite3.c.

1
2
3
4
5
6
7
8
9
10
...
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
....
3178
3179
3180
3181
3182
3183
3184
3185


3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196





3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207

3208
3209
3210
3211
3212
3213
3214
....
6756
6757
6758
6759
6760
6761
6762
6763
6764
6765
6766
6767
6768
6769
6770
....
8008
8009
8010
8011
8012
8013
8014




8015
8016
8017
8018
8019
8020
8021
8022
8023
8024
....
8170
8171
8172
8173
8174
8175
8176
8177
8178
8179
8180
8181
8182
8183
8184
8185
8186
8187
....
8846
8847
8848
8849
8850
8851
8852
8853
8854
8855
8856
8857
8858
8859
8860
8861
....
9004
9005
9006
9007
9008
9009
9010
9011
9012

9013
9014
9015
9016
9017
9018
9019
....
9233
9234
9235
9236
9237
9238
9239
9240



9241
9242
9243
9244









9245
9246
9247
9248
9249
9250
9251
....
9635
9636
9637
9638
9639
9640
9641
9642
9643
9644
9645
9646
9647
9648
9649
9650
9651
9652
9653
9654
9655
9656
9657
9658
9659
9660
9661
9662
9663
9664
9665
9666
9667
9668



9669

9670

9671
9672
9673
9674
9675
9676
9677
9678
9679
9680

9681
9682
9683
9684
9685
9686
9687
9688
9689
9690
9691
9692

9693
9694
9695
9696
9697
9698
9699
9700
9701


9702
9703
9704
9705
9706
9707
9708
....
9731
9732
9733
9734
9735
9736
9737

9738
9739
9740
9741
9742
9743
9744
9745
9746
9747
9748
9749

9750
9751
9752
9753
9754
9755
9756
9757
9758
9759
....
9788
9789
9790
9791
9792
9793
9794
9795
9796
9797
9798
9799
9800
9801
9802
9803
....
9878
9879
9880
9881
9882
9883
9884
9885
9886
9887
9888
9889
9890
9891
9892
.....
10161
10162
10163
10164
10165
10166
10167
10168
10169
10170
10171
10172
10173
10174
10175
10176
.....
10324
10325
10326
10327
10328
10329
10330
10331
10332
10333
10334
10335
10336
10337
10338
10339
10340
10341
10342
10343





10344
10345
10346
10347
10348
10349
10350
.....
10395
10396
10397
10398
10399
10400
10401
10402
10403

10404
10405
10406
10407
10408
10409
10410
10411
10412
10413
10414
10415
10416
10417
10418
10419
10420
10421
10422
10423
10424
10425
10426
10427
10428
10429
10430
10431
.....
10614
10615
10616
10617
10618
10619
10620
10621
10622
10623
10624
10625
10626
10627
10628
10629
10630
10631
10632
10633
10634
10635
10636
10637
10638
.....
10659
10660
10661
10662
10663
10664
10665
10666
10667
10668
10669
10670
10671
10672
10673
.....
10903
10904
10905
10906
10907
10908
10909



10910
10911
10912
10913
10914
10915
10916
10917
10918
10919
10920
10921
10922
10923
10924
10925
10926
10927
10928
10929
10930
10931
10932
10933
10934
10935

10936
10937
10938
10939
10940
10941
10942
.....
11006
11007
11008
11009
11010
11011
11012
11013
11014

11015
11016
11017
11018
11019
11020
11021
11022
11023
.....
11039
11040
11041
11042
11043
11044
11045
11046
11047
11048

11049
11050
11051
11052
11053




11054
11055
11056
11057
11058
11059
11060
11061
11062
11063
11064
11065
11066
11067
11068
11069
11070
11071
11072
11073
11074
11075
11076
11077
11078
11079
11080



11081
11082
11083
11084
11085
11086
11087
11088
11089
11090
11091
11092

11093
11094
11095
11096
11097
11098
11099
11100
11101
11102
11103
11104
11105
11106
11107
11108
11109
11110
11111
11112
11113
11114
11115
11116
11117
11118
11119
11120
11121
11122
11123
11124
11125
11126
11127
11128
11129
11130
11131




11132
11133
11134
11135
11136
11137
11138
.....
11275
11276
11277
11278
11279
11280
11281
11282
11283

11284
11285
11286
11287
11288
11289
11290
.....
11601
11602
11603
11604
11605
11606
11607
11608
11609
11610
11611
11612
11613
11614
11615
.....
11839
11840
11841
11842
11843
11844
11845
11846
11847
11848
11849
11850
11851
11852
11853
.....
11965
11966
11967
11968
11969
11970
11971
11972
11973
11974
11975
11976
11977
11978
11979
.....
12894
12895
12896
12897
12898
12899
12900
12901
12902
12903
12904
12905
12906
12907
12908


12909

12910


12911
12912
12913
12914
12915
12916
12917
12918
12919
12920
12921
12922
.....
13035
13036
13037
13038
13039
13040
13041
13042
13043


13044
13045
13046
13047
13048
13049
13050
.....
13077
13078
13079
13080
13081
13082
13083
13084
13085
13086
13087
13088
13089
13090
13091
.....
15144
15145
15146
15147
15148
15149
15150
15151
























15152
15153
15154
15155
15156
15157
15158
15159
15160
15161
15162


15163
15164
15165
15166

15167
15168
15169
15170
15171
15172

15173
15174
15175
15176
15177
15178
15179
.....
15180
15181
15182
15183
15184
15185
15186
15187

15188
15189
15190
15191
15192




15193
15194

15195

15196
15197
15198
15199
15200
15201
15202
15203
15204
.....
15312
15313
15314
15315
15316
15317
15318
15319
15320
15321
15322
15323
15324
15325
15326
.....
24938
24939
24940
24941
24942
24943
24944
24945
24946
24947
24948
24949
24950
24951
24952
.....
24989
24990
24991
24992
24993
24994
24995

24996
24997
24998
24999
25000
25001
25002
.....
25353
25354
25355
25356
25357
25358
25359






25360
25361
25362
25363
25364
25365
25366
.....
25439
25440
25441
25442
25443
25444
25445
25446














25447
25448
25449








25450



25451
25452
25453
25454
25455
25456
25457
.....
28791
28792
28793
28794
28795
28796
28797
28798
28799
28800
28801
28802
28803
28804
28805
28806
.....
28836
28837
28838
28839
28840
28841
28842
28843
28844
28845
28846










28847
28848
28849
28850
28851
28852
28853
.....
29814
29815
29816
29817
29818
29819
29820
29821
29822
29823
29824
29825
29826
29827
29828
29829
29830
29831
29832
29833
29834
29835
29836
29837
29838
29839
29840


29841
29842
29843



29844
29845
29846
29847
29848
29849
29850
.....
29870
29871
29872
29873
29874
29875
29876


29877
29878
29879
29880
29881
29882
29883
.....
30016
30017
30018
30019
30020
30021
30022


30023
30024
30025
30026
30027
30028
30029
30030
.....
30037
30038
30039
30040
30041
30042
30043











30044
30045
30046
30047
30048
30049
30050
.....
30348
30349
30350
30351
30352
30353
30354
30355
30356
30357
30358
30359
30360
30361
30362
30363
30364
30365
30366
30367
30368
30369
30370
30371
30372
30373
.....
30763
30764
30765
30766
30767
30768
30769
30770
30771
30772
30773
30774
30775
30776
30777
30778
30779
30780
30781
30782
30783
30784
30785
30786
30787
.....
30897
30898
30899
30900
30901
30902
30903
30904
30905
30906
30907
30908
30909
30910
30911
30912
.....
31175
31176
31177
31178
31179
31180
31181
31182
31183
31184
31185
31186
31187
31188
31189
31190
.....
31745
31746
31747
31748
31749
31750
31751
31752
31753
31754
31755
31756
31757
31758
31759
.....
36784
36785
36786
36787
36788
36789
36790

36791
36792
36793
36794
36795
36796
36797
36798
36799
36800
36801
36802
36803
36804
36805
36806
36807
.....
36837
36838
36839
36840
36841
36842
36843
36844
36845

36846
36847
36848
36849
36850
36851
36852
.....
38896
38897
38898
38899
38900
38901
38902
38903
38904
38905
38906
38907
38908
38909
38910
.....
39144
39145
39146
39147
39148
39149
39150
39151
39152
39153
39154
39155
39156
39157
39158
.....
41353
41354
41355
41356
41357
41358
41359
41360
41361
41362
41363
41364
41365
41366
41367
.....
41408
41409
41410
41411
41412
41413
41414
41415
41416
41417
41418
41419
41420
41421
41422
.....
42571
42572
42573
42574
42575
42576
42577
42578
42579
42580
42581
42582
42583
42584
42585
.....
42602
42603
42604
42605
42606
42607
42608
42609
42610
42611
42612
42613
42614
42615
42616
.....
42809
42810
42811
42812
42813
42814
42815
42816
42817
42818
42819
42820
42821
42822
42823
.....
43031
43032
43033
43034
43035
43036
43037
43038
43039
43040
43041
43042
43043
43044
43045
43046
43047
43048
43049
43050
43051
43052
.....
45046
45047
45048
45049
45050
45051
45052
45053
45054
45055
45056
45057
45058
45059
45060
.....
48559
48560
48561
48562
48563
48564
48565
48566
48567
48568
48569
48570
48571
48572
48573
48574
48575
48576
.....
48770
48771
48772
48773
48774
48775
48776



48777
48778
48779
48780
48781
48782
48783
48784
48785
48786
48787
48788
48789
48790
48791
48792
48793
48794
48795
.....
48910
48911
48912
48913
48914
48915
48916
48917
48918

48919
48920
48921
48922
48923
48924
48925
.....
50071
50072
50073
50074
50075
50076
50077
50078
50079
50080
50081
50082
50083
50084
50085
50086
50087
50088
50089
50090
.....
50890
50891
50892
50893
50894
50895
50896
50897
50898
50899
50900
50901
50902
50903
50904
50905
50906
50907
50908
.....
50941
50942
50943
50944
50945
50946
50947
50948
50949
50950
50951
50952
50953
50954
50955
50956
50957
.....
53395
53396
53397
53398
53399
53400
53401
53402
53403
53404
53405
53406
53407
53408
53409
.....
53428
53429
53430
53431
53432
53433
53434







53435
53436
53437
53438
53439



53440
53441
53442
53443
53444
53445
53446
.....
53902
53903
53904
53905
53906
53907
53908






53909
53910
53911
53912
53913
53914
53915
53916
.....
54712
54713
54714
54715
54716
54717
54718
54719
54720
54721
54722
54723
54724
54725
54726
.....
54746
54747
54748
54749
54750
54751
54752
54753

54754
54755
54756
54757
54758
54759
54760
.....
54763
54764
54765
54766
54767
54768
54769
54770
54771
54772
54773
54774
54775
54776
54777
54778
54779
.....
54913
54914
54915
54916
54917
54918
54919
54920
54921
54922
54923
54924
54925
54926
54927
.....
55023
55024
55025
55026
55027
55028
55029
55030
55031
55032
55033
55034
55035
55036
55037
.....
55160
55161
55162
55163
55164
55165
55166
55167
55168
55169
55170
55171
55172
55173
55174
.....
55207
55208
55209
55210
55211
55212
55213
55214
55215
55216
55217
55218
55219
55220
55221
55222
.....
55649
55650
55651
55652
55653
55654
55655
55656
55657
55658
55659
55660
55661
55662
55663
55664
55665
55666
55667
55668
55669
55670
55671
55672
55673
55674
55675
55676
55677
55678
55679
55680
55681
55682
55683
55684
.....
55791
55792
55793
55794
55795
55796
55797

55798


55799
55800
55801
55802
55803
55804
55805
.....
55854
55855
55856
55857
55858
55859
55860
55861
55862
55863
55864
55865
55866
55867
55868
.....
58275
58276
58277
58278
58279
58280
58281

58282
58283
58284
58285
58286
58287
58288
.....
58454
58455
58456
58457
58458
58459
58460

58461
58462
58463
58464
58465
58466
58467
.....
58596
58597
58598
58599
58600
58601
58602
58603


58604




58605
58606
58607
58608
58609
58610
58611
.....
59571
59572
59573
59574
59575
59576
59577
59578
59579
59580
59581
59582

59583
59584
59585
59586
59587
59588
59589
59590
59591
59592
.....
61623
61624
61625
61626
61627
61628
61629
61630
61631
61632
61633
61634
61635
61636
61637
61638
61639
61640
61641
61642
.....
66049
66050
66051
66052
66053
66054
66055
66056
66057
66058
66059
66060
66061




66062
66063
66064
66065
66066
66067
66068



66069
66070
66071
66072
66073
66074
66075
.....
67595
67596
67597
67598
67599
67600
67601
67602
67603
67604
67605
67606
67607
67608
67609
.....
69639
69640
69641
69642
69643
69644
69645

69646
69647
69648
69649
69650
69651
69652
.....
69981
69982
69983
69984
69985
69986
69987
69988
69989
69990
69991
69992
69993
69994
69995
.....
70176
70177
70178
70179
70180
70181
70182

70183
70184
70185
70186
70187
70188
70189
70190
70191
70192
70193





70194
70195
70196
70197
70198
70199
70200
.....
71580
71581
71582
71583
71584
71585
71586


71587
71588



71589
71590
71591
71592
71593
71594
71595
71596
71597
71598
71599
71600
71601
71602
71603
71604
71605
71606
71607
71608
71609
71610
71611


71612
71613
71614
71615
71616
71617
71618
.....
75091
75092
75093
75094
75095
75096
75097
75098

75099
75100
75101
75102
75103
75104
75105
75106
.....
75160
75161
75162
75163
75164
75165
75166
75167
75168
75169
75170
75171
75172



75173
75174
75175
75176
75177
75178
75179
.....
75227
75228
75229
75230
75231
75232
75233
75234
75235

75236
75237
75238
75239
75240
75241
75242
75243
75244
75245
75246
75247
75248
75249
75250
75251
.....
75328
75329
75330
75331
75332
75333
75334
75335
75336
75337
75338
75339
75340
75341
75342
75343
.....
78010
78011
78012
78013
78014
78015
78016
78017
78018
78019
78020
78021
78022
78023
78024
78025
78026
.....
78028
78029
78030
78031
78032
78033
78034
78035
78036
78037
78038
78039
78040
78041
78042
78043
78044
.....
78807
78808
78809
78810
78811
78812
78813
78814
78815
78816
78817
78818
78819
78820
78821
.....
82676
82677
82678
82679
82680
82681
82682
82683
82684
82685
82686
82687
82688
82689
82690
.....
84097
84098
84099
84100
84101
84102
84103
84104
84105
84106
84107
84108
84109
84110
84111
84112
84113
84114
84115
84116
84117
84118
84119
84120
84121
84122
84123
84124
84125
84126
84127
84128
84129
84130
84131
.....
84133
84134
84135
84136
84137
84138
84139
84140
84141
84142
84143
84144
84145
84146
84147
84148
84149
84150
84151
84152
84153
84154
84155
.....
86000
86001
86002
86003
86004
86005
86006








86007
86008
86009
86010
86011
86012
86013
.....
86381
86382
86383
86384
86385
86386
86387
86388
86389
86390
86391
86392
86393
86394
86395
.....
87307
87308
87309
87310
87311
87312
87313
87314
87315
87316
87317


87318
87319
87320
87321
87322
87323
87324
87325
.....
87327
87328
87329
87330
87331
87332
87333


87334
87335
87336
87337
87338
87339
87340
87341
87342
87343
87344
87345
87346
87347
87348
87349
87350
.....
91918
91919
91920
91921
91922
91923
91924
91925

91926
91927
91928
91929
91930
91931
91932
91933
91934
91935
91936
91937
91938
91939
91940
91941
91942
91943
91944
91945
91946
91947
91948
91949
91950
91951
91952
91953
91954
91955
91956
91957
91958
91959
91960
91961
91962
.....
92091
92092
92093
92094
92095
92096
92097
92098
92099
92100
92101
92102
92103
92104
92105
.....
92123
92124
92125
92126
92127
92128
92129
92130
92131
92132
92133
92134
92135
92136
92137
.....
92339
92340
92341
92342
92343
92344
92345
92346
92347
92348
92349
92350
92351
92352
92353
.....
92744
92745
92746
92747
92748
92749
92750
92751
92752
92753
92754
92755
92756
92757
92758
.....
92943
92944
92945
92946
92947
92948
92949
92950
92951
92952
92953
92954
92955
92956
92957
92958
92959
92960
92961
92962
92963
92964
92965
92966
92967
92968
92969
92970
92971
.....
94383
94384
94385
94386
94387
94388
94389

94390
94391
94392
94393
94394
94395
94396
.....
95921
95922
95923
95924
95925
95926
95927



95928
95929

95930
95931
95932
95933
95934
95935
95936
.....
96538
96539
96540
96541
96542
96543
96544
96545
96546
96547
96548
96549
96550
96551
96552
.....
97901
97902
97903
97904
97905
97906
97907


97908
97909
97910
97911
97912
97913
97914
.....
97936
97937
97938
97939
97940
97941
97942

97943
97944
97945
97946
97947
97948
97949
97950
.....
97959
97960
97961
97962
97963
97964
97965



97966
97967
97968
97969
97970
97971



97972
97973
97974
97975
97976
97977
97978
.....
98905
98906
98907
98908
98909
98910
98911
98912
98913
98914
98915
98916
98917
98918
98919
......
101532
101533
101534
101535
101536
101537
101538
101539

101540
101541
101542
101543
101544
101545
101546
101547
101548
101549
101550
101551
101552
......
101573
101574
101575
101576
101577
101578
101579
101580
101581
101582
101583
101584
101585
101586
101587
......
107618
107619
107620
107621
107622
107623
107624








107625
107626
107627
107628
107629
107630
107631
......
107741
107742
107743
107744
107745
107746
107747
107748
107749
107750
107751
107752
107753
107754
107755
107756
107757
107758
107759
107760
107761
107762

107763
107764
107765

107766
107767

107768
107769
107770
107771
107772
107773
107774
107775
107776
107777
107778
107779
107780
107781
107782
107783
107784
......
107840
107841
107842
107843
107844
107845
107846
107847
107848
107849
107850
107851
107852
107853
107854
107855
107856
107857
107858
107859
107860
107861
107862
107863
107864
107865
107866
107867
107868
107869
107870
107871
107872
107873
107874
107875
107876
107877
107878
107879
107880
107881
107882
107883
107884
107885
107886
107887
107888
107889
107890
107891
107892
107893
107894
107895
107896
107897
107898
107899
107900
107901
107902
107903
107904
107905
107906
107907
107908
107909
107910
107911
107912
107913
107914
107915
107916
107917
107918
107919
107920
107921
107922
107923
107924
107925
107926
107927
107928
107929
107930
107931
107932
107933
107934
107935
107936
107937
107938
107939
107940
107941
107942
107943
107944
107945
107946
107947
107948
107949
107950
107951
107952
107953
107954
107955
107956
107957
107958
107959
107960
107961
107962
107963
107964
107965
107966
107967
107968
107969
107970
107971
107972
107973
107974
107975
107976
107977
107978
107979
107980
107981
107982
107983
107984
107985
107986
107987
107988
107989
107990
107991
107992
107993
107994
107995
107996
107997
107998
107999
108000
108001
108002
108003
108004
108005
108006
108007
108008
108009
108010
108011
108012
108013
108014
108015
108016
108017
108018
108019
108020
108021
108022
108023
108024
108025
108026
108027
108028
108029
108030
108031
108032
108033
108034
108035
108036
108037
108038
108039
108040
108041
108042
108043
108044
108045
108046
108047
108048
108049
108050
108051
108052
108053
108054
108055
108056
108057
108058
108059
108060
108061
108062
108063
108064
108065
108066
108067
108068
108069
108070
108071
108072
108073
108074
108075
108076
108077
108078
108079
108080
108081
108082
108083
108084
108085
108086
108087
108088
108089
108090
108091
108092
108093
108094
108095
108096
108097
108098
108099
108100
108101
108102
108103
108104
108105
108106
108107
108108
108109
108110
108111
108112
108113
108114
108115
108116
108117
108118
108119
108120
108121
108122
108123
108124
108125
108126
108127
108128
108129
108130
108131
108132
108133
108134
108135
108136
108137
108138
108139
108140
108141
108142
108143
108144
108145
108146
108147
108148
108149
108150
108151
108152
108153
108154
108155
108156
108157
108158
108159
108160
108161
108162
108163
108164
108165
108166
108167
108168
108169
108170
108171
108172
108173
108174
108175
108176
108177
108178
108179
108180
108181
108182
108183
108184
108185
108186
108187
108188
108189
108190
108191
108192
108193
108194
108195
108196
108197
108198
108199
108200
108201
108202
108203
108204
108205
108206
108207
108208
108209
108210
108211
108212
108213
108214
108215
108216
108217
108218
108219
108220
108221
108222
108223
108224
108225
108226
108227
108228
108229
108230
108231
108232
108233
108234
108235
108236
108237
108238
108239
108240
108241
108242
108243
108244
108245
108246
108247
108248
108249
108250
108251
108252
108253
108254
108255
108256
108257
108258
108259
108260
108261
108262
108263
108264
108265
108266
108267
108268
108269
108270
108271
108272
108273
108274
108275
108276
108277
108278
108279
108280
108281
108282
108283
108284
108285
108286
108287
108288
108289
108290
108291
108292
108293
108294
108295
108296
108297
108298
108299
108300
108301
108302
108303
108304
108305
108306
108307
108308
108309
108310
108311
108312
108313



108314
108315
108316
108317
108318
108319
108320
......
108519
108520
108521
108522
108523
108524
108525
108526
108527
108528
108529
108530
108531
108532
108533
108534
108535
108536
108537
108538
108539
108540
108541
108542
......
108689
108690
108691
108692
108693
108694
108695
108696
108697
108698
108699
108700
108701
108702
108703
108704
108705
108706
108707
108708
108709
108710
108711
108712
108713
108714
108715
108716
108717
108718
108719
108720

108721
108722
108723
108724
108725
108726
108727
108728
108729
108730
108731
108732
108733
108734
108735
108736
108737
108738
108739
108740
108741
108742
108743
108744
108745
108746
108747
108748
108749
108750
108751
108752
108753
108754
108755
108756
108757
108758
108759
108760
108761
108762
108763
108764
108765
108766
108767
108768
108769
108770
108771
108772
108773
108774
108775
108776
108777
108778
108779
108780
108781
108782
108783
108784
108785
108786
108787
108788
108789
108790
108791
108792
108793
108794
108795
108796
108797
108798
108799
108800
108801
108802

108803
108804
108805
108806
108807
108808
108809
108810
108811
108812
108813
108814
108815
108816
108817
108818
108819
108820
108821
108822
108823
108824
108825
108826
108827
108828
108829
108830
108831
108832
108833
108834
108835
108836
108837
108838
108839
108840
108841
108842
108843
108844
108845
108846
108847
108848
108849
108850
108851
108852
108853
108854
108855
108856
108857
108858
108859
108860
108861
108862
108863
108864
108865
108866
108867
108868
108869
108870
108871
108872
108873
108874
108875
108876
108877
108878
......
108946
108947
108948
108949
108950
108951
108952
108953
108954
108955
108956
108957
108958
108959
108960
108961
108962
108963
108964
108965
108966
108967
108968
108969
108970
108971
108972
108973
108974
108975
108976
108977
108978
108979
108980
108981
108982
108983
108984
108985
108986
108987
108988
108989
108990
108991
108992
108993
108994
108995
108996
108997
108998
108999
109000
109001
109002
109003
109004








109005
109006
109007
109008
109009
109010
109011
109012
109013
109014
109015
109016
109017
109018
109019
109020
......
109406
109407
109408
109409
109410
109411
109412
109413
109414
109415
109416
109417
109418
109419
109420
......
109422
109423
109424
109425
109426
109427
109428
109429
109430
109431
109432
109433
109434
109435
109436
109437
109438
109439
109440
109441
109442
109443
109444
109445
109446
......
109459
109460
109461
109462
109463
109464
109465
109466
109467
109468
109469
109470
109471
109472
109473
109474
109475
109476
109477
109478
109479
109480
109481
109482
109483
109484
109485
109486
109487
109488
109489
109490
109491
109492
109493
109494
109495
109496
109497
109498
109499
109500
109501
109502
109503
109504
109505
109506
109507
109508
109509
109510
109511
109512
109513
109514
109515
109516
109517
109518
109519
109520
109521
109522
109523

109524
109525
109526
109527
109528
109529
109530
109531
109532
109533
109534
109535
109536
109537
109538
109539
109540
109541
109542
109543
109544
109545
109546
109547
109548
109549
109550
109551
109552
109553
109554
109555
109556
109557
109558
109559
109560
109561
109562
109563
109564
109565
109566
109567
109568
109569
109570
109571
109572
109573
109574
109575
109576
109577
109578
109579
109580
109581
109582
109583
109584
109585
109586
109587
109588
109589
109590
109591
109592
109593
......
109647
109648
109649
109650
109651
109652
109653
109654
109655
109656
109657
109658
109659
109660
109661
109662
109663
109664
109665
109666
109667
109668
109669
109670
109671
......
109683
109684
109685
109686
109687
109688
109689
109690
109691
109692
109693
109694
109695
109696
109697
......
109702
109703
109704
109705
109706
109707
109708
109709
109710
109711
109712
109713
109714
109715
109716
109717
109718
109719
109720
109721
109722
109723
109724
109725
109726
109727
109728
109729
109730
109731
109732
109733
109734
109735
109736
109737
109738
......
109751
109752
109753
109754
109755
109756
109757
109758
109759
109760
109761
109762
109763

109764
109765
109766
109767
109768
109769
109770
109771
109772
109773
109774
......
109783
109784
109785
109786
109787
109788
109789
109790
109791
109792
109793
109794
109795
109796
109797
109798
109799
109800
109801
109802
109803
109804
109805
109806
109807
109808
109809
109810
109811
109812
109813
109814
109815
109816
109817
109818
109819
109820
109821
109822
109823
109824
109825
109826
109827
109828
109829
109830
109831
109832
109833
109834
109835
109836
109837
109838
109839
109840
109841
109842
109843
109844
109845
109846
109847
109848
109849
109850
109851
109852
109853
109854
109855
109856
109857
109858
109859
109860
109861
109862
109863
109864
109865
109866
109867
109868
109869
109870
109871
109872
109873
109874
109875
109876
109877
109878
109879
109880
109881
109882
109883
109884
109885
109886
109887
109888
109889
109890
109891
109892
109893
109894
109895
109896
109897
109898
109899
109900
109901
109902
109903
109904
109905
109906
109907
109908
109909
109910
109911
109912
109913
109914
109915
109916
109917
109918
109919
109920
109921
109922
109923
109924
109925
109926
109927
109928
109929
109930
109931
109932
109933
109934
109935
109936
109937
109938
109939
109940
109941
109942
109943
109944
109945
109946
109947
109948
109949
109950
109951
109952
109953
109954
109955
109956
109957
109958
109959
109960
109961
109962
109963
109964
109965
109966
109967
109968
109969
109970
109971
109972
109973
109974
109975
109976
109977
109978
109979
109980
109981
109982
109983
109984
109985
109986
109987
109988
109989
109990
109991
109992
109993
109994
109995
109996
109997
109998
109999
110000
110001
110002
110003
110004
110005
110006
110007
110008
110009
110010
110011
110012
110013
110014
110015
110016
110017
110018
110019
110020
110021
110022
110023
110024
110025
110026
110027
110028
110029
110030
110031
110032
110033
110034
110035
110036
110037
110038
110039
110040
110041
110042
110043
110044
110045
110046
110047
110048
110049
110050
110051
110052
110053
110054
110055
110056
110057
110058
110059
110060
110061
110062
110063
110064
110065
110066
110067
110068
110069
110070
110071
110072
110073
110074
110075
110076
110077
110078
110079
110080
110081
110082
110083
110084
110085
110086
110087
110088
110089
110090
110091
110092
110093
110094
110095
110096
110097
110098
110099
110100
110101
110102
110103
110104
110105
110106
110107
110108
110109
110110
110111
110112
110113
110114
110115
110116
110117
110118
110119
110120
110121
110122
110123
110124
110125
110126
110127
110128
110129
110130
110131
110132
110133
110134
110135
110136
110137
110138
110139
110140
110141
110142
110143
110144
110145
110146
110147
110148
110149
110150

110151


110152
110153
110154
110155



















110156
110157
110158
110159
110160
110161
110162
110163
110164
110165
110166
110167

110168
110169
110170
110171
110172
110173
110174
110175
110176
110177
110178
110179
110180
110181
110182
110183
110184
110185
110186
110187
110188
110189
110190
110191
110192
110193
110194
110195
110196
110197
110198
110199
110200
110201
110202
110203
110204
110205
110206
110207
110208
110209
110210
110211
110212
110213
110214
110215
110216
110217
110218
110219
110220
110221
110222
110223
110224
110225
110226
110227
110228
110229
110230
110231
110232
110233
110234
110235
110236
110237
110238
110239
110240
110241
110242
110243
110244
110245
110246
110247
110248
110249
110250
110251
110252
110253
110254
110255
110256
110257
110258
110259
110260
110261
110262
110263
110264
110265
110266
110267
110268
110269
110270
110271
110272
110273
110274
110275
110276
110277
110278
110279
110280
110281
110282
110283
110284
110285
110286
110287
110288
110289
110290
110291
110292
110293
110294
110295
110296
110297
110298
110299
110300
110301
110302
110303
110304
110305
110306
110307
110308
110309
110310
110311
110312
110313
110314
110315
110316
110317
110318
110319
110320
110321
110322
110323
110324
110325
110326
110327
110328
110329
110330
110331
110332
110333
110334
110335
110336
110337
110338
110339
110340
110341
110342
110343
110344
110345
110346
110347
110348
110349
110350
110351
110352
110353
110354
110355
110356
110357
110358
110359
110360
110361
110362
110363
110364
110365
110366
110367
110368
110369
110370
110371
110372
110373
110374
110375
110376
110377
110378
110379
110380
110381
110382
110383
110384
110385
110386
110387
110388
110389
110390
110391
110392
110393
110394
110395
110396
110397
110398
110399
110400
110401
110402
110403
110404
110405
110406
110407
110408
110409
110410
110411
110412
110413
110414
110415
110416
110417
110418
110419
110420
110421
110422
110423
110424
110425
110426
110427
110428
110429
110430
110431
110432
110433
110434
110435
110436
110437
110438
110439
110440
110441
110442
110443
110444
110445
110446
110447
110448
110449
110450
110451
110452
110453
110454
110455
110456






110457
110458
110459
110460
110461
110462
110463
110464
110465
110466
110467
110468
110469
110470
110471
110472
110473
110474
110475
110476
110477
110478
110479
110480
110481
110482
110483
110484
110485
110486
110487
110488
110489
110490
110491
110492
110493
110494
110495
110496
110497
110498
110499
110500
110501
110502
110503
110504
110505
110506
110507
110508
110509
110510
110511
110512
110513
110514
110515
110516
110517
110518
110519
110520
110521
110522
110523
110524
110525
110526
110527
110528
110529
110530
110531
110532
110533
110534
110535
110536
110537
110538
110539
110540
110541
110542
110543
110544
110545
110546
110547
110548
110549
110550
110551
110552
110553
110554
110555
110556
110557
110558
110559
110560
110561
110562
110563
110564
110565
110566
110567
110568
110569
110570
110571
110572
110573
110574
110575
110576
110577
110578
110579
110580
110581
110582
110583
110584
110585
110586
110587
110588
110589
110590
110591
110592
110593
110594
110595
110596
110597
110598
110599
110600
110601
110602
110603
110604
110605
110606
110607
110608
110609
110610
110611
110612
110613
110614
110615
110616
110617
110618
110619
110620
110621
110622
110623
110624
110625
110626
110627
110628
110629
110630
110631
110632
110633
110634
110635
110636
110637
110638
110639
110640
110641
110642
110643
110644
110645
110646
110647
110648
110649
110650
110651
110652
110653
110654
110655
110656
110657
110658
110659
110660
110661
110662
110663
110664
110665
110666
110667
110668
110669
110670
110671
110672
110673
110674
110675
110676
110677
110678
110679
110680
110681
110682
110683
110684
110685
110686
110687
110688
110689
110690
110691
110692
110693
110694
110695
110696
110697
110698
110699
110700
110701
110702
110703
110704
110705
......
110720
110721
110722
110723
110724
110725
110726
110727
110728
110729
110730
110731
110732
110733
110734
110735
110736
110737
110738
110739
110740
110741
110742
110743
110744
110745
110746
110747
110748
......
115165
115166
115167
115168
115169
115170
115171

115172
115173
115174
115175
115176
115177
115178
115179
......
116501
116502
116503
116504
116505
116506
116507
116508
116509
116510
116511
116512
116513
116514
116515
......
118929
118930
118931
118932
118933
118934
118935


118936
118937
118938
118939
118940
118941
118942
118943
......
124751
124752
124753
124754
124755
124756
124757

124758
124759
124760
124761
124762
124763
124764
......
125728
125729
125730
125731
125732
125733
125734












125735
125736
125737
125738
125739
125740
125741
......
125768
125769
125770
125771
125772
125773
125774
125775
125776
125777
125778
125779
125780
125781
125782
125783
125784
125785
125786
125787
......
126020
126021
126022
126023
126024
126025
126026

126027
126028
126029
126030
126031
126032
126033
......
126041
126042
126043
126044
126045
126046
126047

126048
126049
126050
126051
126052
126053
126054
......
127043
127044
127045
127046
127047
127048
127049

127050
127051
127052
127053
127054




127055
127056
127057
127058
127059
127060
127061
......
127168
127169
127170
127171
127172
127173
127174




127175

127176
127177
127178
127179
127180
127181
127182
/******************************************************************************
** This file is an amalgamation of many separate C source files from SQLite
** version 3.7.10.  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
................................................................................
** 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.7.10"
#define SQLITE_VERSION_NUMBER 3007010
#define SQLITE_SOURCE_ID      "2012-01-11 16:16:08 9e31a275ef494ea8713a1d60a15b84157e57c3ff"

/*
** 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
................................................................................
/*
** CAPI3REF: Obtain Values For URI Parameters
**
** These are utility routines, useful to VFS implementations, that check
** to see if a database file was a URI that contained a specific query 
** parameter, and if so obtains the value of that query parameter.
**
** If F is the filename pointer passed into the xOpen() method of a VFS


** implementation and P is the name of the query parameter, then
** sqlite3_uri_parameter(F,P) returns the value of the P
** parameter if it exists or a NULL pointer if P does not appear as a 
** query parameter on F.  If P is a query parameter of F
** has no explicit value, then sqlite3_uri_parameter(F,P) returns
** a pointer to an empty string.
**
** The sqlite3_uri_boolean(F,P,B) routine assumes that P is a boolean
** parameter and returns true (1) or false (0) according to the value
** of P.  The value of P is true if it is "yes" or "true" or "on" or 
** a non-zero number and is false otherwise.  If P is not a query parameter





** on F then sqlite3_uri_boolean(F,P,B) returns (B!=0).
**
** The sqlite3_uri_int64(F,P,D) routine converts the value of P into a
** 64-bit signed integer and returns that integer, or D if P does not
** exist.  If the value of P is something other than an integer, then
** zero is returned.
** 
** If F is a NULL pointer, then sqlite3_uri_parameter(F,P) returns NULL and
** sqlite3_uri_boolean(F,P,B) returns B.  If F is not a NULL pointer and
** is not a pathname pointer that SQLite passed into the xOpen VFS method,
** then the behavior of this routine is undefined and probably undesirable.

*/
SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam);
SQLITE_API int sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault);
SQLITE_API sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int64);


/*
................................................................................
** calling the xDestroy() method, SQLite considers the [sqlite3_pcache*]
** handle invalid, and will not use it with any other sqlite3_pcache_methods2
** functions.
**
** [[the xShrink() page cache method]]
** ^SQLite invokes the xShrink() method when it wants the page cache to
** free up as much of heap memory as possible.  The page cache implementation
** is not obligated to free any memory, but well-behaved implementions should
** do their best.
*/
typedef struct sqlite3_pcache_methods2 sqlite3_pcache_methods2;
struct sqlite3_pcache_methods2 {
  int iVersion;
  void *pArg;
  int (*xInit)(void*);
................................................................................
** A convenience macro that returns the number of elements in
** an array.
*/
#define ArraySize(X)    ((int)(sizeof(X)/sizeof(X[0])))

/*
** The following value as a destructor means to use sqlite3DbFree().




** This is an internal extension to SQLITE_STATIC and SQLITE_TRANSIENT.
*/
#define SQLITE_DYNAMIC   ((sqlite3_destructor_type)sqlite3DbFree)

/*
** When SQLITE_OMIT_WSD is defined, it means that the target platform does
** not support Writable Static Data (WSD) such as global and static variables.
** All variables must either be on the stack or dynamically allocated from
** the heap.  When WSD is unsupported, the variable declarations scattered
** throughout the SQLite code must become constants instead.  The SQLITE_WSD
................................................................................
/* The flags parameter to sqlite3BtreeOpen can be the bitwise or of the
** following values.
**
** NOTE:  These values must match the corresponding PAGER_ values in
** pager.h.
*/
#define BTREE_OMIT_JOURNAL  1  /* Do not create or use a rollback journal */
#define BTREE_NO_READLOCK   2  /* Omit readlocks on readonly files */
#define BTREE_MEMORY        4  /* This is an in-memory DB */
#define BTREE_SINGLE        8  /* The file contains at most 1 b-tree */
#define BTREE_UNORDERED    16  /* Use of a hash implementation is OK */

SQLITE_PRIVATE int sqlite3BtreeClose(Btree*);
SQLITE_PRIVATE int sqlite3BtreeSetCacheSize(Btree*,int);
SQLITE_PRIVATE int sqlite3BtreeSetSafetyLevel(Btree*,int,int,int);
SQLITE_PRIVATE int sqlite3BtreeSyncDisabled(Btree*);
SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int nPagesize, int nReserve, int eFix);
SQLITE_PRIVATE int sqlite3BtreeGetPageSize(Btree*);
................................................................................

/*
** Allowed values for the flags parameter to sqlite3PagerOpen().
**
** NOTE: These values must match the corresponding BTREE_ values in btree.h.
*/
#define PAGER_OMIT_JOURNAL  0x0001    /* Do not use a rollback journal */
#define PAGER_NO_READLOCK   0x0002    /* Omit readlocks on readonly files */
#define PAGER_MEMORY        0x0004    /* In-memory database */

/*
** Valid values for the second argument to sqlite3PagerLockingMode().
*/
#define PAGER_LOCKINGMODE_QUERY      -1
#define PAGER_LOCKINGMODE_NORMAL      0
#define PAGER_LOCKINGMODE_EXCLUSIVE   1
................................................................................
** structure.
*/
struct PgHdr {
  sqlite3_pcache_page *pPage;    /* Pcache object page handle */
  void *pData;                   /* Page data */
  void *pExtra;                  /* Extra content */
  PgHdr *pDirty;                 /* Transient list of dirty pages */
  Pgno pgno;                     /* Page number for this page */
  Pager *pPager;                 /* The pager this page is part of */

#ifdef SQLITE_CHECK_PAGES
  u32 pageHash;                  /* Hash of page content */
#endif
  u16 flags;                     /* PGHDR flags defined below */

  /**********************************************************************
  ** Elements above are public.  All that follows is private to pcache.c
................................................................................
# define SQLITE_TEMPNAME_SIZE (CCHMAXPATHCOMP)
#else
# define SQLITE_TEMPNAME_SIZE 200
#endif

/*
** Determine if we are dealing with Windows NT.
*/



#if defined(_WIN32_WINNT)
# define SQLITE_OS_WINNT 1
#else
# define SQLITE_OS_WINNT 0









#endif

/*
** Determine if we are dealing with WindowsCE - which has a much
** reduced API.
*/
#if defined(_WIN32_WCE)
................................................................................
*/
struct FuncDefHash {
  FuncDef *a[23];       /* Hash table for functions */
};

/*
** Each database connection is an instance of the following structure.
**
** The sqlite.lastRowid records the last insert rowid generated by an
** insert statement.  Inserts on views do not affect its value.  Each
** trigger has its own context, so that lastRowid can be updated inside
** triggers as usual.  The previous value will be restored once the trigger
** exits.  Upon entering a before or instead of trigger, lastRowid is no
** longer (since after version 2.8.12) reset to -1.
**
** The sqlite.nChange does not count changes within triggers and keeps no
** context.  It is reset at start of sqlite3_exec.
** The sqlite.lsChange represents the number of changes made by the last
** insert, update, or delete statement.  It remains constant throughout the
** length of a statement and is then updated by OP_SetCounts.  It keeps a
** context stack just like lastRowid so that the count of changes
** within a trigger is not seen outside the trigger.  Changes to views do not
** affect the value of lsChange.
** The sqlite.csChange keeps track of the number of current changes (since
** the last statement) and is used to update sqlite_lsChange.
**
** The member variables sqlite.errCode, sqlite.zErrMsg and sqlite.zErrMsg16
** store the most recent error code and, if applicable, string. The
** internal function sqlite3Error() is used to set these variables
** consistently.
*/
struct sqlite3 {
  sqlite3_vfs *pVfs;            /* OS Interface */
  int nDb;                      /* Number of backends currently in use */



  Db *aDb;                      /* All backends */

  int flags;                    /* Miscellaneous flags. See below */

  unsigned int openFlags;       /* Flags passed to sqlite3_vfs.xOpen() */
  int errCode;                  /* Most recent error code (SQLITE_*) */
  int errMask;                  /* & result codes with this before returning */
  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() */

  int nextPagesize;             /* Pagesize after VACUUM if >0 */
  int nTable;                   /* Number of tables in the database */
  CollSeq *pDfltColl;           /* The default collating sequence (BINARY) */
  i64 lastRowid;                /* ROWID of most recent insert (see above) */
  u32 magic;                    /* Magic number for detect library misuse */
  int nChange;                  /* Value returned by sqlite3_changes() */
  int nTotalChange;             /* Value returned by sqlite3_total_changes() */
  sqlite3_mutex *mutex;         /* Connection mutex */
  int aLimit[SQLITE_N_LIMIT];   /* Limits */
  struct sqlite3InitInfo {      /* Information used during initialization */
    int iDb;                    /* When back is being initialized */
    int newTnum;                /* Rootpage of table being initialized */

    u8 busy;                    /* TRUE if currently initializing */
    u8 orphanTrigger;           /* Last statement is orphaned TEMP trigger */
  } init;
  int nExtension;               /* Number of loaded extensions */
  void **aExtension;            /* Array of shared library handles */
  struct Vdbe *pVdbe;           /* List of active virtual machines */
  int activeVdbeCnt;            /* Number of VDBEs currently executing */
  int writeVdbeCnt;             /* Number of active VDBEs that are writing */
  int vdbeExecCnt;              /* Number of nested calls to VdbeExec() */


  void (*xTrace)(void*,const char*);        /* Trace function */
  void *pTraceArg;                          /* Argument to the trace function */
  void (*xProfile)(void*,const char*,u64);  /* Profiling function */
  void *pProfileArg;                        /* Argument to profile function */
  void *pCommitArg;                 /* Argument to xCommitCallback() */   
  int (*xCommitCallback)(void*);    /* Invoked at every commit. */
  void *pRollbackArg;               /* Argument to xRollbackCallback() */   
................................................................................
#endif
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
  int (*xProgress)(void *);     /* The progress callback */
  void *pProgressArg;           /* Argument to the progress callback */
  int nProgressOps;             /* Number of opcodes for progress callback */
#endif
#ifndef SQLITE_OMIT_VIRTUALTABLE

  Hash aModule;                 /* populated by sqlite3_create_module() */
  VtabCtx *pVtabCtx;            /* Context for active vtab connect/create */
  VTable **aVTrans;             /* Virtual tables with open transactions */
  int nVTrans;                  /* Allocated size of aVTrans */
  VTable *pDisconnect;    /* Disconnect these in next sqlite3_prepare() */
#endif
  FuncDefHash aFunc;            /* Hash table of connection functions */
  Hash aCollSeq;                /* All collating sequences */
  BusyHandler busyHandler;      /* Busy callback */
  int busyTimeout;              /* Busy handler timeout, in msec */
  Db aDbStatic[2];              /* Static space for the 2 default backends */
  Savepoint *pSavepoint;        /* List of active savepoints */

  int nSavepoint;               /* Number of non-transaction savepoints */
  int nStatement;               /* Number of nested statement-transactions  */
  u8 isTransactionSavepoint;    /* True if the outermost savepoint is a TS */
  i64 nDeferredCons;            /* Net deferred constraints this transaction. */
  int *pnBytesFreed;            /* If not NULL, increment this in DbFree() */

#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
  /* The following variables are all protected by the STATIC_MASTER 
  ** mutex, not by sqlite3.mutex. They are used by code in notify.c. 
  **
................................................................................
                                          /*   DELETE, or UPDATE and return */
                                          /*   the count using a callback. */
#define SQLITE_NullCallback   0x00002000  /* Invoke the callback once if the */
                                          /*   result set is empty */
#define SQLITE_SqlTrace       0x00004000  /* Debug print SQL as it executes */
#define SQLITE_VdbeListing    0x00008000  /* Debug listings of VDBE programs */
#define SQLITE_WriteSchema    0x00010000  /* OK to update SQLITE_MASTER */
#define SQLITE_NoReadlock     0x00020000  /* Readlocks are omitted when 
                                          ** accessing read-only databases */
#define SQLITE_IgnoreChecks   0x00040000  /* Do not enforce check constraints */
#define SQLITE_ReadUncommitted 0x0080000  /* For shared-cache mode */
#define SQLITE_LegacyFileFmt  0x00100000  /* Create new databases in format 1 */
#define SQLITE_FullFSync      0x00200000  /* Use full fsync on the backend */
#define SQLITE_CkptFullFSync  0x00400000  /* Use full fsync for checkpoint */
#define SQLITE_RecoveryMode   0x00800000  /* Ignore schema errors */
#define SQLITE_ReverseOrder   0x01000000  /* Reverse unordered SELECTs */
................................................................................
/*
** Possible values for FuncDef.flags
*/
#define SQLITE_FUNC_LIKE     0x01 /* Candidate for the LIKE optimization */
#define SQLITE_FUNC_CASE     0x02 /* Case-sensitive LIKE-type function */
#define SQLITE_FUNC_EPHEM    0x04 /* Ephemeral.  Delete with VDBE */
#define SQLITE_FUNC_NEEDCOLL 0x08 /* sqlite3GetFuncCollSeq() might be called */
#define SQLITE_FUNC_PRIVATE  0x10 /* Allowed for internal use only */
#define SQLITE_FUNC_COUNT    0x20 /* Built-in count(*) aggregate */
#define SQLITE_FUNC_COALESCE 0x40 /* Built-in coalesce() or ifnull() function */

/*
** The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are
** used to create the initializers for the FuncDef structures.
**
................................................................................
** Allowed values for Tabe.tabFlags.
*/
#define TF_Readonly        0x01    /* Read-only system table */
#define TF_Ephemeral       0x02    /* An ephemeral table */
#define TF_HasPrimaryKey   0x04    /* Table has a primary key */
#define TF_Autoincrement   0x08    /* Integer primary key is autoincrement */
#define TF_Virtual         0x10    /* Is a virtual table */
#define TF_NeedMetadata    0x20    /* aCol[].zType and aCol[].pColl missing */



/*
** Test to see whether or not a table is a virtual table.  This is
** done as a macro so that it will be optimized out when virtual
** table support is omitted from the build.
*/
................................................................................
** it means this is not a unique index.  Otherwise it is a unique index
** and the value of Index.onError indicate the which conflict resolution 
** algorithm to employ whenever an attempt is made to insert a non-unique
** element.
*/
struct Index {
  char *zName;     /* Name of this index */
  int nColumn;     /* Number of columns in the table used by this index */
  int *aiColumn;   /* Which columns are used by this index.  1st is 0 */
  tRowcnt *aiRowEst; /* Result of ANALYZE: Est. rows selected by each column */
  Table *pTable;   /* The SQL table being indexed */
  int tnum;        /* Page containing root of this index in database file */
  u8 onError;      /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
  u8 autoIndex;    /* True if is automatically created (ex: by UNIQUE) */
  u8 bUnordered;   /* Use this index for == or IN queries only */
  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;  /* Array of size Index.nColumn. True==DESC, False==ASC */
  char **azColl;   /* Array of collation sequence names for index */





#ifdef SQLITE_ENABLE_STAT3
  int nSample;             /* Number of elements in aSample[] */
  tRowcnt avgEq;           /* Average nEq value for key values not in aSample */
  IndexSample *aSample;    /* Samples of the left-most key */
#endif
};

................................................................................
struct AggInfo {
  u8 directMode;          /* Direct rendering mode means take data directly
                          ** from source tables rather than from accumulators */
  u8 useSortingIdx;       /* In direct mode, reference the sorting index rather
                          ** than the source table */
  int sortingIdx;         /* Cursor number of the sorting index */
  int sortingIdxPTab;     /* Cursor number of pseudo-table */
  ExprList *pGroupBy;     /* The group by clause */
  int nSortingColumn;     /* Number of columns in the sorting index */

  struct AggInfo_col {    /* For each column used in source tables */
    Table *pTab;             /* Source table */
    int iTable;              /* Cursor number of the source table */
    int iColumn;             /* Column number within the source table */
    int iSorterColumn;       /* Column number in the sorting index */
    int iMem;                /* Memory location that acts as accumulator */
    Expr *pExpr;             /* The original expression */
  } *aCol;
  int nColumn;            /* Number of used entries in aCol[] */
  int nColumnAlloc;       /* Number of slots allocated for aCol[] */
  int nAccumulator;       /* Number of columns that show through to the output.
                          ** Additional columns are used only as parameters to
                          ** aggregate functions */
  struct AggInfo_func {   /* For each aggregate function */
    Expr *pExpr;             /* Expression encoding the function */
    FuncDef *pFunc;          /* The aggregate function implementation */
    int iMem;                /* Memory location that acts as accumulator */
    int iDistinct;           /* Ephemeral table used to enforce DISTINCT */
  } *aFunc;
  int nFunc;              /* Number of entries in aFunc[] */
  int nFuncAlloc;         /* Number of slots allocated for aFunc[] */
};

/*
** The datatype ynVar is a signed integer, either 16-bit or 32-bit.
** Usually it is 16-bits.  But if SQLITE_MAX_VARIABLE_NUMBER is greater
** than 32767 we have to make it 32-bit.  16-bit is preferred because
** it uses less memory in the Expr object, which is a big memory user
................................................................................
** as the list of "expr AS ID" fields following a "SELECT" or in the
** list of "ID = expr" items in an UPDATE.  A list of expressions can
** also be used as the argument to a function, in which case the a.zName
** field is not used.
*/
struct ExprList {
  int nExpr;             /* Number of expressions on the list */
  int nAlloc;            /* Number of entries allocated below */
  int iECursor;          /* VDBE Cursor associated with this ExprList */
  struct ExprList_item {
    Expr *pExpr;           /* The list of expressions */
    char *zName;           /* Token associated with this expression */
    char *zSpan;           /* Original text of the expression */
    u8 sortOrder;          /* 1 for DESC or 0 for ASC */
    u8 done;               /* A flag to indicate when processing is finished */
    u16 iOrderByCol;       /* For ORDER BY, column number in result set */
    u16 iAlias;            /* Index into Parse.aAlias[] for zName */
  } *a;                  /* One entry for each expression */
};

/*
** An instance of this structure is used by the parser to record both
** the parse tree for an expression and the span of input text for an
** expression.
*/
................................................................................
*/
struct IdList {
  struct IdList_item {
    char *zName;      /* Name of the identifier */
    int idx;          /* Index in some Table.aCol[] of a column named zName */
  } *a;
  int nId;         /* Number of identifiers on the list */
  int nAlloc;      /* Number of entries allocated for a[] below */
};

/*
** The bitmask datatype defined below is used for various optimizations.
**
** Changing this from a 64-bit to a 32-bit type limits the number of
** tables in a join to 32 instead of 64.  But it also reduces the size
................................................................................
** sequences for the ORDER BY clause.
*/
struct Select {
  ExprList *pEList;      /* The fields of the result */
  u8 op;                 /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */
  char affinity;         /* MakeRecord with this affinity for SRT_Set */
  u16 selFlags;          /* Various SF_* values */



  SrcList *pSrc;         /* The FROM clause */
  Expr *pWhere;          /* The WHERE clause */
  ExprList *pGroupBy;    /* The GROUP BY clause */
  Expr *pHaving;         /* The HAVING clause */
  ExprList *pOrderBy;    /* The ORDER BY clause */
  Select *pPrior;        /* Prior select in a compound select statement */
  Select *pNext;         /* Next select to the left in a compound */
  Select *pRightmost;    /* Right-most select in a compound select statement */
  Expr *pLimit;          /* LIMIT expression. NULL means not used. */
  Expr *pOffset;         /* OFFSET expression. NULL means not used. */
  int iLimit, iOffset;   /* Memory registers holding LIMIT & OFFSET counters */
  int addrOpenEphm[3];   /* OP_OpenEphem opcodes related to this select */
  double nSelectRow;     /* Estimated number of result rows */
};

/*
** Allowed values for Select.selFlags.  The "SF" prefix stands for
** "Select Flag".
*/
#define SF_Distinct        0x01  /* Output should be DISTINCT */
#define SF_Resolved        0x02  /* Identifiers have been resolved */
#define SF_Aggregate       0x04  /* Contains aggregate functions */
#define SF_UsesEphemeral   0x08  /* Uses the OpenEphemeral opcode */
#define SF_Expanded        0x10  /* sqlite3SelectExpand() called on this */
#define SF_HasTypeInfo     0x20  /* FROM subqueries have Table metadata */
#define SF_UseSorter       0x40  /* Sort using a sorter */



/*
** The results of a select can be distributed in several ways.  The
** "SRT" prefix means "SELECT Result Type".
*/
#define SRT_Union        1  /* Store result as keys in an index */
................................................................................
** The TriggerPrg.aColmask[0] variable is set to a mask of old.* columns
** accessed (or set to 0 for triggers fired as a result of INSERT 
** statements). Similarly, the TriggerPrg.aColmask[1] variable is set to
** a mask of new.* columns used by the program.
*/
struct TriggerPrg {
  Trigger *pTrigger;      /* Trigger this program was coded from */
  int orconf;             /* Default ON CONFLICT policy */
  SubProgram *pProgram;   /* Program implementing pTrigger/orconf */

  u32 aColmask[2];        /* Masks of old.*, new.* columns accessed */
  TriggerPrg *pNext;      /* Next entry in Parse.pTriggerPrg list */
};

/*
** The yDbMask datatype for the bitmask of all attached databases.
*/
#if SQLITE_MAX_ATTACHED>30
  typedef sqlite3_uint64 yDbMask;
................................................................................
** feature is enabled (if sqlite3Tsd()->useSharedData is true). They are
** used to store the set of table-locks required by the statement being
** compiled. Function sqlite3TableLock() is used to add entries to the
** list.
*/
struct Parse {
  sqlite3 *db;         /* The main database structure */
  int rc;              /* Return code from execution */
  char *zErrMsg;       /* An error message */
  Vdbe *pVdbe;         /* An engine for executing database bytecode */

  u8 colNamesSet;      /* TRUE after OP_ColumnName has been issued to pVdbe */
  u8 checkSchema;      /* Causes schema cookie check after an error */
  u8 nested;           /* Number of nested calls to the parser/code generator */
  u8 nTempReg;         /* Number of temporary registers in aTempReg[] */
  u8 nTempInUse;       /* Number of aTempReg[] currently checked out */




  int aTempReg[8];     /* Holding area for temporary registers */
  int nRangeReg;       /* Size of the temporary register block */
  int iRangeReg;       /* First register in temporary register block */
  int nErr;            /* Number of errors seen */
  int nTab;            /* Number of previously allocated VDBE cursors */
  int nMem;            /* Number of memory cells used so far */
  int nSet;            /* Number of sets used so far */
  int nOnce;           /* Number of OP_Once instructions so far */
  int ckBase;          /* Base register of data during check constraints */
  int iCacheLevel;     /* ColCache valid when aColCache[].iLevel<=iCacheLevel */
  int iCacheCnt;       /* Counter used to generate aColCache[].lru values */
  u8 nColCache;        /* Number of entries in aColCache[] */
  u8 iColCache;        /* Next entry in aColCache[] to replace */
  struct yColCache {
    int iTable;           /* Table cursor number */
    int iColumn;          /* Table column number */
    u8 tempReg;           /* iReg is a temp register that needs to be freed */
    int iLevel;           /* Nesting level */
    int iReg;             /* Reg with value of this column. 0 means none. */
    int lru;              /* Least recently used entry has the smallest value */
  } aColCache[SQLITE_N_COLCACHE];  /* One for each column cache entry */
  yDbMask writeMask;   /* Start a write transaction on these databases */
  yDbMask cookieMask;  /* Bitmask of schema verified databases */
  u8 isMultiWrite;     /* True if statement may affect/insert multiple rows */
  u8 mayAbort;         /* True if statement may throw an ABORT exception */
  int cookieGoto;      /* Address of OP_Goto to cookie verifier subroutine */
  int cookieValue[SQLITE_MAX_ATTACHED+2];  /* Values of cookies to verify */



#ifndef SQLITE_OMIT_SHARED_CACHE
  int nTableLock;        /* Number of locks in aTableLock */
  TableLock *aTableLock; /* Required table locks for shared-cache mode */
#endif
  int regRowid;        /* Register holding rowid of CREATE TABLE entry */
  int regRoot;         /* Register holding root page number for new objects */
  AutoincInfo *pAinc;  /* Information about AUTOINCREMENT counters */
  int nMaxArg;         /* Max args passed to user function by sub-program */

  /* Information used while coding trigger programs. */
  Parse *pToplevel;    /* Parse structure for main program (or NULL) */
  Table *pTriggerTab;  /* Table triggers are being coded for */

  u32 oldmask;         /* Mask of old.* columns referenced */
  u32 newmask;         /* Mask of new.* columns referenced */
  u8 eTriggerOp;       /* TK_UPDATE, TK_INSERT or TK_DELETE */
  u8 eOrconf;          /* Default ON CONFLICT policy for trigger steps */
  u8 disableTriggers;  /* True to disable triggers */
  double nQueryLoop;   /* Estimated number of iterations of a query */

  /* Above is constant between recursions.  Below is reset before and after
  ** each recursion */

  int nVar;            /* Number of '?' variables seen in the SQL so far */
  int nzVar;           /* Number of available slots in azVar[] */
  char **azVar;        /* Pointers to names of parameters */
  Vdbe *pReprepare;    /* VM being reprepared (sqlite3Reprepare()) */
  int nAlias;          /* Number of aliased result set columns */
  int *aAlias;         /* Register used to hold aliased result */
  u8 explain;          /* True if the EXPLAIN flag is found on the query */
  Token sNameToken;    /* Token with unqualified schema object name */
  Token sLastToken;    /* The last token parsed */
  const char *zTail;   /* All SQL text past the last semicolon parsed */
  Table *pNewTable;    /* A table being constructed by CREATE TABLE */
  Trigger *pNewTrigger;     /* Trigger under construct by a CREATE TRIGGER */
  const char *zAuthContext; /* The 6th parameter to db->xAuth callbacks */
#ifndef SQLITE_OMIT_VIRTUALTABLE
  Token sArg;                /* Complete text of a module argument */
  u8 declareVtab;            /* True if inside sqlite3_declare_vtab() */
  int nVtabLock;             /* Number of virtual tables to lock */
  Table **apVtabLock;        /* Pointer to virtual tables needing locking */
#endif
  int nHeight;            /* Expression tree height of current sub-select */
  Table *pZombieTab;      /* List of Table objects to delete after code gen */
  TriggerPrg *pTriggerPrg;    /* Linked list of coded triggers */

#ifndef SQLITE_OMIT_EXPLAIN
  int iSelectId;
  int iNextSelectId;
#endif
};





#ifdef SQLITE_OMIT_VIRTUALTABLE
  #define IN_DECLARE_VTAB 0
#else
  #define IN_DECLARE_VTAB (pParse->declareVtab)
#endif

/*
................................................................................

/*
** A pointer to this structure is used to communicate information
** from sqlite3Init and OP_ParseSchema into the sqlite3InitCallback.
*/
typedef struct {
  sqlite3 *db;        /* The database being initialized */
  int iDb;            /* 0 for main database.  1 for TEMP, 2.. for ATTACHed */
  char **pzErrMsg;    /* Error message stored here */

  int rc;             /* Result code stored here */
} InitData;

/*
** Structure containing global configuration data for the SQLite library.
**
** This structure also contains some state information.
................................................................................
SQLITE_PRIVATE   void sqlite3AutoincrementBegin(Parse *pParse);
SQLITE_PRIVATE   void sqlite3AutoincrementEnd(Parse *pParse);
#else
# define sqlite3AutoincrementBegin(X)
# define sqlite3AutoincrementEnd(X)
#endif
SQLITE_PRIVATE void sqlite3Insert(Parse*, SrcList*, ExprList*, Select*, IdList*, int);
SQLITE_PRIVATE void *sqlite3ArrayAllocate(sqlite3*,void*,int,int,int*,int*,int*);
SQLITE_PRIVATE IdList *sqlite3IdListAppend(sqlite3*, IdList*, Token*);
SQLITE_PRIVATE int sqlite3IdListIndex(IdList*,const char*);
SQLITE_PRIVATE SrcList *sqlite3SrcListEnlarge(sqlite3*, SrcList*, int, int);
SQLITE_PRIVATE SrcList *sqlite3SrcListAppend(sqlite3*, SrcList*, Token*, Token*);
SQLITE_PRIVATE SrcList *sqlite3SrcListAppendFromTerm(Parse*, SrcList*, Token*, Token*,
                                      Token*, Select*, Expr*, IdList*);
SQLITE_PRIVATE void sqlite3SrcListIndexedBy(Parse *, SrcList *, Token *);
................................................................................
SQLITE_PRIVATE int sqlite3MulInt64(i64*,i64);
SQLITE_PRIVATE int sqlite3AbsInt32(int);
#ifdef SQLITE_ENABLE_8_3_NAMES
SQLITE_PRIVATE void sqlite3FileSuffix3(const char*, char*);
#else
# define sqlite3FileSuffix3(X,Y)
#endif
SQLITE_PRIVATE u8 sqlite3GetBoolean(const char *z);

SQLITE_PRIVATE const void *sqlite3ValueText(sqlite3_value*, u8);
SQLITE_PRIVATE int sqlite3ValueBytes(sqlite3_value*, u8);
SQLITE_PRIVATE void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8, 
                        void(*)(void*));
SQLITE_PRIVATE void sqlite3ValueFree(sqlite3_value*);
SQLITE_PRIVATE sqlite3_value *sqlite3ValueNew(sqlite3 *);
................................................................................
SQLITE_PRIVATE    void sqlite3VtabUnlock(VTable *);
SQLITE_PRIVATE    void sqlite3VtabUnlockList(sqlite3*);
SQLITE_PRIVATE    int sqlite3VtabSavepoint(sqlite3 *, int, int);
SQLITE_PRIVATE    VTable *sqlite3GetVTable(sqlite3*, Table*);
#  define sqlite3VtabInSync(db) ((db)->nVTrans>0 && (db)->aVTrans==0)
#endif
SQLITE_PRIVATE void sqlite3VtabMakeWritable(Parse*,Table*);
SQLITE_PRIVATE void sqlite3VtabBeginParse(Parse*, Token*, Token*, Token*);
SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse*, Token*);
SQLITE_PRIVATE void sqlite3VtabArgInit(Parse*);
SQLITE_PRIVATE void sqlite3VtabArgExtend(Parse*, Token*);
SQLITE_PRIVATE int sqlite3VtabCallCreate(sqlite3*, int, const char *, char **);
SQLITE_PRIVATE int sqlite3VtabCallConnect(Parse*, Table*);
SQLITE_PRIVATE int sqlite3VtabCallDestroy(sqlite3*, int, const char *);
SQLITE_PRIVATE int sqlite3VtabBegin(sqlite3 *, VTable *);
................................................................................
**
** The currently executing frame is stored in Vdbe.pFrame. Vdbe.pFrame is
** set to NULL if the currently executing frame is the main program.
*/
typedef struct VdbeFrame VdbeFrame;
struct VdbeFrame {
  Vdbe *v;                /* VM this frame belongs to */
  int pc;                 /* Program Counter in parent (calling) frame */
  Op *aOp;                /* Program instructions for parent frame */
  int nOp;                /* Size of aOp array */
  Mem *aMem;              /* Array of memory cells for parent frame */
  int nMem;               /* Number of entries in aMem */
  u8 *aOnceFlag;          /* Array of OP_Once flags for parent frame */
  int nOnceFlag;          /* Number of entries in aOnceFlag */
  VdbeCursor **apCsr;     /* Array of Vdbe cursors for parent frame */


  u16 nCursor;            /* Number of entries in apCsr */

  void *token;            /* Copy of SubProgram.token */


  int nChildMem;          /* Number of memory cells for child frame */
  int nChildCsr;          /* Number of cursors for child frame */
  i64 lastRowid;          /* Last insert rowid (sqlite3.lastRowid) */
  int nChange;            /* Statement changes (Vdbe.nChanges)     */
  VdbeFrame *pParent;     /* Parent of this frame, or NULL if parent is main */
};

#define VdbeFrameMem(p) ((Mem *)&((u8 *)p)[ROUND8(sizeof(VdbeFrame))])

/*
** A value for VdbeCursor.cacheValid that means the cache is always invalid.
*/
................................................................................
** (Mem) which are only defined there.
*/
struct sqlite3_context {
  FuncDef *pFunc;       /* Pointer to function information.  MUST BE FIRST */
  VdbeFunc *pVdbeFunc;  /* Auxilary data, if created. */
  Mem s;                /* The return value is stored here */
  Mem *pMem;            /* Memory cell used to store aggregate context */
  int isError;          /* Error code returned by the function. */
  CollSeq *pColl;       /* Collating sequence */


};

/*
** An Explain object accumulates indented output which is helpful
** in describing recursive data structures.
*/
struct Explain {
................................................................................
  Mem **apArg;            /* Arguments to currently executing user function */
  Mem *aColName;          /* Column names to return */
  Mem *pResultSet;        /* Pointer to an array of results */
  int nMem;               /* Number of memory locations currently allocated */
  int nOp;                /* Number of instructions in the program */
  int nOpAlloc;           /* Number of slots allocated for aOp[] */
  int nLabel;             /* Number of labels used */
  int nLabelAlloc;        /* Number of slots allocated in aLabel[] */
  int *aLabel;            /* Space to hold the labels */
  u16 nResColumn;         /* Number of columns in one row of the result set */
  u16 nCursor;            /* Number of slots in apCsr[] */
  u32 magic;              /* Magic number for sanity checking */
  char *zErrMsg;          /* Error message written here */
  Vdbe *pPrev,*pNext;     /* Linked list of VDBEs with the same Vdbe.db */
  VdbeCursor **apCsr;     /* One element of this array for each open cursor */
................................................................................
*************************************************************************
**
** This file contains low-level memory allocation drivers for when
** SQLite will use the standard C-library malloc/realloc/free interface
** to obtain the memory it needs.
**
** This file contains implementations of the low-level memory allocation
** routines specified in the sqlite3_mem_methods object.
























*/

/*
** This version of the memory allocator is the default.  It is
** used when no other memory allocator is specified using compile-time
** macros.
*/
#ifdef SQLITE_SYSTEM_MALLOC

/*
** Windows systems have malloc_usable_size() but it is called _msize()


*/
#if !defined(HAVE_MALLOC_USABLE_SIZE) && SQLITE_OS_WIN
# define HAVE_MALLOC_USABLE_SIZE 1
# define malloc_usable_size _msize

#endif

#if defined(__APPLE__)

/*
** Use the zone allocator available on apple products

*/
#include <sys/sysctl.h>
#include <malloc/malloc.h>
#include <libkern/OSAtomic.h>
static malloc_zone_t* _sqliteZone_;
#define SQLITE_MALLOC(x) malloc_zone_malloc(_sqliteZone_, (x))
#define SQLITE_FREE(x) malloc_zone_free(_sqliteZone_, (x));
................................................................................
#define SQLITE_REALLOC(x,y) malloc_zone_realloc(_sqliteZone_, (x), (y))
#define SQLITE_MALLOCSIZE(x) \
        (_sqliteZone_ ? _sqliteZone_->size(_sqliteZone_,x) : malloc_size(x))

#else /* if not __APPLE__ */

/*
** Use standard C library malloc and free on non-Apple systems.

*/
#define SQLITE_MALLOC(x)    malloc(x)
#define SQLITE_FREE(x)      free(x)
#define SQLITE_REALLOC(x,y) realloc((x),(y))





#ifdef HAVE_MALLOC_USABLE_SIZE
#include <malloc.h>

#define SQLITE_MALLOCSIZE(x) malloc_usable_size(x)

#else
#undef SQLITE_MALLOCSIZE
#endif

#endif /* __APPLE__ or not __APPLE__ */

/*
** Like malloc(), but remember the size of the allocation
** so that we can find it later using sqlite3MemSize().
................................................................................
  return ROUND8(n);
}

/*
** Initialize this module.
*/
static int sqlite3MemInit(void *NotUsed){
#if defined(__APPLE__)
  int cpuCount;
  size_t len;
  if( _sqliteZone_ ){
    return SQLITE_OK;
  }
  len = sizeof(cpuCount);
  /* One usually wants to use hw.acctivecpu for MT decisions, but not here */
................................................................................
typedef struct unixFile unixFile;
struct unixFile {
  sqlite3_io_methods const *pMethod;  /* Always the first entry */
  sqlite3_vfs *pVfs;                  /* The VFS that created this unixFile */
  unixInodeInfo *pInode;              /* Info about locks on this inode */
  int h;                              /* The file descriptor */
  unsigned char eFileLock;            /* The type of lock held on this fd */
  unsigned char ctrlFlags;            /* Behavioral bits.  UNIXFILE_* flags */
  int lastErrno;                      /* The unix errno from last I/O error */
  void *lockingContext;               /* Locking style specific state */
  UnixUnusedFd *pUnused;              /* Pre-allocated UnixUnusedFd */
  const char *zPath;                  /* Name of the file */
  unixShm *pShm;                      /* Shared memory segment information */
  int szChunk;                        /* Configured by FCNTL_CHUNK_SIZE */
#if SQLITE_ENABLE_LOCKING_STYLE
................................................................................
#else
# define UNIXFILE_DIRSYNC    0x00
#endif
#define UNIXFILE_PSOW        0x10     /* SQLITE_IOCAP_POWERSAFE_OVERWRITE */
#define UNIXFILE_DELETE      0x20     /* Delete on close */
#define UNIXFILE_URI         0x40     /* Filename might have query parameters */
#define UNIXFILE_NOLOCK      0x80     /* Do no file locking */


/*
** Include code that is common to all os_*.c files
*/
/************** Include os_common.h in the middle of os_unix.c ***************/
/************** Begin file os_common.h ***************************************/
/*
................................................................................

  { "mkdir",        (sqlite3_syscall_ptr)mkdir,           0 },
#define osMkdir     ((int(*)(const char*,mode_t))aSyscall[18].pCurrent)

  { "rmdir",        (sqlite3_syscall_ptr)rmdir,           0 },
#define osRmdir     ((int(*)(const char*))aSyscall[19].pCurrent)







}; /* End of the overrideable system calls */

/*
** This is the xSetSystemCall() method of sqlite3_vfs for all of the
** "unix" VFSes.  Return SQLITE_OK opon successfully updating the
** system call pointer, or SQLITE_NOTFOUND if there is no configurable
** system call named zName.
................................................................................
  for(i++; i<ArraySize(aSyscall); i++){
    if( aSyscall[i].pCurrent!=0 ) return aSyscall[i].zName;
  }
  return 0;
}

/*
** Retry open() calls that fail due to EINTR














*/
static int robust_open(const char *z, int f, int m){
  int rc;








  do{ rc = osOpen(z,f,m); }while( rc<0 && errno==EINTR );



  return rc;
}

/*
** Helper functions to obtain and relinquish the global mutex. The
** global mutex is used to protect the unixInodeInfo and
** vxworksFileId objects used by this file, all of which may be 
................................................................................
  pInode = pDbFd->pInode;
  pShmNode = pInode->pShmNode;
  if( pShmNode==0 ){
    struct stat sStat;                 /* fstat() info for database file */

    /* Call fstat() to figure out the permissions on the database file. If
    ** a new *-shm file is created, an attempt will be made to create it
    ** with the same permissions. The actual permissions the file is created
    ** with are subject to the current umask setting.
    */
    if( osFstat(pDbFd->h, &sStat) && pInode->bProcessLock==0 ){
      rc = SQLITE_IOERR_FSTAT;
      goto shm_open_err;
    }

#ifdef SQLITE_SHM_DIRECTORY
................................................................................
      int openFlags = O_RDWR | O_CREAT;
      if( sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0) ){
        openFlags = O_RDONLY;
        pShmNode->isReadonly = 1;
      }
      pShmNode->h = robust_open(zShmFilename, openFlags, (sStat.st_mode&0777));
      if( pShmNode->h<0 ){
        if( pShmNode->h<0 ){
          rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zShmFilename);
          goto shm_open_err;
        }










      }
  
      /* Check to see if another process is holding the dead-man switch.
      ** If not, truncate the file to zero length. 
      */
      rc = SQLITE_OK;
      if( unixShmSystemLock(pShmNode, F_WRLCK, UNIX_SHM_DMS, 1)==SQLITE_OK ){
................................................................................
/*
** This function is called by unixOpen() to determine the unix permissions
** to create new files with. If no error occurs, then SQLITE_OK is returned
** and a value suitable for passing as the third argument to open(2) is
** written to *pMode. If an IO error occurs, an SQLite error code is 
** returned and the value of *pMode is not modified.
**
** If the file being opened is a temporary file, it is always created with
** the octal permissions 0600 (read/writable by owner only). If the file
** is a database or master journal file, it is created with the permissions 
** mask SQLITE_DEFAULT_FILE_PERMISSIONS.
**
** Finally, if the file being opened is a WAL or regular journal file, then 
** this function queries the file-system for the permissions on the 
** corresponding database file and sets *pMode to this value. Whenever 
** possible, WAL and journal files are created using the same permissions 
** as the associated database file.
**
** If the SQLITE_ENABLE_8_3_NAMES option is enabled, then the
** original filename is unavailable.  But 8_3_NAMES is only used for
** FAT filesystems and permissions do not matter there, so just use
** the default permissions.
*/
static int findCreateFileMode(
  const char *zPath,              /* Path of file (possibly) being created */
  int flags,                      /* Flags passed as 4th argument to xOpen() */
  mode_t *pMode                   /* OUT: Permissions to open file with */


){
  int rc = SQLITE_OK;             /* Return Code */
  *pMode = SQLITE_DEFAULT_FILE_PERMISSIONS;



  if( flags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL) ){
    char zDb[MAX_PATHNAME+1];     /* Database file path */
    int nDb;                      /* Number of valid bytes in zDb */
    struct stat sStat;            /* Output of stat() on database file */

    /* zPath is a path to a WAL or journal file. The following block derives
    ** the path to the associated database file from zPath. This block handles
................................................................................
    }
#endif
    memcpy(zDb, zPath, nDb);
    zDb[nDb] = '\0';

    if( 0==osStat(zDb, &sStat) ){
      *pMode = sStat.st_mode & 0777;


    }else{
      rc = SQLITE_IOERR_FSTAT;
    }
  }else if( flags & SQLITE_OPEN_DELETEONCLOSE ){
    *pMode = 0600;
  }
  return rc;
................................................................................
  if( isReadWrite ) openFlags |= O_RDWR;
  if( isCreate )    openFlags |= O_CREAT;
  if( isExclusive ) openFlags |= (O_EXCL|O_NOFOLLOW);
  openFlags |= (O_LARGEFILE|O_BINARY);

  if( fd<0 ){
    mode_t openMode;              /* Permissions to create file with */


    rc = findCreateFileMode(zName, flags, &openMode);
    if( rc!=SQLITE_OK ){
      assert( !p->pUnused );
      assert( eType==SQLITE_OPEN_WAL || eType==SQLITE_OPEN_MAIN_JOURNAL );
      return rc;
    }
    fd = robust_open(zName, openFlags, openMode);
    OSTRACE(("OPENX   %-3d %s 0%o\n", fd, zName, openFlags));
................................................................................
      isReadonly = 1;
      fd = robust_open(zName, openFlags, openMode);
    }
    if( fd<0 ){
      rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zName);
      goto open_finished;
    }











  }
  assert( fd>=0 );
  if( pOutFlags ){
    *pOutFlags = flags;
  }

  if( p->pUnused ){
................................................................................
  ** When testing, initializing zBuf[] to zero is all we do.  That means
  ** that we always use the same random number sequence.  This makes the
  ** tests repeatable.
  */
  memset(zBuf, 0, nBuf);
#if !defined(SQLITE_TEST)
  {
    int pid, fd;
    fd = robust_open("/dev/urandom", O_RDONLY, 0);
    if( fd<0 ){
      time_t t;
      time(&t);
      memcpy(zBuf, &t, sizeof(t));
      pid = getpid();
      memcpy(&zBuf[sizeof(t)], &pid, sizeof(pid));
      assert( sizeof(t)+sizeof(pid)<=(size_t)nBuf );
      nBuf = sizeof(t) + sizeof(pid);
    }else{
      do{ nBuf = osRead(fd, zBuf, nBuf); }while( nBuf<0 && errno==EINTR );
      robust_close(0, fd, __LINE__);
    }
  }
#endif
  return nBuf;
}

................................................................................
  }else{
    pUnused = sqlite3_malloc(sizeof(*pUnused));
    if( !pUnused ){
      return SQLITE_NOMEM;
    }
  }
  if( fd<0 ){
    fd = robust_open(path, openFlags, SQLITE_DEFAULT_FILE_PERMISSIONS);
    terrno = errno;
    if( fd<0 && errno==ENOENT && islockfile ){
      if( proxyCreateLockPath(path) == SQLITE_OK ){
        fd = robust_open(path, openFlags, SQLITE_DEFAULT_FILE_PERMISSIONS);
      }
    }
  }
  if( fd<0 ){
    openFlags = O_RDONLY;
    fd = robust_open(path, openFlags, SQLITE_DEFAULT_FILE_PERMISSIONS);
    terrno = errno;
  }
  if( fd<0 ){
    if( islockfile ){
      return SQLITE_BUSY;
    }
    switch (terrno) {
................................................................................
  /* read the conch content */
  readLen = osPread(conchFile->h, buf, PROXY_MAXCONCHLEN, 0);
  if( readLen<PROXY_PATHINDEX ){
    sqlite3_snprintf(sizeof(errmsg),errmsg,"read error (len %d)",(int)readLen);
    goto end_breaklock;
  }
  /* write it out to the temporary break file */
  fd = robust_open(tPath, (O_RDWR|O_CREAT|O_EXCL),
                   SQLITE_DEFAULT_FILE_PERMISSIONS);
  if( fd<0 ){
    sqlite3_snprintf(sizeof(errmsg), errmsg, "create failed (%d)", errno);
    goto end_breaklock;
  }
  if( osPwrite(fd, buf, readLen, 0) != (ssize_t)readLen ){
    sqlite3_snprintf(sizeof(errmsg), errmsg, "write failed (%d)", errno);
    goto end_breaklock;
................................................................................
      OSTRACE(("TRANSPROXY: CLOSE  %d\n", pFile->h));
      if( rc==SQLITE_OK && pFile->openFlags ){
        int fd;
        if( pFile->h>=0 ){
          robust_close(pFile, pFile->h, __LINE__);
        }
        pFile->h = -1;
        fd = robust_open(pCtx->dbPath, pFile->openFlags,
                      SQLITE_DEFAULT_FILE_PERMISSIONS);
        OSTRACE(("TRANSPROXY: OPEN  %d\n", fd));
        if( fd>=0 ){
          pFile->h = fd;
        }else{
          rc=SQLITE_CANTOPEN_BKPT; /* SQLITE_BUSY? proxyTakeConch called
           during locking */
        }
................................................................................
    UNIXVFS("unix-proxy",    proxyIoFinder ),
#endif
  };
  unsigned int i;          /* Loop counter */

  /* Double-check that the aSyscall[] array has been constructed
  ** correctly.  See ticket [bb3a86e890c8e96ab] */
  assert( ArraySize(aSyscall)==20 );

  /* Register all VFSes defined in the aVfs[] array */
  for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){
    sqlite3_vfs_register(&aVfs[i], i==0);
  }
  return SQLITE_OK; 
}
................................................................................
  PGroup *pGroup;                     /* PGroup this cache belongs to */
  int szPage;                         /* Size of allocated pages in bytes */
  int szExtra;                        /* Size of extra space in bytes */
  int bPurgeable;                     /* True if cache is purgeable */
  unsigned int nMin;                  /* Minimum number of pages reserved */
  unsigned int nMax;                  /* Configured "cache_size" value */
  unsigned int n90pct;                /* nMax*9/10 */


  /* Hash table of all pages. The following variables may only be accessed
  ** when the accessor is holding the PGroup mutex.
  */
  unsigned int nRecyclable;           /* Number of pages in the LRU list */
  unsigned int nPage;                 /* Total number of pages in apHash */
  unsigned int nHash;                 /* Number of slots in apHash[] */
  PgHdr1 **apHash;                    /* Hash table for fast lookup by key */

  unsigned int iMaxKey;               /* Largest key seen since xTruncate() */
};

/*
** Each cache entry is represented by an instance of the following 
** structure. Unless SQLITE_PCACHE_SEPARATE_HEADER is defined, a buffer of
** PgHdr1.pCache->szPage bytes is allocated directly before this structure 
** in memory.
................................................................................
  int isInit;                    /* True if initialized */
  int szSlot;                    /* Size of each free slot */
  int nSlot;                     /* The number of pcache slots */
  int nReserve;                  /* Try to keep nFreeSlot above this */
  void *pStart, *pEnd;           /* Bounds of pagecache malloc range */
  /* Above requires no mutex.  Use mutex below for variable that follow. */
  sqlite3_mutex *mutex;          /* Mutex for accessing the following: */
  int nFreeSlot;                 /* Number of unused pcache slots */
  PgFreeslot *pFree;             /* Free page blocks */

  /* The following value requires a mutex to change.  We skip the mutex on
  ** reading because (1) most platforms read a 32-bit integer atomically and
  ** (2) even if an incorrect value is read, no great harm is done since this
  ** is really just an optimization. */
  int bUnderPressure;            /* True if low on PAGECACHE memory */
} pcache1_g;

................................................................................
**   sub-codes.
*/
struct Pager {
  sqlite3_vfs *pVfs;          /* OS functions to use for IO */
  u8 exclusiveMode;           /* Boolean. True if locking_mode==EXCLUSIVE */
  u8 journalMode;             /* One of the PAGER_JOURNALMODE_* values */
  u8 useJournal;              /* Use a rollback journal on this file */
  u8 noReadlock;              /* Do not bother to obtain readlocks */
  u8 noSync;                  /* Do not sync the journal if true */
  u8 fullSync;                /* Do extra syncs of the journal for robustness */
  u8 ckptSyncFlags;           /* SYNC_NORMAL or SYNC_FULL for checkpoint */
  u8 walSyncFlags;            /* SYNC_NORMAL or SYNC_FULL for wal writes */
  u8 syncFlags;               /* SYNC_NORMAL or SYNC_FULL otherwise */
  u8 tempFile;                /* zFilename is a temporary file */
  u8 readOnly;                /* True for a read-only database */
................................................................................
      assert( pPager->errCode==SQLITE_OK );
      assert( sqlite3PcacheRefCount(pPager->pPCache)==0 || pPager->tempFile );
      break;

    case PAGER_READER:
      assert( pPager->errCode==SQLITE_OK );
      assert( p->eLock!=UNKNOWN_LOCK );
      assert( p->eLock>=SHARED_LOCK || p->noReadlock );
      break;

    case PAGER_WRITER_LOCKED:
      assert( p->eLock!=UNKNOWN_LOCK );
      assert( pPager->errCode==SQLITE_OK );
      if( !pagerUseWal(pPager) ){
        assert( p->eLock>=RESERVED_LOCK );
................................................................................
  /* Query the WAL sub-system for the database size. The WalDbsize()
  ** function returns zero if the WAL is not open (i.e. Pager.pWal==0), or
  ** if the database size is not available. The database size is not
  ** available from the WAL sub-system if the log file is empty or
  ** contains no valid committed transactions.
  */
  assert( pPager->eState==PAGER_OPEN );
  assert( pPager->eLock>=SHARED_LOCK || pPager->noReadlock );
  nPage = sqlite3WalDbsize(pPager->pWal);

  /* If the database size was not available from the WAL sub-system,
  ** determine it based on the size of the database file. If the size
  ** of the database file is not an integer multiple of the page-size,
  ** round down to the nearest page. Except, any file larger than 0
  ** bytes in size is considered to contain at least one page.
................................................................................
** a WAL on a none-empty database, this ensures there is no race condition 
** between the xAccess() below and an xDelete() being executed by some 
** other connection.
*/
static int pagerOpenWalIfPresent(Pager *pPager){
  int rc = SQLITE_OK;
  assert( pPager->eState==PAGER_OPEN );
  assert( pPager->eLock>=SHARED_LOCK || pPager->noReadlock );

  if( !pPager->tempFile ){
    int isWal;                    /* True if WAL file exists */
    Pgno nPage;                   /* Size of the database file */

    rc = pagerPagecount(pPager, &nPage);
    if( rc ) return rc;
................................................................................
**
** The nExtra parameter specifies the number of bytes of space allocated
** along with each page reference. This space is available to the user
** via the sqlite3PagerGetExtra() API.
**
** The flags argument is used to specify properties that affect the
** operation of the pager. It should be passed some bitwise combination
** of the PAGER_OMIT_JOURNAL and PAGER_NO_READLOCK flags.
**
** The vfsFlags parameter is a bitmask to pass to the flags parameter
** of the xOpen() method of the supplied VFS when opening files. 
**
** If the pager object is allocated and the specified file opened 
** successfully, SQLITE_OK is returned and *ppPager set to point to
** the new pager object. If an error occurs, *ppPager is set to NULL
................................................................................
  int tempFile = 0;        /* True for temp files (incl. in-memory files) */
  int memDb = 0;           /* True if this is an in-memory file */
  int readOnly = 0;        /* True if this is a read-only file */
  int journalFileSize;     /* Bytes to allocate for each journal fd */
  char *zPathname = 0;     /* Full path to database file */
  int nPathname = 0;       /* Number of bytes in zPathname */
  int useJournal = (flags & PAGER_OMIT_JOURNAL)==0; /* False to omit journal */
  int noReadlock = (flags & PAGER_NO_READLOCK)!=0;  /* True to omit read-lock */
  int pcacheSize = sqlite3PcacheSize();       /* Bytes to allocate for PCache */
  u32 szPageDflt = SQLITE_DEFAULT_PAGE_SIZE;  /* Default page size */
  const char *zUri = 0;    /* URI args to copy */
  int nUri = 0;            /* Number of bytes of URI args at *zUri */

  /* Figure out how much space is required for each journal file-handle
  ** (there are two of them, the main journal and the sub-journal). This
................................................................................
  sqlite3PcacheOpen(szPageDflt, nExtra, !memDb,
                    !memDb?pagerStress:0, (void *)pPager, pPager->pPCache);

  PAGERTRACE(("OPEN %d %s\n", FILEHANDLEID(pPager->fd), pPager->zFilename));
  IOTRACE(("OPEN %p %s\n", pPager, pPager->zFilename))

  pPager->useJournal = (u8)useJournal;
  pPager->noReadlock = (noReadlock && readOnly) ?1:0;
  /* pPager->stmtOpen = 0; */
  /* pPager->stmtInUse = 0; */
  /* pPager->nRef = 0; */
  /* pPager->stmtSize = 0; */
  /* pPager->stmtJSize = 0; */
  /* pPager->nPage = 0; */
  pPager->mxPgno = SQLITE_MAX_PAGE_COUNT;
................................................................................
  assert( pPager->eState==PAGER_OPEN || pPager->eState==PAGER_READER );
  if( NEVER(MEMDB && pPager->errCode) ){ return pPager->errCode; }

  if( !pagerUseWal(pPager) && pPager->eState==PAGER_OPEN ){
    int bHotJournal = 1;          /* True if there exists a hot journal-file */

    assert( !MEMDB );
    assert( pPager->noReadlock==0 || pPager->readOnly );

    if( pPager->noReadlock==0 ){
      rc = pager_wait_on_lock(pPager, SHARED_LOCK);
      if( rc!=SQLITE_OK ){
        assert( pPager->eLock==NO_LOCK || pPager->eLock==UNKNOWN_LOCK );
        goto failed;
      }
    }

    /* If a journal file exists, and there is no RESERVED lock on the
    ** database file, then it either needs to be played back or deleted.
    */
    if( pPager->eLock<=SHARED_LOCK ){
      rc = hasHotJournal(pPager, &bHotJournal);
................................................................................
** lock on the database file and use heap-memory to store the wal-index
** in. Otherwise, use the normal shared-memory.
*/
static int pagerOpenWal(Pager *pPager){
  int rc = SQLITE_OK;

  assert( pPager->pWal==0 && pPager->tempFile==0 );
  assert( pPager->eLock==SHARED_LOCK || pPager->eLock==EXCLUSIVE_LOCK || pPager->noReadlock);

  /* If the pager is already in exclusive-mode, the WAL module will use 
  ** heap-memory for the wal-index instead of the VFS shared-memory 
  ** implementation. Take the exclusive lock now, before opening the WAL
  ** file, to make sure this is safe.
  */
  if( pPager->exclusiveMode ){
................................................................................
  u8 max1bytePayload;  /* min(maxLocal,127) */
  u16 maxLocal;        /* Copy of BtShared.maxLocal or BtShared.maxLeaf */
  u16 minLocal;        /* Copy of BtShared.minLocal or BtShared.minLeaf */
  u16 cellOffset;      /* Index in aData of first cell pointer */
  u16 nFree;           /* Number of free bytes on the page */
  u16 nCell;           /* Number of cells on this page, local and ovfl */
  u16 maskPage;        /* Mask for page offset */
  struct _OvflCell {   /* Cells that will not fit on aData[] */
    u8 *pCell;          /* Pointers to the body of the overflow cell */
    u16 idx;            /* Insert this cell before idx-th non-overflow cell */
  } aOvfl[5];
  BtShared *pBt;       /* Pointer to BtShared that this page is part of */
  u8 *aData;           /* Pointer to disk image of the page data */
  u8 *aDataEnd;        /* One byte past the end of usable data */
  u8 *aCellIdx;        /* The cell index area */
  DbPage *pDbPage;     /* Pager page handle */
  Pgno pgno;           /* Page number for this page */
};
................................................................................
** found at self->pBt->mutex. 
*/
struct BtCursor {
  Btree *pBtree;            /* The Btree to which this cursor belongs */
  BtShared *pBt;            /* The BtShared this cursor points to */
  BtCursor *pNext, *pPrev;  /* Forms a linked list of all cursors */
  struct KeyInfo *pKeyInfo; /* Argument passed to comparison function */



  Pgno pgnoRoot;            /* The root page of this tree */
  sqlite3_int64 cachedRowid; /* Next rowid cache.  0 means not valid */
  CellInfo info;            /* A parse of the cell we are pointing at */
  i64 nKey;        /* Size of pKey, or last integer key */
  void *pKey;      /* Saved key that was cursor's last known position */
  int skipNext;    /* Prev() is noop if negative. Next() is noop if positive */
  u8 wrFlag;                /* True if writable */
  u8 atLast;                /* Cursor pointing to the last entry */
  u8 validNKey;             /* True if info.nKey is valid */
  u8 eState;                /* One of the CURSOR_XXX constants (see below) */
#ifndef SQLITE_OMIT_INCRBLOB
  Pgno *aOverflow;          /* Cache of overflow page locations */
  u8 isIncrblobHandle;      /* True if this cursor is an incr. io handle */
#endif
  i16 iPage;                            /* Index of current page in apPage */
  u16 aiIdx[BTCURSOR_MAX_DEPTH];        /* Current index in apPage[i] */
  MemPage *apPage[BTCURSOR_MAX_DEPTH];  /* Pages from root to current page */
};

................................................................................
** This structure is passed around through all the sanity checking routines
** in order to keep track of some global state information.
*/
typedef struct IntegrityCk IntegrityCk;
struct IntegrityCk {
  BtShared *pBt;    /* The tree being checked out */
  Pager *pPager;    /* The associated pager.  Also accessible by pBt->pPager */
  Pgno nPage;       /* Number of pages in the database */
  int *anRef;       /* Number of times each page is referenced */

  int mxErr;        /* Stop accumulating errors when this reaches zero */
  int nErr;         /* Number of messages written to zErrMsg so far */
  int mallocFailed; /* A memory allocation error has occurred */
  StrAccum errMsg;  /* Accumulate the error message text here */
};

/*
................................................................................
** pages that do contain overflow cells.
*/
static u8 *findOverflowCell(MemPage *pPage, int iCell){
  int i;
  assert( sqlite3_mutex_held(pPage->pBt->mutex) );
  for(i=pPage->nOverflow-1; i>=0; i--){
    int k;
    struct _OvflCell *pOvfl;
    pOvfl = &pPage->aOvfl[i];
    k = pOvfl->idx;
    if( k<=iCell ){
      if( k==iCell ){
        return pOvfl->pCell;
      }
      iCell--;
    }
  }
  return findCell(pPage, iCell);
}

................................................................................
** be exclusively in memory, or it might use a disk-based memory cache.
** Either way, the ephemeral database will be automatically deleted 
** when sqlite3BtreeClose() is called.
**
** If zFilename is ":memory:" then an in-memory database is created
** that is automatically destroyed when it is closed.
**
** The "flags" parameter is a bitmask that might contain bits
** BTREE_OMIT_JOURNAL and/or BTREE_NO_READLOCK.  The BTREE_NO_READLOCK
** bit is also set if the SQLITE_NoReadlock flags is set in db->flags.
** These flags are passed through into sqlite3PagerOpen() and must
** be the same values as PAGER_OMIT_JOURNAL and PAGER_NO_READLOCK.
**
** If the database is already opened in the same database connection
** and we are in shared cache mode, then the open will fail with an
** SQLITE_CONSTRAINT error.  We cannot allow two or more BtShared
** objects in the same database connection since doing so will lead
** to problems with locking.
*/
................................................................................

  /* Only a BTREE_SINGLE database can be BTREE_UNORDERED */
  assert( (flags & BTREE_UNORDERED)==0 || (flags & BTREE_SINGLE)!=0 );

  /* A BTREE_SINGLE database is always a temporary and/or ephemeral */
  assert( (flags & BTREE_SINGLE)==0 || isTempDb );

  if( db->flags & SQLITE_NoReadlock ){
    flags |= BTREE_NO_READLOCK;
  }
  if( isMemdb ){
    flags |= BTREE_MEMORY;
  }
  if( (vfsFlags & SQLITE_OPEN_MAIN_DB)!=0 && (isMemdb || isTempDb) ){
    vfsFlags = (vfsFlags & ~SQLITE_OPEN_MAIN_DB) | SQLITE_OPEN_TEMP_DB;
  }
  p = sqlite3MallocZero(sizeof(Btree));
................................................................................
  pCur->validNKey = 0;
  if( pNewPage->nCell<1 || pNewPage->intKey!=pCur->apPage[i]->intKey ){
    return SQLITE_CORRUPT_BKPT;
  }
  return SQLITE_OK;
}

#ifndef NDEBUG
/*
** Page pParent is an internal (non-leaf) tree page. This function 
** asserts that page number iChild is the left-child if the iIdx'th
** cell in page pParent. Or, if iIdx is equal to the total number of
** cells in pParent, that page number iChild is the right-child of
** the page.
*/
................................................................................
** the largest cell index.
*/
static void moveToParent(BtCursor *pCur){
  assert( cursorHoldsMutex(pCur) );
  assert( pCur->eState==CURSOR_VALID );
  assert( pCur->iPage>0 );
  assert( pCur->apPage[pCur->iPage] );







  assertParentIndex(
    pCur->apPage[pCur->iPage-1], 
    pCur->aiIdx[pCur->iPage-1], 
    pCur->apPage[pCur->iPage]->pgno
  );



  releasePage(pCur->apPage[pCur->iPage]);
  pCur->iPage--;
  pCur->info.nSize = 0;
  pCur->validNKey = 0;
}

/*
................................................................................
    return SQLITE_OK;
  }
  pCur->skipNext = 0;

  pPage = pCur->apPage[pCur->iPage];
  idx = ++pCur->aiIdx[pCur->iPage];
  assert( pPage->isInit );






  assert( idx<=pPage->nCell );

  pCur->info.nSize = 0;
  pCur->validNKey = 0;
  if( idx>=pPage->nCell ){
    if( !pPage->leaf ){
      rc = moveToChild(pCur, get4byte(&pPage->aData[pPage->hdrOffset+8]));
      if( rc ) return rc;
................................................................................
/*
** Insert a new cell on pPage at cell index "i".  pCell points to the
** content of the cell.
**
** If the cell content will fit on the page, then put it there.  If it
** will not fit, then make a copy of the cell content into pTemp if
** pTemp is not null.  Regardless of pTemp, allocate a new entry
** in pPage->aOvfl[] and make it point to the cell content (either
** in pTemp or the original pCell) and also record its index. 
** Allocating a new entry in pPage->aCell[] implies that 
** pPage->nOverflow is incremented.
**
** If nSkip is non-zero, then do not copy the first nSkip bytes of the
** cell. The caller will overwrite them after this function returns. If
** nSkip is non-zero, then pCell may not point to an invalid memory location 
................................................................................

  int nSkip = (iChild ? 4 : 0);

  if( *pRC ) return;

  assert( i>=0 && i<=pPage->nCell+pPage->nOverflow );
  assert( pPage->nCell<=MX_CELL(pPage->pBt) && MX_CELL(pPage->pBt)<=10921 );
  assert( pPage->nOverflow<=ArraySize(pPage->aOvfl) );

  assert( sqlite3_mutex_held(pPage->pBt->mutex) );
  /* The cell should normally be sized correctly.  However, when moving a
  ** malformed cell from a leaf page to an interior page, if the cell size
  ** wanted to be less than 4 but got rounded up to 4 on the leaf, then size
  ** might be less than 8 (leaf-size + pointer) on the interior node.  Hence
  ** the term after the || in the following assert(). */
  assert( sz==cellSizePtr(pPage, pCell) || (sz==8 && iChild>0) );
................................................................................
      memcpy(pTemp+nSkip, pCell+nSkip, sz-nSkip);
      pCell = pTemp;
    }
    if( iChild ){
      put4byte(pCell, iChild);
    }
    j = pPage->nOverflow++;
    assert( j<(int)(sizeof(pPage->aOvfl)/sizeof(pPage->aOvfl[0])) );
    pPage->aOvfl[j].pCell = pCell;
    pPage->aOvfl[j].idx = (u16)i;
  }else{
    int rc = sqlite3PagerWrite(pPage->pDbPage);
    if( rc!=SQLITE_OK ){
      *pRC = rc;
      return;
    }
    assert( sqlite3PagerIswriteable(pPage->pDbPage) );
................................................................................
  ** may be inserted. If both these operations are successful, proceed.
  */
  rc = allocateBtreePage(pBt, &pNew, &pgnoNew, 0, 0);

  if( rc==SQLITE_OK ){

    u8 *pOut = &pSpace[4];
    u8 *pCell = pPage->aOvfl[0].pCell;
    u16 szCell = cellSizePtr(pPage, pCell);
    u8 *pStop;

    assert( sqlite3PagerIswriteable(pNew->pDbPage) );
    assert( pPage->aData[0]==(PTF_INTKEY|PTF_LEAFDATA|PTF_LEAF) );
    zeroPage(pNew, PTF_INTKEY|PTF_LEAFDATA|PTF_LEAF);
    assemblePage(pNew, 1, &pCell, &szCell);
................................................................................
** on page pFrom to page pTo. If page pFrom was not a leaf page, then
** the pointer-map entries for each child page are updated so that the
** parent page stored in the pointer map is page pTo. If pFrom contained
** any cells with overflow page pointers, then the corresponding pointer
** map entries are also updated so that the parent page is page pTo.
**
** If pFrom is currently carrying any overflow cells (entries in the
** MemPage.aOvfl[] array), they are not copied to pTo. 
**
** Before returning, page pTo is reinitialized using btreeInitPage().
**
** The performance of this function is not critical. It is only used by 
** the balance_shallower() and balance_deeper() procedures, neither of
** which are called often under normal circumstances.
*/
................................................................................

  /* At this point pParent may have at most one overflow cell. And if
  ** this overflow cell is present, it must be the cell with 
  ** index iParentIdx. This scenario comes about when this function
  ** is called (indirectly) from sqlite3BtreeDelete().
  */
  assert( pParent->nOverflow==0 || pParent->nOverflow==1 );
  assert( pParent->nOverflow==0 || pParent->aOvfl[0].idx==iParentIdx );

  if( !aOvflSpace ){
    return SQLITE_NOMEM;
  }

  /* Find the sibling pages to balance. Also locate the cells in pParent 
  ** that divide the siblings. An attempt is made to find NN siblings on 
................................................................................
    if( rc ){
      memset(apOld, 0, (i+1)*sizeof(MemPage*));
      goto balance_cleanup;
    }
    nMaxCells += 1+apOld[i]->nCell+apOld[i]->nOverflow;
    if( (i--)==0 ) break;

    if( i+nxDiv==pParent->aOvfl[0].idx && pParent->nOverflow ){
      apDiv[i] = pParent->aOvfl[0].pCell;
      pgno = get4byte(apDiv[i]);
      szNew[i] = cellSizePtr(pParent, apDiv[i]);
      pParent->nOverflow = 0;
    }else{
      apDiv[i] = findCell(pParent, i+nxDiv-pParent->nOverflow);
      pgno = get4byte(apDiv[i]);
      szNew[i] = cellSizePtr(pParent, apDiv[i]);
................................................................................
    ** setting a pointer map entry is a relatively expensive operation, this
    ** code only sets pointer map entries for child or overflow pages that have
    ** actually moved between pages.  */
    MemPage *pNew = apNew[0];
    MemPage *pOld = apCopy[0];
    int nOverflow = pOld->nOverflow;
    int iNextOld = pOld->nCell + nOverflow;
    int iOverflow = (nOverflow ? pOld->aOvfl[0].idx : -1);
    j = 0;                             /* Current 'old' sibling page */
    k = 0;                             /* Current 'new' sibling page */
    for(i=0; i<nCell; i++){
      int isDivider = 0;
      while( i==iNextOld ){
        /* Cell i is the cell immediately following the last cell on old
        ** sibling page j. If the siblings are not leaf pages of an
        ** intkey b-tree, then cell i was a divider cell. */
        assert( j+1 < ArraySize(apCopy) );
        pOld = apCopy[++j];
        iNextOld = i + !leafData + pOld->nCell + pOld->nOverflow;
        if( pOld->nOverflow ){
          nOverflow = pOld->nOverflow;
          iOverflow = i + !leafData + pOld->aOvfl[0].idx;
        }
        isDivider = !leafData;  
      }

      assert(nOverflow>0 || iOverflow<i );
      assert(nOverflow<2 || pOld->aOvfl[0].idx==pOld->aOvfl[1].idx-1);
      assert(nOverflow<3 || pOld->aOvfl[1].idx==pOld->aOvfl[2].idx-1);
      if( i==iOverflow ){
        isDivider = 1;
        if( (--nOverflow)>0 ){
          iOverflow++;
        }
      }

................................................................................
  assert( sqlite3PagerIswriteable(pChild->pDbPage) );
  assert( sqlite3PagerIswriteable(pRoot->pDbPage) );
  assert( pChild->nCell==pRoot->nCell );

  TRACE(("BALANCE: copy root %d into %d\n", pRoot->pgno, pChild->pgno));

  /* Copy the overflow cells from pRoot to pChild */

  memcpy(pChild->aOvfl, pRoot->aOvfl, pRoot->nOverflow*sizeof(pRoot->aOvfl[0]));


  pChild->nOverflow = pRoot->nOverflow;

  /* Zero the contents of pRoot. Then install pChild as the right-child. */
  zeroPage(pRoot, pChild->aData[0] & ~PTF_LEAF);
  put4byte(&pRoot->aData[pRoot->hdrOffset+8], pgnoChild);

  *ppChild = pChild;
................................................................................
      int const iIdx = pCur->aiIdx[iPage-1];

      rc = sqlite3PagerWrite(pParent->pDbPage);
      if( rc==SQLITE_OK ){
#ifndef SQLITE_OMIT_QUICKBALANCE
        if( pPage->hasData
         && pPage->nOverflow==1
         && pPage->aOvfl[0].idx==pPage->nCell
         && pParent->pgno!=1
         && pParent->nCell==iIdx
        ){
          /* Call balance_quick() to create a new sibling of pPage on which
          ** to store the overflow cell. balance_quick() inserts a new cell
          ** into pParent, which may cause pParent overflow. If this
          ** happens, the next interation of the do-loop will balance pParent 
................................................................................
    }
  }

  if( pMem->z && preserve && pMem->zMalloc && pMem->z!=pMem->zMalloc ){
    memcpy(pMem->zMalloc, pMem->z, pMem->n);
  }
  if( pMem->flags&MEM_Dyn && pMem->xDel ){

    pMem->xDel((void *)(pMem->z));
  }

  pMem->z = pMem->zMalloc;
  if( pMem->z==0 ){
    pMem->flags = MEM_Null;
  }else{
................................................................................
  assert( p->db==0 || sqlite3_mutex_held(p->db->mutex) );
  if( p->flags&MEM_Agg ){
    sqlite3VdbeMemFinalize(p, p->u.pDef);
    assert( (p->flags & MEM_Agg)==0 );
    sqlite3VdbeMemRelease(p);
  }else if( p->flags&MEM_Dyn && p->xDel ){
    assert( (p->flags&MEM_RowSet)==0 );

    p->xDel((void *)p->z);
    p->xDel = 0;
  }else if( p->flags&MEM_RowSet ){
    sqlite3RowSetClear(p->u.pRowSet);
  }else if( p->flags&MEM_Frame ){
    sqlite3VdbeMemSetNull(p);
  }
................................................................................
  **
  ** The second and third terms in the following conditional enforces
  ** the second condition under the assumption that addition overflow causes
  ** values to wrap around.  On x86 hardware, the third term is always
  ** true and could be omitted.  But we leave it in because other
  ** architectures might behave differently.
  */
  if( pMem->r==(double)pMem->u.i && pMem->u.i>SMALLEST_INT64


      && ALWAYS(pMem->u.i<LARGEST_INT64) ){




    pMem->flags |= MEM_Int;
  }
}

/*
** Convert pMem to type integer.  Invalidate any prior representations.
*/
................................................................................
** The VDBE knows that a P2 value is a label because labels are
** always negative and P2 values are suppose to be non-negative.
** Hence, a negative P2 value is a label that has yet to be resolved.
**
** Zero is returned if a malloc() fails.
*/
SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Vdbe *p){
  int i;
  i = p->nLabel++;
  assert( p->magic==VDBE_MAGIC_INIT );
  if( i>=p->nLabelAlloc ){
    int n = p->nLabelAlloc*2 + 5;

    p->aLabel = sqlite3DbReallocOrFree(p->db, p->aLabel,
                                       n*sizeof(p->aLabel[0]));
    p->nLabelAlloc = sqlite3DbMallocSize(p->db, p->aLabel)/sizeof(p->aLabel[0]);
  }
  if( p->aLabel ){
    p->aLabel[i] = -1;
  }
  return -1-i;
}

................................................................................
      if( eStatementOp!=SAVEPOINT_ROLLBACK ){
        sqlite3VdbeSetChanges(db, p->nChange);
      }else{
        sqlite3VdbeSetChanges(db, 0);
      }
      p->nChange = 0;
    }
  
    /* Rollback or commit any schema changes that occurred. */
    if( p->rc!=SQLITE_OK && db->flags&SQLITE_InternChanges ){
      sqlite3ResetInternalSchema(db, -1);
      db->flags = (db->flags | SQLITE_InternChanges);
    }

    /* Release the locks */
    sqlite3VdbeLeave(p);
  }

  /* We have successfully halted and closed the VM.  Record this fact. */
  if( p->pc>=0 ){
................................................................................
  break;

arithmetic_result_is_null:
  sqlite3VdbeMemSetNull(pOut);
  break;
}

/* Opcode: CollSeq * * P4
**
** P4 is a pointer to a CollSeq struct. If the next call to a user function
** or aggregate calls sqlite3GetFuncCollSeq(), this collation sequence will
** be returned. This is used by the built-in min(), max() and nullif()
** functions.




**
** The interface used by the implementation of the aforementioned functions
** to retrieve the collation sequence set by this opcode is not available
** publicly, only to user functions defined in func.c.
*/
case OP_CollSeq: {
  assert( pOp->p4type==P4_COLLSEQ );



  break;
}

/* Opcode: Function P1 P2 P3 P4 P5
**
** Invoke a user function (P4 is a pointer to a Function structure that
** defines the function) with P5 arguments taken from register P2 and
................................................................................
** on the file.
**
** If a write-transaction is started and the Vdbe.usesStmtJournal flag is
** true (this flag is set if the Vdbe may modify more than one row and may
** throw an ABORT exception), a statement transaction may also be opened.
** More specifically, a statement transaction is opened iff the database
** connection is currently not in autocommit mode, or if there are other
** active statements. A statement transaction allows the affects of this
** VDBE to be rolled back after an error without having to roll back the
** entire transaction. If no error is encountered, the statement transaction
** will automatically commit when the VDBE halts.
**
** If P2 is zero, then a read-lock is obtained on the database file.
*/
case OP_Transaction: {
................................................................................
      assert( !db->mallocFailed );
      rc = sqlite3_exec(db, u.by.zSql, sqlite3InitCallback, &u.by.initData, 0);
      if( rc==SQLITE_OK ) rc = u.by.initData.rc;
      sqlite3DbFree(db, u.by.zSql);
      db->init.busy = 0;
    }
  }

  if( rc==SQLITE_NOMEM ){
    goto no_mem;
  }
  break;
}

#if !defined(SQLITE_OMIT_ANALYZE)
................................................................................
  p->nMem = u.cc.pFrame->nChildMem;
  p->nCursor = (u16)u.cc.pFrame->nChildCsr;
  p->apCsr = (VdbeCursor **)&aMem[p->nMem+1];
  p->aOp = aOp = u.cc.pProgram->aOp;
  p->nOp = u.cc.pProgram->nOp;
  p->aOnceFlag = (u8 *)&p->apCsr[p->nCursor];
  p->nOnceFlag = u.cc.pProgram->nOnce;
  p->nOp = u.cc.pProgram->nOp;
  pc = -1;
  memset(p->aOnceFlag, 0, p->nOnceFlag);

  break;
}

/* Opcode: Param P1 P2 * * *
................................................................................
  u.cf.ctx.s.flags = MEM_Null;
  u.cf.ctx.s.z = 0;
  u.cf.ctx.s.zMalloc = 0;
  u.cf.ctx.s.xDel = 0;
  u.cf.ctx.s.db = db;
  u.cf.ctx.isError = 0;
  u.cf.ctx.pColl = 0;

  if( u.cf.ctx.pFunc->flags & SQLITE_FUNC_NEEDCOLL ){
    assert( pOp>p->aOp );
    assert( pOp[-1].p4type==P4_COLLSEQ );
    assert( pOp[-1].opcode==OP_CollSeq );
    u.cf.ctx.pColl = pOp[-1].p4.pColl;
  }
  (u.cf.ctx.pFunc->xStep)(&u.cf.ctx, u.cf.n, u.cf.apVal); /* IMP: R-24505-23230 */
  if( u.cf.ctx.isError ){
    sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(&u.cf.ctx.s));
    rc = u.cf.ctx.isError;
  }






  sqlite3VdbeMemRelease(&u.cf.ctx.s);

  break;
}

/* Opcode: AggFinal P1 P2 * P4 *
................................................................................
**     aTree[] = { X, 0   0, 6    0, 3, 5, 6 }
**
** In other words, each time we advance to the next sorter element, log2(N)
** key comparison operations are required, where N is the number of segments
** being merged (rounded up to the next power of 2).
*/
struct VdbeSorter {


  int nInMemory;                  /* Current size of pRecord list as PMA */
  int nTree;                      /* Used size of aTree/aIter (power of 2) */



  VdbeSorterIter *aIter;          /* Array of iterators to merge */
  int *aTree;                     /* Current state of incremental merge */
  i64 iWriteOff;                  /* Current write offset within file pTemp1 */
  i64 iReadOff;                   /* Current read offset within file pTemp1 */
  sqlite3_file *pTemp1;           /* PMA file 1 */
  int nPMA;                       /* Number of PMAs stored in pTemp1 */
  SorterRecord *pRecord;          /* Head of in-memory record list */
  int mnPmaSize;                  /* Minimum PMA size, in bytes */
  int mxPmaSize;                  /* Maximum PMA size, in bytes.  0==no limit */
  UnpackedRecord *pUnpacked;      /* Used to unpack keys */
};

/*
** The following type is an iterator for a PMA. It caches the current key in 
** variables nKey/aKey. If the iterator is at EOF, pFile==0.
*/
struct VdbeSorterIter {
  i64 iReadOff;                   /* Current read offset */
  i64 iEof;                       /* 1 byte past EOF for this iterator */
  sqlite3_file *pFile;            /* File iterator is reading from */
  int nAlloc;                     /* Bytes of space at aAlloc */
  u8 *aAlloc;                     /* Allocated space */
  int nKey;                       /* Number of bytes in key */


  u8 *aKey;                       /* Pointer to current key */
};

/*
** A structure to store a single record. All in-memory records are connected
** together into a linked list headed at VdbeSorter.pRecord using the 
** SorterRecord.pNext pointer.
................................................................................
  ExprList *pNew;
  struct ExprList_item *pItem, *pOldItem;
  int i;
  if( p==0 ) return 0;
  pNew = sqlite3DbMallocRaw(db, sizeof(*pNew) );
  if( pNew==0 ) return 0;
  pNew->iECursor = 0;
  pNew->nExpr = pNew->nAlloc = p->nExpr;

  pNew->a = pItem = sqlite3DbMallocRaw(db,  p->nExpr*sizeof(p->a[0]) );
  if( pItem==0 ){
    sqlite3DbFree(db, pNew);
    return 0;
  } 
  pOldItem = p->a;
  for(i=0; i<p->nExpr; i++, pItem++, pOldItem++){
    Expr *pOldExpr = pOldItem->pExpr;
................................................................................
}
SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3 *db, IdList *p){
  IdList *pNew;
  int i;
  if( p==0 ) return 0;
  pNew = sqlite3DbMallocRaw(db, sizeof(*pNew) );
  if( pNew==0 ) return 0;
  pNew->nId = pNew->nAlloc = p->nId;
  pNew->a = sqlite3DbMallocRaw(db, p->nId*sizeof(p->a[0]) );
  if( pNew->a==0 ){
    sqlite3DbFree(db, pNew);
    return 0;
  }



  for(i=0; i<p->nId; i++){
    struct IdList_item *pNewItem = &pNew->a[i];
    struct IdList_item *pOldItem = &p->a[i];
    pNewItem->zName = sqlite3DbStrDup(db, pOldItem->zName);
    pNewItem->idx = pOldItem->idx;
  }
  return pNew;
................................................................................
){
  sqlite3 *db = pParse->db;
  if( pList==0 ){
    pList = sqlite3DbMallocZero(db, sizeof(ExprList) );
    if( pList==0 ){
      goto no_mem;
    }
    assert( pList->nAlloc==0 );
  }

  if( pList->nAlloc<=pList->nExpr ){
    struct ExprList_item *a;
    int n = pList->nAlloc*2 + 4;
    a = sqlite3DbRealloc(db, pList->a, n*sizeof(pList->a[0]));
    if( a==0 ){
      goto no_mem;
    }
    pList->a = a;
    pList->nAlloc = sqlite3DbMallocSize(db, a)/sizeof(a[0]);
  }
  assert( pList->a!=0 );
  if( 1 ){
    struct ExprList_item *pItem = &pList->a[pList->nExpr++];
    memset(pItem, 0, sizeof(*pItem));
    pItem->pExpr = pExpr;
  }
................................................................................
/*
** Delete an entire expression list.
*/
SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){
  int i;
  struct ExprList_item *pItem;
  if( pList==0 ) return;
  assert( pList->a!=0 || (pList->nExpr==0 && pList->nAlloc==0) );
  assert( pList->nExpr<=pList->nAlloc );
  for(pItem=pList->a, i=0; i<pList->nExpr; i++, pItem++){
    sqlite3ExprDelete(db, pItem->pExpr);
    sqlite3DbFree(db, pItem->zName);
    sqlite3DbFree(db, pItem->zSpan);
  }
  sqlite3DbFree(db, pList->a);
  sqlite3DbFree(db, pList);
................................................................................
*/
static int addAggInfoColumn(sqlite3 *db, AggInfo *pInfo){
  int i;
  pInfo->aCol = sqlite3ArrayAllocate(
       db,
       pInfo->aCol,
       sizeof(pInfo->aCol[0]),
       3,
       &pInfo->nColumn,
       &pInfo->nColumnAlloc,
       &i
  );
  return i;
}    

/*
** Add a new element to the pAggInfo->aFunc[] array.  Return the index of
................................................................................
*/
static int addAggInfoFunc(sqlite3 *db, AggInfo *pInfo){
  int i;
  pInfo->aFunc = sqlite3ArrayAllocate(
       db, 
       pInfo->aFunc,
       sizeof(pInfo->aFunc[0]),
       3,
       &pInfo->nFunc,
       &pInfo->nFuncAlloc,
       &i
  );
  return i;
}    

/*
** This is the xExprCallback for a tree walker.  It is used to
................................................................................
#endif
          "tbl_name = %Q, "
          "name = CASE "
            "WHEN type='table' THEN %Q "
            "WHEN name LIKE 'sqlite_autoindex%%' AND type='index' THEN "
             "'sqlite_autoindex_' || %Q || substr(name,%d+18) "
            "ELSE name END "
      "WHERE tbl_name=%Q AND "
          "(type='table' OR type='index' OR type='trigger');", 
      zDb, SCHEMA_TABLE(iDb), zName, zName, zName, 
#ifndef SQLITE_OMIT_TRIGGER
      zName,
#endif
      zName, nTabName, zTabName
  );
................................................................................
                             sqlite3Strlen30(p->zName),p);
    if( pOld ){
      assert( p==pOld );  /* Malloc must have failed inside HashInsert() */
      db->mallocFailed = 1;
      return;
    }
    pParse->pNewTable = 0;
    db->nTable++;
    db->flags |= SQLITE_InternChanges;

#ifndef SQLITE_OMIT_ALTERTABLE
    if( !p->pSelect ){
      const char *zName = (const char *)pParse->sNameToken.z;
      int nName;
      assert( !pSelect && pCons && pEnd );
................................................................................
** might be the same as the pArray parameter or it might be a different
** pointer if the array was resized.
*/
SQLITE_PRIVATE void *sqlite3ArrayAllocate(
  sqlite3 *db,      /* Connection to notify of malloc failures */
  void *pArray,     /* Array of objects.  Might be reallocated */
  int szEntry,      /* Size of each object in the array */
  int initSize,     /* Suggested initial allocation, in elements */
  int *pnEntry,     /* Number of objects currently in use */
  int *pnAlloc,     /* Current size of the allocation, in elements */
  int *pIdx         /* Write the index of a new slot here */
){
  char *z;
  if( *pnEntry >= *pnAlloc ){
    void *pNew;
    int newSize;
    newSize = (*pnAlloc)*2 + initSize;
    pNew = sqlite3DbRealloc(db, pArray, newSize*szEntry);
    if( pNew==0 ){
      *pIdx = -1;
      return pArray;
    }
    *pnAlloc = sqlite3DbMallocSize(db, pNew)/szEntry;
    pArray = pNew;
  }
  z = (char*)pArray;
  memset(&z[*pnEntry * szEntry], 0, szEntry);
  *pIdx = *pnEntry;
  ++*pnEntry;
  return pArray;
}

/*
** Append a new element to the given IdList.  Create a new IdList if
** need be.
................................................................................
** A new IdList is returned, or NULL if malloc() fails.
*/
SQLITE_PRIVATE IdList *sqlite3IdListAppend(sqlite3 *db, IdList *pList, Token *pToken){
  int i;
  if( pList==0 ){
    pList = sqlite3DbMallocZero(db, sizeof(IdList) );
    if( pList==0 ) return 0;
    pList->nAlloc = 0;
  }
  pList->a = sqlite3ArrayAllocate(
      db,
      pList->a,
      sizeof(pList->a[0]),
      5,
      &pList->nId,
      &pList->nAlloc,
      &i
  );
  if( i<0 ){
    sqlite3IdListDelete(db, pList);
    return 0;
  }
  pList->a[i].zName = sqlite3NameFromToken(db, pToken);
................................................................................

/*
** Return the collating function associated with a function.
*/
static CollSeq *sqlite3GetFuncCollSeq(sqlite3_context *context){
  return context->pColl;
}









/*
** Implementation of the non-aggregate min() and max() functions
*/
static void minmaxFunc(
  sqlite3_context *context,
  int argc,
................................................................................
    ** (or -9223372036854775808) since when you do abs() of that
    ** number of you get the same value back again.  To do this
    ** in a way that is testable, mask the sign bit off of negative
    ** values, resulting in a positive value.  Then take the 
    ** 2s complement of that positive value.  The end result can
    ** therefore be no less than -9223372036854775807.
    */
    r = -(r ^ (((sqlite3_int64)1)<<63));
  }
  sqlite3_result_int64(context, r);
}

/*
** Implementation of randomblob(N).  Return a random blob
** that is N bytes long.
................................................................................
  int NotUsed, 
  sqlite3_value **argv
){
  Mem *pArg  = (Mem *)argv[0];
  Mem *pBest;
  UNUSED_PARAMETER(NotUsed);

  if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
  pBest = (Mem *)sqlite3_aggregate_context(context, sizeof(*pBest));
  if( !pBest ) return;



  if( pBest->flags ){
    int max;
    int cmp;
    CollSeq *pColl = sqlite3GetFuncCollSeq(context);
    /* This step function is used for both the min() and max() aggregates,
    ** the only difference between the two being that the sense of the
    ** comparison is inverted. For the max() aggregate, the
    ** sqlite3_user_data() function returns (void *)-1. For min() it
................................................................................
    ** Therefore the next statement sets variable 'max' to 1 for the max()
    ** aggregate, or 0 for min().
    */
    max = sqlite3_user_data(context)!=0;
    cmp = sqlite3MemCompare(pBest, pArg, pColl);
    if( (max && cmp<0) || (!max && cmp>0) ){
      sqlite3VdbeMemCopy(pBest, pArg);


    }
  }else{
    sqlite3VdbeMemCopy(pBest, pArg);
  }
}
static void minMaxFinalize(sqlite3_context *context){
  sqlite3_value *pRes;
  pRes = (sqlite3_value *)sqlite3_aggregate_context(context, 0);
  if( pRes ){
    if( ALWAYS(pRes->flags) ){
      sqlite3_result_value(context, pRes);
    }
    sqlite3VdbeMemRelease(pRes);
  }
}

/*
................................................................................
*************************************************************************
** This file contains code used to implement the PRAGMA command.
*/

/*
** Interpret the given string as a safety level.  Return 0 for OFF,
** 1 for ON or NORMAL and 2 for FULL.  Return 1 for an empty or 
** unrecognized string argument.

**
** Note that the values returned are one less that the values that
** should be passed into sqlite3BtreeSetSafetyLevel().  The is done
** to support legacy SQL code.  The safety level used to be boolean
** and older scripts may have used numbers 0 for OFF and 1 for ON.
*/
static u8 getSafetyLevel(const char *z){
                             /* 123456789 123456789 */
  static const char zText[] = "onoffalseyestruefull";
  static const u8 iOffset[] = {0, 1, 2, 4, 9, 12, 16};
  static const u8 iLength[] = {2, 2, 3, 5, 3, 4, 4};
  static const u8 iValue[] =  {1, 0, 0, 0, 1, 1, 2};
  int i, n;
  if( sqlite3Isdigit(*z) ){
    return (u8)sqlite3Atoi(z);
  }
  n = sqlite3Strlen30(z);
  for(i=0; i<ArraySize(iLength); i++){
    if( iLength[i]==n && sqlite3StrNICmp(&zText[iOffset[i]],z,n)==0 ){
      return iValue[i];
    }
  }
  return 1;
}

/*
** Interpret the given string as a boolean value.
*/
SQLITE_PRIVATE u8 sqlite3GetBoolean(const char *z){
  return getSafetyLevel(z)&1;
}

/* The sqlite3GetBoolean() function is used by other modules but the
** remainder of this file is specific to PRAGMA processing.  So omit
** the rest of the file if PRAGMAs are omitted from the build.
*/
#if !defined(SQLITE_OMIT_PRAGMA)
................................................................................
    { "vdbe_trace",               SQLITE_VdbeTrace     },
#endif
#ifndef SQLITE_OMIT_CHECK
    { "ignore_check_constraints", SQLITE_IgnoreChecks  },
#endif
    /* The following is VERY experimental */
    { "writable_schema",          SQLITE_WriteSchema|SQLITE_RecoveryMode },
    { "omit_readlock",            SQLITE_NoReadlock    },

    /* TODO: Maybe it shouldn't be possible to change the ReadUncommitted
    ** flag if there are any active statements. */
    { "read_uncommitted",         SQLITE_ReadUncommitted },
    { "recursive_triggers",       SQLITE_RecTriggers },

    /* This flag may only be set if both foreign-key and trigger support
................................................................................
          int mask = p->mask;          /* Mask of bits to set or clear. */
          if( db->autoCommit==0 ){
            /* Foreign key support may not be enabled or disabled while not
            ** in auto-commit mode.  */
            mask &= ~(SQLITE_ForeignKeys);
          }

          if( sqlite3GetBoolean(zRight) ){
            db->flags |= mask;
          }else{
            db->flags &= ~mask;
          }

          /* Many of the flag-pragmas modify the code generated by the SQL 
          ** compiler (eg. count_changes). So add an opcode to expire all
................................................................................
  ** flag setting and reports thenew value.
  */
  if( sqlite3StrICmp(zLeft,"secure_delete")==0 ){
    Btree *pBt = pDb->pBt;
    int b = -1;
    assert( pBt!=0 );
    if( zRight ){
      b = sqlite3GetBoolean(zRight);
    }
    if( pId2->n==0 && b>=0 ){
      int ii;
      for(ii=0; ii<db->nDb; ii++){
        sqlite3BtreeSecureDelete(db->aDb[ii].pBt, b);
      }
    }
................................................................................
    if( !zRight ){
      returnSingleInt(pParse, "synchronous", pDb->safety_level-1);
    }else{
      if( !db->autoCommit ){
        sqlite3ErrorMsg(pParse, 
            "Safety level may not be changed inside a transaction");
      }else{
        pDb->safety_level = getSafetyLevel(zRight)+1;
      }
    }
  }else
#endif /* SQLITE_OMIT_PAGER_PRAGMAS */

#ifndef SQLITE_OMIT_FLAG_PRAGMAS
  if( flagPragma(pParse, zLeft, zRight) ){
................................................................................
    }
  }else
#endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */

#ifndef NDEBUG
  if( sqlite3StrICmp(zLeft, "parser_trace")==0 ){
    if( zRight ){
      if( sqlite3GetBoolean(zRight) ){
        sqlite3ParserTrace(stderr, "parser: ");
      }else{
        sqlite3ParserTrace(0, 0);
      }
    }
  }else
#endif

  /* Reinstall the LIKE and GLOB functions.  The variant of LIKE
  ** used will be case sensitive or not depending on the RHS.
  */
  if( sqlite3StrICmp(zLeft, "case_sensitive_like")==0 ){
    if( zRight ){
      sqlite3RegisterLikeFunctions(db, sqlite3GetBoolean(zRight));
    }
  }else

#ifndef SQLITE_INTEGRITY_CHECK_ERROR_MAX
# define SQLITE_INTEGRITY_CHECK_ERROR_MAX 100
#endif

................................................................................
    pNew = &standin;
    memset(pNew, 0, sizeof(*pNew));
  }
  if( pEList==0 ){
    pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db,TK_ALL,0));
  }
  pNew->pEList = pEList;

  pNew->pSrc = pSrc;
  pNew->pWhere = pWhere;
  pNew->pGroupBy = pGroupBy;
  pNew->pHaving = pHaving;
  pNew->pOrderBy = pOrderBy;
  pNew->selFlags = isDistinct ? SF_Distinct : 0;
  pNew->op = TK_SELECT;
................................................................................
  }

  /* Make sure all SELECTs in the statement have the same number of elements
  ** in their result sets.
  */
  assert( p->pEList && pPrior->pEList );
  if( p->pEList->nExpr!=pPrior->pEList->nExpr ){



    sqlite3ErrorMsg(pParse, "SELECTs to the left and right of %s"
      " do not have the same number of result columns", selectOpName(p->op));

    rc = 1;
    goto multi_select_end;
  }

  /* Compound SELECTs that have an ORDER BY clause are handled separately.
  */
  if( p->pOrderBy ){
................................................................................
      }
      if( j==nOrderBy ){
        Expr *pNew = sqlite3Expr(db, TK_INTEGER, 0);
        if( pNew==0 ) return SQLITE_NOMEM;
        pNew->flags |= EP_IntValue;
        pNew->u.iValue = i;
        pOrderBy = sqlite3ExprListAppend(pParse, pOrderBy, pNew);
        pOrderBy->a[nOrderBy++].iOrderByCol = (u16)i;
      }
    }
  }

  /* Compute the comparison permutation and keyinfo that is used with
  ** the permutation used to determine if the next
  ** row of results comes from selectA or selectB.  Also add explicit
................................................................................
/*
** Update the accumulator memory cells for an aggregate based on
** the current cursor position.
*/
static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
  Vdbe *v = pParse->pVdbe;
  int i;


  struct AggInfo_func *pF;
  struct AggInfo_col *pC;

  pAggInfo->directMode = 1;
  sqlite3ExprCacheClear(pParse);
  for(i=0, pF=pAggInfo->aFunc; i<pAggInfo->nFunc; i++, pF++){
    int nArg;
................................................................................
      assert( pList!=0 );  /* pList!=0 if pF->pFunc has NEEDCOLL */
      for(j=0, pItem=pList->a; !pColl && j<nArg; j++, pItem++){
        pColl = sqlite3ExprCollSeq(pParse, pItem->pExpr);
      }
      if( !pColl ){
        pColl = pParse->db->pDfltColl;
      }

      sqlite3VdbeAddOp4(v, OP_CollSeq, 0, 0, 0, (char *)pColl, P4_COLLSEQ);
    }
    sqlite3VdbeAddOp4(v, OP_AggStep, 0, regAgg, pF->iMem,
                      (void*)pF->pFunc, P4_FUNCDEF);
    sqlite3VdbeChangeP5(v, (u8)nArg);
    sqlite3ExprCacheAffinityChange(pParse, regAgg, nArg);
    sqlite3ReleaseTempRange(pParse, regAgg, nArg);
    if( addrNext ){
................................................................................
  ** to pC->iMem. But by the time the value is used, the original register
  ** may have been used, invalidating the underlying buffer holding the
  ** text or blob value. See ticket [883034dcb5].
  **
  ** Another solution would be to change the OP_SCopy used to copy cached
  ** values to an OP_Copy.
  */



  sqlite3ExprCacheClear(pParse);
  for(i=0, pC=pAggInfo->aCol; i<pAggInfo->nAccumulator; i++, pC++){
    sqlite3ExprCode(pParse, pC->pExpr, pC->iMem);
  }
  pAggInfo->directMode = 0;
  sqlite3ExprCacheClear(pParse);



}

/*
** Add a single OP_Explain instruction to the VDBE to explain a simple
** count(*) query ("SELECT count(*) FROM pTab").
*/
#ifndef SQLITE_OMIT_EXPLAIN
................................................................................
  }
  sqlite3ExplainPrintf(pVdbe, "END");
  sqlite3ExplainPop(pVdbe);
}

/* End of the structure debug printing code
*****************************************************************************/
#endif /* defined(SQLITE_TEST) || defined(SQLITE_DEBUG) */

/************** End of select.c **********************************************/
/************** Begin file table.c *******************************************/
/*
** 2001 September 15
**
** The author disclaims copyright to this source code.  In place of
................................................................................
** statement.  The module name has been parsed, but the optional list
** of parameters that follow the module name are still pending.
*/
SQLITE_PRIVATE void sqlite3VtabBeginParse(
  Parse *pParse,        /* Parsing context */
  Token *pName1,        /* Name of new table, or database name */
  Token *pName2,        /* Name of new table or NULL */
  Token *pModuleName    /* Name of the module for the virtual table */

){
  int iDb;              /* The database the table is being created in */
  Table *pTable;        /* The new virtual table */
  sqlite3 *db;          /* Database connection */

  sqlite3StartTable(pParse, pName1, pName2, 0, 0, 1, 0);
  pTable = pParse->pNewTable;
  if( pTable==0 ) return;
  assert( 0==pTable->pIndex );

  db = pParse->db;
  iDb = sqlite3SchemaToIndex(db, pTable->pSchema);
  assert( iDb>=0 );
................................................................................

/*
** This routine takes the module argument that has been accumulating
** in pParse->zArg[] and appends it to the list of arguments on the
** virtual table currently under construction in pParse->pTable.
*/
static void addArgumentToVtab(Parse *pParse){
  if( pParse->sArg.z && ALWAYS(pParse->pNewTable) ){
    const char *z = (const char*)pParse->sArg.z;
    int n = pParse->sArg.n;
    sqlite3 *db = pParse->db;
    addModuleArgument(db, pParse->pNewTable, sqlite3DbStrNDup(db, z, n));
  }
}

................................................................................
struct TrigEvent { int a; IdList * b; };

/*
** An instance of this structure holds the ATTACH key and the key type.
*/
struct AttachKey { int type;  Token key; };










  /* This is a utility routine used to set the ExprSpan.zStart and
  ** ExprSpan.zEnd values of pOut so that the span covers the complete
  ** range of text beginning with pStart and going to the end of pEnd.
  */
  static void spanSet(ExprSpan *pOut, Token *pStart, Token *pEnd){
    pOut->zStart = pStart->z;
................................................................................
**    sqlite3ParserARG_FETCH     Code to extract %extra_argument from yypParser
**    YYNSTATE           the combined number of states.
**    YYNRULE            the number of rules in the grammar
**    YYERRORSYMBOL      is the code number of the error symbol.  If not
**                       defined, then do no error processing.
*/
#define YYCODETYPE unsigned char
#define YYNOCODE 253
#define YYACTIONTYPE unsigned short int
#define YYWILDCARD 67
#define sqlite3ParserTOKENTYPE Token
typedef union {
  int yyinit;
  sqlite3ParserTOKENTYPE yy0;
  int yy4;
  struct TrigEvent yy90;
  ExprSpan yy118;
  TriggerStep* yy203;
  u8 yy210;
  struct {int value; int mask;} yy215;
  SrcList* yy259;
  struct LimitVal yy292;

  Expr* yy314;
  ExprList* yy322;
  struct LikeOp yy342;

  IdList* yy384;
  Select* yy387;

} YYMINORTYPE;
#ifndef YYSTACKDEPTH
#define YYSTACKDEPTH 100
#endif
#define sqlite3ParserARG_SDECL Parse *pParse;
#define sqlite3ParserARG_PDECL ,Parse *pParse
#define sqlite3ParserARG_FETCH Parse *pParse = yypParser->pParse
#define sqlite3ParserARG_STORE yypParser->pParse = pParse
#define YYNSTATE 630
#define YYNRULE 329
#define YYFALLBACK 1
#define YY_NO_ACTION      (YYNSTATE+YYNRULE+2)
#define YY_ACCEPT_ACTION  (YYNSTATE+YYNRULE+1)
#define YY_ERROR_ACTION   (YYNSTATE+YYNRULE)

/* The yyzerominor constant is used to initialize instances of
** YYMINORTYPE objects to zero. */
................................................................................
**                     yy_action.  Used to detect hash collisions.
**  yy_shift_ofst[]    For each state, the offset into yy_action for
**                     shifting terminals.
**  yy_reduce_ofst[]   For each state, the offset into yy_action for
**                     shifting non-terminals after a reduce.
**  yy_default[]       Default action for each state.
*/
#define YY_ACTTAB_COUNT (1557)
static const YYACTIONTYPE yy_action[] = {
 /*     0 */   313,  960,  186,  419,    2,  172,  627,  597,   55,   55,
 /*    10 */    55,   55,   48,   53,   53,   53,   53,   52,   52,   51,
 /*    20 */    51,   51,   50,  238,  302,  283,  623,  622,  516,  515,
 /*    30 */   590,  584,   55,   55,   55,   55,  282,   53,   53,   53,
 /*    40 */    53,   52,   52,   51,   51,   51,   50,  238,    6,   56,
 /*    50 */    57,   47,  582,  581,  583,  583,   54,   54,   55,   55,
 /*    60 */    55,   55,  608,   53,   53,   53,   53,   52,   52,   51,
 /*    70 */    51,   51,   50,  238,  313,  597,  409,  330,  579,  579,
 /*    80 */    32,   53,   53,   53,   53,   52,   52,   51,   51,   51,
 /*    90 */    50,  238,  330,  217,  620,  619,  166,  411,  624,  382,
 /*   100 */   379,  378,    7,  491,  590,  584,  200,  199,  198,   58,
 /*   110 */   377,  300,  414,  621,  481,   66,  623,  622,  621,  580,
 /*   120 */   254,  601,   94,   56,   57,   47,  582,  581,  583,  583,
 /*   130 */    54,   54,   55,   55,   55,   55,  671,   53,   53,   53,
 /*   140 */    53,   52,   52,   51,   51,   51,   50,  238,  313,  532,
 /*   150 */   226,  506,  507,  133,  177,  139,  284,  385,  279,  384,
 /*   160 */   169,  197,  342,  398,  251,  226,  253,  275,  388,  167,
 /*   170 */   139,  284,  385,  279,  384,  169,  570,  236,  590,  584,
 /*   180 */   672,  240,  275,  157,  620,  619,  554,  437,   51,   51,
 /*   190 */    51,   50,  238,  343,  439,  553,  438,   56,   57,   47,
 /*   200 */   582,  581,  583,  583,   54,   54,   55,   55,   55,   55,
 /*   210 */   465,   53,   53,   53,   53,   52,   52,   51,   51,   51,
 /*   220 */    50,  238,  313,  390,   52,   52,   51,   51,   51,   50,
 /*   230 */   238,  391,  166,  491,  566,  382,  379,  378,  409,  440,
 /*   240 */   579,  579,  252,  440,  607,   66,  377,  513,  621,   49,
 /*   250 */    46,  147,  590,  584,  621,   16,  466,  189,  621,  441,
 /*   260 */   442,  673,  526,  441,  340,  577,  595,   64,  194,  482,
 /*   270 */   434,   56,   57,   47,  582,  581,  583,  583,   54,   54,
 /*   280 */    55,   55,   55,   55,   30,   53,   53,   53,   53,   52,
 /*   290 */    52,   51,   51,   51,   50,  238,  313,  593,  593,  593,
 /*   300 */   387,  578,  606,  493,  259,  351,  258,  411,    1,  623,
 /*   310 */   622,  496,  623,  622,   65,  240,  623,  622,  597,  443,
 /*   320 */   237,  239,  414,  341,  237,  602,  590,  584,   18,  603,
 /*   330 */   166,  601,   87,  382,  379,  378,   67,  623,  622,   38,
 /*   340 */   623,  622,  176,  270,  377,   56,   57,   47,  582,  581,
 /*   350 */   583,  583,   54,   54,   55,   55,   55,   55,  175,   53,
 /*   360 */    53,   53,   53,   52,   52,   51,   51,   51,   50,  238,
 /*   370 */   313,  396,  233,  411,  531,  565,  317,  620,  619,   44,
 /*   380 */   620,  619,  240,  206,  620,  619,  597,  266,  414,  268,
 /*   390 */   409,  597,  579,  579,  352,  184,  505,  601,   73,  533,
 /*   400 */   590,  584,  466,  548,  190,  620,  619,  576,  620,  619,
 /*   410 */   547,  383,  551,   35,  332,  575,  574,  600,  504,   56,
 /*   420 */    57,   47,  582,  581,  583,  583,   54,   54,   55,   55,
 /*   430 */    55,   55,  567,   53,   53,   53,   53,   52,   52,   51,
 /*   440 */    51,   51,   50,  238,  313,  411,  561,  561,  528,  364,
 /*   450 */   259,  351,  258,  183,  361,  549,  524,  374,  411,  597,
 /*   460 */   414,  240,  560,  560,  409,  604,  579,  579,  328,  601,
 /*   470 */    93,  623,  622,  414,  590,  584,  237,  564,  559,  559,
 /*   480 */   520,  402,  601,   87,  409,  210,  579,  579,  168,  421,
 /*   490 */   950,  519,  950,   56,   57,   47,  582,  581,  583,  583,
 /*   500 */    54,   54,   55,   55,   55,   55,  192,   53,   53,   53,
 /*   510 */    53,   52,   52,   51,   51,   51,   50,  238,  313,  600,
 /*   520 */   293,  563,  511,  234,  357,  146,  475,  475,  367,  411,
 /*   530 */   562,  411,  358,  542,  425,  171,  411,  215,  144,  620,
 /*   540 */   619,  544,  318,  353,  414,  203,  414,  275,  590,  584,
 /*   550 */   549,  414,  174,  601,   94,  601,   79,  558,  471,   61,
 /*   560 */   601,   79,  421,  949,  350,  949,   34,   56,   57,   47,
 /*   570 */   582,  581,  583,  583,   54,   54,   55,   55,   55,   55,
 /*   580 */   535,   53,   53,   53,   53,   52,   52,   51,   51,   51,
 /*   590 */    50,  238,  313,  307,  424,  394,  272,   49,   46,  147,
 /*   600 */   349,  322,    4,  411,  491,  312,  321,  425,  568,  492,
 /*   610 */   216,  264,  407,  575,  574,  429,   66,  549,  414,  621,
 /*   620 */   540,  602,  590,  584,   13,  603,  621,  601,   72,   12,
 /*   630 */   618,  617,  616,  202,  210,  621,  546,  469,  422,  319,
 /*   640 */   148,   56,   57,   47,  582,  581,  583,  583,   54,   54,
 /*   650 */    55,   55,   55,   55,  338,   53,   53,   53,   53,   52,
 /*   660 */    52,   51,   51,   51,   50,  238,  313,  600,  600,  411,
 /*   670 */    39,   21,   37,  170,  237,  875,  411,  572,  572,  201,
 /*   680 */   144,  473,  538,  331,  414,  474,  143,  146,  630,  628,
 /*   690 */   334,  414,  353,  601,   68,  168,  590,  584,  132,  365,
 /*   700 */   601,   96,  307,  423,  530,  336,   49,   46,  147,  568,
 /*   710 */   406,  216,  549,  360,  529,   56,   57,   47,  582,  581,
 /*   720 */   583,  583,   54,   54,   55,   55,   55,   55,  411,   53,
 /*   730 */    53,   53,   53,   52,   52,   51,   51,   51,   50,  238,
 /*   740 */   313,  411,  605,  414,  484,  510,  172,  422,  597,  318,
 /*   750 */   496,  485,  601,   99,  411,  142,  414,  411,  231,  411,
 /*   760 */   540,  411,  359,  629,    2,  601,   97,  426,  308,  414,
 /*   770 */   590,  584,  414,   20,  414,  621,  414,  621,  601,  106,
 /*   780 */   503,  601,  105,  601,  108,  601,  109,  204,   28,   56,
 /*   790 */    57,   47,  582,  581,  583,  583,   54,   54,   55,   55,
 /*   800 */    55,   55,  411,   53,   53,   53,   53,   52,   52,   51,
 /*   810 */    51,   51,   50,  238,  313,  411,  597,  414,  411,  276,
 /*   820 */   214,  600,  411,  366,  213,  381,  601,  134,  274,  500,
 /*   830 */   414,  167,  130,  414,  621,  411,  354,  414,  376,  601,
 /*   840 */   135,  129,  601,  100,  590,  584,  601,  104,  522,  521,
 /*   850 */   414,  621,  224,  273,  600,  167,  327,  282,  600,  601,
 /*   860 */   103,  468,  521,   56,   57,   47,  582,  581,  583,  583,
 /*   870 */    54,   54,   55,   55,   55,   55,  411,   53,   53,   53,
 /*   880 */    53,   52,   52,   51,   51,   51,   50,  238,  313,  411,
 /*   890 */    27,  414,  411,  375,  276,  167,  359,  544,   50,  238,
 /*   900 */   601,   95,  128,  223,  414,  411,  165,  414,  411,  621,
 /*   910 */   411,  621,  612,  601,  102,  372,  601,   76,  590,  584,
 /*   920 */   414,  570,  236,  414,  470,  414,  167,  621,  188,  601,
 /*   930 */    98,  225,  601,  138,  601,  137,  232,   56,   45,   47,
 /*   940 */   582,  581,  583,  583,   54,   54,   55,   55,   55,   55,
 /*   950 */   411,   53,   53,   53,   53,   52,   52,   51,   51,   51,
 /*   960 */    50,  238,  313,  276,  276,  414,  411,  276,  544,  459,
 /*   970 */   359,  171,  209,  479,  601,  136,  628,  334,  621,  621,
 /*   980 */   125,  414,  621,  368,  411,  621,  257,  540,  589,  588,
 /*   990 */   601,   75,  590,  584,  458,  446,   23,   23,  124,  414,
 /*  1000 */   326,  325,  621,  427,  324,  309,  600,  288,  601,   92,
 /*  1010 */   586,  585,   57,   47,  582,  581,  583,  583,   54,   54,
 /*  1020 */    55,   55,   55,   55,  411,   53,   53,   53,   53,   52,
 /*  1030 */    52,   51,   51,   51,   50,  238,  313,  587,  411,  414,
 /*  1040 */   411,  207,  611,  476,  171,  472,  160,  123,  601,   91,
 /*  1050 */   323,  261,   15,  414,  464,  414,  411,  621,  411,  354,
 /*  1060 */   222,  411,  601,   74,  601,   90,  590,  584,  159,  264,
 /*  1070 */   158,  414,  461,  414,  621,  600,  414,  121,  120,   25,
 /*  1080 */   601,   89,  601,  101,  621,  601,   88,   47,  582,  581,
 /*  1090 */   583,  583,   54,   54,   55,   55,   55,   55,  544,   53,
 /*  1100 */    53,   53,   53,   52,   52,   51,   51,   51,   50,  238,
 /*  1110 */    43,  405,  263,    3,  610,  264,  140,  415,  622,   24,
 /*  1120 */   410,   11,  456,  594,  118,  155,  219,  452,  408,  621,
 /*  1130 */   621,  621,  156,   43,  405,  621,    3,  286,  621,  113,
 /*  1140 */   415,  622,  111,  445,  411,  400,  557,  403,  545,   10,
 /*  1150 */   411,  408,  264,  110,  205,  436,  541,  566,  453,  414,
 /*  1160 */   621,  621,   63,  621,  435,  414,  411,  621,  601,   94,
 /*  1170 */   403,  621,  411,  337,  601,   86,  150,   40,   41,  534,
 /*  1180 */   566,  414,  242,  264,   42,  413,  412,  414,  600,  595,
 /*  1190 */   601,   85,  191,  333,  107,  451,  601,   84,  621,  539,
 /*  1200 */    40,   41,  420,  230,  411,  149,  316,   42,  413,  412,
 /*  1210 */   398,  127,  595,  315,  621,  399,  278,  625,  181,  414,
 /*  1220 */   593,  593,  593,  592,  591,   14,  450,  411,  601,   71,
 /*  1230 */   240,  621,   43,  405,  264,    3,  615,  180,  264,  415,
 /*  1240 */   622,  614,  414,  593,  593,  593,  592,  591,   14,  621,
 /*  1250 */   408,  601,   70,  621,  417,   33,  405,  613,    3,  411,
 /*  1260 */   264,  411,  415,  622,  418,  626,  178,  509,    8,  403,
 /*  1270 */   241,  416,  126,  408,  414,  621,  414,  449,  208,  566,
 /*  1280 */   240,  221,  621,  601,   83,  601,   82,  599,  297,  277,
 /*  1290 */   296,   30,  403,   31,  395,  264,  295,  397,  489,   40,
 /*  1300 */    41,  411,  566,  220,  621,  294,   42,  413,  412,  271,
 /*  1310 */   621,  595,  600,  621,   59,   60,  414,  269,  267,  623,
 /*  1320 */   622,   36,   40,   41,  621,  601,   81,  598,  235,   42,
 /*  1330 */   413,  412,  621,  621,  595,  265,  344,  411,  248,  556,
 /*  1340 */   173,  185,  593,  593,  593,  592,  591,   14,  218,   29,
 /*  1350 */   621,  543,  414,  305,  304,  303,  179,  301,  411,  566,
 /*  1360 */   454,  601,   80,  289,  335,  593,  593,  593,  592,  591,
 /*  1370 */    14,  411,  287,  414,  151,  392,  246,  260,  411,  196,
 /*  1380 */   195,  523,  601,   69,  411,  245,  414,  526,  537,  285,
 /*  1390 */   389,  595,  621,  414,  536,  601,   17,  362,  153,  414,
 /*  1400 */   466,  463,  601,   78,  154,  414,  462,  152,  601,   77,
 /*  1410 */   355,  255,  621,  455,  601,    9,  621,  386,  444,  517,
 /*  1420 */   247,  621,  593,  593,  593,  621,  621,  244,  621,  243,
 /*  1430 */   430,  518,  292,  621,  329,  621,  145,  393,  280,  513,
 /*  1440 */   291,  131,  621,  514,  621,  621,  311,  621,  259,  346,
 /*  1450 */   249,  621,  621,  229,  314,  621,  228,  512,  227,  240,
 /*  1460 */   494,  488,  310,  164,  487,  486,  373,  480,  163,  262,
 /*  1470 */   369,  371,  162,   26,  212,  478,  477,  161,  141,  363,
 /*  1480 */   467,  122,  339,  187,  119,  348,  347,  117,  116,  115,
 /*  1490 */   114,  112,  182,  457,  320,   22,  433,  432,  448,   19,
 /*  1500 */   609,  431,  428,   62,  193,  596,  573,  298,  555,  552,
 /*  1510 */   571,  404,  290,  380,  498,  510,  495,  306,  281,  499,
 /*  1520 */   250,    5,  497,  460,  345,  447,  569,  550,  238,  299,
 /*  1530 */   527,  525,  508,  961,  502,  501,  961,  401,  961,  211,
 /*  1540 */   490,  356,  256,  961,  483,  961,  961,  961,  961,  961,
 /*  1550 */   961,  961,  961,  961,  961,  961,  370,
};
static const YYCODETYPE yy_lookahead[] = {
 /*     0 */    19,  142,  143,  144,  145,   24,    1,   26,   77,   78,
 /*    10 */    79,   80,   81,   82,   83,   84,   85,   86,   87,   88,
 /*    20 */    89,   90,   91,   92,   15,   98,   26,   27,    7,    8,
 /*    30 */    49,   50,   77,   78,   79,   80,  109,   82,   83,   84,
 /*    40 */    85,   86,   87,   88,   89,   90,   91,   92,   22,   68,
 /*    50 */    69,   70,   71,   72,   73,   74,   75,   76,   77,   78,
 /*    60 */    79,   80,   23,   82,   83,   84,   85,   86,   87,   88,
 /*    70 */    89,   90,   91,   92,   19,   94,  112,   19,  114,  115,
 /*    80 */    25,   82,   83,   84,   85,   86,   87,   88,   89,   90,
 /*    90 */    91,   92,   19,   22,   94,   95,   96,  150,  150,   99,
 /*   100 */   100,  101,   76,  150,   49,   50,  105,  106,  107,   54,
 /*   110 */   110,  158,  165,  165,  161,  162,   26,   27,  165,  113,
 /*   120 */    16,  174,  175,   68,   69,   70,   71,   72,   73,   74,
 /*   130 */    75,   76,   77,   78,   79,   80,  118,   82,   83,   84,
 /*   140 */    85,   86,   87,   88,   89,   90,   91,   92,   19,   23,
 /*   150 */    92,   97,   98,   24,   96,   97,   98,   99,  100,  101,
 /*   160 */   102,   25,   97,  216,   60,   92,   62,  109,  221,   25,
 /*   170 */    97,   98,   99,  100,  101,  102,   86,   87,   49,   50,
 /*   180 */   118,  116,  109,   25,   94,   95,   32,   97,   88,   89,
 /*   190 */    90,   91,   92,  128,  104,   41,  106,   68,   69,   70,
 /*   200 */    71,   72,   73,   74,   75,   76,   77,   78,   79,   80,
 /*   210 */    11,   82,   83,   84,   85,   86,   87,   88,   89,   90,
 /*   220 */    91,   92,   19,   19,   86,   87,   88,   89,   90,   91,
 /*   230 */    92,   27,   96,  150,   66,   99,  100,  101,  112,  150,
 /*   240 */   114,  115,  138,  150,  161,  162,  110,  103,  165,  222,
 /*   250 */   223,  224,   49,   50,  165,   22,   57,   24,  165,  170,
 /*   260 */   171,  118,   94,  170,  171,   23,   98,   25,  185,  186,
 /*   270 */   243,   68,   69,   70,   71,   72,   73,   74,   75,   76,
 /*   280 */    77,   78,   79,   80,  126,   82,   83,   84,   85,   86,
 /*   290 */    87,   88,   89,   90,   91,   92,   19,  129,  130,  131,
 /*   300 */    88,   23,  172,  173,  105,  106,  107,  150,   22,   26,
 /*   310 */    27,  181,   26,   27,   22,  116,   26,   27,   26,  230,
 /*   320 */   231,  197,  165,  230,  231,  113,   49,   50,  204,  117,
 /*   330 */    96,  174,  175,   99,  100,  101,   22,   26,   27,  136,
 /*   340 */    26,   27,  118,   16,  110,   68,   69,   70,   71,   72,
 /*   350 */    73,   74,   75,   76,   77,   78,   79,   80,  118,   82,
 /*   360 */    83,   84,   85,   86,   87,   88,   89,   90,   91,   92,
 /*   370 */    19,  214,  215,  150,   23,   23,  155,   94,   95,   22,
 /*   380 */    94,   95,  116,  160,   94,   95,   94,   60,  165,   62,
 /*   390 */   112,   26,  114,  115,  128,   23,   36,  174,  175,   88,
 /*   400 */    49,   50,   57,  120,   22,   94,   95,   23,   94,   95,
 /*   410 */   120,   51,   25,  136,  169,  170,  171,  194,   58,   68,
 /*   420 */    69,   70,   71,   72,   73,   74,   75,   76,   77,   78,
 /*   430 */    79,   80,   23,   82,   83,   84,   85,   86,   87,   88,
 /*   440 */    89,   90,   91,   92,   19,  150,   12,   12,   23,  228,
 /*   450 */   105,  106,  107,   23,  233,   25,  165,   19,  150,   94,
 /*   460 */   165,  116,   28,   28,  112,  174,  114,  115,  108,  174,
 /*   470 */   175,   26,   27,  165,   49,   50,  231,   11,   44,   44,
 /*   480 */    46,   46,  174,  175,  112,  160,  114,  115,   50,   22,
 /*   490 */    23,   57,   25,   68,   69,   70,   71,   72,   73,   74,
 /*   500 */    75,   76,   77,   78,   79,   80,  119,   82,   83,   84,
 /*   510 */    85,   86,   87,   88,   89,   90,   91,   92,   19,  194,
 /*   520 */   225,   23,   23,  215,   19,   95,  105,  106,  107,  150,
 /*   530 */    23,  150,   27,   23,   67,   25,  150,  206,  207,   94,
 /*   540 */    95,  166,  104,  218,  165,   22,  165,  109,   49,   50,
 /*   550 */   120,  165,   25,  174,  175,  174,  175,   23,   21,  234,
 /*   560 */   174,  175,   22,   23,  239,   25,   25,   68,   69,   70,
 /*   570 */    71,   72,   73,   74,   75,   76,   77,   78,   79,   80,
 /*   580 */   205,   82,   83,   84,   85,   86,   87,   88,   89,   90,
 /*   590 */    91,   92,   19,   22,   23,  216,   23,  222,  223,  224,
 /*   600 */    63,  220,   35,  150,  150,  163,  220,   67,  166,  167,
 /*   610 */   168,  150,  169,  170,  171,  161,  162,   25,  165,  165,
 /*   620 */   150,  113,   49,   50,   25,  117,  165,  174,  175,   35,
 /*   630 */     7,    8,    9,  160,  160,  165,  120,  100,   67,  247,
 /*   640 */   248,   68,   69,   70,   71,   72,   73,   74,   75,   76,
 /*   650 */    77,   78,   79,   80,  193,   82,   83,   84,   85,   86,
 /*   660 */    87,   88,   89,   90,   91,   92,   19,  194,  194,  150,
 /*   670 */   135,   24,  137,   35,  231,  138,  150,  129,  130,  206,
 /*   680 */   207,   30,   27,  213,  165,   34,  118,   95,    0,    1,
 /*   690 */     2,  165,  218,  174,  175,   50,   49,   50,   22,   48,
 /*   700 */   174,  175,   22,   23,   23,  244,  222,  223,  224,  166,
 /*   710 */   167,  168,  120,  239,   23,   68,   69,   70,   71,   72,
 /*   720 */    73,   74,   75,   76,   77,   78,   79,   80,  150,   82,
 /*   730 */    83,   84,   85,   86,   87,   88,   89,   90,   91,   92,
 /*   740 */    19,  150,  173,  165,  181,  182,   24,   67,   26,  104,
 /*   750 */   181,  188,  174,  175,  150,   39,  165,  150,   52,  150,
 /*   760 */   150,  150,  150,  144,  145,  174,  175,  249,  250,  165,
 /*   770 */    49,   50,  165,   52,  165,  165,  165,  165,  174,  175,
 /*   780 */    29,  174,  175,  174,  175,  174,  175,  160,   22,   68,
 /*   790 */    69,   70,   71,   72,   73,   74,   75,   76,   77,   78,
 /*   800 */    79,   80,  150,   82,   83,   84,   85,   86,   87,   88,
 /*   810 */    89,   90,   91,   92,   19,  150,   94,  165,  150,  150,
 /*   820 */   160,  194,  150,  213,  160,   52,  174,  175,   23,   23,
 /*   830 */   165,   25,   22,  165,  165,  150,  150,  165,   52,  174,
 /*   840 */   175,   22,  174,  175,   49,   50,  174,  175,  190,  191,
 /*   850 */   165,  165,  240,   23,  194,   25,  187,  109,  194,  174,
 /*   860 */   175,  190,  191,   68,   69,   70,   71,   72,   73,   74,
 /*   870 */    75,   76,   77,   78,   79,   80,  150,   82,   83,   84,
 /*   880 */    85,   86,   87,   88,   89,   90,   91,   92,   19,  150,
 /*   890 */    22,  165,  150,   23,  150,   25,  150,  166,   91,   92,
 /*   900 */   174,  175,   22,  217,  165,  150,  102,  165,  150,  165,
 /*   910 */   150,  165,  150,  174,  175,   19,  174,  175,   49,   50,
 /*   920 */   165,   86,   87,  165,   23,  165,   25,  165,   24,  174,
 /*   930 */   175,  187,  174,  175,  174,  175,  205,   68,   69,   70,
 /*   940 */    71,   72,   73,   74,   75,   76,   77,   78,   79,   80,
 /*   950 */   150,   82,   83,   84,   85,   86,   87,   88,   89,   90,
 /*   960 */    91,   92,   19,  150,  150,  165,  150,  150,  166,   23,
 /*   970 */   150,   25,  160,   20,  174,  175,    1,    2,  165,  165,
 /*   980 */   104,  165,  165,   43,  150,  165,  240,  150,   49,   50,
 /*   990 */   174,  175,   49,   50,   23,   23,   25,   25,   53,  165,
 /*  1000 */   187,  187,  165,   23,  187,   25,  194,  205,  174,  175,
 /*  1010 */    71,   72,   69,   70,   71,   72,   73,   74,   75,   76,
 /*  1020 */    77,   78,   79,   80,  150,   82,   83,   84,   85,   86,
 /*  1030 */    87,   88,   89,   90,   91,   92,   19,   98,  150,  165,
 /*  1040 */   150,  160,  150,   59,   25,   53,  104,   22,  174,  175,
 /*  1050 */   213,  138,    5,  165,    1,  165,  150,  165,  150,  150,
 /*  1060 */   240,  150,  174,  175,  174,  175,   49,   50,  118,  150,
 /*  1070 */    35,  165,   27,  165,  165,  194,  165,  108,  127,   76,
 /*  1080 */   174,  175,  174,  175,  165,  174,  175,   70,   71,   72,
 /*  1090 */    73,   74,   75,   76,   77,   78,   79,   80,  166,   82,
 /*  1100 */    83,   84,   85,   86,   87,   88,   89,   90,   91,   92,
 /*  1110 */    19,   20,  193,   22,  150,  150,  150,   26,   27,   76,
 /*  1120 */   150,   22,    1,  150,  119,  121,  217,   20,   37,  165,
 /*  1130 */   165,  165,   16,   19,   20,  165,   22,  205,  165,  119,
 /*  1140 */    26,   27,  108,  128,  150,  150,  150,   56,  150,   22,
 /*  1150 */   150,   37,  150,  127,  160,   23,  150,   66,  193,  165,
 /*  1160 */   165,  165,   16,  165,   23,  165,  150,  165,  174,  175,
 /*  1170 */    56,  165,  150,   65,  174,  175,   15,   86,   87,   88,
 /*  1180 */    66,  165,  140,  150,   93,   94,   95,  165,  194,   98,
 /*  1190 */   174,  175,   22,    3,  164,  193,  174,  175,  165,  150,
 /*  1200 */    86,   87,    4,  180,  150,  248,  251,   93,   94,   95,
 /*  1210 */   216,  180,   98,  251,  165,  221,  150,  149,    6,  165,
 /*  1220 */   129,  130,  131,  132,  133,  134,  193,  150,  174,  175,
 /*  1230 */   116,  165,   19,   20,  150,   22,  149,  151,  150,   26,
 /*  1240 */    27,  149,  165,  129,  130,  131,  132,  133,  134,  165,
 /*  1250 */    37,  174,  175,  165,  149,   19,   20,   13,   22,  150,
 /*  1260 */   150,  150,   26,   27,  146,  147,  151,  150,   25,   56,
 /*  1270 */   152,  159,  154,   37,  165,  165,  165,  193,  160,   66,
 /*  1280 */   116,  193,  165,  174,  175,  174,  175,  194,  199,  150,
 /*  1290 */   200,  126,   56,  124,  123,  150,  201,  122,  150,   86,
 /*  1300 */    87,  150,   66,  193,  165,  202,   93,   94,   95,  150,
 /*  1310 */   165,   98,  194,  165,  125,   22,  165,  150,  150,   26,
 /*  1320 */    27,  135,   86,   87,  165,  174,  175,  203,  226,   93,
 /*  1330 */    94,   95,  165,  165,   98,  150,  218,  150,  193,  157,
 /*  1340 */   118,  157,  129,  130,  131,  132,  133,  134,    5,  104,
 /*  1350 */   165,  211,  165,   10,   11,   12,   13,   14,  150,   66,
 /*  1360 */    17,  174,  175,  210,  246,  129,  130,  131,  132,  133,
 /*  1370 */   134,  150,  210,  165,   31,  121,   33,  150,  150,   86,
 /*  1380 */    87,  176,  174,  175,  150,   42,  165,   94,  211,  210,
 /*  1390 */   150,   98,  165,  165,  211,  174,  175,  150,   55,  165,
 /*  1400 */    57,  150,  174,  175,   61,  165,  150,   64,  174,  175,
 /*  1410 */   150,  150,  165,  150,  174,  175,  165,  104,  150,  184,
 /*  1420 */   150,  165,  129,  130,  131,  165,  165,  150,  165,  150,
 /*  1430 */   150,  176,  150,  165,   47,  165,  150,  150,  176,  103,
 /*  1440 */   150,   22,  165,  178,  165,  165,  179,  165,  105,  106,
 /*  1450 */   107,  165,  165,  229,  111,  165,   92,  176,  229,  116,
 /*  1460 */   184,  176,  179,  156,  176,  176,   18,  157,  156,  237,
 /*  1470 */    45,  157,  156,  135,  157,  157,  238,  156,   68,  157,
 /*  1480 */   189,  189,  139,  219,   22,  157,   18,  192,  192,  192,
 /*  1490 */   192,  189,  219,  199,  157,  242,   40,  157,  199,  242,
 /*  1500 */   153,  157,   38,  245,  196,  166,  232,  198,  177,  177,
 /*  1510 */   232,  227,  209,  178,  166,  182,  166,  148,  177,  177,
 /*  1520 */   209,  196,  177,  199,  209,  199,  166,  208,   92,  195,
 /*  1530 */   174,  174,  183,  252,  183,  183,  252,  191,  252,  235,
 /*  1540 */   186,  241,  241,  252,  186,  252,  252,  252,  252,  252,
 /*  1550 */   252,  252,  252,  252,  252,  252,  236,
};
#define YY_SHIFT_USE_DFLT (-74)
#define YY_SHIFT_COUNT (418)
#define YY_SHIFT_MIN   (-73)
#define YY_SHIFT_MAX   (1468)
static const short yy_shift_ofst[] = {
 /*     0 */   975, 1114, 1343, 1114, 1213, 1213,   90,   90,    0,  -19,
 /*    10 */  1213, 1213, 1213, 1213, 1213,  345,  445,  721, 1091, 1213,
 /*    20 */  1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213,
 /*    30 */  1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213,
 /*    40 */  1213, 1213, 1213, 1213, 1213, 1213, 1213, 1236, 1213, 1213,
 /*    50 */  1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213, 1213,
 /*    60 */  1213,  199,  445,  445,  835,  835,  365, 1164,   55,  647,
 /*    70 */   573,  499,  425,  351,  277,  203,  129,  795,  795,  795,
 /*    80 */   795,  795,  795,  795,  795,  795,  795,  795,  795,  795,
 /*    90 */   795,  795,  795,  795,  795,  869,  795,  943, 1017, 1017,
 /*   100 */   -69,  -45,  -45,  -45,  -45,  -45,   -1,   58,  138,  100,
 /*   110 */   445,  445,  445,  445,  445,  445,  445,  445,  445,  445,
 /*   120 */   445,  445,  445,  445,  445,  445,  537,  438,  445,  445,
 /*   130 */   445,  445,  445,  365,  807, 1436,  -74,  -74,  -74, 1293,
 /*   140 */    73,  434,  434,  311,  314,  290,  283,  286,  540,  467,
 /*   150 */   445,  445,  445,  445,  445,  445,  445,  445,  445,  445,
 /*   160 */   445,  445,  445,  445,  445,  445,  445,  445,  445,  445,
 /*   170 */   445,  445,  445,  445,  445,  445,  445,  445,  445,  445,
 /*   180 */   445,  445,   65,  722,  722,  722,  688,  266, 1164, 1164,
 /*   190 */  1164,  -74,  -74,  -74,  136,  168,  168,  234,  360,  360,
 /*   200 */   360,  430,  372,  435,  352,  278,  126,  -36,  -36,  -36,
 /*   210 */   -36,  421,  651,  -36,  -36,  592,  292,  212,  623,  158,
 /*   220 */   204,  204,  505,  158,  505,  144,  365,  154,  365,  154,
 /*   230 */   645,  154,  204,  154,  154,  535,  548,  548,  365,  387,
 /*   240 */   508,  233, 1464, 1222, 1222, 1456, 1456, 1222, 1462, 1410,
 /*   250 */  1165, 1468, 1468, 1468, 1468, 1222, 1165, 1462, 1410, 1410,
 /*   260 */  1222, 1448, 1338, 1425, 1222, 1222, 1448, 1222, 1448, 1222,
 /*   270 */  1448, 1419, 1313, 1313, 1313, 1387, 1364, 1364, 1419, 1313,
 /*   280 */  1336, 1313, 1387, 1313, 1313, 1254, 1245, 1254, 1245, 1254,
 /*   290 */  1245, 1222, 1222, 1186, 1189, 1175, 1169, 1171, 1165, 1164,
 /*   300 */  1243, 1244, 1244, 1212, 1212, 1212, 1212,  -74,  -74,  -74,
 /*   310 */   -74,  -74,  -74,  939,  104,  680,  571,  327,    1,  980,
 /*   320 */    26,  972,  971,  946,  901,  870,  830,  806,   54,   21,
 /*   330 */   -73,  510,  242, 1198, 1190, 1170, 1042, 1161, 1108, 1146,
 /*   340 */  1141, 1132, 1015, 1127, 1026, 1034, 1020, 1107, 1004, 1116,
 /*   350 */  1121, 1005, 1099,  951, 1043, 1003,  969, 1045, 1035,  950,
 /*   360 */  1053, 1047, 1025,  942,  913,  992, 1019,  945,  984,  940,
 /*   370 */   876,  904,  953,  896,  748,  804,  880,  786,  868,  819,
 /*   380 */   805,  810,  773,  751,  766,  706,  716,  691,  681,  568,
 /*   390 */   655,  638,  676,  516,  541,  594,  599,  567,  541,  534,
 /*   400 */   507,  527,  498,  523,  466,  382,  409,  384,  357,    6,
 /*   410 */   240,  224,  143,   62,   18,   71,   39,    9,    5,
};
#define YY_REDUCE_USE_DFLT (-142)
#define YY_REDUCE_COUNT (312)
#define YY_REDUCE_MIN   (-141)
#define YY_REDUCE_MAX   (1369)
static const short yy_reduce_ofst[] = {
 /*     0 */  -141,  994, 1118,  223,  157,  -53,   93,   89,   83,  375,
 /*    10 */   386,  381,  379,  308,  295,  325,  -47,   27, 1240, 1234,
 /*    20 */  1228, 1221, 1208, 1187, 1151, 1111, 1109, 1077, 1054, 1022,
 /*    30 */  1016, 1000,  911,  908,  906,  890,  888,  874,  834,  816,
 /*    40 */   800,  760,  758,  755,  742,  739,  726,  685,  672,  668,
 /*    50 */   665,  652,  611,  609,  607,  604,  591,  578,  526,  519,
 /*    60 */   453,  474,  454,  461,  443,  245,  442,  473,  484,  484,
 /*    70 */   484,  484,  484,  484,  484,  484,  484,  484,  484,  484,
 /*    80 */   484,  484,  484,  484,  484,  484,  484,  484,  484,  484,
 /*    90 */   484,  484,  484,  484,  484,  484,  484,  484,  484,  484,
 /*   100 */   484,  484,  484,  484,  484,  484,  484,  130,  484,  484,
 /*   110 */  1145,  909, 1110, 1088, 1084, 1033, 1002,  965,  820,  837,
 /*   120 */   746,  686,  612,  817,  610,  919,  221,  563,  814,  813,
 /*   130 */   744,  669,  470,  543,  484,  484,  484,  484,  484,  291,
 /*   140 */   569,  671,  658,  970, 1290, 1287, 1286, 1282,  518,  518,
 /*   150 */  1280, 1279, 1277, 1270, 1268, 1263, 1261, 1260, 1256, 1251,
 /*   160 */  1247, 1227, 1185, 1168, 1167, 1159, 1148, 1139, 1117, 1066,
 /*   170 */  1049, 1006,  998,  996,  995,  973,  970,  966,  964,  892,
 /*   180 */   762,  -52,  881,  932,  802,  731,  619,  812,  664,  660,
 /*   190 */   627,  392,  331,  124, 1358, 1357, 1356, 1354, 1352, 1351,
 /*   200 */  1349, 1319, 1334, 1346, 1334, 1334, 1334, 1334, 1334, 1334,
 /*   210 */  1334, 1320, 1304, 1334, 1334, 1319, 1360, 1325, 1369, 1326,
 /*   220 */  1315, 1311, 1301, 1324, 1300, 1335, 1350, 1345, 1348, 1342,
 /*   230 */  1333, 1341, 1303, 1332, 1331, 1284, 1278, 1274, 1339, 1309,
 /*   240 */  1308, 1347, 1258, 1344, 1340, 1257, 1253, 1337, 1273, 1302,
 /*   250 */  1299, 1298, 1297, 1296, 1295, 1328, 1294, 1264, 1292, 1291,
 /*   260 */  1322, 1321, 1238, 1232, 1318, 1317, 1316, 1314, 1312, 1310,
 /*   270 */  1307, 1283, 1289, 1288, 1285, 1276, 1229, 1224, 1267, 1281,
 /*   280 */  1265, 1262, 1235, 1255, 1205, 1183, 1179, 1177, 1162, 1140,
 /*   290 */  1153, 1184, 1182, 1102, 1124, 1103, 1095, 1090, 1089, 1093,
 /*   300 */  1112, 1115, 1086, 1105, 1092, 1087, 1068,  962,  955,  957,
 /*   310 */  1031, 1023, 1030,
};
static const YYACTIONTYPE yy_default[] = {
 /*     0 */   635,  870,  959,  959,  959,  870,  899,  899,  959,  759,
 /*    10 */   959,  959,  959,  959,  868,  959,  959,  933,  959,  959,
 /*    20 */   959,  959,  959,  959,  959,  959,  959,  959,  959,  959,
 /*    30 */   959,  959,  959,  959,  959,  959,  959,  959,  959,  959,
 /*    40 */   959,  959,  959,  959,  959,  959,  959,  959,  959,  959,
 /*    50 */   959,  959,  959,  959,  959,  959,  959,  959,  959,  959,
 /*    60 */   959,  959,  959,  959,  899,  899,  674,  763,  794,  959,
 /*    70 */   959,  959,  959,  959,  959,  959,  959,  932,  934,  809,
 /*    80 */   808,  802,  801,  912,  774,  799,  792,  785,  796,  871,
 /*    90 */   864,  865,  863,  867,  872,  959,  795,  831,  848,  830,
 /*   100 */   842,  847,  854,  846,  843,  833,  832,  666,  834,  835,
 /*   110 */   959,  959,  959,  959,  959,  959,  959,  959,  959,  959,
 /*   120 */   959,  959,  959,  959,  959,  959,  661,  728,  959,  959,
 /*   130 */   959,  959,  959,  959,  836,  837,  851,  850,  849,  959,
 /*   140 */   959,  959,  959,  959,  959,  959,  959,  959,  959,  959,
 /*   150 */   959,  939,  937,  959,  883,  959,  959,  959,  959,  959,
 /*   160 */   959,  959,  959,  959,  959,  959,  959,  959,  959,  959,
 /*   170 */   959,  959,  959,  959,  959,  959,  959,  959,  959,  959,
 /*   180 */   959,  641,  959,  759,  759,  759,  635,  959,  959,  959,
 /*   190 */   959,  951,  763,  753,  719,  959,  959,  959,  959,  959,
 /*   200 */   959,  959,  959,  959,  959,  959,  959,  804,  742,  922,
 /*   210 */   924,  959,  905,  740,  663,  761,  676,  751,  643,  798,
 /*   220 */   776,  776,  917,  798,  917,  700,  959,  788,  959,  788,
 /*   230 */   697,  788,  776,  788,  788,  866,  959,  959,  959,  760,
 /*   240 */   751,  959,  944,  767,  767,  936,  936,  767,  810,  732,
 /*   250 */   798,  739,  739,  739,  739,  767,  798,  810,  732,  732,
 /*   260 */   767,  658,  911,  909,  767,  767,  658,  767,  658,  767,
 /*   270 */   658,  876,  730,  730,  730,  715,  880,  880,  876,  730,
 /*   280 */   700,  730,  715,  730,  730,  780,  775,  780,  775,  780,
 /*   290 */   775,  767,  767,  959,  793,  781,  791,  789,  798,  959,
 /*   300 */   718,  651,  651,  640,  640,  640,  640,  956,  956,  951,
 /*   310 */   702,  702,  684,  959,  959,  959,  959,  959,  959,  959,
 /*   320 */   885,  959,  959,  959,  959,  959,  959,  959,  959,  959,
 /*   330 */   959,  959,  959,  959,  636,  946,  959,  959,  943,  959,
 /*   340 */   959,  959,  959,  959,  959,  959,  959,  959,  959,  959,
 /*   350 */   959,  959,  959,  959,  959,  959,  959,  959,  959,  915,
 /*   360 */   959,  959,  959,  959,  959,  959,  908,  907,  959,  959,
 /*   370 */   959,  959,  959,  959,  959,  959,  959,  959,  959,  959,
 /*   380 */   959,  959,  959,  959,  959,  959,  959,  959,  959,  959,
 /*   390 */   959,  959,  959,  959,  790,  959,  782,  959,  869,  959,
 /*   400 */   959,  959,  959,  959,  959,  959,  959,  959,  959,  745,
 /*   410 */   819,  959,  818,  822,  817,  668,  959,  649,  959,  632,
 /*   420 */   637,  955,  958,  957,  954,  953,  952,  947,  945,  942,
 /*   430 */   941,  940,  938,  935,  931,  889,  887,  894,  893,  892,
 /*   440 */   891,  890,  888,  886,  884,  805,  803,  800,  797,  930,
 /*   450 */   882,  741,  738,  737,  657,  948,  914,  923,  921,  811,
 /*   460 */   920,  919,  918,  916,  913,  900,  807,  806,  733,  874,
 /*   470 */   873,  660,  904,  903,  902,  906,  910,  901,  769,  659,
 /*   480 */   656,  665,  722,  721,  729,  727,  726,  725,  724,  723,
 /*   490 */   720,  667,  675,  686,  714,  699,  698,  879,  881,  878,
 /*   500 */   877,  707,  706,  712,  711,  710,  709,  708,  705,  704,
 /*   510 */   703,  696,  695,  701,  694,  717,  716,  713,  693,  736,
 /*   520 */   735,  734,  731,  692,  691,  690,  822,  689,  688,  828,
 /*   530 */   827,  815,  858,  756,  755,  754,  766,  765,  778,  777,
 /*   540 */   813,  812,  779,  764,  758,  757,  773,  772,  771,  770,
 /*   550 */   762,  752,  784,  787,  786,  783,  860,  768,  857,  929,
 /*   560 */   928,  927,  926,  925,  862,  861,  829,  826,  679,  680,
 /*   570 */   898,  896,  897,  895,  682,  681,  678,  677,  859,  747,
 /*   580 */   746,  855,  852,  844,  840,  856,  853,  845,  841,  839,
 /*   590 */   838,  824,  823,  821,  820,  816,  825,  670,  748,  744,
 /*   600 */   743,  814,  750,  749,  687,  685,  683,  664,  662,  655,
 /*   610 */   653,  652,  654,  650,  648,  647,  646,  645,  644,  673,
 /*   620 */   672,  671,  669,  668,  642,  639,  638,  634,  633,  631,



};

/* The next table maps tokens into fallback tokens.  If a construct
** like the following:
** 
**      %fallback ID X Y Z.
**
................................................................................
  "init_deferred_pred_opt",  "conslist",      "tcons",         "idxlist",     
  "defer_subclause_opt",  "orconf",        "resolvetype",   "raisetype",   
  "ifexists",      "fullname",      "oneselect",     "multiselect_op",
  "distinct",      "selcollist",    "from",          "where_opt",   
  "groupby_opt",   "having_opt",    "orderby_opt",   "limit_opt",   
  "sclp",          "as",            "seltablist",    "stl_prefix",  
  "joinop",        "indexed_opt",   "on_opt",        "using_opt",   
  "joinop2",       "inscollist",    "sortlist",      "sortitem",    
  "nexprlist",     "setlist",       "insert_cmd",    "inscollist_opt",
  "itemlist",      "exprlist",      "likeop",        "between_op",  
  "in_op",         "case_operand",  "case_exprlist",  "case_else",   
  "uniqueflag",    "collate",       "nmnum",         "plus_opt",    
  "number",        "trigger_decl",  "trigger_cmd_list",  "trigger_time",
  "trigger_event",  "foreach_clause",  "when_clause",   "trigger_cmd", 
  "trnm",          "tridxby",       "database_kw_opt",  "key_opt",     
  "add_column_fullname",  "kwcolumn_opt",  "create_vtab",   "vtabarglist", 
  "vtabarg",       "vtabargtoken",  "lp",            "anylist",     
};
#endif /* NDEBUG */

#ifndef NDEBUG
/* For tracing reduce actions, the names of all rules are required.
*/
static const char *const yyRuleName[] = {
................................................................................
 /* 146 */ "indexed_opt ::=",
 /* 147 */ "indexed_opt ::= INDEXED BY nm",
 /* 148 */ "indexed_opt ::= NOT INDEXED",
 /* 149 */ "using_opt ::= USING LP inscollist RP",
 /* 150 */ "using_opt ::=",
 /* 151 */ "orderby_opt ::=",
 /* 152 */ "orderby_opt ::= ORDER BY sortlist",
 /* 153 */ "sortlist ::= sortlist COMMA sortitem sortorder",
 /* 154 */ "sortlist ::= sortitem sortorder",
 /* 155 */ "sortitem ::= expr",
 /* 156 */ "sortorder ::= ASC",
 /* 157 */ "sortorder ::= DESC",
 /* 158 */ "sortorder ::=",
 /* 159 */ "groupby_opt ::=",
 /* 160 */ "groupby_opt ::= GROUP BY nexprlist",
 /* 161 */ "having_opt ::=",
 /* 162 */ "having_opt ::= HAVING expr",
 /* 163 */ "limit_opt ::=",
 /* 164 */ "limit_opt ::= LIMIT expr",
 /* 165 */ "limit_opt ::= LIMIT expr OFFSET expr",
 /* 166 */ "limit_opt ::= LIMIT expr COMMA expr",
 /* 167 */ "cmd ::= DELETE FROM fullname indexed_opt where_opt",
 /* 168 */ "where_opt ::=",
 /* 169 */ "where_opt ::= WHERE expr",
 /* 170 */ "cmd ::= UPDATE orconf fullname indexed_opt SET setlist where_opt",
 /* 171 */ "setlist ::= setlist COMMA nm EQ expr",
 /* 172 */ "setlist ::= nm EQ expr",
 /* 173 */ "cmd ::= insert_cmd INTO fullname inscollist_opt VALUES LP itemlist RP",
 /* 174 */ "cmd ::= insert_cmd INTO fullname inscollist_opt select",
 /* 175 */ "cmd ::= insert_cmd INTO fullname inscollist_opt DEFAULT VALUES",
 /* 176 */ "insert_cmd ::= INSERT orconf",
 /* 177 */ "insert_cmd ::= REPLACE",

 /* 178 */ "itemlist ::= itemlist COMMA expr",
 /* 179 */ "itemlist ::= expr",
 /* 180 */ "inscollist_opt ::=",
 /* 181 */ "inscollist_opt ::= LP inscollist RP",
 /* 182 */ "inscollist ::= inscollist COMMA nm",
 /* 183 */ "inscollist ::= nm",
 /* 184 */ "expr ::= term",
 /* 185 */ "expr ::= LP expr RP",
 /* 186 */ "term ::= NULL",
 /* 187 */ "expr ::= id",
 /* 188 */ "expr ::= JOIN_KW",
 /* 189 */ "expr ::= nm DOT nm",
 /* 190 */ "expr ::= nm DOT nm DOT nm",
 /* 191 */ "term ::= INTEGER|FLOAT|BLOB",
 /* 192 */ "term ::= STRING",
 /* 193 */ "expr ::= REGISTER",
 /* 194 */ "expr ::= VARIABLE",
 /* 195 */ "expr ::= expr COLLATE ids",
 /* 196 */ "expr ::= CAST LP expr AS typetoken RP",
 /* 197 */ "expr ::= ID LP distinct exprlist RP",
 /* 198 */ "expr ::= ID LP STAR RP",
 /* 199 */ "term ::= CTIME_KW",
 /* 200 */ "expr ::= expr AND expr",
 /* 201 */ "expr ::= expr OR expr",
 /* 202 */ "expr ::= expr LT|GT|GE|LE expr",
 /* 203 */ "expr ::= expr EQ|NE expr",
 /* 204 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr",
 /* 205 */ "expr ::= expr PLUS|MINUS expr",
 /* 206 */ "expr ::= expr STAR|SLASH|REM expr",
 /* 207 */ "expr ::= expr CONCAT expr",
 /* 208 */ "likeop ::= LIKE_KW",
 /* 209 */ "likeop ::= NOT LIKE_KW",
 /* 210 */ "likeop ::= MATCH",
 /* 211 */ "likeop ::= NOT MATCH",
 /* 212 */ "expr ::= expr likeop expr",
 /* 213 */ "expr ::= expr likeop expr ESCAPE expr",
 /* 214 */ "expr ::= expr ISNULL|NOTNULL",
 /* 215 */ "expr ::= expr NOT NULL",
 /* 216 */ "expr ::= expr IS expr",
 /* 217 */ "expr ::= expr IS NOT expr",
 /* 218 */ "expr ::= NOT expr",
 /* 219 */ "expr ::= BITNOT expr",
 /* 220 */ "expr ::= MINUS expr",
 /* 221 */ "expr ::= PLUS expr",
 /* 222 */ "between_op ::= BETWEEN",
 /* 223 */ "between_op ::= NOT BETWEEN",
 /* 224 */ "expr ::= expr between_op expr AND expr",
 /* 225 */ "in_op ::= IN",
 /* 226 */ "in_op ::= NOT IN",
 /* 227 */ "expr ::= expr in_op LP exprlist RP",
 /* 228 */ "expr ::= LP select RP",
 /* 229 */ "expr ::= expr in_op LP select RP",
 /* 230 */ "expr ::= expr in_op nm dbnm",
 /* 231 */ "expr ::= EXISTS LP select RP",
 /* 232 */ "expr ::= CASE case_operand case_exprlist case_else END",
 /* 233 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr",
 /* 234 */ "case_exprlist ::= WHEN expr THEN expr",
 /* 235 */ "case_else ::= ELSE expr",
 /* 236 */ "case_else ::=",
 /* 237 */ "case_operand ::= expr",
 /* 238 */ "case_operand ::=",
 /* 239 */ "exprlist ::= nexprlist",
 /* 240 */ "exprlist ::=",
 /* 241 */ "nexprlist ::= nexprlist COMMA expr",
 /* 242 */ "nexprlist ::= expr",
 /* 243 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP idxlist RP",
 /* 244 */ "uniqueflag ::= UNIQUE",
 /* 245 */ "uniqueflag ::=",
 /* 246 */ "idxlist_opt ::=",
 /* 247 */ "idxlist_opt ::= LP idxlist RP",
 /* 248 */ "idxlist ::= idxlist COMMA nm collate sortorder",
 /* 249 */ "idxlist ::= nm collate sortorder",
 /* 250 */ "collate ::=",
 /* 251 */ "collate ::= COLLATE ids",
 /* 252 */ "cmd ::= DROP INDEX ifexists fullname",
 /* 253 */ "cmd ::= VACUUM",
 /* 254 */ "cmd ::= VACUUM nm",
 /* 255 */ "cmd ::= PRAGMA nm dbnm",
 /* 256 */ "cmd ::= PRAGMA nm dbnm EQ nmnum",
 /* 257 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP",
 /* 258 */ "cmd ::= PRAGMA nm dbnm EQ minus_num",
 /* 259 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP",

 /* 260 */ "nmnum ::= plus_num",
 /* 261 */ "nmnum ::= nm",
 /* 262 */ "nmnum ::= ON",
 /* 263 */ "nmnum ::= DELETE",
 /* 264 */ "nmnum ::= DEFAULT",
 /* 265 */ "plus_num ::= plus_opt number",
 /* 266 */ "minus_num ::= MINUS number",
 /* 267 */ "number ::= INTEGER|FLOAT",
 /* 268 */ "plus_opt ::= PLUS",
 /* 269 */ "plus_opt ::=",
 /* 270 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END",
 /* 271 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause",
 /* 272 */ "trigger_time ::= BEFORE",
 /* 273 */ "trigger_time ::= AFTER",
 /* 274 */ "trigger_time ::= INSTEAD OF",
 /* 275 */ "trigger_time ::=",
 /* 276 */ "trigger_event ::= DELETE|INSERT",
 /* 277 */ "trigger_event ::= UPDATE",
 /* 278 */ "trigger_event ::= UPDATE OF inscollist",
 /* 279 */ "foreach_clause ::=",
 /* 280 */ "foreach_clause ::= FOR EACH ROW",
 /* 281 */ "when_clause ::=",
 /* 282 */ "when_clause ::= WHEN expr",
 /* 283 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI",
 /* 284 */ "trigger_cmd_list ::= trigger_cmd SEMI",
 /* 285 */ "trnm ::= nm",
 /* 286 */ "trnm ::= nm DOT nm",
 /* 287 */ "tridxby ::=",
 /* 288 */ "tridxby ::= INDEXED BY nm",
 /* 289 */ "tridxby ::= NOT INDEXED",
 /* 290 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt",
 /* 291 */ "trigger_cmd ::= insert_cmd INTO trnm inscollist_opt VALUES LP itemlist RP",
 /* 292 */ "trigger_cmd ::= insert_cmd INTO trnm inscollist_opt select",
 /* 293 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt",
 /* 294 */ "trigger_cmd ::= select",
 /* 295 */ "expr ::= RAISE LP IGNORE RP",
 /* 296 */ "expr ::= RAISE LP raisetype COMMA nm RP",
 /* 297 */ "raisetype ::= ROLLBACK",
 /* 298 */ "raisetype ::= ABORT",
 /* 299 */ "raisetype ::= FAIL",
 /* 300 */ "cmd ::= DROP TRIGGER ifexists fullname",
 /* 301 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt",
 /* 302 */ "cmd ::= DETACH database_kw_opt expr",
 /* 303 */ "key_opt ::=",
 /* 304 */ "key_opt ::= KEY expr",
 /* 305 */ "database_kw_opt ::= DATABASE",
 /* 306 */ "database_kw_opt ::=",
 /* 307 */ "cmd ::= REINDEX",
 /* 308 */ "cmd ::= REINDEX nm dbnm",
 /* 309 */ "cmd ::= ANALYZE",
 /* 310 */ "cmd ::= ANALYZE nm dbnm",
 /* 311 */ "cmd ::= ALTER TABLE fullname RENAME TO nm",
 /* 312 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt column",
 /* 313 */ "add_column_fullname ::= fullname",
 /* 314 */ "kwcolumn_opt ::=",
 /* 315 */ "kwcolumn_opt ::= COLUMNKW",
 /* 316 */ "cmd ::= create_vtab",
 /* 317 */ "cmd ::= create_vtab LP vtabarglist RP",
 /* 318 */ "create_vtab ::= createkw VIRTUAL TABLE nm dbnm USING nm",
 /* 319 */ "vtabarglist ::= vtabarg",
 /* 320 */ "vtabarglist ::= vtabarglist COMMA vtabarg",
 /* 321 */ "vtabarg ::=",
 /* 322 */ "vtabarg ::= vtabarg vtabargtoken",
 /* 323 */ "vtabargtoken ::= ANY",
 /* 324 */ "vtabargtoken ::= lp anylist RP",
 /* 325 */ "lp ::= LP",
 /* 326 */ "anylist ::=",
 /* 327 */ "anylist ::= anylist LP anylist RP",
 /* 328 */ "anylist ::= anylist ANY",
};
#endif /* NDEBUG */


#if YYSTACKDEPTH<=0
/*
** Try to increase the size of the parser stack.
................................................................................
    ** Note: during a reduce, the only symbols destroyed are those
    ** which appear on the RHS of the rule, but which are not used
    ** inside the C code.
    */
    case 160: /* select */
    case 194: /* oneselect */
{
sqlite3SelectDelete(pParse->db, (yypminor->yy387));
}
      break;
    case 174: /* term */
    case 175: /* expr */
{
sqlite3ExprDelete(pParse->db, (yypminor->yy118).pExpr);
}
      break;
    case 179: /* idxlist_opt */
    case 187: /* idxlist */
    case 197: /* selcollist */
    case 200: /* groupby_opt */
    case 202: /* orderby_opt */
    case 204: /* sclp */
    case 214: /* sortlist */
    case 216: /* nexprlist */
    case 217: /* setlist */
    case 220: /* itemlist */
    case 221: /* exprlist */
    case 226: /* case_exprlist */
{
sqlite3ExprListDelete(pParse->db, (yypminor->yy322));
}
      break;
    case 193: /* fullname */
    case 198: /* from */
    case 206: /* seltablist */
    case 207: /* stl_prefix */
{
sqlite3SrcListDelete(pParse->db, (yypminor->yy259));
}
      break;
    case 199: /* where_opt */
    case 201: /* having_opt */
    case 210: /* on_opt */
    case 215: /* sortitem */
    case 225: /* case_operand */
    case 227: /* case_else */
    case 238: /* when_clause */
    case 243: /* key_opt */
{
sqlite3ExprDelete(pParse->db, (yypminor->yy314));
}
      break;
    case 211: /* using_opt */
    case 213: /* inscollist */
    case 219: /* inscollist_opt */
{
sqlite3IdListDelete(pParse->db, (yypminor->yy384));
}
      break;








    case 234: /* trigger_cmd_list */
    case 239: /* trigger_cmd */
{
sqlite3DeleteTriggerStep(pParse->db, (yypminor->yy203));
}
      break;
    case 236: /* trigger_event */
{
sqlite3IdListDelete(pParse->db, (yypminor->yy90).b);
}
      break;
    default:  break;   /* If no destructor action specified: do nothing */
  }
}

/*
................................................................................
  { 209, 2 },
  { 211, 4 },
  { 211, 0 },
  { 202, 0 },
  { 202, 3 },
  { 214, 4 },
  { 214, 2 },
  { 215, 1 },
  { 177, 1 },
  { 177, 1 },
  { 177, 0 },
  { 200, 0 },
  { 200, 3 },
  { 201, 0 },
  { 201, 2 },
................................................................................
  { 203, 2 },
  { 203, 4 },
  { 203, 4 },
  { 147, 5 },
  { 199, 0 },
  { 199, 2 },
  { 147, 7 },
  { 217, 5 },
  { 217, 3 },
  { 147, 8 },
  { 147, 5 },
  { 147, 6 },
  { 218, 2 },
  { 218, 1 },
  { 220, 3 },
  { 220, 1 },
  { 219, 0 },
  { 219, 3 },
  { 213, 3 },
  { 213, 1 },
  { 175, 1 },
  { 175, 3 },
  { 174, 1 },
  { 175, 1 },
  { 175, 1 },
................................................................................
  { 175, 3 },
  { 175, 3 },
  { 175, 3 },
  { 175, 3 },
  { 175, 3 },
  { 175, 3 },
  { 175, 3 },
  { 222, 1 },
  { 222, 2 },
  { 222, 1 },
  { 222, 2 },
  { 175, 3 },
  { 175, 5 },
  { 175, 2 },
  { 175, 3 },
  { 175, 3 },
  { 175, 4 },
  { 175, 2 },
  { 175, 2 },
  { 175, 2 },
  { 175, 2 },
  { 223, 1 },
  { 223, 2 },
  { 175, 5 },
  { 224, 1 },
  { 224, 2 },
  { 175, 5 },
  { 175, 3 },
  { 175, 5 },
  { 175, 4 },
  { 175, 4 },
  { 175, 5 },
  { 226, 5 },
  { 226, 4 },
  { 227, 2 },
  { 227, 0 },
  { 225, 1 },
  { 225, 0 },
  { 221, 1 },
  { 221, 0 },
  { 216, 3 },
  { 216, 1 },
  { 147, 11 },
  { 228, 1 },
  { 228, 0 },
  { 179, 0 },
  { 179, 3 },
  { 187, 5 },
  { 187, 3 },
  { 229, 0 },
  { 229, 2 },
  { 147, 4 },
  { 147, 1 },
  { 147, 2 },
  { 147, 3 },
  { 147, 5 },
  { 147, 6 },
  { 147, 5 },
  { 147, 6 },
  { 230, 1 },
  { 230, 1 },
  { 230, 1 },
  { 230, 1 },
  { 230, 1 },
  { 170, 2 },

  { 171, 2 },
  { 232, 1 },
  { 231, 1 },
  { 231, 0 },
  { 147, 5 },
  { 233, 11 },
  { 235, 1 },
  { 235, 1 },
  { 235, 2 },
  { 235, 0 },
  { 236, 1 },
  { 236, 1 },
  { 236, 3 },
  { 237, 0 },
  { 237, 3 },
  { 238, 0 },
  { 238, 2 },
  { 234, 3 },
  { 234, 2 },
  { 240, 1 },
  { 240, 3 },
  { 241, 0 },
  { 241, 3 },
  { 241, 2 },
  { 239, 7 },
  { 239, 8 },
  { 239, 5 },
  { 239, 5 },
  { 239, 1 },
  { 175, 4 },
  { 175, 6 },
  { 191, 1 },
  { 191, 1 },
  { 191, 1 },
  { 147, 4 },
  { 147, 6 },
  { 147, 3 },
  { 243, 0 },
  { 243, 2 },
  { 242, 1 },
  { 242, 0 },
  { 147, 1 },
  { 147, 3 },
  { 147, 1 },
  { 147, 3 },
  { 147, 6 },
  { 147, 6 },
  { 244, 1 },
  { 245, 0 },
  { 245, 1 },
  { 147, 1 },
  { 147, 4 },
  { 246, 7 },
  { 247, 1 },
  { 247, 3 },
  { 248, 0 },
  { 248, 2 },
  { 249, 1 },
  { 249, 3 },
  { 250, 1 },
  { 251, 0 },
  { 251, 4 },
  { 251, 2 },
};

static void yy_accept(yyParser*);  /* Forward Declaration */

/*
** Perform a reduce action and the shift that must immediately
** follow the reduce.
................................................................................
      case 7: /* explain ::= EXPLAIN QUERY PLAN */
{ sqlite3BeginParse(pParse, 2); }
        break;
      case 8: /* cmdx ::= cmd */
{ sqlite3FinishCoding(pParse); }
        break;
      case 9: /* cmd ::= BEGIN transtype trans_opt */
{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy4);}
        break;
      case 13: /* transtype ::= */
{yygotominor.yy4 = TK_DEFERRED;}
        break;
      case 14: /* transtype ::= DEFERRED */
      case 15: /* transtype ::= IMMEDIATE */ yytestcase(yyruleno==15);
      case 16: /* transtype ::= EXCLUSIVE */ yytestcase(yyruleno==16);
      case 115: /* multiselect_op ::= UNION */ yytestcase(yyruleno==115);
      case 117: /* multiselect_op ::= EXCEPT|INTERSECT */ yytestcase(yyruleno==117);
{yygotominor.yy4 = yymsp[0].major;}
        break;
      case 17: /* cmd ::= COMMIT trans_opt */
      case 18: /* cmd ::= END trans_opt */ yytestcase(yyruleno==18);
{sqlite3CommitTransaction(pParse);}
        break;
      case 19: /* cmd ::= ROLLBACK trans_opt */
{sqlite3RollbackTransaction(pParse);}
................................................................................
      case 24: /* cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */
{
  sqlite3Savepoint(pParse, SAVEPOINT_ROLLBACK, &yymsp[0].minor.yy0);
}
        break;
      case 26: /* create_table ::= createkw temp TABLE ifnotexists nm dbnm */
{
   sqlite3StartTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,yymsp[-4].minor.yy4,0,0,yymsp[-2].minor.yy4);
}
        break;
      case 27: /* createkw ::= CREATE */
{
  pParse->db->lookaside.bEnabled = 0;
  yygotominor.yy0 = yymsp[0].minor.yy0;
}
................................................................................
      case 83: /* defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ yytestcase(yyruleno==83);
      case 85: /* init_deferred_pred_opt ::= */ yytestcase(yyruleno==85);
      case 87: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ yytestcase(yyruleno==87);
      case 98: /* defer_subclause_opt ::= */ yytestcase(yyruleno==98);
      case 109: /* ifexists ::= */ yytestcase(yyruleno==109);
      case 120: /* distinct ::= ALL */ yytestcase(yyruleno==120);
      case 121: /* distinct ::= */ yytestcase(yyruleno==121);
      case 222: /* between_op ::= BETWEEN */ yytestcase(yyruleno==222);
      case 225: /* in_op ::= IN */ yytestcase(yyruleno==225);
{yygotominor.yy4 = 0;}
        break;
      case 29: /* ifnotexists ::= IF NOT EXISTS */
      case 30: /* temp ::= TEMP */ yytestcase(yyruleno==30);
      case 71: /* autoinc ::= AUTOINCR */ yytestcase(yyruleno==71);
      case 86: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */ yytestcase(yyruleno==86);
      case 108: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==108);
      case 119: /* distinct ::= DISTINCT */ yytestcase(yyruleno==119);
      case 223: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==223);
      case 226: /* in_op ::= NOT IN */ yytestcase(yyruleno==226);
{yygotominor.yy4 = 1;}
        break;
      case 32: /* create_table_args ::= LP columnlist conslist_opt RP */
{
  sqlite3EndTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,0);
}
        break;
      case 33: /* create_table_args ::= AS select */
{
  sqlite3EndTable(pParse,0,0,yymsp[0].minor.yy387);
  sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy387);
}
        break;
      case 36: /* column ::= columnid type carglist */
{
  yygotominor.yy0.z = yymsp[-2].minor.yy0.z;
  yygotominor.yy0.n = (int)(pParse->sLastToken.z-yymsp[-2].minor.yy0.z) + pParse->sLastToken.n;
}
................................................................................
      case 43: /* nm ::= JOIN_KW */ yytestcase(yyruleno==43);
      case 46: /* typetoken ::= typename */ yytestcase(yyruleno==46);
      case 49: /* typename ::= ids */ yytestcase(yyruleno==49);
      case 127: /* as ::= AS nm */ yytestcase(yyruleno==127);
      case 128: /* as ::= ids */ yytestcase(yyruleno==128);
      case 138: /* dbnm ::= DOT nm */ yytestcase(yyruleno==138);
      case 147: /* indexed_opt ::= INDEXED BY nm */ yytestcase(yyruleno==147);
      case 251: /* collate ::= COLLATE ids */ yytestcase(yyruleno==251);
      case 260: /* nmnum ::= plus_num */ yytestcase(yyruleno==260);
      case 261: /* nmnum ::= nm */ yytestcase(yyruleno==261);
      case 262: /* nmnum ::= ON */ yytestcase(yyruleno==262);
      case 263: /* nmnum ::= DELETE */ yytestcase(yyruleno==263);
      case 264: /* nmnum ::= DEFAULT */ yytestcase(yyruleno==264);

      case 265: /* plus_num ::= plus_opt number */ yytestcase(yyruleno==265);
      case 266: /* minus_num ::= MINUS number */ yytestcase(yyruleno==266);
      case 267: /* number ::= INTEGER|FLOAT */ yytestcase(yyruleno==267);
      case 285: /* trnm ::= nm */ yytestcase(yyruleno==285);
{yygotominor.yy0 = yymsp[0].minor.yy0;}
        break;
      case 45: /* type ::= typetoken */
{sqlite3AddColumnType(pParse,&yymsp[0].minor.yy0);}
        break;
      case 47: /* typetoken ::= typename LP signed RP */
{
................................................................................
}
        break;
      case 50: /* typename ::= typename ids */
{yygotominor.yy0.z=yymsp[-1].minor.yy0.z; yygotominor.yy0.n=yymsp[0].minor.yy0.n+(int)(yymsp[0].minor.yy0.z-yymsp[-1].minor.yy0.z);}
        break;
      case 57: /* ccons ::= DEFAULT term */
      case 59: /* ccons ::= DEFAULT PLUS term */ yytestcase(yyruleno==59);
{sqlite3AddDefaultValue(pParse,&yymsp[0].minor.yy118);}
        break;
      case 58: /* ccons ::= DEFAULT LP expr RP */
{sqlite3AddDefaultValue(pParse,&yymsp[-1].minor.yy118);}
        break;
      case 60: /* ccons ::= DEFAULT MINUS term */
{
  ExprSpan v;
  v.pExpr = sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy118.pExpr, 0, 0);
  v.zStart = yymsp[-1].minor.yy0.z;
  v.zEnd = yymsp[0].minor.yy118.zEnd;
  sqlite3AddDefaultValue(pParse,&v);
}
        break;
      case 61: /* ccons ::= DEFAULT id */
{
  ExprSpan v;
  spanExpr(&v, pParse, TK_STRING, &yymsp[0].minor.yy0);
  sqlite3AddDefaultValue(pParse,&v);
}
        break;
      case 63: /* ccons ::= NOT NULL onconf */
{sqlite3AddNotNull(pParse, yymsp[0].minor.yy4);}
        break;
      case 64: /* ccons ::= PRIMARY KEY sortorder onconf autoinc */
{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy4,yymsp[0].minor.yy4,yymsp[-2].minor.yy4);}
        break;
      case 65: /* ccons ::= UNIQUE onconf */
{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy4,0,0,0,0);}
        break;
      case 66: /* ccons ::= CHECK LP expr RP */
{sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy118.pExpr);}
        break;
      case 67: /* ccons ::= REFERENCES nm idxlist_opt refargs */
{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy322,yymsp[0].minor.yy4);}
        break;
      case 68: /* ccons ::= defer_subclause */
{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy4);}
        break;
      case 69: /* ccons ::= COLLATE ids */
{sqlite3AddCollateType(pParse, &yymsp[0].minor.yy0);}
        break;
      case 72: /* refargs ::= */
{ yygotominor.yy4 = OE_None*0x0101; /* EV: R-19803-45884 */}
        break;
      case 73: /* refargs ::= refargs refarg */
{ yygotominor.yy4 = (yymsp[-1].minor.yy4 & ~yymsp[0].minor.yy215.mask) | yymsp[0].minor.yy215.value; }
        break;
      case 74: /* refarg ::= MATCH nm */
      case 75: /* refarg ::= ON INSERT refact */ yytestcase(yyruleno==75);
{ yygotominor.yy215.value = 0;     yygotominor.yy215.mask = 0x000000; }
        break;
      case 76: /* refarg ::= ON DELETE refact */
{ yygotominor.yy215.value = yymsp[0].minor.yy4;     yygotominor.yy215.mask = 0x0000ff; }
        break;
      case 77: /* refarg ::= ON UPDATE refact */
{ yygotominor.yy215.value = yymsp[0].minor.yy4<<8;  yygotominor.yy215.mask = 0x00ff00; }
        break;
      case 78: /* refact ::= SET NULL */
{ yygotominor.yy4 = OE_SetNull;  /* EV: R-33326-45252 */}
        break;
      case 79: /* refact ::= SET DEFAULT */
{ yygotominor.yy4 = OE_SetDflt;  /* EV: R-33326-45252 */}
        break;
      case 80: /* refact ::= CASCADE */
{ yygotominor.yy4 = OE_Cascade;  /* EV: R-33326-45252 */}
        break;
      case 81: /* refact ::= RESTRICT */
{ yygotominor.yy4 = OE_Restrict; /* EV: R-33326-45252 */}
        break;
      case 82: /* refact ::= NO ACTION */
{ yygotominor.yy4 = OE_None;     /* EV: R-33326-45252 */}
        break;
      case 84: /* defer_subclause ::= DEFERRABLE init_deferred_pred_opt */
      case 99: /* defer_subclause_opt ::= defer_subclause */ yytestcase(yyruleno==99);
      case 101: /* onconf ::= ON CONFLICT resolvetype */ yytestcase(yyruleno==101);
      case 104: /* resolvetype ::= raisetype */ yytestcase(yyruleno==104);
{yygotominor.yy4 = yymsp[0].minor.yy4;}
        break;
      case 88: /* conslist_opt ::= */
{yygotominor.yy0.n = 0; yygotominor.yy0.z = 0;}
        break;
      case 89: /* conslist_opt ::= COMMA conslist */
{yygotominor.yy0 = yymsp[-1].minor.yy0;}
        break;
      case 94: /* tcons ::= PRIMARY KEY LP idxlist autoinc RP onconf */
{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy322,yymsp[0].minor.yy4,yymsp[-2].minor.yy4,0);}
        break;
      case 95: /* tcons ::= UNIQUE LP idxlist RP onconf */
{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy322,yymsp[0].minor.yy4,0,0,0,0);}
        break;
      case 96: /* tcons ::= CHECK LP expr RP onconf */
{sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy118.pExpr);}
        break;
      case 97: /* tcons ::= FOREIGN KEY LP idxlist RP REFERENCES nm idxlist_opt refargs defer_subclause_opt */
{
    sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy322, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy322, yymsp[-1].minor.yy4);
    sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy4);
}
        break;
      case 100: /* onconf ::= */
{yygotominor.yy4 = OE_Default;}
        break;
      case 102: /* orconf ::= */
{yygotominor.yy210 = OE_Default;}
        break;
      case 103: /* orconf ::= OR resolvetype */
{yygotominor.yy210 = (u8)yymsp[0].minor.yy4;}
        break;
      case 105: /* resolvetype ::= IGNORE */
{yygotominor.yy4 = OE_Ignore;}
        break;
      case 106: /* resolvetype ::= REPLACE */
{yygotominor.yy4 = OE_Replace;}
        break;
      case 107: /* cmd ::= DROP TABLE ifexists fullname */
{
  sqlite3DropTable(pParse, yymsp[0].minor.yy259, 0, yymsp[-1].minor.yy4);
}
        break;
      case 110: /* cmd ::= createkw temp VIEW ifnotexists nm dbnm AS select */
{
  sqlite3CreateView(pParse, &yymsp[-7].minor.yy0, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, yymsp[0].minor.yy387, yymsp[-6].minor.yy4, yymsp[-4].minor.yy4);
}
        break;
      case 111: /* cmd ::= DROP VIEW ifexists fullname */
{
  sqlite3DropTable(pParse, yymsp[0].minor.yy259, 1, yymsp[-1].minor.yy4);
}
        break;
      case 112: /* cmd ::= select */
{
  SelectDest dest = {SRT_Output, 0, 0, 0, 0};
  sqlite3Select(pParse, yymsp[0].minor.yy387, &dest);
  sqlite3ExplainBegin(pParse->pVdbe);
  sqlite3ExplainSelect(pParse->pVdbe, yymsp[0].minor.yy387);
  sqlite3ExplainFinish(pParse->pVdbe);
  sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy387);
}
        break;
      case 113: /* select ::= oneselect */
{yygotominor.yy387 = yymsp[0].minor.yy387;}
        break;
      case 114: /* select ::= select multiselect_op oneselect */
{
  if( yymsp[0].minor.yy387 ){
    yymsp[0].minor.yy387->op = (u8)yymsp[-1].minor.yy4;
    yymsp[0].minor.yy387->pPrior = yymsp[-2].minor.yy387;
  }else{
    sqlite3SelectDelete(pParse->db, yymsp[-2].minor.yy387);
  }
  yygotominor.yy387 = yymsp[0].minor.yy387;
}
        break;
      case 116: /* multiselect_op ::= UNION ALL */
{yygotominor.yy4 = TK_ALL;}
        break;
      case 118: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
{
  yygotominor.yy387 = sqlite3SelectNew(pParse,yymsp[-6].minor.yy322,yymsp[-5].minor.yy259,yymsp[-4].minor.yy314,yymsp[-3].minor.yy322,yymsp[-2].minor.yy314,yymsp[-1].minor.yy322,yymsp[-7].minor.yy4,yymsp[0].minor.yy292.pLimit,yymsp[0].minor.yy292.pOffset);
}
        break;
      case 122: /* sclp ::= selcollist COMMA */
      case 247: /* idxlist_opt ::= LP idxlist RP */ yytestcase(yyruleno==247);
{yygotominor.yy322 = yymsp[-1].minor.yy322;}
        break;
      case 123: /* sclp ::= */
      case 151: /* orderby_opt ::= */ yytestcase(yyruleno==151);
      case 159: /* groupby_opt ::= */ yytestcase(yyruleno==159);
      case 240: /* exprlist ::= */ yytestcase(yyruleno==240);
      case 246: /* idxlist_opt ::= */ yytestcase(yyruleno==246);
{yygotominor.yy322 = 0;}
        break;
      case 124: /* selcollist ::= sclp expr as */
{
   yygotominor.yy322 = sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy322, yymsp[-1].minor.yy118.pExpr);
   if( yymsp[0].minor.yy0.n>0 ) sqlite3ExprListSetName(pParse, yygotominor.yy322, &yymsp[0].minor.yy0, 1);
   sqlite3ExprListSetSpan(pParse,yygotominor.yy322,&yymsp[-1].minor.yy118);
}
        break;
      case 125: /* selcollist ::= sclp STAR */
{
  Expr *p = sqlite3Expr(pParse->db, TK_ALL, 0);
  yygotominor.yy322 = sqlite3ExprListAppend(pParse, yymsp[-1].minor.yy322, p);
}
        break;
      case 126: /* selcollist ::= sclp nm DOT STAR */
{
  Expr *pRight = sqlite3PExpr(pParse, TK_ALL, 0, 0, &yymsp[0].minor.yy0);
  Expr *pLeft = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[-2].minor.yy0);
  Expr *pDot = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight, 0);
  yygotominor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy322, pDot);
}
        break;
      case 129: /* as ::= */
{yygotominor.yy0.n = 0;}
        break;
      case 130: /* from ::= */
{yygotominor.yy259 = sqlite3DbMallocZero(pParse->db, sizeof(*yygotominor.yy259));}
        break;
      case 131: /* from ::= FROM seltablist */
{
  yygotominor.yy259 = yymsp[0].minor.yy259;
  sqlite3SrcListShiftJoinType(yygotominor.yy259);
}
        break;
      case 132: /* stl_prefix ::= seltablist joinop */
{
   yygotominor.yy259 = yymsp[-1].minor.yy259;
   if( ALWAYS(yygotominor.yy259 && yygotominor.yy259->nSrc>0) ) yygotominor.yy259->a[yygotominor.yy259->nSrc-1].jointype = (u8)yymsp[0].minor.yy4;
}
        break;
      case 133: /* stl_prefix ::= */
{yygotominor.yy259 = 0;}
        break;
      case 134: /* seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */
{
  yygotominor.yy259 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy259,&yymsp[-5].minor.yy0,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,0,yymsp[-1].minor.yy314,yymsp[0].minor.yy384);
  sqlite3SrcListIndexedBy(pParse, yygotominor.yy259, &yymsp[-2].minor.yy0);
}
        break;
      case 135: /* seltablist ::= stl_prefix LP select RP as on_opt using_opt */
{
    yygotominor.yy259 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy259,0,0,&yymsp[-2].minor.yy0,yymsp[-4].minor.yy387,yymsp[-1].minor.yy314,yymsp[0].minor.yy384);
  }
        break;
      case 136: /* seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */
{
    if( yymsp[-6].minor.yy259==0 && yymsp[-2].minor.yy0.n==0 && yymsp[-1].minor.yy314==0 && yymsp[0].minor.yy384==0 ){
      yygotominor.yy259 = yymsp[-4].minor.yy259;
    }else{
      Select *pSubquery;
      sqlite3SrcListShiftJoinType(yymsp[-4].minor.yy259);
      pSubquery = sqlite3SelectNew(pParse,0,yymsp[-4].minor.yy259,0,0,0,0,0,0,0);
      yygotominor.yy259 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy259,0,0,&yymsp[-2].minor.yy0,pSubquery,yymsp[-1].minor.yy314,yymsp[0].minor.yy384);
    }
  }
        break;
      case 137: /* dbnm ::= */
      case 146: /* indexed_opt ::= */ yytestcase(yyruleno==146);
{yygotominor.yy0.z=0; yygotominor.yy0.n=0;}
        break;
      case 139: /* fullname ::= nm dbnm */
{yygotominor.yy259 = sqlite3SrcListAppend(pParse->db,0,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0);}
        break;
      case 140: /* joinop ::= COMMA|JOIN */
{ yygotominor.yy4 = JT_INNER; }
        break;
      case 141: /* joinop ::= JOIN_KW JOIN */
{ yygotominor.yy4 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); }
        break;
      case 142: /* joinop ::= JOIN_KW nm JOIN */
{ yygotominor.yy4 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); }
        break;
      case 143: /* joinop ::= JOIN_KW nm nm JOIN */
{ yygotominor.yy4 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0); }
        break;
      case 144: /* on_opt ::= ON expr */
      case 155: /* sortitem ::= expr */ yytestcase(yyruleno==155);
      case 162: /* having_opt ::= HAVING expr */ yytestcase(yyruleno==162);
      case 169: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==169);
      case 235: /* case_else ::= ELSE expr */ yytestcase(yyruleno==235);
      case 237: /* case_operand ::= expr */ yytestcase(yyruleno==237);
{yygotominor.yy314 = yymsp[0].minor.yy118.pExpr;}
        break;
      case 145: /* on_opt ::= */
      case 161: /* having_opt ::= */ yytestcase(yyruleno==161);
      case 168: /* where_opt ::= */ yytestcase(yyruleno==168);
      case 236: /* case_else ::= */ yytestcase(yyruleno==236);
      case 238: /* case_operand ::= */ yytestcase(yyruleno==238);
{yygotominor.yy314 = 0;}
        break;
      case 148: /* indexed_opt ::= NOT INDEXED */
{yygotominor.yy0.z=0; yygotominor.yy0.n=1;}
        break;
      case 149: /* using_opt ::= USING LP inscollist RP */
      case 181: /* inscollist_opt ::= LP inscollist RP */ yytestcase(yyruleno==181);
{yygotominor.yy384 = yymsp[-1].minor.yy384;}
        break;
      case 150: /* using_opt ::= */
      case 180: /* inscollist_opt ::= */ yytestcase(yyruleno==180);
{yygotominor.yy384 = 0;}
        break;
      case 152: /* orderby_opt ::= ORDER BY sortlist */
      case 160: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==160);
      case 239: /* exprlist ::= nexprlist */ yytestcase(yyruleno==239);
{yygotominor.yy322 = yymsp[0].minor.yy322;}
        break;
      case 153: /* sortlist ::= sortlist COMMA sortitem sortorder */
{
  yygotominor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy322,yymsp[-1].minor.yy314);
  if( yygotominor.yy322 ) yygotominor.yy322->a[yygotominor.yy322->nExpr-1].sortOrder = (u8)yymsp[0].minor.yy4;
}
        break;
      case 154: /* sortlist ::= sortitem sortorder */
{
  yygotominor.yy322 = sqlite3ExprListAppend(pParse,0,yymsp[-1].minor.yy314);
  if( yygotominor.yy322 && ALWAYS(yygotominor.yy322->a) ) yygotominor.yy322->a[0].sortOrder = (u8)yymsp[0].minor.yy4;
}
        break;
      case 156: /* sortorder ::= ASC */
      case 158: /* sortorder ::= */ yytestcase(yyruleno==158);
{yygotominor.yy4 = SQLITE_SO_ASC;}
        break;
      case 157: /* sortorder ::= DESC */
{yygotominor.yy4 = SQLITE_SO_DESC;}
        break;
      case 163: /* limit_opt ::= */
{yygotominor.yy292.pLimit = 0; yygotominor.yy292.pOffset = 0;}
        break;
      case 164: /* limit_opt ::= LIMIT expr */
{yygotominor.yy292.pLimit = yymsp[0].minor.yy118.pExpr; yygotominor.yy292.pOffset = 0;}
        break;
      case 165: /* limit_opt ::= LIMIT expr OFFSET expr */
{yygotominor.yy292.pLimit = yymsp[-2].minor.yy118.pExpr; yygotominor.yy292.pOffset = yymsp[0].minor.yy118.pExpr;}
        break;
      case 166: /* limit_opt ::= LIMIT expr COMMA expr */
{yygotominor.yy292.pOffset = yymsp[-2].minor.yy118.pExpr; yygotominor.yy292.pLimit = yymsp[0].minor.yy118.pExpr;}
        break;
      case 167: /* cmd ::= DELETE FROM fullname indexed_opt where_opt */
{
  sqlite3SrcListIndexedBy(pParse, yymsp[-2].minor.yy259, &yymsp[-1].minor.yy0);
  sqlite3DeleteFrom(pParse,yymsp[-2].minor.yy259,yymsp[0].minor.yy314);
}
        break;
      case 170: /* cmd ::= UPDATE orconf fullname indexed_opt SET setlist where_opt */
{
  sqlite3SrcListIndexedBy(pParse, yymsp[-4].minor.yy