Fossil SCM

Merge trunk

jan.nijtmans 2015-05-20 11:45 sync-forkwarn merge
Commit 9f507ffe494859c604109f735f4962ecdfc2c184
+1 -1
--- VERSION
+++ VERSION
@@ -1,1 +1,1 @@
1
-1.32
1
+1.33
22
--- VERSION
+++ VERSION
@@ -1,1 +1,1 @@
1 1.32
2
--- VERSION
+++ VERSION
@@ -1,1 +1,1 @@
1 1.33
2
+1
--- auto.def
+++ auto.def
@@ -299,10 +299,11 @@
299299
if {![cc-check-functions getpassphrase]} {
300300
# Haiku needs this
301301
cc-check-function-in-lib getpass bsd
302302
}
303303
cc-check-function-in-lib dlopen dl
304
+cc-check-function-in-lib sin m
304305
305306
# Check for the FuseFS library
306307
if {[opt-bool fusefs]} {
307308
if {[cc-check-function-in-lib fuse_mount fuse]} {
308309
define FOSSIL_HAVE_FUSEFS 1
309310
--- auto.def
+++ auto.def
@@ -299,10 +299,11 @@
299 if {![cc-check-functions getpassphrase]} {
300 # Haiku needs this
301 cc-check-function-in-lib getpass bsd
302 }
303 cc-check-function-in-lib dlopen dl
 
304
305 # Check for the FuseFS library
306 if {[opt-bool fusefs]} {
307 if {[cc-check-function-in-lib fuse_mount fuse]} {
308 define FOSSIL_HAVE_FUSEFS 1
309
--- auto.def
+++ auto.def
@@ -299,10 +299,11 @@
299 if {![cc-check-functions getpassphrase]} {
300 # Haiku needs this
301 cc-check-function-in-lib getpass bsd
302 }
303 cc-check-function-in-lib dlopen dl
304 cc-check-function-in-lib sin m
305
306 # Check for the FuseFS library
307 if {[opt-bool fusefs]} {
308 if {[cc-check-function-in-lib fuse_mount fuse]} {
309 define FOSSIL_HAVE_FUSEFS 1
310
--- skins/default/details.txt
+++ skins/default/details.txt
@@ -1,4 +1,4 @@
11
timeline-arrowheads: 1
2
-timeline-circle-nodes: 0
3
-timeline-color-graph-lines: 0
2
+timeline-circle-nodes: 1
3
+timeline-color-graph-lines: 1
44
white-foreground: 0
55
--- skins/default/details.txt
+++ skins/default/details.txt
@@ -1,4 +1,4 @@
1 timeline-arrowheads: 1
2 timeline-circle-nodes: 0
3 timeline-color-graph-lines: 0
4 white-foreground: 0
5
--- skins/default/details.txt
+++ skins/default/details.txt
@@ -1,4 +1,4 @@
1 timeline-arrowheads: 1
2 timeline-circle-nodes: 1
3 timeline-color-graph-lines: 1
4 white-foreground: 0
5
--- skins/eagle/css.txt
+++ skins/eagle/css.txt
@@ -168,10 +168,58 @@
168168
}
169169
170170
tr.timelineSelected {
171171
background-color: #7EA2D9;
172172
}
173
+
174
+/* commit node */
175
+.tl-node {
176
+ width: 10px;
177
+ height: 10px;
178
+ border: 1px solid #fff;
179
+ background: #485D7B;
180
+ cursor: pointer;
181
+}
182
+
183
+/* leaf commit marker */
184
+.tl-node.leaf:after {
185
+ content: '';
186
+ position: absolute;
187
+ top: 3px;
188
+ left: 3px;
189
+ width: 4px;
190
+ height: 4px;
191
+ background: #fff;
192
+}
193
+
194
+/* up arrow */
195
+.tl-arrow.u {
196
+ margin-top: -1px;
197
+ border-width: 0 3px;
198
+ border-bottom: 7px solid #fff;
199
+}
200
+
201
+/* small up arrow */
202
+.tl-arrow.u.sm {
203
+ border-bottom: 5px solid #fff;
204
+}
205
+
206
+/* line */
207
+.tl-line {
208
+ background: #fff;
209
+ width: 2px;
210
+}
211
+
212
+/* left merge arrow */
213
+.tl-arrow.merge.l {
214
+ border-right: 3px solid #fff;
215
+}
216
+
217
+/* right merge arrow */
218
+.tl-arrow.merge.r {
219
+ border-left: 3px solid #fff;
220
+}
173221
174222
/* Side-by-side diff */
175223
table.sbsdiff {
176224
background-color: #485D7B;
177225
font-family: fixed, Dejavu Sans Mono, Monaco, Lucida Console, monospace;
@@ -264,14 +312,10 @@
264312
/* line numbers in a diff */
265313
span.diffln {
266314
color: white;
267315
}
268316
269
-#canvas {
270
- background-color: #485D7B;
271
-}
272
-
273317
.fileage tr:hover {
274318
background-color: #7EA2D9;
275319
}
276320
277321
.fileage td {
278322
--- skins/eagle/css.txt
+++ skins/eagle/css.txt
@@ -168,10 +168,58 @@
168 }
169
170 tr.timelineSelected {
171 background-color: #7EA2D9;
172 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
173
174 /* Side-by-side diff */
175 table.sbsdiff {
176 background-color: #485D7B;
177 font-family: fixed, Dejavu Sans Mono, Monaco, Lucida Console, monospace;
@@ -264,14 +312,10 @@
264 /* line numbers in a diff */
265 span.diffln {
266 color: white;
267 }
268
269 #canvas {
270 background-color: #485D7B;
271 }
272
273 .fileage tr:hover {
274 background-color: #7EA2D9;
275 }
276
277 .fileage td {
278
--- skins/eagle/css.txt
+++ skins/eagle/css.txt
@@ -168,10 +168,58 @@
168 }
169
170 tr.timelineSelected {
171 background-color: #7EA2D9;
172 }
173
174 /* commit node */
175 .tl-node {
176 width: 10px;
177 height: 10px;
178 border: 1px solid #fff;
179 background: #485D7B;
180 cursor: pointer;
181 }
182
183 /* leaf commit marker */
184 .tl-node.leaf:after {
185 content: '';
186 position: absolute;
187 top: 3px;
188 left: 3px;
189 width: 4px;
190 height: 4px;
191 background: #fff;
192 }
193
194 /* up arrow */
195 .tl-arrow.u {
196 margin-top: -1px;
197 border-width: 0 3px;
198 border-bottom: 7px solid #fff;
199 }
200
201 /* small up arrow */
202 .tl-arrow.u.sm {
203 border-bottom: 5px solid #fff;
204 }
205
206 /* line */
207 .tl-line {
208 background: #fff;
209 width: 2px;
210 }
211
212 /* left merge arrow */
213 .tl-arrow.merge.l {
214 border-right: 3px solid #fff;
215 }
216
217 /* right merge arrow */
218 .tl-arrow.merge.r {
219 border-left: 3px solid #fff;
220 }
221
222 /* Side-by-side diff */
223 table.sbsdiff {
224 background-color: #485D7B;
225 font-family: fixed, Dejavu Sans Mono, Monaco, Lucida Console, monospace;
@@ -264,14 +312,10 @@
312 /* line numbers in a diff */
313 span.diffln {
314 color: white;
315 }
316
 
 
 
 
317 .fileage tr:hover {
318 background-color: #7EA2D9;
319 }
320
321 .fileage td {
322
--- skins/xekri/css.txt
+++ skins/xekri/css.txt
@@ -202,10 +202,17 @@
202202
}
203203
204204
div.content table[bgcolor="white"] {
205205
color: #000;
206206
}
207
+
208
+.piechartLabel {
209
+ fill: white;
210
+}
211
+.piechartLine {
212
+ stroke: white;
213
+}
207214
208215
/**************************************
209216
* Main Area: Footer
210217
*/
211218
@@ -700,15 +707,10 @@
700707
701708
/**************************************
702709
* Timeline
703710
*/
704711
705
-#canvas {
706
- color: #000;
707
- background-color: #fff;
708
-}
709
-
710712
div.divider {
711713
color: #ee0;
712714
font-size: 1.2rem;
713715
font-weight: bold;
714716
margin-top: 1rem;
@@ -1027,6 +1029,5 @@
10271029
}
10281030
/* odd table row color */
10291031
tr.row1 {
10301032
/* Use default */
10311033
}
1032
-
10331034
--- skins/xekri/css.txt
+++ skins/xekri/css.txt
@@ -202,10 +202,17 @@
202 }
203
204 div.content table[bgcolor="white"] {
205 color: #000;
206 }
 
 
 
 
 
 
 
207
208 /**************************************
209 * Main Area: Footer
210 */
211
@@ -700,15 +707,10 @@
700
701 /**************************************
702 * Timeline
703 */
704
705 #canvas {
706 color: #000;
707 background-color: #fff;
708 }
709
710 div.divider {
711 color: #ee0;
712 font-size: 1.2rem;
713 font-weight: bold;
714 margin-top: 1rem;
@@ -1027,6 +1029,5 @@
1027 }
1028 /* odd table row color */
1029 tr.row1 {
1030 /* Use default */
1031 }
1032
1033
--- skins/xekri/css.txt
+++ skins/xekri/css.txt
@@ -202,10 +202,17 @@
202 }
203
204 div.content table[bgcolor="white"] {
205 color: #000;
206 }
207
208 .piechartLabel {
209 fill: white;
210 }
211 .piechartLine {
212 stroke: white;
213 }
214
215 /**************************************
216 * Main Area: Footer
217 */
218
@@ -700,15 +707,10 @@
707
708 /**************************************
709 * Timeline
710 */
711
 
 
 
 
 
712 div.divider {
713 color: #ee0;
714 font-size: 1.2rem;
715 font-weight: bold;
716 margin-top: 1rem;
@@ -1027,6 +1029,5 @@
1029 }
1030 /* odd table row color */
1031 tr.row1 {
1032 /* Use default */
1033 }
 
1034
--- skins/xekri/header.txt
+++ skins/xekri/header.txt
@@ -127,10 +127,11 @@
127127
menulink /ticket Tickets
128128
}
129129
if {[anoncap j]} {
130130
menulink /wiki Wiki
131131
}
132
+ menulink /sitemap More...
132133
if {[hascap s]} {
133134
menulink /setup Admin
134135
} elseif {[hascap a]} {
135136
menulink /setup_ulist Users
136137
}
137138
--- skins/xekri/header.txt
+++ skins/xekri/header.txt
@@ -127,10 +127,11 @@
127 menulink /ticket Tickets
128 }
129 if {[anoncap j]} {
130 menulink /wiki Wiki
131 }
 
132 if {[hascap s]} {
133 menulink /setup Admin
134 } elseif {[hascap a]} {
135 menulink /setup_ulist Users
136 }
137
--- skins/xekri/header.txt
+++ skins/xekri/header.txt
@@ -127,10 +127,11 @@
127 menulink /ticket Tickets
128 }
129 if {[anoncap j]} {
130 menulink /wiki Wiki
131 }
132 menulink /sitemap More...
133 if {[hascap s]} {
134 menulink /setup Admin
135 } elseif {[hascap a]} {
136 menulink /setup_ulist Users
137 }
138
+8 -2
--- src/add.c
+++ src/add.c
@@ -317,12 +317,10 @@
317317
isDir = file_wd_isdir(zName);
318318
if( isDir==1 ){
319319
vfile_scan(&fullName, nRoot-1, scanFlags, pClean, pIgnore);
320320
}else if( isDir==0 ){
321321
fossil_warning("not found: %s", zName);
322
- }else if( file_access(zName, R_OK) ){
323
- fossil_fatal("cannot open %s", zName);
324322
}else{
325323
char *zTreeName = &zName[nRoot];
326324
if( !forceFlag && glob_match(pIgnore, zTreeName) ){
327325
Blob ans;
328326
char cReply;
@@ -632,10 +630,18 @@
632630
}
633631
634632
/* We should be done with options.. */
635633
verify_all_options();
636634
635
+ /* Fail if unprocessed arguments are present, in case user expect the
636
+ ** addremove command to accept a list of file or directory.
637
+ */
638
+ if( g.argc>2 ){
639
+ fossil_fatal(
640
+ "%s: Can only work on the entire checkout, no arguments supported.",
641
+ g.argv[1]);
642
+ }
637643
db_must_be_within_tree();
638644
if( zCleanFlag==0 ){
639645
zCleanFlag = db_get("clean-glob", 0);
640646
}
641647
if( zIgnoreFlag==0 ){
642648
--- src/add.c
+++ src/add.c
@@ -317,12 +317,10 @@
317 isDir = file_wd_isdir(zName);
318 if( isDir==1 ){
319 vfile_scan(&fullName, nRoot-1, scanFlags, pClean, pIgnore);
320 }else if( isDir==0 ){
321 fossil_warning("not found: %s", zName);
322 }else if( file_access(zName, R_OK) ){
323 fossil_fatal("cannot open %s", zName);
324 }else{
325 char *zTreeName = &zName[nRoot];
326 if( !forceFlag && glob_match(pIgnore, zTreeName) ){
327 Blob ans;
328 char cReply;
@@ -632,10 +630,18 @@
632 }
633
634 /* We should be done with options.. */
635 verify_all_options();
636
 
 
 
 
 
 
 
 
637 db_must_be_within_tree();
638 if( zCleanFlag==0 ){
639 zCleanFlag = db_get("clean-glob", 0);
640 }
641 if( zIgnoreFlag==0 ){
642
--- src/add.c
+++ src/add.c
@@ -317,12 +317,10 @@
317 isDir = file_wd_isdir(zName);
318 if( isDir==1 ){
319 vfile_scan(&fullName, nRoot-1, scanFlags, pClean, pIgnore);
320 }else if( isDir==0 ){
321 fossil_warning("not found: %s", zName);
 
 
322 }else{
323 char *zTreeName = &zName[nRoot];
324 if( !forceFlag && glob_match(pIgnore, zTreeName) ){
325 Blob ans;
326 char cReply;
@@ -632,10 +630,18 @@
630 }
631
632 /* We should be done with options.. */
633 verify_all_options();
634
635 /* Fail if unprocessed arguments are present, in case user expect the
636 ** addremove command to accept a list of file or directory.
637 */
638 if( g.argc>2 ){
639 fossil_fatal(
640 "%s: Can only work on the entire checkout, no arguments supported.",
641 g.argv[1]);
642 }
643 db_must_be_within_tree();
644 if( zCleanFlag==0 ){
645 zCleanFlag = db_get("clean-glob", 0);
646 }
647 if( zIgnoreFlag==0 ){
648
--- src/allrepo.c
+++ src/allrepo.c
@@ -231,10 +231,11 @@
231231
collect_argument(&extra, "verbose","v");
232232
}else if( strncmp(zCmd, "rebuild", n)==0 ){
233233
zCmd = "rebuild";
234234
collect_argument(&extra, "cluster",0);
235235
collect_argument(&extra, "compress",0);
236
+ collect_argument(&extra, "compress-only",0);
236237
collect_argument(&extra, "noverify",0);
237238
collect_argument_value(&extra, "pagesize");
238239
collect_argument(&extra, "vacuum",0);
239240
collect_argument(&extra, "deanalyze",0);
240241
collect_argument(&extra, "analyze",0);
241242
--- src/allrepo.c
+++ src/allrepo.c
@@ -231,10 +231,11 @@
231 collect_argument(&extra, "verbose","v");
232 }else if( strncmp(zCmd, "rebuild", n)==0 ){
233 zCmd = "rebuild";
234 collect_argument(&extra, "cluster",0);
235 collect_argument(&extra, "compress",0);
 
236 collect_argument(&extra, "noverify",0);
237 collect_argument_value(&extra, "pagesize");
238 collect_argument(&extra, "vacuum",0);
239 collect_argument(&extra, "deanalyze",0);
240 collect_argument(&extra, "analyze",0);
241
--- src/allrepo.c
+++ src/allrepo.c
@@ -231,10 +231,11 @@
231 collect_argument(&extra, "verbose","v");
232 }else if( strncmp(zCmd, "rebuild", n)==0 ){
233 zCmd = "rebuild";
234 collect_argument(&extra, "cluster",0);
235 collect_argument(&extra, "compress",0);
236 collect_argument(&extra, "compress-only",0);
237 collect_argument(&extra, "noverify",0);
238 collect_argument_value(&extra, "pagesize");
239 collect_argument(&extra, "vacuum",0);
240 collect_argument(&extra, "deanalyze",0);
241 collect_argument(&extra, "analyze",0);
242
+2 -2
--- src/blob.c
+++ src/blob.c
@@ -300,11 +300,11 @@
300300
** Return a pointer to a null-terminated string for a blob.
301301
*/
302302
char *blob_str(Blob *p){
303303
blob_is_init(p);
304304
if( p->nUsed==0 ){
305
- blob_append(p, "", 1);
305
+ blob_append(p, "", 1); /* NOTE: Changes nUsed. */
306306
p->nUsed = 0;
307307
}
308308
if( p->aData[p->nUsed]!=0 ){
309309
blob_materialize(p);
310310
}
@@ -839,11 +839,11 @@
839839
#if defined(_WIN32)
840840
fflush(stdout);
841841
_setmode(_fileno(stdout), _O_TEXT);
842842
#endif
843843
}else{
844
- file_mkfolder(zFilename, 1);
844
+ file_mkfolder(zFilename, 1, 0);
845845
out = fossil_fopen(zFilename, "wb");
846846
if( out==0 ){
847847
fossil_fatal_recursive("unable to open file \"%s\" for writing",
848848
zFilename);
849849
return 0;
850850
--- src/blob.c
+++ src/blob.c
@@ -300,11 +300,11 @@
300 ** Return a pointer to a null-terminated string for a blob.
301 */
302 char *blob_str(Blob *p){
303 blob_is_init(p);
304 if( p->nUsed==0 ){
305 blob_append(p, "", 1);
306 p->nUsed = 0;
307 }
308 if( p->aData[p->nUsed]!=0 ){
309 blob_materialize(p);
310 }
@@ -839,11 +839,11 @@
839 #if defined(_WIN32)
840 fflush(stdout);
841 _setmode(_fileno(stdout), _O_TEXT);
842 #endif
843 }else{
844 file_mkfolder(zFilename, 1);
845 out = fossil_fopen(zFilename, "wb");
846 if( out==0 ){
847 fossil_fatal_recursive("unable to open file \"%s\" for writing",
848 zFilename);
849 return 0;
850
--- src/blob.c
+++ src/blob.c
@@ -300,11 +300,11 @@
300 ** Return a pointer to a null-terminated string for a blob.
301 */
302 char *blob_str(Blob *p){
303 blob_is_init(p);
304 if( p->nUsed==0 ){
305 blob_append(p, "", 1); /* NOTE: Changes nUsed. */
306 p->nUsed = 0;
307 }
308 if( p->aData[p->nUsed]!=0 ){
309 blob_materialize(p);
310 }
@@ -839,11 +839,11 @@
839 #if defined(_WIN32)
840 fflush(stdout);
841 _setmode(_fileno(stdout), _O_TEXT);
842 #endif
843 }else{
844 file_mkfolder(zFilename, 1, 0);
845 out = fossil_fopen(zFilename, "wb");
846 if( out==0 ){
847 fossil_fatal_recursive("unable to open file \"%s\" for writing",
848 zFilename);
849 return 0;
850
+33 -7
--- src/checkin.c
+++ src/checkin.c
@@ -113,10 +113,18 @@
113113
blob_appendf(report, "ADDED_BY_MERGE %s\n", zDisplayName);
114114
}else if( isChnged==4 ){
115115
blob_appendf(report, "UPDATED_BY_INTEGRATE %s\n", zDisplayName);
116116
}else if( isChnged==5 ){
117117
blob_appendf(report, "ADDED_BY_INTEGRATE %s\n", zDisplayName);
118
+ }else if( isChnged==6 ){
119
+ blob_appendf(report, "EXECUTABLE %s\n", zDisplayName);
120
+ }else if( isChnged==7 ){
121
+ blob_appendf(report, "SYMLINK %s\n", zDisplayName);
122
+ }else if( isChnged==8 ){
123
+ blob_appendf(report, "UNEXEC %s\n", zDisplayName);
124
+ }else if( isChnged==9 ){
125
+ blob_appendf(report, "UNLINK %s\n", zDisplayName);
118126
}else if( file_contains_merge_marker(zFullName) ){
119127
blob_appendf(report, "CONFLICT %s\n", zDisplayName);
120128
}else{
121129
blob_appendf(report, "EDITED %s\n", zDisplayName);
122130
}
@@ -1633,10 +1641,12 @@
16331641
int dryRunFlag; /* True for a test run. Debugging only */
16341642
CheckinInfo sCiInfo; /* Information about this check-in */
16351643
const char *zComFile; /* Read commit message from this file */
16361644
int nTag = 0; /* Number of --tag arguments */
16371645
const char *zTag; /* A single --tag argument */
1646
+ ManifestFile *pFile; /* File structure in the manifest */
1647
+ Manifest *pManifest; /* Manifest structure */
16381648
Blob manifest; /* Manifest in baseline form */
16391649
Blob muuid; /* Manifest uuid */
16401650
Blob cksum1, cksum2; /* Before and after commit checksums */
16411651
Blob cksum1b; /* Checksum recorded in the manifest */
16421652
int szD; /* Size of the delta manifest */
@@ -1900,11 +1910,11 @@
19001910
/* Step 2: Insert records for all modified files into the blob
19011911
** table. If there were arguments passed to this command, only
19021912
** the identified files are inserted (if they have been modified).
19031913
*/
19041914
db_prepare(&q,
1905
- "SELECT id, %Q || pathname, mrid, %s, chnged, %s, %s FROM vfile "
1915
+ "SELECT id, %Q || pathname, mrid, %s, %s, %s FROM vfile "
19061916
"WHERE chnged==1 AND NOT deleted AND is_selected(id)",
19071917
g.zLocalRoot,
19081918
glob_expr("pathname", db_get("crnl-glob","")),
19091919
glob_expr("pathname", db_get("binary-glob","")),
19101920
glob_expr("pathname", db_get("encoding-glob",""))
@@ -1911,19 +1921,18 @@
19111921
);
19121922
while( db_step(&q)==SQLITE_ROW ){
19131923
int id, rid;
19141924
const char *zFullname;
19151925
Blob content;
1916
- int crnlOk, binOk, encodingOk, chnged;
1926
+ int crnlOk, binOk, encodingOk;
19171927
19181928
id = db_column_int(&q, 0);
19191929
zFullname = db_column_text(&q, 1);
19201930
rid = db_column_int(&q, 2);
19211931
crnlOk = db_column_int(&q, 3);
1922
- chnged = db_column_int(&q, 4);
1923
- binOk = db_column_int(&q, 5);
1924
- encodingOk = db_column_int(&q, 6);
1932
+ binOk = db_column_int(&q, 4);
1933
+ encodingOk = db_column_int(&q, 5);
19251934
19261935
blob_zero(&content);
19271936
if( file_wd_islink(zFullname) ){
19281937
/* Instead of file content, put link destination path */
19291938
blob_read_link(&content, zFullname);
@@ -1933,11 +1942,11 @@
19331942
/* Do not emit any warnings when they are disabled. */
19341943
if( !noWarningFlag ){
19351944
abortCommit |= commit_warning(&content, crnlOk, binOk,
19361945
encodingOk, zFullname);
19371946
}
1938
- if( chnged==1 && contains_merge_marker(&content) ){
1947
+ if( contains_merge_marker(&content) ){
19391948
Blob fname; /* Relative pathname of the file */
19401949
19411950
nConflict++;
19421951
file_relative_name(zFullname, &fname, 0);
19431952
fossil_print("possible unresolved merge conflict in %s\n",
@@ -2071,11 +2080,10 @@
20712080
blob_write_to_file(&muuid, zManifestFile);
20722081
free(zManifestFile);
20732082
blob_reset(&muuid);
20742083
}
20752084
2076
-
20772085
/* Update the vfile and vmerge tables */
20782086
db_multi_exec(
20792087
"DELETE FROM vfile WHERE (vid!=%d OR deleted) AND is_selected(id);"
20802088
"DELETE FROM vmerge;"
20812089
"UPDATE vfile SET vid=%d;"
@@ -2082,10 +2090,28 @@
20822090
"UPDATE vfile SET rid=mrid, chnged=0, deleted=0, origname=NULL"
20832091
" WHERE is_selected(id);"
20842092
, vid, nvid
20852093
);
20862094
db_lset_int("checkout", nvid);
2095
+
2096
+ /* Update the isexe and islink columns of the vfile table */
2097
+ db_prepare(&q,
2098
+ "UPDATE vfile SET isexe=:exec, islink=:link"
2099
+ " WHERE vid=:vid AND pathname=:path AND (isexe!=:exec OR islink!=:link)"
2100
+ );
2101
+ db_bind_int(&q, ":vid", nvid);
2102
+ pManifest = manifest_get(nvid, CFTYPE_MANIFEST, 0);
2103
+ manifest_file_rewind(pManifest);
2104
+ while( (pFile = manifest_file_next(pManifest, 0)) ){
2105
+ db_bind_int(&q, ":exec", pFile->zPerm && strstr(pFile->zPerm, "x"));
2106
+ db_bind_int(&q, ":link", pFile->zPerm && strstr(pFile->zPerm, "l"));
2107
+ db_bind_text(&q, ":path", pFile->zName);
2108
+ db_step(&q);
2109
+ db_reset(&q);
2110
+ }
2111
+ db_finalize(&q);
2112
+ manifest_destroy(pManifest);
20872113
20882114
if( useCksum ){
20892115
/* Verify that the repository checksum matches the expected checksum
20902116
** calculated before the check-in started (and stored as the R record
20912117
** of the manifest file).
20922118
--- src/checkin.c
+++ src/checkin.c
@@ -113,10 +113,18 @@
113 blob_appendf(report, "ADDED_BY_MERGE %s\n", zDisplayName);
114 }else if( isChnged==4 ){
115 blob_appendf(report, "UPDATED_BY_INTEGRATE %s\n", zDisplayName);
116 }else if( isChnged==5 ){
117 blob_appendf(report, "ADDED_BY_INTEGRATE %s\n", zDisplayName);
 
 
 
 
 
 
 
 
118 }else if( file_contains_merge_marker(zFullName) ){
119 blob_appendf(report, "CONFLICT %s\n", zDisplayName);
120 }else{
121 blob_appendf(report, "EDITED %s\n", zDisplayName);
122 }
@@ -1633,10 +1641,12 @@
1633 int dryRunFlag; /* True for a test run. Debugging only */
1634 CheckinInfo sCiInfo; /* Information about this check-in */
1635 const char *zComFile; /* Read commit message from this file */
1636 int nTag = 0; /* Number of --tag arguments */
1637 const char *zTag; /* A single --tag argument */
 
 
1638 Blob manifest; /* Manifest in baseline form */
1639 Blob muuid; /* Manifest uuid */
1640 Blob cksum1, cksum2; /* Before and after commit checksums */
1641 Blob cksum1b; /* Checksum recorded in the manifest */
1642 int szD; /* Size of the delta manifest */
@@ -1900,11 +1910,11 @@
1900 /* Step 2: Insert records for all modified files into the blob
1901 ** table. If there were arguments passed to this command, only
1902 ** the identified files are inserted (if they have been modified).
1903 */
1904 db_prepare(&q,
1905 "SELECT id, %Q || pathname, mrid, %s, chnged, %s, %s FROM vfile "
1906 "WHERE chnged==1 AND NOT deleted AND is_selected(id)",
1907 g.zLocalRoot,
1908 glob_expr("pathname", db_get("crnl-glob","")),
1909 glob_expr("pathname", db_get("binary-glob","")),
1910 glob_expr("pathname", db_get("encoding-glob",""))
@@ -1911,19 +1921,18 @@
1911 );
1912 while( db_step(&q)==SQLITE_ROW ){
1913 int id, rid;
1914 const char *zFullname;
1915 Blob content;
1916 int crnlOk, binOk, encodingOk, chnged;
1917
1918 id = db_column_int(&q, 0);
1919 zFullname = db_column_text(&q, 1);
1920 rid = db_column_int(&q, 2);
1921 crnlOk = db_column_int(&q, 3);
1922 chnged = db_column_int(&q, 4);
1923 binOk = db_column_int(&q, 5);
1924 encodingOk = db_column_int(&q, 6);
1925
1926 blob_zero(&content);
1927 if( file_wd_islink(zFullname) ){
1928 /* Instead of file content, put link destination path */
1929 blob_read_link(&content, zFullname);
@@ -1933,11 +1942,11 @@
1933 /* Do not emit any warnings when they are disabled. */
1934 if( !noWarningFlag ){
1935 abortCommit |= commit_warning(&content, crnlOk, binOk,
1936 encodingOk, zFullname);
1937 }
1938 if( chnged==1 && contains_merge_marker(&content) ){
1939 Blob fname; /* Relative pathname of the file */
1940
1941 nConflict++;
1942 file_relative_name(zFullname, &fname, 0);
1943 fossil_print("possible unresolved merge conflict in %s\n",
@@ -2071,11 +2080,10 @@
2071 blob_write_to_file(&muuid, zManifestFile);
2072 free(zManifestFile);
2073 blob_reset(&muuid);
2074 }
2075
2076
2077 /* Update the vfile and vmerge tables */
2078 db_multi_exec(
2079 "DELETE FROM vfile WHERE (vid!=%d OR deleted) AND is_selected(id);"
2080 "DELETE FROM vmerge;"
2081 "UPDATE vfile SET vid=%d;"
@@ -2082,10 +2090,28 @@
2082 "UPDATE vfile SET rid=mrid, chnged=0, deleted=0, origname=NULL"
2083 " WHERE is_selected(id);"
2084 , vid, nvid
2085 );
2086 db_lset_int("checkout", nvid);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2087
2088 if( useCksum ){
2089 /* Verify that the repository checksum matches the expected checksum
2090 ** calculated before the check-in started (and stored as the R record
2091 ** of the manifest file).
2092
--- src/checkin.c
+++ src/checkin.c
@@ -113,10 +113,18 @@
113 blob_appendf(report, "ADDED_BY_MERGE %s\n", zDisplayName);
114 }else if( isChnged==4 ){
115 blob_appendf(report, "UPDATED_BY_INTEGRATE %s\n", zDisplayName);
116 }else if( isChnged==5 ){
117 blob_appendf(report, "ADDED_BY_INTEGRATE %s\n", zDisplayName);
118 }else if( isChnged==6 ){
119 blob_appendf(report, "EXECUTABLE %s\n", zDisplayName);
120 }else if( isChnged==7 ){
121 blob_appendf(report, "SYMLINK %s\n", zDisplayName);
122 }else if( isChnged==8 ){
123 blob_appendf(report, "UNEXEC %s\n", zDisplayName);
124 }else if( isChnged==9 ){
125 blob_appendf(report, "UNLINK %s\n", zDisplayName);
126 }else if( file_contains_merge_marker(zFullName) ){
127 blob_appendf(report, "CONFLICT %s\n", zDisplayName);
128 }else{
129 blob_appendf(report, "EDITED %s\n", zDisplayName);
130 }
@@ -1633,10 +1641,12 @@
1641 int dryRunFlag; /* True for a test run. Debugging only */
1642 CheckinInfo sCiInfo; /* Information about this check-in */
1643 const char *zComFile; /* Read commit message from this file */
1644 int nTag = 0; /* Number of --tag arguments */
1645 const char *zTag; /* A single --tag argument */
1646 ManifestFile *pFile; /* File structure in the manifest */
1647 Manifest *pManifest; /* Manifest structure */
1648 Blob manifest; /* Manifest in baseline form */
1649 Blob muuid; /* Manifest uuid */
1650 Blob cksum1, cksum2; /* Before and after commit checksums */
1651 Blob cksum1b; /* Checksum recorded in the manifest */
1652 int szD; /* Size of the delta manifest */
@@ -1900,11 +1910,11 @@
1910 /* Step 2: Insert records for all modified files into the blob
1911 ** table. If there were arguments passed to this command, only
1912 ** the identified files are inserted (if they have been modified).
1913 */
1914 db_prepare(&q,
1915 "SELECT id, %Q || pathname, mrid, %s, %s, %s FROM vfile "
1916 "WHERE chnged==1 AND NOT deleted AND is_selected(id)",
1917 g.zLocalRoot,
1918 glob_expr("pathname", db_get("crnl-glob","")),
1919 glob_expr("pathname", db_get("binary-glob","")),
1920 glob_expr("pathname", db_get("encoding-glob",""))
@@ -1911,19 +1921,18 @@
1921 );
1922 while( db_step(&q)==SQLITE_ROW ){
1923 int id, rid;
1924 const char *zFullname;
1925 Blob content;
1926 int crnlOk, binOk, encodingOk;
1927
1928 id = db_column_int(&q, 0);
1929 zFullname = db_column_text(&q, 1);
1930 rid = db_column_int(&q, 2);
1931 crnlOk = db_column_int(&q, 3);
1932 binOk = db_column_int(&q, 4);
1933 encodingOk = db_column_int(&q, 5);
 
1934
1935 blob_zero(&content);
1936 if( file_wd_islink(zFullname) ){
1937 /* Instead of file content, put link destination path */
1938 blob_read_link(&content, zFullname);
@@ -1933,11 +1942,11 @@
1942 /* Do not emit any warnings when they are disabled. */
1943 if( !noWarningFlag ){
1944 abortCommit |= commit_warning(&content, crnlOk, binOk,
1945 encodingOk, zFullname);
1946 }
1947 if( contains_merge_marker(&content) ){
1948 Blob fname; /* Relative pathname of the file */
1949
1950 nConflict++;
1951 file_relative_name(zFullname, &fname, 0);
1952 fossil_print("possible unresolved merge conflict in %s\n",
@@ -2071,11 +2080,10 @@
2080 blob_write_to_file(&muuid, zManifestFile);
2081 free(zManifestFile);
2082 blob_reset(&muuid);
2083 }
2084
 
2085 /* Update the vfile and vmerge tables */
2086 db_multi_exec(
2087 "DELETE FROM vfile WHERE (vid!=%d OR deleted) AND is_selected(id);"
2088 "DELETE FROM vmerge;"
2089 "UPDATE vfile SET vid=%d;"
@@ -2082,10 +2090,28 @@
2090 "UPDATE vfile SET rid=mrid, chnged=0, deleted=0, origname=NULL"
2091 " WHERE is_selected(id);"
2092 , vid, nvid
2093 );
2094 db_lset_int("checkout", nvid);
2095
2096 /* Update the isexe and islink columns of the vfile table */
2097 db_prepare(&q,
2098 "UPDATE vfile SET isexe=:exec, islink=:link"
2099 " WHERE vid=:vid AND pathname=:path AND (isexe!=:exec OR islink!=:link)"
2100 );
2101 db_bind_int(&q, ":vid", nvid);
2102 pManifest = manifest_get(nvid, CFTYPE_MANIFEST, 0);
2103 manifest_file_rewind(pManifest);
2104 while( (pFile = manifest_file_next(pManifest, 0)) ){
2105 db_bind_int(&q, ":exec", pFile->zPerm && strstr(pFile->zPerm, "x"));
2106 db_bind_int(&q, ":link", pFile->zPerm && strstr(pFile->zPerm, "l"));
2107 db_bind_text(&q, ":path", pFile->zName);
2108 db_step(&q);
2109 db_reset(&q);
2110 }
2111 db_finalize(&q);
2112 manifest_destroy(pManifest);
2113
2114 if( useCksum ){
2115 /* Verify that the repository checksum matches the expected checksum
2116 ** calculated before the check-in started (and stored as the R record
2117 ** of the manifest file).
2118
+52 -23
--- src/db.c
+++ src/db.c
@@ -1894,53 +1894,72 @@
18941894
** might be generated.
18951895
*/
18961896
char *db_get_versioned(const char *zName, char *zNonVersionedSetting){
18971897
char *zVersionedSetting = 0;
18981898
int noWarn = 0;
1899
+ int found = 0;
18991900
struct _cacheEntry {
19001901
struct _cacheEntry *next;
19011902
const char *zName, *zValue;
19021903
} *cacheEntry = 0;
19031904
static struct _cacheEntry *cache = 0;
19041905
1905
- if( !g.localOpen) return zNonVersionedSetting;
1906
+ if( !g.localOpen && g.zOpenRevision==0 ) return zNonVersionedSetting;
19061907
/* Look up name in cache */
19071908
cacheEntry = cache;
19081909
while( cacheEntry!=0 ){
19091910
if( fossil_strcmp(cacheEntry->zName, zName)==0 ){
19101911
zVersionedSetting = fossil_strdup(cacheEntry->zValue);
19111912
break;
19121913
}
19131914
cacheEntry = cacheEntry->next;
19141915
}
1915
- /* Attempt to read value from file in checkout if there wasn't a cache hit
1916
- ** and a checkout is open. */
1916
+ /* Attempt to read value from file in checkout if there wasn't a cache hit. */
19171917
if( cacheEntry==0 ){
19181918
Blob versionedPathname;
1919
- char *zVersionedPathname;
1919
+ Blob setting;
19201920
blob_zero(&versionedPathname);
1921
+ blob_zero(&setting);
19211922
blob_appendf(&versionedPathname, "%s.fossil-settings/%s",
19221923
g.zLocalRoot, zName);
1923
- zVersionedPathname = blob_str(&versionedPathname);
1924
- if( file_size(zVersionedPathname)>=0 ){
1924
+ if( !g.localOpen ){
1925
+ /* Repository is in the process of being opened, but files have not been
1926
+ * written to disk. Load from the database. */
1927
+ Blob noWarnFile;
1928
+ if( historical_version_of_file(g.zOpenRevision,
1929
+ blob_str(&versionedPathname),
1930
+ &setting, 0, 0, 0, 2)!=2 ){
1931
+ found = 1;
1932
+ }
1933
+ /* See if there's a no-warn flag */
1934
+ blob_append(&versionedPathname, ".no-warn", -1);
1935
+ blob_zero(&noWarnFile);
1936
+ if( historical_version_of_file(g.zOpenRevision,
1937
+ blob_str(&versionedPathname),
1938
+ &noWarnFile, 0, 0, 0, 2)!=2 ){
1939
+ noWarn = 1;
1940
+ }
1941
+ blob_reset(&noWarnFile);
1942
+ }else if( file_size(blob_str(&versionedPathname))>=0 ){
19251943
/* File exists, and contains the value for this setting. Load from
19261944
** the file. */
1927
- Blob setting;
1928
- blob_zero(&setting);
1929
- if( blob_read_from_file(&setting, zVersionedPathname) >= 0 ){
1930
- blob_trim(&setting); /* Avoid non-obvious problems with line endings
1931
- ** on boolean properties */
1932
- zVersionedSetting = fossil_strdup(blob_str(&setting));
1933
- }
1934
- blob_reset(&setting);
1945
+ if( blob_read_from_file(&setting, blob_str(&versionedPathname))>=0 ){
1946
+ found = 1;
1947
+ }
19351948
/* See if there's a no-warn flag */
19361949
blob_append(&versionedPathname, ".no-warn", -1);
19371950
if( file_size(blob_str(&versionedPathname))>=0 ){
19381951
noWarn = 1;
19391952
}
19401953
}
19411954
blob_reset(&versionedPathname);
1955
+ if( found ){
1956
+ blob_trim(&setting); /* Avoid non-obvious problems with line endings
1957
+ ** on boolean properties */
1958
+ zVersionedSetting = fossil_strdup(blob_str(&setting));
1959
+ }
1960
+ blob_reset(&setting);
19421961
/* Store result in cache, which can be the value or 0 if not found */
19431962
cacheEntry = (struct _cacheEntry*)fossil_malloc(sizeof(struct _cacheEntry));
19441963
cacheEntry->next = cache;
19451964
cacheEntry->zName = zName;
19461965
cacheEntry->zValue = fossil_strdup(zVersionedSetting);
@@ -2198,12 +2217,10 @@
21982217
void cmd_open(void){
21992218
int emptyFlag;
22002219
int keepFlag;
22012220
int forceMissingFlag;
22022221
int allowNested;
2203
- char **oldArgv;
2204
- int oldArgc;
22052222
static char *azNewArgv[] = { 0, "checkout", "--prompt", 0, 0, 0, 0 };
22062223
22072224
url_proxy_options();
22082225
emptyFlag = find_option("empty",0,0)!=0;
22092226
keepFlag = find_option("keep",0,0)!=0;
@@ -2218,10 +2235,26 @@
22182235
}
22192236
if( !allowNested && db_open_local(0) ){
22202237
fossil_fatal("already within an open tree rooted at %s", g.zLocalRoot);
22212238
}
22222239
db_open_repository(g.argv[2]);
2240
+
2241
+ /* Figure out which revision to open. */
2242
+ if( !emptyFlag ){
2243
+ if( g.argc==4 ){
2244
+ g.zOpenRevision = g.argv[3];
2245
+ }else if( db_exists("SELECT 1 FROM event WHERE type='ci'") ){
2246
+ g.zOpenRevision = db_get("main-branch", "trunk");
2247
+ }
2248
+ }
2249
+
2250
+ if( g.zOpenRevision ){
2251
+ /* Since the repository is open and we know the revision now,
2252
+ ** refresh the allow-symlinks flag. */
2253
+ g.allowSymlinks = db_get_boolean("allow-symlinks", 0);
2254
+ }
2255
+
22232256
#if defined(_WIN32) || defined(__CYGWIN__)
22242257
# define LOCALDB_NAME "./_FOSSIL_"
22252258
#else
22262259
# define LOCALDB_NAME "./.fslckout"
22272260
#endif
@@ -2233,22 +2266,18 @@
22332266
db_delete_on_failure(LOCALDB_NAME);
22342267
db_open_local(0);
22352268
db_lset("repository", g.argv[2]);
22362269
db_record_repository_filename(g.argv[2]);
22372270
db_lset_int("checkout", 0);
2238
- oldArgv = g.argv;
2239
- oldArgc = g.argc;
22402271
azNewArgv[0] = g.argv[0];
22412272
g.argv = azNewArgv;
22422273
if( !emptyFlag ){
22432274
g.argc = 3;
2244
- if( oldArgc==4 ){
2245
- azNewArgv[g.argc-1] = oldArgv[3];
2246
- }else if( !db_exists("SELECT 1 FROM event WHERE type='ci'") ){
2247
- azNewArgv[g.argc-1] = "--latest";
2275
+ if( g.zOpenRevision ){
2276
+ azNewArgv[g.argc-1] = g.zOpenRevision;
22482277
}else{
2249
- azNewArgv[g.argc-1] = db_get("main-branch", "trunk");
2278
+ azNewArgv[g.argc-1] = "--latest";
22502279
}
22512280
if( keepFlag ){
22522281
azNewArgv[g.argc++] = "--keep";
22532282
}
22542283
if( forceMissingFlag ){
22552284
--- src/db.c
+++ src/db.c
@@ -1894,53 +1894,72 @@
1894 ** might be generated.
1895 */
1896 char *db_get_versioned(const char *zName, char *zNonVersionedSetting){
1897 char *zVersionedSetting = 0;
1898 int noWarn = 0;
 
1899 struct _cacheEntry {
1900 struct _cacheEntry *next;
1901 const char *zName, *zValue;
1902 } *cacheEntry = 0;
1903 static struct _cacheEntry *cache = 0;
1904
1905 if( !g.localOpen) return zNonVersionedSetting;
1906 /* Look up name in cache */
1907 cacheEntry = cache;
1908 while( cacheEntry!=0 ){
1909 if( fossil_strcmp(cacheEntry->zName, zName)==0 ){
1910 zVersionedSetting = fossil_strdup(cacheEntry->zValue);
1911 break;
1912 }
1913 cacheEntry = cacheEntry->next;
1914 }
1915 /* Attempt to read value from file in checkout if there wasn't a cache hit
1916 ** and a checkout is open. */
1917 if( cacheEntry==0 ){
1918 Blob versionedPathname;
1919 char *zVersionedPathname;
1920 blob_zero(&versionedPathname);
 
1921 blob_appendf(&versionedPathname, "%s.fossil-settings/%s",
1922 g.zLocalRoot, zName);
1923 zVersionedPathname = blob_str(&versionedPathname);
1924 if( file_size(zVersionedPathname)>=0 ){
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1925 /* File exists, and contains the value for this setting. Load from
1926 ** the file. */
1927 Blob setting;
1928 blob_zero(&setting);
1929 if( blob_read_from_file(&setting, zVersionedPathname) >= 0 ){
1930 blob_trim(&setting); /* Avoid non-obvious problems with line endings
1931 ** on boolean properties */
1932 zVersionedSetting = fossil_strdup(blob_str(&setting));
1933 }
1934 blob_reset(&setting);
1935 /* See if there's a no-warn flag */
1936 blob_append(&versionedPathname, ".no-warn", -1);
1937 if( file_size(blob_str(&versionedPathname))>=0 ){
1938 noWarn = 1;
1939 }
1940 }
1941 blob_reset(&versionedPathname);
 
 
 
 
 
 
1942 /* Store result in cache, which can be the value or 0 if not found */
1943 cacheEntry = (struct _cacheEntry*)fossil_malloc(sizeof(struct _cacheEntry));
1944 cacheEntry->next = cache;
1945 cacheEntry->zName = zName;
1946 cacheEntry->zValue = fossil_strdup(zVersionedSetting);
@@ -2198,12 +2217,10 @@
2198 void cmd_open(void){
2199 int emptyFlag;
2200 int keepFlag;
2201 int forceMissingFlag;
2202 int allowNested;
2203 char **oldArgv;
2204 int oldArgc;
2205 static char *azNewArgv[] = { 0, "checkout", "--prompt", 0, 0, 0, 0 };
2206
2207 url_proxy_options();
2208 emptyFlag = find_option("empty",0,0)!=0;
2209 keepFlag = find_option("keep",0,0)!=0;
@@ -2218,10 +2235,26 @@
2218 }
2219 if( !allowNested && db_open_local(0) ){
2220 fossil_fatal("already within an open tree rooted at %s", g.zLocalRoot);
2221 }
2222 db_open_repository(g.argv[2]);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2223 #if defined(_WIN32) || defined(__CYGWIN__)
2224 # define LOCALDB_NAME "./_FOSSIL_"
2225 #else
2226 # define LOCALDB_NAME "./.fslckout"
2227 #endif
@@ -2233,22 +2266,18 @@
2233 db_delete_on_failure(LOCALDB_NAME);
2234 db_open_local(0);
2235 db_lset("repository", g.argv[2]);
2236 db_record_repository_filename(g.argv[2]);
2237 db_lset_int("checkout", 0);
2238 oldArgv = g.argv;
2239 oldArgc = g.argc;
2240 azNewArgv[0] = g.argv[0];
2241 g.argv = azNewArgv;
2242 if( !emptyFlag ){
2243 g.argc = 3;
2244 if( oldArgc==4 ){
2245 azNewArgv[g.argc-1] = oldArgv[3];
2246 }else if( !db_exists("SELECT 1 FROM event WHERE type='ci'") ){
2247 azNewArgv[g.argc-1] = "--latest";
2248 }else{
2249 azNewArgv[g.argc-1] = db_get("main-branch", "trunk");
2250 }
2251 if( keepFlag ){
2252 azNewArgv[g.argc++] = "--keep";
2253 }
2254 if( forceMissingFlag ){
2255
--- src/db.c
+++ src/db.c
@@ -1894,53 +1894,72 @@
1894 ** might be generated.
1895 */
1896 char *db_get_versioned(const char *zName, char *zNonVersionedSetting){
1897 char *zVersionedSetting = 0;
1898 int noWarn = 0;
1899 int found = 0;
1900 struct _cacheEntry {
1901 struct _cacheEntry *next;
1902 const char *zName, *zValue;
1903 } *cacheEntry = 0;
1904 static struct _cacheEntry *cache = 0;
1905
1906 if( !g.localOpen && g.zOpenRevision==0 ) return zNonVersionedSetting;
1907 /* Look up name in cache */
1908 cacheEntry = cache;
1909 while( cacheEntry!=0 ){
1910 if( fossil_strcmp(cacheEntry->zName, zName)==0 ){
1911 zVersionedSetting = fossil_strdup(cacheEntry->zValue);
1912 break;
1913 }
1914 cacheEntry = cacheEntry->next;
1915 }
1916 /* Attempt to read value from file in checkout if there wasn't a cache hit. */
 
1917 if( cacheEntry==0 ){
1918 Blob versionedPathname;
1919 Blob setting;
1920 blob_zero(&versionedPathname);
1921 blob_zero(&setting);
1922 blob_appendf(&versionedPathname, "%s.fossil-settings/%s",
1923 g.zLocalRoot, zName);
1924 if( !g.localOpen ){
1925 /* Repository is in the process of being opened, but files have not been
1926 * written to disk. Load from the database. */
1927 Blob noWarnFile;
1928 if( historical_version_of_file(g.zOpenRevision,
1929 blob_str(&versionedPathname),
1930 &setting, 0, 0, 0, 2)!=2 ){
1931 found = 1;
1932 }
1933 /* See if there's a no-warn flag */
1934 blob_append(&versionedPathname, ".no-warn", -1);
1935 blob_zero(&noWarnFile);
1936 if( historical_version_of_file(g.zOpenRevision,
1937 blob_str(&versionedPathname),
1938 &noWarnFile, 0, 0, 0, 2)!=2 ){
1939 noWarn = 1;
1940 }
1941 blob_reset(&noWarnFile);
1942 }else if( file_size(blob_str(&versionedPathname))>=0 ){
1943 /* File exists, and contains the value for this setting. Load from
1944 ** the file. */
1945 if( blob_read_from_file(&setting, blob_str(&versionedPathname))>=0 ){
1946 found = 1;
1947 }
 
 
 
 
 
1948 /* See if there's a no-warn flag */
1949 blob_append(&versionedPathname, ".no-warn", -1);
1950 if( file_size(blob_str(&versionedPathname))>=0 ){
1951 noWarn = 1;
1952 }
1953 }
1954 blob_reset(&versionedPathname);
1955 if( found ){
1956 blob_trim(&setting); /* Avoid non-obvious problems with line endings
1957 ** on boolean properties */
1958 zVersionedSetting = fossil_strdup(blob_str(&setting));
1959 }
1960 blob_reset(&setting);
1961 /* Store result in cache, which can be the value or 0 if not found */
1962 cacheEntry = (struct _cacheEntry*)fossil_malloc(sizeof(struct _cacheEntry));
1963 cacheEntry->next = cache;
1964 cacheEntry->zName = zName;
1965 cacheEntry->zValue = fossil_strdup(zVersionedSetting);
@@ -2198,12 +2217,10 @@
2217 void cmd_open(void){
2218 int emptyFlag;
2219 int keepFlag;
2220 int forceMissingFlag;
2221 int allowNested;
 
 
2222 static char *azNewArgv[] = { 0, "checkout", "--prompt", 0, 0, 0, 0 };
2223
2224 url_proxy_options();
2225 emptyFlag = find_option("empty",0,0)!=0;
2226 keepFlag = find_option("keep",0,0)!=0;
@@ -2218,10 +2235,26 @@
2235 }
2236 if( !allowNested && db_open_local(0) ){
2237 fossil_fatal("already within an open tree rooted at %s", g.zLocalRoot);
2238 }
2239 db_open_repository(g.argv[2]);
2240
2241 /* Figure out which revision to open. */
2242 if( !emptyFlag ){
2243 if( g.argc==4 ){
2244 g.zOpenRevision = g.argv[3];
2245 }else if( db_exists("SELECT 1 FROM event WHERE type='ci'") ){
2246 g.zOpenRevision = db_get("main-branch", "trunk");
2247 }
2248 }
2249
2250 if( g.zOpenRevision ){
2251 /* Since the repository is open and we know the revision now,
2252 ** refresh the allow-symlinks flag. */
2253 g.allowSymlinks = db_get_boolean("allow-symlinks", 0);
2254 }
2255
2256 #if defined(_WIN32) || defined(__CYGWIN__)
2257 # define LOCALDB_NAME "./_FOSSIL_"
2258 #else
2259 # define LOCALDB_NAME "./.fslckout"
2260 #endif
@@ -2233,22 +2266,18 @@
2266 db_delete_on_failure(LOCALDB_NAME);
2267 db_open_local(0);
2268 db_lset("repository", g.argv[2]);
2269 db_record_repository_filename(g.argv[2]);
2270 db_lset_int("checkout", 0);
 
 
2271 azNewArgv[0] = g.argv[0];
2272 g.argv = azNewArgv;
2273 if( !emptyFlag ){
2274 g.argc = 3;
2275 if( g.zOpenRevision ){
2276 azNewArgv[g.argc-1] = g.zOpenRevision;
 
 
2277 }else{
2278 azNewArgv[g.argc-1] = "--latest";
2279 }
2280 if( keepFlag ){
2281 azNewArgv[g.argc++] = "--keep";
2282 }
2283 if( forceMissingFlag ){
2284
--- src/descendants.c
+++ src/descendants.c
@@ -369,18 +369,17 @@
369369
Blob sql;
370370
int showAll = find_option("all", "a", 0)!=0;
371371
int showClosed = find_option("closed", "c", 0)!=0;
372372
int recomputeFlag = find_option("recompute",0,0)!=0;
373373
int showForks = g.argv[1][0]!='l';
374
- int byBranch = (find_option("bybranch",0,0)!=0) || showForks;
375374
int multipleFlag = (find_option("multiple","m",0))!=0 || showForks;
375
+ int byBranch = (find_option("bybranch",0,0)!=0) || multipleFlag;
376376
const char *zWidth = find_option("width","W",1);
377377
char *zLastBr = 0;
378378
int n, width;
379379
char zLineNo[10];
380380
381
- if( multipleFlag ) byBranch = 1;
382381
if( zWidth ){
383382
width = atoi(zWidth);
384383
if( (width!=0) && (width<=39) ){
385384
fossil_fatal("-W|--width value must be >39 or 0");
386385
}
@@ -447,10 +446,14 @@
447446
const char *zCom = db_column_text(&q, 3);
448447
const char *zBr = db_column_text(&q, 7);
449448
char *z;
450449
451450
if( byBranch && fossil_strcmp(zBr, zLastBr)!=0 ){
451
+ if( showForks ){
452
+ fossil_print("WARNING: multiple open leaves on the following branches:\n");
453
+ showForks = 0;
454
+ }
452455
fossil_print("*** %s ***\n", zBr);
453456
fossil_free(zLastBr);
454457
zLastBr = fossil_strdup(zBr);
455458
if( multipleFlag ) n = 0;
456459
}
@@ -461,11 +464,10 @@
461464
comment_print(z, zCom, 7, width, g.comFmtFlags);
462465
fossil_free(z);
463466
}
464467
fossil_free(zLastBr);
465468
db_finalize(&q);
466
- if( showForks && !zLastBr ) fossil_print("*** OK, no multiple leaves on the same branch found ***\n");
467469
}
468470
469471
/*
470472
** WEBPAGE: leaves
471473
**
472474
--- src/descendants.c
+++ src/descendants.c
@@ -369,18 +369,17 @@
369 Blob sql;
370 int showAll = find_option("all", "a", 0)!=0;
371 int showClosed = find_option("closed", "c", 0)!=0;
372 int recomputeFlag = find_option("recompute",0,0)!=0;
373 int showForks = g.argv[1][0]!='l';
374 int byBranch = (find_option("bybranch",0,0)!=0) || showForks;
375 int multipleFlag = (find_option("multiple","m",0))!=0 || showForks;
 
376 const char *zWidth = find_option("width","W",1);
377 char *zLastBr = 0;
378 int n, width;
379 char zLineNo[10];
380
381 if( multipleFlag ) byBranch = 1;
382 if( zWidth ){
383 width = atoi(zWidth);
384 if( (width!=0) && (width<=39) ){
385 fossil_fatal("-W|--width value must be >39 or 0");
386 }
@@ -447,10 +446,14 @@
447 const char *zCom = db_column_text(&q, 3);
448 const char *zBr = db_column_text(&q, 7);
449 char *z;
450
451 if( byBranch && fossil_strcmp(zBr, zLastBr)!=0 ){
 
 
 
 
452 fossil_print("*** %s ***\n", zBr);
453 fossil_free(zLastBr);
454 zLastBr = fossil_strdup(zBr);
455 if( multipleFlag ) n = 0;
456 }
@@ -461,11 +464,10 @@
461 comment_print(z, zCom, 7, width, g.comFmtFlags);
462 fossil_free(z);
463 }
464 fossil_free(zLastBr);
465 db_finalize(&q);
466 if( showForks && !zLastBr ) fossil_print("*** OK, no multiple leaves on the same branch found ***\n");
467 }
468
469 /*
470 ** WEBPAGE: leaves
471 **
472
--- src/descendants.c
+++ src/descendants.c
@@ -369,18 +369,17 @@
369 Blob sql;
370 int showAll = find_option("all", "a", 0)!=0;
371 int showClosed = find_option("closed", "c", 0)!=0;
372 int recomputeFlag = find_option("recompute",0,0)!=0;
373 int showForks = g.argv[1][0]!='l';
 
374 int multipleFlag = (find_option("multiple","m",0))!=0 || showForks;
375 int byBranch = (find_option("bybranch",0,0)!=0) || multipleFlag;
376 const char *zWidth = find_option("width","W",1);
377 char *zLastBr = 0;
378 int n, width;
379 char zLineNo[10];
380
 
381 if( zWidth ){
382 width = atoi(zWidth);
383 if( (width!=0) && (width<=39) ){
384 fossil_fatal("-W|--width value must be >39 or 0");
385 }
@@ -447,10 +446,14 @@
446 const char *zCom = db_column_text(&q, 3);
447 const char *zBr = db_column_text(&q, 7);
448 char *z;
449
450 if( byBranch && fossil_strcmp(zBr, zLastBr)!=0 ){
451 if( showForks ){
452 fossil_print("WARNING: multiple open leaves on the following branches:\n");
453 showForks = 0;
454 }
455 fossil_print("*** %s ***\n", zBr);
456 fossil_free(zLastBr);
457 zLastBr = fossil_strdup(zBr);
458 if( multipleFlag ) n = 0;
459 }
@@ -461,11 +464,10 @@
464 comment_print(z, zCom, 7, width, g.comFmtFlags);
465 fossil_free(z);
466 }
467 fossil_free(zLastBr);
468 db_finalize(&q);
 
469 }
470
471 /*
472 ** WEBPAGE: leaves
473 **
474
--- src/descendants.c
+++ src/descendants.c
@@ -369,18 +369,17 @@
369369
Blob sql;
370370
int showAll = find_option("all", "a", 0)!=0;
371371
int showClosed = find_option("closed", "c", 0)!=0;
372372
int recomputeFlag = find_option("recompute",0,0)!=0;
373373
int showForks = g.argv[1][0]!='l';
374
- int byBranch = (find_option("bybranch",0,0)!=0) || showForks;
375374
int multipleFlag = (find_option("multiple","m",0))!=0 || showForks;
375
+ int byBranch = (find_option("bybranch",0,0)!=0) || multipleFlag;
376376
const char *zWidth = find_option("width","W",1);
377377
char *zLastBr = 0;
378378
int n, width;
379379
char zLineNo[10];
380380
381
- if( multipleFlag ) byBranch = 1;
382381
if( zWidth ){
383382
width = atoi(zWidth);
384383
if( (width!=0) && (width<=39) ){
385384
fossil_fatal("-W|--width value must be >39 or 0");
386385
}
@@ -447,10 +446,14 @@
447446
const char *zCom = db_column_text(&q, 3);
448447
const char *zBr = db_column_text(&q, 7);
449448
char *z;
450449
451450
if( byBranch && fossil_strcmp(zBr, zLastBr)!=0 ){
451
+ if( showForks ){
452
+ fossil_print("WARNING: multiple open leaves on the following branches:\n");
453
+ showForks = 0;
454
+ }
452455
fossil_print("*** %s ***\n", zBr);
453456
fossil_free(zLastBr);
454457
zLastBr = fossil_strdup(zBr);
455458
if( multipleFlag ) n = 0;
456459
}
@@ -461,11 +464,10 @@
461464
comment_print(z, zCom, 7, width, g.comFmtFlags);
462465
fossil_free(z);
463466
}
464467
fossil_free(zLastBr);
465468
db_finalize(&q);
466
- if( showForks && !zLastBr ) fossil_print("*** OK, no multiple leaves on the same branch found ***\n");
467469
}
468470
469471
/*
470472
** WEBPAGE: leaves
471473
**
472474
--- src/descendants.c
+++ src/descendants.c
@@ -369,18 +369,17 @@
369 Blob sql;
370 int showAll = find_option("all", "a", 0)!=0;
371 int showClosed = find_option("closed", "c", 0)!=0;
372 int recomputeFlag = find_option("recompute",0,0)!=0;
373 int showForks = g.argv[1][0]!='l';
374 int byBranch = (find_option("bybranch",0,0)!=0) || showForks;
375 int multipleFlag = (find_option("multiple","m",0))!=0 || showForks;
 
376 const char *zWidth = find_option("width","W",1);
377 char *zLastBr = 0;
378 int n, width;
379 char zLineNo[10];
380
381 if( multipleFlag ) byBranch = 1;
382 if( zWidth ){
383 width = atoi(zWidth);
384 if( (width!=0) && (width<=39) ){
385 fossil_fatal("-W|--width value must be >39 or 0");
386 }
@@ -447,10 +446,14 @@
447 const char *zCom = db_column_text(&q, 3);
448 const char *zBr = db_column_text(&q, 7);
449 char *z;
450
451 if( byBranch && fossil_strcmp(zBr, zLastBr)!=0 ){
 
 
 
 
452 fossil_print("*** %s ***\n", zBr);
453 fossil_free(zLastBr);
454 zLastBr = fossil_strdup(zBr);
455 if( multipleFlag ) n = 0;
456 }
@@ -461,11 +464,10 @@
461 comment_print(z, zCom, 7, width, g.comFmtFlags);
462 fossil_free(z);
463 }
464 fossil_free(zLastBr);
465 db_finalize(&q);
466 if( showForks && !zLastBr ) fossil_print("*** OK, no multiple leaves on the same branch found ***\n");
467 }
468
469 /*
470 ** WEBPAGE: leaves
471 **
472
--- src/descendants.c
+++ src/descendants.c
@@ -369,18 +369,17 @@
369 Blob sql;
370 int showAll = find_option("all", "a", 0)!=0;
371 int showClosed = find_option("closed", "c", 0)!=0;
372 int recomputeFlag = find_option("recompute",0,0)!=0;
373 int showForks = g.argv[1][0]!='l';
 
374 int multipleFlag = (find_option("multiple","m",0))!=0 || showForks;
375 int byBranch = (find_option("bybranch",0,0)!=0) || multipleFlag;
376 const char *zWidth = find_option("width","W",1);
377 char *zLastBr = 0;
378 int n, width;
379 char zLineNo[10];
380
 
381 if( zWidth ){
382 width = atoi(zWidth);
383 if( (width!=0) && (width<=39) ){
384 fossil_fatal("-W|--width value must be >39 or 0");
385 }
@@ -447,10 +446,14 @@
446 const char *zCom = db_column_text(&q, 3);
447 const char *zBr = db_column_text(&q, 7);
448 char *z;
449
450 if( byBranch && fossil_strcmp(zBr, zLastBr)!=0 ){
451 if( showForks ){
452 fossil_print("WARNING: multiple open leaves on the following branches:\n");
453 showForks = 0;
454 }
455 fossil_print("*** %s ***\n", zBr);
456 fossil_free(zLastBr);
457 zLastBr = fossil_strdup(zBr);
458 if( multipleFlag ) n = 0;
459 }
@@ -461,11 +464,10 @@
464 comment_print(z, zCom, 7, width, g.comFmtFlags);
465 fossil_free(z);
466 }
467 fossil_free(zLastBr);
468 db_finalize(&q);
 
469 }
470
471 /*
472 ** WEBPAGE: leaves
473 **
474
+12 -5
--- src/file.c
+++ src/file.c
@@ -386,11 +386,11 @@
386386
FILE *in, *out;
387387
int got;
388388
char zBuf[8192];
389389
in = fossil_fopen(zFrom, "rb");
390390
if( in==0 ) fossil_fatal("cannot open \"%s\" for reading", zFrom);
391
- file_mkfolder(zTo, 0);
391
+ file_mkfolder(zTo, 0, 0);
392392
out = fossil_fopen(zTo, "wb");
393393
if( out==0 ) fossil_fatal("cannot open \"%s\" for writing", zTo);
394394
while( (got=fread(zBuf, 1, sizeof(zBuf), in))>0 ){
395395
fwrite(zBuf, 1, got, out);
396396
}
@@ -530,13 +530,16 @@
530530
}
531531
532532
/*
533533
** Create the tree of directories in which zFilename belongs, if that sequence
534534
** of directories does not already exist.
535
+**
536
+** On success, return zero. On error, return errorReturn if positive, otherwise
537
+** print an error message and abort.
535538
*/
536
-void file_mkfolder(const char *zFilename, int forceFlag){
537
- int i, nName;
539
+int file_mkfolder(const char *zFilename, int forceFlag, int errorReturn){
540
+ int i, nName, rc = 0;
538541
char *zName;
539542
540543
nName = strlen(zFilename);
541544
zName = mprintf("%s", zFilename);
542545
nName = file_simplify_name(zName, nName, 0);
@@ -550,20 +553,24 @@
550553
** C: in this example.
551554
*/
552555
if( !(i==2 && zName[1]==':') ){
553556
#endif
554557
if( file_mkdir(zName, forceFlag) && file_isdir(zName)!=1 ){
555
- fossil_fatal_recursive("unable to create directory %s", zName);
556
- return;
558
+ if (errorReturn <= 0) {
559
+ fossil_fatal_recursive("unable to create directory %s", zName);
560
+ }
561
+ rc = errorReturn;
562
+ break;
557563
}
558564
#if defined(_WIN32) || defined(__CYGWIN__)
559565
}
560566
#endif
561567
zName[i] = '/';
562568
}
563569
}
564570
free(zName);
571
+ return rc;
565572
}
566573
567574
/*
568575
** Removes the directory named in the argument, if it exists. The directory
569576
** must be empty and cannot be the current directory or the root directory.
570577
--- src/file.c
+++ src/file.c
@@ -386,11 +386,11 @@
386 FILE *in, *out;
387 int got;
388 char zBuf[8192];
389 in = fossil_fopen(zFrom, "rb");
390 if( in==0 ) fossil_fatal("cannot open \"%s\" for reading", zFrom);
391 file_mkfolder(zTo, 0);
392 out = fossil_fopen(zTo, "wb");
393 if( out==0 ) fossil_fatal("cannot open \"%s\" for writing", zTo);
394 while( (got=fread(zBuf, 1, sizeof(zBuf), in))>0 ){
395 fwrite(zBuf, 1, got, out);
396 }
@@ -530,13 +530,16 @@
530 }
531
532 /*
533 ** Create the tree of directories in which zFilename belongs, if that sequence
534 ** of directories does not already exist.
 
 
 
535 */
536 void file_mkfolder(const char *zFilename, int forceFlag){
537 int i, nName;
538 char *zName;
539
540 nName = strlen(zFilename);
541 zName = mprintf("%s", zFilename);
542 nName = file_simplify_name(zName, nName, 0);
@@ -550,20 +553,24 @@
550 ** C: in this example.
551 */
552 if( !(i==2 && zName[1]==':') ){
553 #endif
554 if( file_mkdir(zName, forceFlag) && file_isdir(zName)!=1 ){
555 fossil_fatal_recursive("unable to create directory %s", zName);
556 return;
 
 
 
557 }
558 #if defined(_WIN32) || defined(__CYGWIN__)
559 }
560 #endif
561 zName[i] = '/';
562 }
563 }
564 free(zName);
 
565 }
566
567 /*
568 ** Removes the directory named in the argument, if it exists. The directory
569 ** must be empty and cannot be the current directory or the root directory.
570
--- src/file.c
+++ src/file.c
@@ -386,11 +386,11 @@
386 FILE *in, *out;
387 int got;
388 char zBuf[8192];
389 in = fossil_fopen(zFrom, "rb");
390 if( in==0 ) fossil_fatal("cannot open \"%s\" for reading", zFrom);
391 file_mkfolder(zTo, 0, 0);
392 out = fossil_fopen(zTo, "wb");
393 if( out==0 ) fossil_fatal("cannot open \"%s\" for writing", zTo);
394 while( (got=fread(zBuf, 1, sizeof(zBuf), in))>0 ){
395 fwrite(zBuf, 1, got, out);
396 }
@@ -530,13 +530,16 @@
530 }
531
532 /*
533 ** Create the tree of directories in which zFilename belongs, if that sequence
534 ** of directories does not already exist.
535 **
536 ** On success, return zero. On error, return errorReturn if positive, otherwise
537 ** print an error message and abort.
538 */
539 int file_mkfolder(const char *zFilename, int forceFlag, int errorReturn){
540 int i, nName, rc = 0;
541 char *zName;
542
543 nName = strlen(zFilename);
544 zName = mprintf("%s", zFilename);
545 nName = file_simplify_name(zName, nName, 0);
@@ -550,20 +553,24 @@
553 ** C: in this example.
554 */
555 if( !(i==2 && zName[1]==':') ){
556 #endif
557 if( file_mkdir(zName, forceFlag) && file_isdir(zName)!=1 ){
558 if (errorReturn <= 0) {
559 fossil_fatal_recursive("unable to create directory %s", zName);
560 }
561 rc = errorReturn;
562 break;
563 }
564 #if defined(_WIN32) || defined(__CYGWIN__)
565 }
566 #endif
567 zName[i] = '/';
568 }
569 }
570 free(zName);
571 return rc;
572 }
573
574 /*
575 ** Removes the directory named in the argument, if it exists. The directory
576 ** must be empty and cannot be the current directory or the root directory.
577
+3 -8
--- src/finfo.c
+++ src/finfo.c
@@ -182,11 +182,11 @@
182182
if( rid==0 ){
183183
fossil_fatal("no history for file: %b", &fname);
184184
}
185185
zFilename = blob_str(&fname);
186186
db_prepare(&q,
187
- "SELECT b.uuid, ci.uuid, date(event.mtime%s),"
187
+ "SELECT DISTINCT b.uuid, ci.uuid, date(event.mtime%s),"
188188
" coalesce(event.ecomment, event.comment),"
189189
" coalesce(event.euser, event.user),"
190190
" (SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0"
191191
" AND tagxref.rid=mlink.mid)" /* Tags */
192192
" FROM mlink, blob b, event, blob ci, filename"
@@ -403,12 +403,10 @@
403403
if( fShowId ) blob_appendf(&title, " (%d)", fnid);
404404
}
405405
@ <h2>%b(&title)</h2>
406406
blob_reset(&title);
407407
pGraph = graph_init();
408
- @ <div id="canvas" style="position:relative;width:1px;height:1px;"
409
- @ onclick="clickOnGraph(event)"></div>
410408
@ <table id="timelineTable" class="timelineTable">
411409
while( db_step(&q)==SQLITE_ROW ){
412410
const char *zDate = db_column_text(&q, 0);
413411
const char *zCom = db_column_text(&q, 1);
414412
const char *zUser = db_column_text(&q, 2);
@@ -459,11 +457,11 @@
459457
}
460458
memcpy(zTime, &zDate[11], 5);
461459
zTime[5] = 0;
462460
@ <tr><td class="timelineTime">
463461
@ %z(href("%R/timeline?c=%t",zDate))%s(zTime)</a></td>
464
- @ <td class="timelineGraph"><div id="m%d(gidx)"></div></td>
462
+ @ <td class="timelineGraph"><div id="m%d(gidx)" class="tl-nodemark"></div></td>
465463
if( zBgClr && zBgClr[0] ){
466464
@ <td class="timelineTableCell" style="background-color: %h(zBgClr);">
467465
}else{
468466
@ <td class="timelineTableCell">
469467
}
@@ -536,15 +534,12 @@
536534
graph_finish(pGraph, 1);
537535
if( pGraph->nErr ){
538536
graph_free(pGraph);
539537
pGraph = 0;
540538
}else{
541
- int w = pGraph->mxRail*pGraph->iRailPitch + 28;
542
- @ <tr><td></td><td>
543
- @ <div id="grbtm" style="width:%d(w)px;"></div>
544
- @ </td><td></td></tr>
539
+ @ <tr class="timelineBottom"><td></td><td></td><td></td></tr>
545540
}
546541
}
547542
@ </table>
548543
timeline_output_graph_javascript(pGraph, 0, 1);
549544
style_footer();
550545
}
551546
--- src/finfo.c
+++ src/finfo.c
@@ -182,11 +182,11 @@
182 if( rid==0 ){
183 fossil_fatal("no history for file: %b", &fname);
184 }
185 zFilename = blob_str(&fname);
186 db_prepare(&q,
187 "SELECT b.uuid, ci.uuid, date(event.mtime%s),"
188 " coalesce(event.ecomment, event.comment),"
189 " coalesce(event.euser, event.user),"
190 " (SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0"
191 " AND tagxref.rid=mlink.mid)" /* Tags */
192 " FROM mlink, blob b, event, blob ci, filename"
@@ -403,12 +403,10 @@
403 if( fShowId ) blob_appendf(&title, " (%d)", fnid);
404 }
405 @ <h2>%b(&title)</h2>
406 blob_reset(&title);
407 pGraph = graph_init();
408 @ <div id="canvas" style="position:relative;width:1px;height:1px;"
409 @ onclick="clickOnGraph(event)"></div>
410 @ <table id="timelineTable" class="timelineTable">
411 while( db_step(&q)==SQLITE_ROW ){
412 const char *zDate = db_column_text(&q, 0);
413 const char *zCom = db_column_text(&q, 1);
414 const char *zUser = db_column_text(&q, 2);
@@ -459,11 +457,11 @@
459 }
460 memcpy(zTime, &zDate[11], 5);
461 zTime[5] = 0;
462 @ <tr><td class="timelineTime">
463 @ %z(href("%R/timeline?c=%t",zDate))%s(zTime)</a></td>
464 @ <td class="timelineGraph"><div id="m%d(gidx)"></div></td>
465 if( zBgClr && zBgClr[0] ){
466 @ <td class="timelineTableCell" style="background-color: %h(zBgClr);">
467 }else{
468 @ <td class="timelineTableCell">
469 }
@@ -536,15 +534,12 @@
536 graph_finish(pGraph, 1);
537 if( pGraph->nErr ){
538 graph_free(pGraph);
539 pGraph = 0;
540 }else{
541 int w = pGraph->mxRail*pGraph->iRailPitch + 28;
542 @ <tr><td></td><td>
543 @ <div id="grbtm" style="width:%d(w)px;"></div>
544 @ </td><td></td></tr>
545 }
546 }
547 @ </table>
548 timeline_output_graph_javascript(pGraph, 0, 1);
549 style_footer();
550 }
551
--- src/finfo.c
+++ src/finfo.c
@@ -182,11 +182,11 @@
182 if( rid==0 ){
183 fossil_fatal("no history for file: %b", &fname);
184 }
185 zFilename = blob_str(&fname);
186 db_prepare(&q,
187 "SELECT DISTINCT b.uuid, ci.uuid, date(event.mtime%s),"
188 " coalesce(event.ecomment, event.comment),"
189 " coalesce(event.euser, event.user),"
190 " (SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0"
191 " AND tagxref.rid=mlink.mid)" /* Tags */
192 " FROM mlink, blob b, event, blob ci, filename"
@@ -403,12 +403,10 @@
403 if( fShowId ) blob_appendf(&title, " (%d)", fnid);
404 }
405 @ <h2>%b(&title)</h2>
406 blob_reset(&title);
407 pGraph = graph_init();
 
 
408 @ <table id="timelineTable" class="timelineTable">
409 while( db_step(&q)==SQLITE_ROW ){
410 const char *zDate = db_column_text(&q, 0);
411 const char *zCom = db_column_text(&q, 1);
412 const char *zUser = db_column_text(&q, 2);
@@ -459,11 +457,11 @@
457 }
458 memcpy(zTime, &zDate[11], 5);
459 zTime[5] = 0;
460 @ <tr><td class="timelineTime">
461 @ %z(href("%R/timeline?c=%t",zDate))%s(zTime)</a></td>
462 @ <td class="timelineGraph"><div id="m%d(gidx)" class="tl-nodemark"></div></td>
463 if( zBgClr && zBgClr[0] ){
464 @ <td class="timelineTableCell" style="background-color: %h(zBgClr);">
465 }else{
466 @ <td class="timelineTableCell">
467 }
@@ -536,15 +534,12 @@
534 graph_finish(pGraph, 1);
535 if( pGraph->nErr ){
536 graph_free(pGraph);
537 pGraph = 0;
538 }else{
539 @ <tr class="timelineBottom"><td></td><td></td><td></td></tr>
 
 
 
540 }
541 }
542 @ </table>
543 timeline_output_graph_javascript(pGraph, 0, 1);
544 style_footer();
545 }
546
+8 -15
--- src/graph.c
+++ src/graph.c
@@ -47,11 +47,11 @@
4747
u8 isDup; /* True if this is duplicate of a prior entry */
4848
u8 isLeaf; /* True if this is a leaf node */
4949
u8 timeWarp; /* Child is earlier in time */
5050
u8 bDescender; /* True if riser from bottom of graph to here. */
5151
i8 iRail; /* Which rail this check-in appears on. 0-based.*/
52
- i8 mergeOut; /* Merge out on rail mergeOut/4. -1 for none */
52
+ i8 mergeOut; /* Merge out to this rail. -1 if no merge-out */
5353
u8 mergeIn[GR_MAX_RAIL]; /* Merge in from non-zero rails */
5454
int aiRiser[GR_MAX_RAIL]; /* Risers from this node to a higher row. */
5555
int mergeUpto; /* Draw the mergeOut rail up to this level */
5656
u64 mergeDown; /* Draw merge lines up from bottom of graph */
5757
@@ -61,11 +61,10 @@
6161
/* Context while building a graph
6262
*/
6363
struct GraphContext {
6464
int nErr; /* Number of errors encountered */
6565
int mxRail; /* Number of rails required to render the graph */
66
- int iRailPitch; /* Pixels between rail centers */
6766
GraphRow *pFirst; /* First row in the list */
6867
GraphRow *pLast; /* Last row in the list */
6968
int nBranch; /* Number of distinct branches */
7069
char **azBranch; /* Names of the branches */
7170
int nRow; /* Number of rows */
@@ -294,28 +293,27 @@
294293
u = pParent->aiRiser[pParent->iRail];
295294
if( u>=0 && u<pChild->idx ){
296295
/* The thick arrow up to the next primary child of pDesc goes
297296
** further up than the thin merge arrow riser, so draw them both
298297
** on the same rail. */
299
- pParent->mergeOut = pParent->iRail*4;
300
- if( pParent->iRail<pChild->iRail ) pParent->mergeOut += 2;
298
+ pParent->mergeOut = pParent->iRail;
301299
pParent->mergeUpto = pChild->idx;
302300
}else{
303301
/* The thin merge arrow riser is taller than the thick primary
304302
** child riser, so use separate rails. */
305303
int iTarget = pParent->iRail;
306304
pParent->mergeOut = findFreeRail(p, pChild->idx, pParent->idx-1,
307
- 0, iTarget)*4 + 1;
305
+ 0, iTarget);
308306
pParent->mergeUpto = pChild->idx;
309
- mask = BIT(pParent->mergeOut/4);
307
+ mask = BIT(pParent->mergeOut);
310308
for(pLoop=pChild->pNext; pLoop && pLoop->rid!=pParent->rid;
311309
pLoop=pLoop->pNext){
312310
pLoop->railInUse |= mask;
313311
}
314312
}
315313
}
316
- pChild->mergeIn[pParent->mergeOut/4] = (pParent->mergeOut&3)+1;
314
+ pChild->mergeIn[pParent->mergeOut] = 1;
317315
}
318316
319317
/*
320318
** Compute the maximum rail number.
321319
*/
@@ -322,11 +320,11 @@
322320
static void find_max_rail(GraphContext *p){
323321
GraphRow *pRow;
324322
p->mxRail = 0;
325323
for(pRow=p->pFirst; pRow; pRow=pRow->pNext){
326324
if( pRow->iRail>p->mxRail ) p->mxRail = pRow->iRail;
327
- if( pRow->mergeOut/4>p->mxRail ) p->mxRail = pRow->mergeOut/4;
325
+ if( pRow->mergeOut>p->mxRail ) p->mxRail = pRow->mergeOut;
328326
while( p->mxRail<GR_MAX_RAIL && pRow->mergeDown>(BIT(p->mxRail+1)-1) ){
329327
p->mxRail++;
330328
}
331329
}
332330
}
@@ -540,11 +538,11 @@
540538
if( pDesc==0 ){
541539
/* Merge from a node that is off-screen */
542540
int iMrail = findFreeRail(p, pRow->idx, p->nRow, 0, 0);
543541
if( p->mxRail>=GR_MAX_RAIL ) return;
544542
mask = BIT(iMrail);
545
- pRow->mergeIn[iMrail] = 2;
543
+ pRow->mergeIn[iMrail] = 1;
546544
pRow->mergeDown |= mask;
547545
for(pLoop=pRow->pNext; pLoop; pLoop=pLoop->pNext){
548546
pLoop->railInUse |= mask;
549547
}
550548
}else{
@@ -569,11 +567,11 @@
569567
if( !pRow->isDup ) continue;
570568
pRow->iRail = dupRail;
571569
pDesc = hashFind(p, pRow->rid);
572570
assert( pDesc!=0 && pDesc!=pRow );
573571
createMergeRiser(p, pDesc, pRow);
574
- if( pDesc->mergeOut/4>mxRail ) mxRail = pDesc->mergeOut/4;
572
+ if( pDesc->mergeOut>mxRail ) mxRail = pDesc->mergeOut;
575573
}
576574
if( dupRail<=mxRail ){
577575
dupRail = mxRail+1;
578576
for(pRow=p->pFirst; pRow; pRow=pRow->pNext){
579577
if( pRow->isDup ) pRow->iRail = dupRail;
@@ -584,12 +582,7 @@
584582
585583
/*
586584
** Find the maximum rail number.
587585
*/
588586
find_max_rail(p);
589
- p->iRailPitch = atoi(PD("railpitch","0"));
590
- if( p->iRailPitch<=0 ){
591
- p->iRailPitch = 18 - (p->mxRail/3);
592
- if( p->iRailPitch<11 ) p->iRailPitch = 11;
593
- }
594587
p->nErr = 0;
595588
}
596589
--- src/graph.c
+++ src/graph.c
@@ -47,11 +47,11 @@
47 u8 isDup; /* True if this is duplicate of a prior entry */
48 u8 isLeaf; /* True if this is a leaf node */
49 u8 timeWarp; /* Child is earlier in time */
50 u8 bDescender; /* True if riser from bottom of graph to here. */
51 i8 iRail; /* Which rail this check-in appears on. 0-based.*/
52 i8 mergeOut; /* Merge out on rail mergeOut/4. -1 for none */
53 u8 mergeIn[GR_MAX_RAIL]; /* Merge in from non-zero rails */
54 int aiRiser[GR_MAX_RAIL]; /* Risers from this node to a higher row. */
55 int mergeUpto; /* Draw the mergeOut rail up to this level */
56 u64 mergeDown; /* Draw merge lines up from bottom of graph */
57
@@ -61,11 +61,10 @@
61 /* Context while building a graph
62 */
63 struct GraphContext {
64 int nErr; /* Number of errors encountered */
65 int mxRail; /* Number of rails required to render the graph */
66 int iRailPitch; /* Pixels between rail centers */
67 GraphRow *pFirst; /* First row in the list */
68 GraphRow *pLast; /* Last row in the list */
69 int nBranch; /* Number of distinct branches */
70 char **azBranch; /* Names of the branches */
71 int nRow; /* Number of rows */
@@ -294,28 +293,27 @@
294 u = pParent->aiRiser[pParent->iRail];
295 if( u>=0 && u<pChild->idx ){
296 /* The thick arrow up to the next primary child of pDesc goes
297 ** further up than the thin merge arrow riser, so draw them both
298 ** on the same rail. */
299 pParent->mergeOut = pParent->iRail*4;
300 if( pParent->iRail<pChild->iRail ) pParent->mergeOut += 2;
301 pParent->mergeUpto = pChild->idx;
302 }else{
303 /* The thin merge arrow riser is taller than the thick primary
304 ** child riser, so use separate rails. */
305 int iTarget = pParent->iRail;
306 pParent->mergeOut = findFreeRail(p, pChild->idx, pParent->idx-1,
307 0, iTarget)*4 + 1;
308 pParent->mergeUpto = pChild->idx;
309 mask = BIT(pParent->mergeOut/4);
310 for(pLoop=pChild->pNext; pLoop && pLoop->rid!=pParent->rid;
311 pLoop=pLoop->pNext){
312 pLoop->railInUse |= mask;
313 }
314 }
315 }
316 pChild->mergeIn[pParent->mergeOut/4] = (pParent->mergeOut&3)+1;
317 }
318
319 /*
320 ** Compute the maximum rail number.
321 */
@@ -322,11 +320,11 @@
322 static void find_max_rail(GraphContext *p){
323 GraphRow *pRow;
324 p->mxRail = 0;
325 for(pRow=p->pFirst; pRow; pRow=pRow->pNext){
326 if( pRow->iRail>p->mxRail ) p->mxRail = pRow->iRail;
327 if( pRow->mergeOut/4>p->mxRail ) p->mxRail = pRow->mergeOut/4;
328 while( p->mxRail<GR_MAX_RAIL && pRow->mergeDown>(BIT(p->mxRail+1)-1) ){
329 p->mxRail++;
330 }
331 }
332 }
@@ -540,11 +538,11 @@
540 if( pDesc==0 ){
541 /* Merge from a node that is off-screen */
542 int iMrail = findFreeRail(p, pRow->idx, p->nRow, 0, 0);
543 if( p->mxRail>=GR_MAX_RAIL ) return;
544 mask = BIT(iMrail);
545 pRow->mergeIn[iMrail] = 2;
546 pRow->mergeDown |= mask;
547 for(pLoop=pRow->pNext; pLoop; pLoop=pLoop->pNext){
548 pLoop->railInUse |= mask;
549 }
550 }else{
@@ -569,11 +567,11 @@
569 if( !pRow->isDup ) continue;
570 pRow->iRail = dupRail;
571 pDesc = hashFind(p, pRow->rid);
572 assert( pDesc!=0 && pDesc!=pRow );
573 createMergeRiser(p, pDesc, pRow);
574 if( pDesc->mergeOut/4>mxRail ) mxRail = pDesc->mergeOut/4;
575 }
576 if( dupRail<=mxRail ){
577 dupRail = mxRail+1;
578 for(pRow=p->pFirst; pRow; pRow=pRow->pNext){
579 if( pRow->isDup ) pRow->iRail = dupRail;
@@ -584,12 +582,7 @@
584
585 /*
586 ** Find the maximum rail number.
587 */
588 find_max_rail(p);
589 p->iRailPitch = atoi(PD("railpitch","0"));
590 if( p->iRailPitch<=0 ){
591 p->iRailPitch = 18 - (p->mxRail/3);
592 if( p->iRailPitch<11 ) p->iRailPitch = 11;
593 }
594 p->nErr = 0;
595 }
596
--- src/graph.c
+++ src/graph.c
@@ -47,11 +47,11 @@
47 u8 isDup; /* True if this is duplicate of a prior entry */
48 u8 isLeaf; /* True if this is a leaf node */
49 u8 timeWarp; /* Child is earlier in time */
50 u8 bDescender; /* True if riser from bottom of graph to here. */
51 i8 iRail; /* Which rail this check-in appears on. 0-based.*/
52 i8 mergeOut; /* Merge out to this rail. -1 if no merge-out */
53 u8 mergeIn[GR_MAX_RAIL]; /* Merge in from non-zero rails */
54 int aiRiser[GR_MAX_RAIL]; /* Risers from this node to a higher row. */
55 int mergeUpto; /* Draw the mergeOut rail up to this level */
56 u64 mergeDown; /* Draw merge lines up from bottom of graph */
57
@@ -61,11 +61,10 @@
61 /* Context while building a graph
62 */
63 struct GraphContext {
64 int nErr; /* Number of errors encountered */
65 int mxRail; /* Number of rails required to render the graph */
 
66 GraphRow *pFirst; /* First row in the list */
67 GraphRow *pLast; /* Last row in the list */
68 int nBranch; /* Number of distinct branches */
69 char **azBranch; /* Names of the branches */
70 int nRow; /* Number of rows */
@@ -294,28 +293,27 @@
293 u = pParent->aiRiser[pParent->iRail];
294 if( u>=0 && u<pChild->idx ){
295 /* The thick arrow up to the next primary child of pDesc goes
296 ** further up than the thin merge arrow riser, so draw them both
297 ** on the same rail. */
298 pParent->mergeOut = pParent->iRail;
 
299 pParent->mergeUpto = pChild->idx;
300 }else{
301 /* The thin merge arrow riser is taller than the thick primary
302 ** child riser, so use separate rails. */
303 int iTarget = pParent->iRail;
304 pParent->mergeOut = findFreeRail(p, pChild->idx, pParent->idx-1,
305 0, iTarget);
306 pParent->mergeUpto = pChild->idx;
307 mask = BIT(pParent->mergeOut);
308 for(pLoop=pChild->pNext; pLoop && pLoop->rid!=pParent->rid;
309 pLoop=pLoop->pNext){
310 pLoop->railInUse |= mask;
311 }
312 }
313 }
314 pChild->mergeIn[pParent->mergeOut] = 1;
315 }
316
317 /*
318 ** Compute the maximum rail number.
319 */
@@ -322,11 +320,11 @@
320 static void find_max_rail(GraphContext *p){
321 GraphRow *pRow;
322 p->mxRail = 0;
323 for(pRow=p->pFirst; pRow; pRow=pRow->pNext){
324 if( pRow->iRail>p->mxRail ) p->mxRail = pRow->iRail;
325 if( pRow->mergeOut>p->mxRail ) p->mxRail = pRow->mergeOut;
326 while( p->mxRail<GR_MAX_RAIL && pRow->mergeDown>(BIT(p->mxRail+1)-1) ){
327 p->mxRail++;
328 }
329 }
330 }
@@ -540,11 +538,11 @@
538 if( pDesc==0 ){
539 /* Merge from a node that is off-screen */
540 int iMrail = findFreeRail(p, pRow->idx, p->nRow, 0, 0);
541 if( p->mxRail>=GR_MAX_RAIL ) return;
542 mask = BIT(iMrail);
543 pRow->mergeIn[iMrail] = 1;
544 pRow->mergeDown |= mask;
545 for(pLoop=pRow->pNext; pLoop; pLoop=pLoop->pNext){
546 pLoop->railInUse |= mask;
547 }
548 }else{
@@ -569,11 +567,11 @@
567 if( !pRow->isDup ) continue;
568 pRow->iRail = dupRail;
569 pDesc = hashFind(p, pRow->rid);
570 assert( pDesc!=0 && pDesc!=pRow );
571 createMergeRiser(p, pDesc, pRow);
572 if( pDesc->mergeOut>mxRail ) mxRail = pDesc->mergeOut;
573 }
574 if( dupRail<=mxRail ){
575 dupRail = mxRail+1;
576 for(pRow=p->pFirst; pRow; pRow=pRow->pNext){
577 if( pRow->isDup ) pRow->iRail = dupRail;
@@ -584,12 +582,7 @@
582
583 /*
584 ** Find the maximum rail number.
585 */
586 find_max_rail(p);
 
 
 
 
 
587 p->nErr = 0;
588 }
589
+2 -2
--- src/http.c
+++ src/http.c
@@ -338,14 +338,14 @@
338338
j = strlen(zLine) - 1;
339339
while( j>4 && fossil_strcmp(&zLine[j-4],"/xfer")==0 ){
340340
j -= 4;
341341
zLine[j] = 0;
342342
}
343
+ fossil_print("redirect with status %d to %s\n", rc, &zLine[i]);
344
+ url_parse(&zLine[i], 0);
343345
transport_close(&g.url);
344346
transport_global_shutdown(&g.url);
345
- fossil_print("redirect with status %d to %s\n", rc, &zLine[i]);
346
- url_parse(&zLine[i], 0);
347347
fSeenHttpAuth = 0;
348348
if( g.zHttpAuth ) free(g.zHttpAuth);
349349
g.zHttpAuth = get_httpauth();
350350
return http_exchange(pSend, pReply, useLogin, maxRedirect);
351351
}else if( fossil_strnicmp(zLine, "content-type: ", 14)==0 ){
352352
--- src/http.c
+++ src/http.c
@@ -338,14 +338,14 @@
338 j = strlen(zLine) - 1;
339 while( j>4 && fossil_strcmp(&zLine[j-4],"/xfer")==0 ){
340 j -= 4;
341 zLine[j] = 0;
342 }
 
 
343 transport_close(&g.url);
344 transport_global_shutdown(&g.url);
345 fossil_print("redirect with status %d to %s\n", rc, &zLine[i]);
346 url_parse(&zLine[i], 0);
347 fSeenHttpAuth = 0;
348 if( g.zHttpAuth ) free(g.zHttpAuth);
349 g.zHttpAuth = get_httpauth();
350 return http_exchange(pSend, pReply, useLogin, maxRedirect);
351 }else if( fossil_strnicmp(zLine, "content-type: ", 14)==0 ){
352
--- src/http.c
+++ src/http.c
@@ -338,14 +338,14 @@
338 j = strlen(zLine) - 1;
339 while( j>4 && fossil_strcmp(&zLine[j-4],"/xfer")==0 ){
340 j -= 4;
341 zLine[j] = 0;
342 }
343 fossil_print("redirect with status %d to %s\n", rc, &zLine[i]);
344 url_parse(&zLine[i], 0);
345 transport_close(&g.url);
346 transport_global_shutdown(&g.url);
 
 
347 fSeenHttpAuth = 0;
348 if( g.zHttpAuth ) free(g.zHttpAuth);
349 g.zHttpAuth = get_httpauth();
350 return http_exchange(pSend, pReply, useLogin, maxRedirect);
351 }else if( fossil_strnicmp(zLine, "content-type: ", 14)==0 ){
352
+28 -15
--- src/info.c
+++ src/info.c
@@ -222,11 +222,10 @@
222222
if( rid==0 ){
223223
fossil_fatal("no such object: %s\n", g.argv[2]);
224224
}
225225
show_common_info(rid, "uuid:", 1, 1);
226226
}
227
- fossil_print("multiple leaves on the same branch:\n");
228227
leaves_cmd();
229228
}
230229
231230
/*
232231
** Show information about all tags on a given check-in.
@@ -370,54 +369,68 @@
370369
const char *zOldName, /* Prior name. NULL if no name change. */
371370
u64 diffFlags, /* Flags for text_diff(). Zero to omit diffs */
372371
ReCompiled *pRe, /* Only show diffs that match this regex, if not NULL */
373372
int mperm /* executable or symlink permission for zNew */
374373
){
374
+ @ <p>
375375
if( !g.perm.Hyperlink ){
376376
if( zNew==0 ){
377
- @ <p>Deleted %h(zName)</p>
377
+ @ Deleted %h(zName).
378378
}else if( zOld==0 ){
379
- @ <p>Added %h(zName)</p>
379
+ @ Added %h(zName).
380380
}else if( zOldName!=0 && fossil_strcmp(zName,zOldName)!=0 ){
381
- @ <p>Name change from %h(zOldName) to %h(zName)
381
+ @ Name change from %h(zOldName) to %h(zName).
382382
}else if( fossil_strcmp(zNew, zOld)==0 ){
383
- @ <p>Execute permission %s(( mperm==PERM_EXE )?"set":"cleared")
384
- @ for %h(zName)</p>
383
+ if( mperm==PERM_EXE ){
384
+ @ %h(zName) became executable.
385
+ }else if( mperm==PERM_LNK ){
386
+ @ %h(zName) became a symlink.
387
+ }else{
388
+ @ %h(zName) became a regular file.
389
+ }
385390
}else{
386
- @ <p>Changes to %h(zName)</p>
391
+ @ Changes to %h(zName).
387392
}
388393
if( diffFlags ){
389394
append_diff(zOld, zNew, diffFlags, pRe);
390395
}
391396
}else{
392397
if( zOld && zNew ){
393398
if( fossil_strcmp(zOld, zNew)!=0 ){
394
- @ <p>Modified %z(href("%R/finfo?name=%T",zName))%h(zName)</a>
399
+ @ Modified %z(href("%R/finfo?name=%T",zName))%h(zName)</a>
395400
@ from %z(href("%R/artifact/%!S",zOld))[%S(zOld)]</a>
396401
@ to %z(href("%R/artifact/%!S",zNew))[%S(zNew)]</a>.
397402
}else if( zOldName!=0 && fossil_strcmp(zName,zOldName)!=0 ){
398
- @ <p>Name change
403
+ @ Name change
399404
@ from %z(href("%R/finfo?name=%T",zOldName))%h(zOldName)</a>
400405
@ to %z(href("%R/finfo?name=%T",zName))%h(zName)</a>.
401406
}else{
402
- @ <p>Execute permission %s(( mperm==PERM_EXE )?"set":"cleared") for
403
- @ %z(href("%R/finfo?name=%T",zName))%h(zName)</a>
407
+ @ %z(href("%R/finfo?name=%T",zName))%h(zName)</a> became
408
+ if( mperm==PERM_EXE ){
409
+ @ executable with contents
410
+ }else if( mperm==PERM_LNK ){
411
+ @ a symlink with target
412
+ }else{
413
+ @ a regular file with contents
414
+ }
415
+ @ %z(href("%R/artifact/%!S",zNew))[%S(zNew)]</a>.
404416
}
405417
}else if( zOld ){
406
- @ <p>Deleted %z(href("%R/finfo?name=%T",zName))%h(zName)</a>
407
- @ version %z(href("%R/artifact/%!S",zOld))[%S(zOld)]</a>
418
+ @ Deleted %z(href("%R/finfo?name=%T",zName))%h(zName)</a>
419
+ @ version %z(href("%R/artifact/%!S",zOld))[%S(zOld)]</a>.
408420
}else{
409
- @ <p>Added %z(href("%R/finfo?name=%T",zName))%h(zName)</a>
410
- @ version %z(href("%R/artifact/%!S",zNew))[%S(zNew)]</a>
421
+ @ Added %z(href("%R/finfo?name=%T",zName))%h(zName)</a>
422
+ @ version %z(href("%R/artifact/%!S",zNew))[%S(zNew)]</a>.
411423
}
412424
if( diffFlags ){
413425
append_diff(zOld, zNew, diffFlags, pRe);
414426
}else if( zOld && zNew && fossil_strcmp(zOld,zNew)!=0 ){
415427
@ &nbsp;&nbsp;
416428
@ %z(href("%R/fdiff?v1=%!S&v2=%!S&sbs=1",zOld,zNew))[diff]</a>
417429
}
418430
}
431
+ @ </p>
419432
}
420433
421434
/*
422435
** Generate javascript to enhance HTML diffs.
423436
*/
424437
--- src/info.c
+++ src/info.c
@@ -222,11 +222,10 @@
222 if( rid==0 ){
223 fossil_fatal("no such object: %s\n", g.argv[2]);
224 }
225 show_common_info(rid, "uuid:", 1, 1);
226 }
227 fossil_print("multiple leaves on the same branch:\n");
228 leaves_cmd();
229 }
230
231 /*
232 ** Show information about all tags on a given check-in.
@@ -370,54 +369,68 @@
370 const char *zOldName, /* Prior name. NULL if no name change. */
371 u64 diffFlags, /* Flags for text_diff(). Zero to omit diffs */
372 ReCompiled *pRe, /* Only show diffs that match this regex, if not NULL */
373 int mperm /* executable or symlink permission for zNew */
374 ){
 
375 if( !g.perm.Hyperlink ){
376 if( zNew==0 ){
377 @ <p>Deleted %h(zName)</p>
378 }else if( zOld==0 ){
379 @ <p>Added %h(zName)</p>
380 }else if( zOldName!=0 && fossil_strcmp(zName,zOldName)!=0 ){
381 @ <p>Name change from %h(zOldName) to %h(zName)
382 }else if( fossil_strcmp(zNew, zOld)==0 ){
383 @ <p>Execute permission %s(( mperm==PERM_EXE )?"set":"cleared")
384 @ for %h(zName)</p>
 
 
 
 
 
385 }else{
386 @ <p>Changes to %h(zName)</p>
387 }
388 if( diffFlags ){
389 append_diff(zOld, zNew, diffFlags, pRe);
390 }
391 }else{
392 if( zOld && zNew ){
393 if( fossil_strcmp(zOld, zNew)!=0 ){
394 @ <p>Modified %z(href("%R/finfo?name=%T",zName))%h(zName)</a>
395 @ from %z(href("%R/artifact/%!S",zOld))[%S(zOld)]</a>
396 @ to %z(href("%R/artifact/%!S",zNew))[%S(zNew)]</a>.
397 }else if( zOldName!=0 && fossil_strcmp(zName,zOldName)!=0 ){
398 @ <p>Name change
399 @ from %z(href("%R/finfo?name=%T",zOldName))%h(zOldName)</a>
400 @ to %z(href("%R/finfo?name=%T",zName))%h(zName)</a>.
401 }else{
402 @ <p>Execute permission %s(( mperm==PERM_EXE )?"set":"cleared") for
403 @ %z(href("%R/finfo?name=%T",zName))%h(zName)</a>
 
 
 
 
 
 
 
404 }
405 }else if( zOld ){
406 @ <p>Deleted %z(href("%R/finfo?name=%T",zName))%h(zName)</a>
407 @ version %z(href("%R/artifact/%!S",zOld))[%S(zOld)]</a>
408 }else{
409 @ <p>Added %z(href("%R/finfo?name=%T",zName))%h(zName)</a>
410 @ version %z(href("%R/artifact/%!S",zNew))[%S(zNew)]</a>
411 }
412 if( diffFlags ){
413 append_diff(zOld, zNew, diffFlags, pRe);
414 }else if( zOld && zNew && fossil_strcmp(zOld,zNew)!=0 ){
415 @ &nbsp;&nbsp;
416 @ %z(href("%R/fdiff?v1=%!S&v2=%!S&sbs=1",zOld,zNew))[diff]</a>
417 }
418 }
 
419 }
420
421 /*
422 ** Generate javascript to enhance HTML diffs.
423 */
424
--- src/info.c
+++ src/info.c
@@ -222,11 +222,10 @@
222 if( rid==0 ){
223 fossil_fatal("no such object: %s\n", g.argv[2]);
224 }
225 show_common_info(rid, "uuid:", 1, 1);
226 }
 
227 leaves_cmd();
228 }
229
230 /*
231 ** Show information about all tags on a given check-in.
@@ -370,54 +369,68 @@
369 const char *zOldName, /* Prior name. NULL if no name change. */
370 u64 diffFlags, /* Flags for text_diff(). Zero to omit diffs */
371 ReCompiled *pRe, /* Only show diffs that match this regex, if not NULL */
372 int mperm /* executable or symlink permission for zNew */
373 ){
374 @ <p>
375 if( !g.perm.Hyperlink ){
376 if( zNew==0 ){
377 @ Deleted %h(zName).
378 }else if( zOld==0 ){
379 @ Added %h(zName).
380 }else if( zOldName!=0 && fossil_strcmp(zName,zOldName)!=0 ){
381 @ Name change from %h(zOldName) to %h(zName).
382 }else if( fossil_strcmp(zNew, zOld)==0 ){
383 if( mperm==PERM_EXE ){
384 @ %h(zName) became executable.
385 }else if( mperm==PERM_LNK ){
386 @ %h(zName) became a symlink.
387 }else{
388 @ %h(zName) became a regular file.
389 }
390 }else{
391 @ Changes to %h(zName).
392 }
393 if( diffFlags ){
394 append_diff(zOld, zNew, diffFlags, pRe);
395 }
396 }else{
397 if( zOld && zNew ){
398 if( fossil_strcmp(zOld, zNew)!=0 ){
399 @ Modified %z(href("%R/finfo?name=%T",zName))%h(zName)</a>
400 @ from %z(href("%R/artifact/%!S",zOld))[%S(zOld)]</a>
401 @ to %z(href("%R/artifact/%!S",zNew))[%S(zNew)]</a>.
402 }else if( zOldName!=0 && fossil_strcmp(zName,zOldName)!=0 ){
403 @ Name change
404 @ from %z(href("%R/finfo?name=%T",zOldName))%h(zOldName)</a>
405 @ to %z(href("%R/finfo?name=%T",zName))%h(zName)</a>.
406 }else{
407 @ %z(href("%R/finfo?name=%T",zName))%h(zName)</a> became
408 if( mperm==PERM_EXE ){
409 @ executable with contents
410 }else if( mperm==PERM_LNK ){
411 @ a symlink with target
412 }else{
413 @ a regular file with contents
414 }
415 @ %z(href("%R/artifact/%!S",zNew))[%S(zNew)]</a>.
416 }
417 }else if( zOld ){
418 @ Deleted %z(href("%R/finfo?name=%T",zName))%h(zName)</a>
419 @ version %z(href("%R/artifact/%!S",zOld))[%S(zOld)]</a>.
420 }else{
421 @ Added %z(href("%R/finfo?name=%T",zName))%h(zName)</a>
422 @ version %z(href("%R/artifact/%!S",zNew))[%S(zNew)]</a>.
423 }
424 if( diffFlags ){
425 append_diff(zOld, zNew, diffFlags, pRe);
426 }else if( zOld && zNew && fossil_strcmp(zOld,zNew)!=0 ){
427 @ &nbsp;&nbsp;
428 @ %z(href("%R/fdiff?v1=%!S&v2=%!S&sbs=1",zOld,zNew))[diff]</a>
429 }
430 }
431 @ </p>
432 }
433
434 /*
435 ** Generate javascript to enhance HTML diffs.
436 */
437
+28 -15
--- src/info.c
+++ src/info.c
@@ -222,11 +222,10 @@
222222
if( rid==0 ){
223223
fossil_fatal("no such object: %s\n", g.argv[2]);
224224
}
225225
show_common_info(rid, "uuid:", 1, 1);
226226
}
227
- fossil_print("multiple leaves on the same branch:\n");
228227
leaves_cmd();
229228
}
230229
231230
/*
232231
** Show information about all tags on a given check-in.
@@ -370,54 +369,68 @@
370369
const char *zOldName, /* Prior name. NULL if no name change. */
371370
u64 diffFlags, /* Flags for text_diff(). Zero to omit diffs */
372371
ReCompiled *pRe, /* Only show diffs that match this regex, if not NULL */
373372
int mperm /* executable or symlink permission for zNew */
374373
){
374
+ @ <p>
375375
if( !g.perm.Hyperlink ){
376376
if( zNew==0 ){
377
- @ <p>Deleted %h(zName)</p>
377
+ @ Deleted %h(zName).
378378
}else if( zOld==0 ){
379
- @ <p>Added %h(zName)</p>
379
+ @ Added %h(zName).
380380
}else if( zOldName!=0 && fossil_strcmp(zName,zOldName)!=0 ){
381
- @ <p>Name change from %h(zOldName) to %h(zName)
381
+ @ Name change from %h(zOldName) to %h(zName).
382382
}else if( fossil_strcmp(zNew, zOld)==0 ){
383
- @ <p>Execute permission %s(( mperm==PERM_EXE )?"set":"cleared")
384
- @ for %h(zName)</p>
383
+ if( mperm==PERM_EXE ){
384
+ @ %h(zName) became executable.
385
+ }else if( mperm==PERM_LNK ){
386
+ @ %h(zName) became a symlink.
387
+ }else{
388
+ @ %h(zName) became a regular file.
389
+ }
385390
}else{
386
- @ <p>Changes to %h(zName)</p>
391
+ @ Changes to %h(zName).
387392
}
388393
if( diffFlags ){
389394
append_diff(zOld, zNew, diffFlags, pRe);
390395
}
391396
}else{
392397
if( zOld && zNew ){
393398
if( fossil_strcmp(zOld, zNew)!=0 ){
394
- @ <p>Modified %z(href("%R/finfo?name=%T",zName))%h(zName)</a>
399
+ @ Modified %z(href("%R/finfo?name=%T",zName))%h(zName)</a>
395400
@ from %z(href("%R/artifact/%!S",zOld))[%S(zOld)]</a>
396401
@ to %z(href("%R/artifact/%!S",zNew))[%S(zNew)]</a>.
397402
}else if( zOldName!=0 && fossil_strcmp(zName,zOldName)!=0 ){
398
- @ <p>Name change
403
+ @ Name change
399404
@ from %z(href("%R/finfo?name=%T",zOldName))%h(zOldName)</a>
400405
@ to %z(href("%R/finfo?name=%T",zName))%h(zName)</a>.
401406
}else{
402
- @ <p>Execute permission %s(( mperm==PERM_EXE )?"set":"cleared") for
403
- @ %z(href("%R/finfo?name=%T",zName))%h(zName)</a>
407
+ @ %z(href("%R/finfo?name=%T",zName))%h(zName)</a> became
408
+ if( mperm==PERM_EXE ){
409
+ @ executable with contents
410
+ }else if( mperm==PERM_LNK ){
411
+ @ a symlink with target
412
+ }else{
413
+ @ a regular file with contents
414
+ }
415
+ @ %z(href("%R/artifact/%!S",zNew))[%S(zNew)]</a>.
404416
}
405417
}else if( zOld ){
406
- @ <p>Deleted %z(href("%R/finfo?name=%T",zName))%h(zName)</a>
407
- @ version %z(href("%R/artifact/%!S",zOld))[%S(zOld)]</a>
418
+ @ Deleted %z(href("%R/finfo?name=%T",zName))%h(zName)</a>
419
+ @ version %z(href("%R/artifact/%!S",zOld))[%S(zOld)]</a>.
408420
}else{
409
- @ <p>Added %z(href("%R/finfo?name=%T",zName))%h(zName)</a>
410
- @ version %z(href("%R/artifact/%!S",zNew))[%S(zNew)]</a>
421
+ @ Added %z(href("%R/finfo?name=%T",zName))%h(zName)</a>
422
+ @ version %z(href("%R/artifact/%!S",zNew))[%S(zNew)]</a>.
411423
}
412424
if( diffFlags ){
413425
append_diff(zOld, zNew, diffFlags, pRe);
414426
}else if( zOld && zNew && fossil_strcmp(zOld,zNew)!=0 ){
415427
@ &nbsp;&nbsp;
416428
@ %z(href("%R/fdiff?v1=%!S&v2=%!S&sbs=1",zOld,zNew))[diff]</a>
417429
}
418430
}
431
+ @ </p>
419432
}
420433
421434
/*
422435
** Generate javascript to enhance HTML diffs.
423436
*/
424437
--- src/info.c
+++ src/info.c
@@ -222,11 +222,10 @@
222 if( rid==0 ){
223 fossil_fatal("no such object: %s\n", g.argv[2]);
224 }
225 show_common_info(rid, "uuid:", 1, 1);
226 }
227 fossil_print("multiple leaves on the same branch:\n");
228 leaves_cmd();
229 }
230
231 /*
232 ** Show information about all tags on a given check-in.
@@ -370,54 +369,68 @@
370 const char *zOldName, /* Prior name. NULL if no name change. */
371 u64 diffFlags, /* Flags for text_diff(). Zero to omit diffs */
372 ReCompiled *pRe, /* Only show diffs that match this regex, if not NULL */
373 int mperm /* executable or symlink permission for zNew */
374 ){
 
375 if( !g.perm.Hyperlink ){
376 if( zNew==0 ){
377 @ <p>Deleted %h(zName)</p>
378 }else if( zOld==0 ){
379 @ <p>Added %h(zName)</p>
380 }else if( zOldName!=0 && fossil_strcmp(zName,zOldName)!=0 ){
381 @ <p>Name change from %h(zOldName) to %h(zName)
382 }else if( fossil_strcmp(zNew, zOld)==0 ){
383 @ <p>Execute permission %s(( mperm==PERM_EXE )?"set":"cleared")
384 @ for %h(zName)</p>
 
 
 
 
 
385 }else{
386 @ <p>Changes to %h(zName)</p>
387 }
388 if( diffFlags ){
389 append_diff(zOld, zNew, diffFlags, pRe);
390 }
391 }else{
392 if( zOld && zNew ){
393 if( fossil_strcmp(zOld, zNew)!=0 ){
394 @ <p>Modified %z(href("%R/finfo?name=%T",zName))%h(zName)</a>
395 @ from %z(href("%R/artifact/%!S",zOld))[%S(zOld)]</a>
396 @ to %z(href("%R/artifact/%!S",zNew))[%S(zNew)]</a>.
397 }else if( zOldName!=0 && fossil_strcmp(zName,zOldName)!=0 ){
398 @ <p>Name change
399 @ from %z(href("%R/finfo?name=%T",zOldName))%h(zOldName)</a>
400 @ to %z(href("%R/finfo?name=%T",zName))%h(zName)</a>.
401 }else{
402 @ <p>Execute permission %s(( mperm==PERM_EXE )?"set":"cleared") for
403 @ %z(href("%R/finfo?name=%T",zName))%h(zName)</a>
 
 
 
 
 
 
 
404 }
405 }else if( zOld ){
406 @ <p>Deleted %z(href("%R/finfo?name=%T",zName))%h(zName)</a>
407 @ version %z(href("%R/artifact/%!S",zOld))[%S(zOld)]</a>
408 }else{
409 @ <p>Added %z(href("%R/finfo?name=%T",zName))%h(zName)</a>
410 @ version %z(href("%R/artifact/%!S",zNew))[%S(zNew)]</a>
411 }
412 if( diffFlags ){
413 append_diff(zOld, zNew, diffFlags, pRe);
414 }else if( zOld && zNew && fossil_strcmp(zOld,zNew)!=0 ){
415 @ &nbsp;&nbsp;
416 @ %z(href("%R/fdiff?v1=%!S&v2=%!S&sbs=1",zOld,zNew))[diff]</a>
417 }
418 }
 
419 }
420
421 /*
422 ** Generate javascript to enhance HTML diffs.
423 */
424
--- src/info.c
+++ src/info.c
@@ -222,11 +222,10 @@
222 if( rid==0 ){
223 fossil_fatal("no such object: %s\n", g.argv[2]);
224 }
225 show_common_info(rid, "uuid:", 1, 1);
226 }
 
227 leaves_cmd();
228 }
229
230 /*
231 ** Show information about all tags on a given check-in.
@@ -370,54 +369,68 @@
369 const char *zOldName, /* Prior name. NULL if no name change. */
370 u64 diffFlags, /* Flags for text_diff(). Zero to omit diffs */
371 ReCompiled *pRe, /* Only show diffs that match this regex, if not NULL */
372 int mperm /* executable or symlink permission for zNew */
373 ){
374 @ <p>
375 if( !g.perm.Hyperlink ){
376 if( zNew==0 ){
377 @ Deleted %h(zName).
378 }else if( zOld==0 ){
379 @ Added %h(zName).
380 }else if( zOldName!=0 && fossil_strcmp(zName,zOldName)!=0 ){
381 @ Name change from %h(zOldName) to %h(zName).
382 }else if( fossil_strcmp(zNew, zOld)==0 ){
383 if( mperm==PERM_EXE ){
384 @ %h(zName) became executable.
385 }else if( mperm==PERM_LNK ){
386 @ %h(zName) became a symlink.
387 }else{
388 @ %h(zName) became a regular file.
389 }
390 }else{
391 @ Changes to %h(zName).
392 }
393 if( diffFlags ){
394 append_diff(zOld, zNew, diffFlags, pRe);
395 }
396 }else{
397 if( zOld && zNew ){
398 if( fossil_strcmp(zOld, zNew)!=0 ){
399 @ Modified %z(href("%R/finfo?name=%T",zName))%h(zName)</a>
400 @ from %z(href("%R/artifact/%!S",zOld))[%S(zOld)]</a>
401 @ to %z(href("%R/artifact/%!S",zNew))[%S(zNew)]</a>.
402 }else if( zOldName!=0 && fossil_strcmp(zName,zOldName)!=0 ){
403 @ Name change
404 @ from %z(href("%R/finfo?name=%T",zOldName))%h(zOldName)</a>
405 @ to %z(href("%R/finfo?name=%T",zName))%h(zName)</a>.
406 }else{
407 @ %z(href("%R/finfo?name=%T",zName))%h(zName)</a> became
408 if( mperm==PERM_EXE ){
409 @ executable with contents
410 }else if( mperm==PERM_LNK ){
411 @ a symlink with target
412 }else{
413 @ a regular file with contents
414 }
415 @ %z(href("%R/artifact/%!S",zNew))[%S(zNew)]</a>.
416 }
417 }else if( zOld ){
418 @ Deleted %z(href("%R/finfo?name=%T",zName))%h(zName)</a>
419 @ version %z(href("%R/artifact/%!S",zOld))[%S(zOld)]</a>.
420 }else{
421 @ Added %z(href("%R/finfo?name=%T",zName))%h(zName)</a>
422 @ version %z(href("%R/artifact/%!S",zNew))[%S(zNew)]</a>.
423 }
424 if( diffFlags ){
425 append_diff(zOld, zNew, diffFlags, pRe);
426 }else if( zOld && zNew && fossil_strcmp(zOld,zNew)!=0 ){
427 @ &nbsp;&nbsp;
428 @ %z(href("%R/fdiff?v1=%!S&v2=%!S&sbs=1",zOld,zNew))[diff]</a>
429 }
430 }
431 @ </p>
432 }
433
434 /*
435 ** Generate javascript to enhance HTML diffs.
436 */
437
+1
--- src/json.c
+++ src/json.c
@@ -1292,10 +1292,11 @@
12921292
INT(g, nAux);
12931293
INT(g, allowSymlinks);
12941294
12951295
CSTR(g, zMainDbType);
12961296
CSTR(g, zConfigDbType);
1297
+ CSTR(g, zOpenRevision);
12971298
CSTR(g, zLocalRoot);
12981299
CSTR(g, zPath);
12991300
CSTR(g, zExtra);
13001301
CSTR(g, zBaseURL);
13011302
CSTR(g, zTop);
13021303
--- src/json.c
+++ src/json.c
@@ -1292,10 +1292,11 @@
1292 INT(g, nAux);
1293 INT(g, allowSymlinks);
1294
1295 CSTR(g, zMainDbType);
1296 CSTR(g, zConfigDbType);
 
1297 CSTR(g, zLocalRoot);
1298 CSTR(g, zPath);
1299 CSTR(g, zExtra);
1300 CSTR(g, zBaseURL);
1301 CSTR(g, zTop);
1302
--- src/json.c
+++ src/json.c
@@ -1292,10 +1292,11 @@
1292 INT(g, nAux);
1293 INT(g, allowSymlinks);
1294
1295 CSTR(g, zMainDbType);
1296 CSTR(g, zConfigDbType);
1297 CSTR(g, zOpenRevision);
1298 CSTR(g, zLocalRoot);
1299 CSTR(g, zPath);
1300 CSTR(g, zExtra);
1301 CSTR(g, zBaseURL);
1302 CSTR(g, zTop);
1303
+13 -5
--- src/main.c
+++ src/main.c
@@ -135,10 +135,11 @@
135135
char *zRepositoryOption; /* Most recent cached repository option value */
136136
char *zRepositoryName; /* Name of the repository database */
137137
char *zLocalDbName; /* Name of the local database */
138138
const char *zMainDbType;/* "configdb", "localdb", or "repository" */
139139
const char *zConfigDbType; /* "configdb", "localdb", or "repository" */
140
+ char *zOpenRevision; /* Check-in version to use during database open */
140141
int localOpen; /* True if the local database is open */
141142
char *zLocalRoot; /* The directory holding the local database */
142143
int minPrefix; /* Number of digits needed for a distinct UUID */
143144
int fSqlTrace; /* True if --sqltrace flag is present */
144145
int fSqlStats; /* True if --sqltrace or --sqlstats are present */
@@ -1441,20 +1442,27 @@
14411442
vfile_scan(&base, blob_size(&base), 0, 0, 0);
14421443
db_multi_exec("DELETE FROM sfile WHERE x NOT GLOB '*.fossil'");
14431444
n = db_int(0, "SELECT count(*) FROM sfile");
14441445
if( n>0 ){
14451446
Stmt q;
1447
+ @ <html>
1448
+ @ <head>
1449
+ @ <title>Repository List</title>
1450
+ @ </head>
1451
+ @ <body>
14461452
@ <h1>Available Repositories:</h1>
14471453
@ <ol>
14481454
db_prepare(&q, "SELECT x, substr(x,-7,-100000)||'/home'"
14491455
" FROM sfile ORDER BY x COLLATE nocase;");
14501456
while( db_step(&q)==SQLITE_ROW ){
14511457
const char *zName = db_column_text(&q, 0);
14521458
const char *zUrl = db_column_text(&q, 1);
1453
- @ <li><a href="%h(zUrl)">%h(zName)</a></li>
1459
+ @ <li><a href="%h(zUrl)" target="_blank">%h(zName)</a></li>
14541460
}
14551461
@ </ol>
1462
+ @ </body>
1463
+ @ </html>
14561464
cgi_reply();
14571465
}
14581466
sqlite3_close(g.db);
14591467
g.db = 0;
14601468
return n;
@@ -1563,16 +1571,16 @@
15631571
zRepo[j] = '.';
15641572
}
15651573
15661574
if( szFile<1024 ){
15671575
set_base_url(0);
1568
- if( zNotFound ){
1569
- cgi_redirect(zNotFound);
1570
- }else if( strcmp(zPathInfo,"/")==0
1576
+ if( strcmp(zPathInfo,"/")==0
15711577
&& allowRepoList
15721578
&& repo_list_page() ){
15731579
/* Will return a list of repositories */
1580
+ }else if( zNotFound ){
1581
+ cgi_redirect(zNotFound);
15741582
}else{
15751583
#ifdef FOSSIL_ENABLE_JSON
15761584
if(g.json.isJsonMode){
15771585
json_err(FSL_JSON_E_RESOURCE_NOT_FOUND,NULL,1);
15781586
return;
@@ -2169,18 +2177,18 @@
21692177
zIpAddr = fossil_getenv("REMOTE_HOST"); /* From stunnel */
21702178
cgi_replace_parameter("HTTPS","on");
21712179
}
21722180
zHost = find_option("host", 0, 1);
21732181
if( zHost ) cgi_replace_parameter("HTTP_HOST",zHost);
2174
- g.cgiOutput = 1;
21752182
21762183
/* We should be done with options.. */
21772184
verify_all_options();
21782185
21792186
if( g.argc!=2 && g.argc!=3 && g.argc!=5 && g.argc!=6 ){
21802187
fossil_fatal("no repository specified");
21812188
}
2189
+ g.cgiOutput = 1;
21822190
g.fullHttpReply = 1;
21832191
if( g.argc>=5 ){
21842192
g.httpIn = fossil_fopen(g.argv[2], "rb");
21852193
g.httpOut = fossil_fopen(g.argv[3], "wb");
21862194
zIpAddr = g.argv[4];
21872195
--- src/main.c
+++ src/main.c
@@ -135,10 +135,11 @@
135 char *zRepositoryOption; /* Most recent cached repository option value */
136 char *zRepositoryName; /* Name of the repository database */
137 char *zLocalDbName; /* Name of the local database */
138 const char *zMainDbType;/* "configdb", "localdb", or "repository" */
139 const char *zConfigDbType; /* "configdb", "localdb", or "repository" */
 
140 int localOpen; /* True if the local database is open */
141 char *zLocalRoot; /* The directory holding the local database */
142 int minPrefix; /* Number of digits needed for a distinct UUID */
143 int fSqlTrace; /* True if --sqltrace flag is present */
144 int fSqlStats; /* True if --sqltrace or --sqlstats are present */
@@ -1441,20 +1442,27 @@
1441 vfile_scan(&base, blob_size(&base), 0, 0, 0);
1442 db_multi_exec("DELETE FROM sfile WHERE x NOT GLOB '*.fossil'");
1443 n = db_int(0, "SELECT count(*) FROM sfile");
1444 if( n>0 ){
1445 Stmt q;
 
 
 
 
 
1446 @ <h1>Available Repositories:</h1>
1447 @ <ol>
1448 db_prepare(&q, "SELECT x, substr(x,-7,-100000)||'/home'"
1449 " FROM sfile ORDER BY x COLLATE nocase;");
1450 while( db_step(&q)==SQLITE_ROW ){
1451 const char *zName = db_column_text(&q, 0);
1452 const char *zUrl = db_column_text(&q, 1);
1453 @ <li><a href="%h(zUrl)">%h(zName)</a></li>
1454 }
1455 @ </ol>
 
 
1456 cgi_reply();
1457 }
1458 sqlite3_close(g.db);
1459 g.db = 0;
1460 return n;
@@ -1563,16 +1571,16 @@
1563 zRepo[j] = '.';
1564 }
1565
1566 if( szFile<1024 ){
1567 set_base_url(0);
1568 if( zNotFound ){
1569 cgi_redirect(zNotFound);
1570 }else if( strcmp(zPathInfo,"/")==0
1571 && allowRepoList
1572 && repo_list_page() ){
1573 /* Will return a list of repositories */
 
 
1574 }else{
1575 #ifdef FOSSIL_ENABLE_JSON
1576 if(g.json.isJsonMode){
1577 json_err(FSL_JSON_E_RESOURCE_NOT_FOUND,NULL,1);
1578 return;
@@ -2169,18 +2177,18 @@
2169 zIpAddr = fossil_getenv("REMOTE_HOST"); /* From stunnel */
2170 cgi_replace_parameter("HTTPS","on");
2171 }
2172 zHost = find_option("host", 0, 1);
2173 if( zHost ) cgi_replace_parameter("HTTP_HOST",zHost);
2174 g.cgiOutput = 1;
2175
2176 /* We should be done with options.. */
2177 verify_all_options();
2178
2179 if( g.argc!=2 && g.argc!=3 && g.argc!=5 && g.argc!=6 ){
2180 fossil_fatal("no repository specified");
2181 }
 
2182 g.fullHttpReply = 1;
2183 if( g.argc>=5 ){
2184 g.httpIn = fossil_fopen(g.argv[2], "rb");
2185 g.httpOut = fossil_fopen(g.argv[3], "wb");
2186 zIpAddr = g.argv[4];
2187
--- src/main.c
+++ src/main.c
@@ -135,10 +135,11 @@
135 char *zRepositoryOption; /* Most recent cached repository option value */
136 char *zRepositoryName; /* Name of the repository database */
137 char *zLocalDbName; /* Name of the local database */
138 const char *zMainDbType;/* "configdb", "localdb", or "repository" */
139 const char *zConfigDbType; /* "configdb", "localdb", or "repository" */
140 char *zOpenRevision; /* Check-in version to use during database open */
141 int localOpen; /* True if the local database is open */
142 char *zLocalRoot; /* The directory holding the local database */
143 int minPrefix; /* Number of digits needed for a distinct UUID */
144 int fSqlTrace; /* True if --sqltrace flag is present */
145 int fSqlStats; /* True if --sqltrace or --sqlstats are present */
@@ -1441,20 +1442,27 @@
1442 vfile_scan(&base, blob_size(&base), 0, 0, 0);
1443 db_multi_exec("DELETE FROM sfile WHERE x NOT GLOB '*.fossil'");
1444 n = db_int(0, "SELECT count(*) FROM sfile");
1445 if( n>0 ){
1446 Stmt q;
1447 @ <html>
1448 @ <head>
1449 @ <title>Repository List</title>
1450 @ </head>
1451 @ <body>
1452 @ <h1>Available Repositories:</h1>
1453 @ <ol>
1454 db_prepare(&q, "SELECT x, substr(x,-7,-100000)||'/home'"
1455 " FROM sfile ORDER BY x COLLATE nocase;");
1456 while( db_step(&q)==SQLITE_ROW ){
1457 const char *zName = db_column_text(&q, 0);
1458 const char *zUrl = db_column_text(&q, 1);
1459 @ <li><a href="%h(zUrl)" target="_blank">%h(zName)</a></li>
1460 }
1461 @ </ol>
1462 @ </body>
1463 @ </html>
1464 cgi_reply();
1465 }
1466 sqlite3_close(g.db);
1467 g.db = 0;
1468 return n;
@@ -1563,16 +1571,16 @@
1571 zRepo[j] = '.';
1572 }
1573
1574 if( szFile<1024 ){
1575 set_base_url(0);
1576 if( strcmp(zPathInfo,"/")==0
 
 
1577 && allowRepoList
1578 && repo_list_page() ){
1579 /* Will return a list of repositories */
1580 }else if( zNotFound ){
1581 cgi_redirect(zNotFound);
1582 }else{
1583 #ifdef FOSSIL_ENABLE_JSON
1584 if(g.json.isJsonMode){
1585 json_err(FSL_JSON_E_RESOURCE_NOT_FOUND,NULL,1);
1586 return;
@@ -2169,18 +2177,18 @@
2177 zIpAddr = fossil_getenv("REMOTE_HOST"); /* From stunnel */
2178 cgi_replace_parameter("HTTPS","on");
2179 }
2180 zHost = find_option("host", 0, 1);
2181 if( zHost ) cgi_replace_parameter("HTTP_HOST",zHost);
 
2182
2183 /* We should be done with options.. */
2184 verify_all_options();
2185
2186 if( g.argc!=2 && g.argc!=3 && g.argc!=5 && g.argc!=6 ){
2187 fossil_fatal("no repository specified");
2188 }
2189 g.cgiOutput = 1;
2190 g.fullHttpReply = 1;
2191 if( g.argc>=5 ){
2192 g.httpIn = fossil_fopen(g.argv[2], "rb");
2193 g.httpOut = fossil_fopen(g.argv[3], "wb");
2194 zIpAddr = g.argv[4];
2195
+14 -1
--- src/main.mk
+++ src/main.mk
@@ -84,10 +84,11 @@
8484
$(SRCDIR)/merge.c \
8585
$(SRCDIR)/merge3.c \
8686
$(SRCDIR)/moderate.c \
8787
$(SRCDIR)/name.c \
8888
$(SRCDIR)/path.c \
89
+ $(SRCDIR)/piechart.c \
8990
$(SRCDIR)/pivot.c \
9091
$(SRCDIR)/popen.c \
9192
$(SRCDIR)/pqueue.c \
9293
$(SRCDIR)/printf.c \
9394
$(SRCDIR)/publish.c \
@@ -255,10 +256,11 @@
255256
$(OBJDIR)/merge_.c \
256257
$(OBJDIR)/merge3_.c \
257258
$(OBJDIR)/moderate_.c \
258259
$(OBJDIR)/name_.c \
259260
$(OBJDIR)/path_.c \
261
+ $(OBJDIR)/piechart_.c \
260262
$(OBJDIR)/pivot_.c \
261263
$(OBJDIR)/popen_.c \
262264
$(OBJDIR)/pqueue_.c \
263265
$(OBJDIR)/printf_.c \
264266
$(OBJDIR)/publish_.c \
@@ -375,10 +377,11 @@
375377
$(OBJDIR)/merge.o \
376378
$(OBJDIR)/merge3.o \
377379
$(OBJDIR)/moderate.o \
378380
$(OBJDIR)/name.o \
379381
$(OBJDIR)/path.o \
382
+ $(OBJDIR)/piechart.o \
380383
$(OBJDIR)/pivot.o \
381384
$(OBJDIR)/popen.o \
382385
$(OBJDIR)/pqueue.o \
383386
$(OBJDIR)/printf.o \
384387
$(OBJDIR)/publish.o \
@@ -474,11 +477,12 @@
474477
-DSQLITE_THREADSAFE=0 \
475478
-DSQLITE_DEFAULT_FILE_FORMAT=4 \
476479
-DSQLITE_OMIT_DEPRECATED \
477480
-DSQLITE_ENABLE_EXPLAIN_COMMENTS \
478481
-DSQLITE_ENABLE_FTS4 \
479
- -DSQLITE_ENABLE_FTS3_PARENTHESIS
482
+ -DSQLITE_ENABLE_FTS3_PARENTHESIS \
483
+ -DSQLITE_ENABLE_DBSTAT_VTAB
480484
481485
# Setup the options used to compile the included SQLite shell.
482486
SHELL_OPTIONS = -Dmain=sqlite3_shell \
483487
-DSQLITE_OMIT_LOAD_EXTENSION=1 \
484488
-DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) \
@@ -606,10 +610,11 @@
606610
$(OBJDIR)/merge_.c:$(OBJDIR)/merge.h \
607611
$(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h \
608612
$(OBJDIR)/moderate_.c:$(OBJDIR)/moderate.h \
609613
$(OBJDIR)/name_.c:$(OBJDIR)/name.h \
610614
$(OBJDIR)/path_.c:$(OBJDIR)/path.h \
615
+ $(OBJDIR)/piechart_.c:$(OBJDIR)/piechart.h \
611616
$(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h \
612617
$(OBJDIR)/popen_.c:$(OBJDIR)/popen.h \
613618
$(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h \
614619
$(OBJDIR)/printf_.c:$(OBJDIR)/printf.h \
615620
$(OBJDIR)/publish_.c:$(OBJDIR)/publish.h \
@@ -1234,10 +1239,18 @@
12341239
12351240
$(OBJDIR)/path.o: $(OBJDIR)/path_.c $(OBJDIR)/path.h $(SRCDIR)/config.h
12361241
$(XTCC) -o $(OBJDIR)/path.o -c $(OBJDIR)/path_.c
12371242
12381243
$(OBJDIR)/path.h: $(OBJDIR)/headers
1244
+
1245
+$(OBJDIR)/piechart_.c: $(SRCDIR)/piechart.c $(OBJDIR)/translate
1246
+ $(OBJDIR)/translate $(SRCDIR)/piechart.c >$@
1247
+
1248
+$(OBJDIR)/piechart.o: $(OBJDIR)/piechart_.c $(OBJDIR)/piechart.h $(SRCDIR)/config.h
1249
+ $(XTCC) -o $(OBJDIR)/piechart.o -c $(OBJDIR)/piechart_.c
1250
+
1251
+$(OBJDIR)/piechart.h: $(OBJDIR)/headers
12391252
12401253
$(OBJDIR)/pivot_.c: $(SRCDIR)/pivot.c $(OBJDIR)/translate
12411254
$(OBJDIR)/translate $(SRCDIR)/pivot.c >$@
12421255
12431256
$(OBJDIR)/pivot.o: $(OBJDIR)/pivot_.c $(OBJDIR)/pivot.h $(SRCDIR)/config.h
12441257
--- src/main.mk
+++ src/main.mk
@@ -84,10 +84,11 @@
84 $(SRCDIR)/merge.c \
85 $(SRCDIR)/merge3.c \
86 $(SRCDIR)/moderate.c \
87 $(SRCDIR)/name.c \
88 $(SRCDIR)/path.c \
 
89 $(SRCDIR)/pivot.c \
90 $(SRCDIR)/popen.c \
91 $(SRCDIR)/pqueue.c \
92 $(SRCDIR)/printf.c \
93 $(SRCDIR)/publish.c \
@@ -255,10 +256,11 @@
255 $(OBJDIR)/merge_.c \
256 $(OBJDIR)/merge3_.c \
257 $(OBJDIR)/moderate_.c \
258 $(OBJDIR)/name_.c \
259 $(OBJDIR)/path_.c \
 
260 $(OBJDIR)/pivot_.c \
261 $(OBJDIR)/popen_.c \
262 $(OBJDIR)/pqueue_.c \
263 $(OBJDIR)/printf_.c \
264 $(OBJDIR)/publish_.c \
@@ -375,10 +377,11 @@
375 $(OBJDIR)/merge.o \
376 $(OBJDIR)/merge3.o \
377 $(OBJDIR)/moderate.o \
378 $(OBJDIR)/name.o \
379 $(OBJDIR)/path.o \
 
380 $(OBJDIR)/pivot.o \
381 $(OBJDIR)/popen.o \
382 $(OBJDIR)/pqueue.o \
383 $(OBJDIR)/printf.o \
384 $(OBJDIR)/publish.o \
@@ -474,11 +477,12 @@
474 -DSQLITE_THREADSAFE=0 \
475 -DSQLITE_DEFAULT_FILE_FORMAT=4 \
476 -DSQLITE_OMIT_DEPRECATED \
477 -DSQLITE_ENABLE_EXPLAIN_COMMENTS \
478 -DSQLITE_ENABLE_FTS4 \
479 -DSQLITE_ENABLE_FTS3_PARENTHESIS
 
480
481 # Setup the options used to compile the included SQLite shell.
482 SHELL_OPTIONS = -Dmain=sqlite3_shell \
483 -DSQLITE_OMIT_LOAD_EXTENSION=1 \
484 -DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) \
@@ -606,10 +610,11 @@
606 $(OBJDIR)/merge_.c:$(OBJDIR)/merge.h \
607 $(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h \
608 $(OBJDIR)/moderate_.c:$(OBJDIR)/moderate.h \
609 $(OBJDIR)/name_.c:$(OBJDIR)/name.h \
610 $(OBJDIR)/path_.c:$(OBJDIR)/path.h \
 
611 $(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h \
612 $(OBJDIR)/popen_.c:$(OBJDIR)/popen.h \
613 $(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h \
614 $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h \
615 $(OBJDIR)/publish_.c:$(OBJDIR)/publish.h \
@@ -1234,10 +1239,18 @@
1234
1235 $(OBJDIR)/path.o: $(OBJDIR)/path_.c $(OBJDIR)/path.h $(SRCDIR)/config.h
1236 $(XTCC) -o $(OBJDIR)/path.o -c $(OBJDIR)/path_.c
1237
1238 $(OBJDIR)/path.h: $(OBJDIR)/headers
 
 
 
 
 
 
 
 
1239
1240 $(OBJDIR)/pivot_.c: $(SRCDIR)/pivot.c $(OBJDIR)/translate
1241 $(OBJDIR)/translate $(SRCDIR)/pivot.c >$@
1242
1243 $(OBJDIR)/pivot.o: $(OBJDIR)/pivot_.c $(OBJDIR)/pivot.h $(SRCDIR)/config.h
1244
--- src/main.mk
+++ src/main.mk
@@ -84,10 +84,11 @@
84 $(SRCDIR)/merge.c \
85 $(SRCDIR)/merge3.c \
86 $(SRCDIR)/moderate.c \
87 $(SRCDIR)/name.c \
88 $(SRCDIR)/path.c \
89 $(SRCDIR)/piechart.c \
90 $(SRCDIR)/pivot.c \
91 $(SRCDIR)/popen.c \
92 $(SRCDIR)/pqueue.c \
93 $(SRCDIR)/printf.c \
94 $(SRCDIR)/publish.c \
@@ -255,10 +256,11 @@
256 $(OBJDIR)/merge_.c \
257 $(OBJDIR)/merge3_.c \
258 $(OBJDIR)/moderate_.c \
259 $(OBJDIR)/name_.c \
260 $(OBJDIR)/path_.c \
261 $(OBJDIR)/piechart_.c \
262 $(OBJDIR)/pivot_.c \
263 $(OBJDIR)/popen_.c \
264 $(OBJDIR)/pqueue_.c \
265 $(OBJDIR)/printf_.c \
266 $(OBJDIR)/publish_.c \
@@ -375,10 +377,11 @@
377 $(OBJDIR)/merge.o \
378 $(OBJDIR)/merge3.o \
379 $(OBJDIR)/moderate.o \
380 $(OBJDIR)/name.o \
381 $(OBJDIR)/path.o \
382 $(OBJDIR)/piechart.o \
383 $(OBJDIR)/pivot.o \
384 $(OBJDIR)/popen.o \
385 $(OBJDIR)/pqueue.o \
386 $(OBJDIR)/printf.o \
387 $(OBJDIR)/publish.o \
@@ -474,11 +477,12 @@
477 -DSQLITE_THREADSAFE=0 \
478 -DSQLITE_DEFAULT_FILE_FORMAT=4 \
479 -DSQLITE_OMIT_DEPRECATED \
480 -DSQLITE_ENABLE_EXPLAIN_COMMENTS \
481 -DSQLITE_ENABLE_FTS4 \
482 -DSQLITE_ENABLE_FTS3_PARENTHESIS \
483 -DSQLITE_ENABLE_DBSTAT_VTAB
484
485 # Setup the options used to compile the included SQLite shell.
486 SHELL_OPTIONS = -Dmain=sqlite3_shell \
487 -DSQLITE_OMIT_LOAD_EXTENSION=1 \
488 -DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) \
@@ -606,10 +610,11 @@
610 $(OBJDIR)/merge_.c:$(OBJDIR)/merge.h \
611 $(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h \
612 $(OBJDIR)/moderate_.c:$(OBJDIR)/moderate.h \
613 $(OBJDIR)/name_.c:$(OBJDIR)/name.h \
614 $(OBJDIR)/path_.c:$(OBJDIR)/path.h \
615 $(OBJDIR)/piechart_.c:$(OBJDIR)/piechart.h \
616 $(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h \
617 $(OBJDIR)/popen_.c:$(OBJDIR)/popen.h \
618 $(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h \
619 $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h \
620 $(OBJDIR)/publish_.c:$(OBJDIR)/publish.h \
@@ -1234,10 +1239,18 @@
1239
1240 $(OBJDIR)/path.o: $(OBJDIR)/path_.c $(OBJDIR)/path.h $(SRCDIR)/config.h
1241 $(XTCC) -o $(OBJDIR)/path.o -c $(OBJDIR)/path_.c
1242
1243 $(OBJDIR)/path.h: $(OBJDIR)/headers
1244
1245 $(OBJDIR)/piechart_.c: $(SRCDIR)/piechart.c $(OBJDIR)/translate
1246 $(OBJDIR)/translate $(SRCDIR)/piechart.c >$@
1247
1248 $(OBJDIR)/piechart.o: $(OBJDIR)/piechart_.c $(OBJDIR)/piechart.h $(SRCDIR)/config.h
1249 $(XTCC) -o $(OBJDIR)/piechart.o -c $(OBJDIR)/piechart_.c
1250
1251 $(OBJDIR)/piechart.h: $(OBJDIR)/headers
1252
1253 $(OBJDIR)/pivot_.c: $(SRCDIR)/pivot.c $(OBJDIR)/translate
1254 $(OBJDIR)/translate $(SRCDIR)/pivot.c >$@
1255
1256 $(OBJDIR)/pivot.o: $(OBJDIR)/pivot_.c $(OBJDIR)/pivot.h $(SRCDIR)/config.h
1257
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -90,10 +90,11 @@
9090
merge
9191
merge3
9292
moderate
9393
name
9494
path
95
+ piechart
9596
pivot
9697
popen
9798
pqueue
9899
printf
99100
publish
@@ -159,10 +160,11 @@
159160
-DSQLITE_DEFAULT_FILE_FORMAT=4
160161
-DSQLITE_OMIT_DEPRECATED
161162
-DSQLITE_ENABLE_EXPLAIN_COMMENTS
162163
-DSQLITE_ENABLE_FTS4
163164
-DSQLITE_ENABLE_FTS3_PARENTHESIS
165
+ -DSQLITE_ENABLE_DBSTAT_VTAB
164166
}
165167
#lappend SQLITE_OPTIONS -DSQLITE_ENABLE_FTS3=1
166168
#lappend SQLITE_OPTIONS -DSQLITE_ENABLE_STAT4
167169
#lappend SQLITE_OPTIONS -DSQLITE_WIN32_NO_ANSI
168170
#lappend SQLITE_OPTIONS -DSQLITE_WINNT_MAX_PATH_CHARS=4096
169171
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -90,10 +90,11 @@
90 merge
91 merge3
92 moderate
93 name
94 path
 
95 pivot
96 popen
97 pqueue
98 printf
99 publish
@@ -159,10 +160,11 @@
159 -DSQLITE_DEFAULT_FILE_FORMAT=4
160 -DSQLITE_OMIT_DEPRECATED
161 -DSQLITE_ENABLE_EXPLAIN_COMMENTS
162 -DSQLITE_ENABLE_FTS4
163 -DSQLITE_ENABLE_FTS3_PARENTHESIS
 
164 }
165 #lappend SQLITE_OPTIONS -DSQLITE_ENABLE_FTS3=1
166 #lappend SQLITE_OPTIONS -DSQLITE_ENABLE_STAT4
167 #lappend SQLITE_OPTIONS -DSQLITE_WIN32_NO_ANSI
168 #lappend SQLITE_OPTIONS -DSQLITE_WINNT_MAX_PATH_CHARS=4096
169
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -90,10 +90,11 @@
90 merge
91 merge3
92 moderate
93 name
94 path
95 piechart
96 pivot
97 popen
98 pqueue
99 printf
100 publish
@@ -159,10 +160,11 @@
160 -DSQLITE_DEFAULT_FILE_FORMAT=4
161 -DSQLITE_OMIT_DEPRECATED
162 -DSQLITE_ENABLE_EXPLAIN_COMMENTS
163 -DSQLITE_ENABLE_FTS4
164 -DSQLITE_ENABLE_FTS3_PARENTHESIS
165 -DSQLITE_ENABLE_DBSTAT_VTAB
166 }
167 #lappend SQLITE_OPTIONS -DSQLITE_ENABLE_FTS3=1
168 #lappend SQLITE_OPTIONS -DSQLITE_ENABLE_STAT4
169 #lappend SQLITE_OPTIONS -DSQLITE_WIN32_NO_ANSI
170 #lappend SQLITE_OPTIONS -DSQLITE_WINNT_MAX_PATH_CHARS=4096
171
--- src/markdown_html.c
+++ src/markdown_html.c
@@ -34,16 +34,16 @@
3434
3535
/* INTER_BLOCK -- skip a line between block level elements */
3636
#define INTER_BLOCK(ob) \
3737
do { if( blob_size(ob)>0 ) blob_append(ob, "\n", 1); } while (0)
3838
39
-/* BLOB_APPEND_LITTERAL -- append a string litteral to a blob */
40
-#define BLOB_APPEND_LITTERAL(blob, litteral) \
41
- blob_append((blob), "" litteral, (sizeof litteral)-1)
39
+/* BLOB_APPEND_LITERAL -- append a string literal to a blob */
40
+#define BLOB_APPEND_LITERAL(blob, literal) \
41
+ blob_append((blob), "" literal, (sizeof literal)-1)
4242
/*
4343
* The empty string in the second argument leads to a syntax error
44
- * when the macro is not used with a string litteral. Unfortunately
44
+ * when the macro is not used with a string literal. Unfortunately
4545
* the error is not overly explicit.
4646
*/
4747
4848
/* BLOB_APPEND_BLOB -- append blob contents to another */
4949
#define BLOB_APPEND_BLOB(dest, src) \
@@ -65,17 +65,17 @@
6565
i++;
6666
}
6767
blob_append(ob, data+beg, i-beg);
6868
while( i<size ){
6969
if( data[i]=='<' ){
70
- BLOB_APPEND_LITTERAL(ob, "&lt;");
70
+ BLOB_APPEND_LITERAL(ob, "&lt;");
7171
}else if( data[i]=='>' ){
72
- BLOB_APPEND_LITTERAL(ob, "&gt;");
72
+ BLOB_APPEND_LITERAL(ob, "&gt;");
7373
}else if( data[i]=='&' ){
74
- BLOB_APPEND_LITTERAL(ob, "&amp;");
74
+ BLOB_APPEND_LITERAL(ob, "&amp;");
7575
}else if( data[i]=='"' ){
76
- BLOB_APPEND_LITTERAL(ob, "&quot;");
76
+ BLOB_APPEND_LITERAL(ob, "&quot;");
7777
}else{
7878
break;
7979
}
8080
i++;
8181
}
@@ -88,41 +88,41 @@
8888
/* Size of the prolog: "<div class='markdown'>\n" */
8989
#define PROLOG_SIZE 23
9090
9191
static void html_prolog(struct Blob *ob, void *opaque){
9292
INTER_BLOCK(ob);
93
- BLOB_APPEND_LITTERAL(ob, "<div class=\"markdown\">\n");
93
+ BLOB_APPEND_LITERAL(ob, "<div class=\"markdown\">\n");
9494
assert( blob_size(ob)==PROLOG_SIZE );
9595
}
9696
9797
static void html_epilog(struct Blob *ob, void *opaque){
9898
INTER_BLOCK(ob);
99
- BLOB_APPEND_LITTERAL(ob, "</div>\n");
99
+ BLOB_APPEND_LITERAL(ob, "</div>\n");
100100
}
101101
102102
static void html_raw_block(struct Blob *ob, struct Blob *text, void *opaque){
103103
char *data = blob_buffer(text);
104104
size_t first = 0, size = blob_size(text);
105105
INTER_BLOCK(ob);
106106
while( first<size && data[first]=='\n' ) first++;
107107
while( size>first && data[size-1]=='\n' ) size--;
108108
blob_append(ob, data+first, size-first);
109
- BLOB_APPEND_LITTERAL(ob, "\n");
109
+ BLOB_APPEND_LITERAL(ob, "\n");
110110
}
111111
112112
static void html_blockcode(struct Blob *ob, struct Blob *text, void *opaque){
113113
INTER_BLOCK(ob);
114
- BLOB_APPEND_LITTERAL(ob, "<pre><code>");
114
+ BLOB_APPEND_LITERAL(ob, "<pre><code>");
115115
html_escape(ob, blob_buffer(text), blob_size(text));
116
- BLOB_APPEND_LITTERAL(ob, "</code></pre>\n");
116
+ BLOB_APPEND_LITERAL(ob, "</code></pre>\n");
117117
}
118118
119119
static void html_blockquote(struct Blob *ob, struct Blob *text, void *opaque){
120120
INTER_BLOCK(ob);
121
- BLOB_APPEND_LITTERAL(ob, "<blockquote>\n");
121
+ BLOB_APPEND_LITERAL(ob, "<blockquote>\n");
122122
BLOB_APPEND_BLOB(ob, text);
123
- BLOB_APPEND_LITTERAL(ob, "</blockquote>\n");
123
+ BLOB_APPEND_LITERAL(ob, "</blockquote>\n");
124124
}
125125
126126
static void html_header(
127127
struct Blob *ob,
128128
struct Blob *text,
@@ -141,11 +141,11 @@
141141
blob_appendf(ob, "</h%d>", level);
142142
}
143143
144144
static void html_hrule(struct Blob *ob, void *opaque){
145145
INTER_BLOCK(ob);
146
- BLOB_APPEND_LITTERAL(ob, "<hr />\n");
146
+ BLOB_APPEND_LITERAL(ob, "<hr />\n");
147147
}
148148
149149
150150
static void html_list(
151151
struct Blob *ob,
@@ -169,20 +169,20 @@
169169
void *opaque
170170
){
171171
char *text_data = blob_buffer(text);
172172
size_t text_size = blob_size(text);
173173
while( text_size>0 && text_data[text_size-1]=='\n' ) text_size--;
174
- BLOB_APPEND_LITTERAL(ob, "<li>");
174
+ BLOB_APPEND_LITERAL(ob, "<li>");
175175
blob_append(ob, text_data, text_size);
176
- BLOB_APPEND_LITTERAL(ob, "</li>\n");
176
+ BLOB_APPEND_LITERAL(ob, "</li>\n");
177177
}
178178
179179
static void html_paragraph(struct Blob *ob, struct Blob *text, void *opaque){
180180
INTER_BLOCK(ob);
181
- BLOB_APPEND_LITTERAL(ob, "<p>");
181
+ BLOB_APPEND_LITERAL(ob, "<p>");
182182
BLOB_APPEND_BLOB(ob, text);
183
- BLOB_APPEND_LITTERAL(ob, "</p>\n");
183
+ BLOB_APPEND_LITERAL(ob, "</p>\n");
184184
}
185185
186186
187187
static void html_table(
188188
struct Blob *ob,
@@ -189,68 +189,68 @@
189189
struct Blob *head_row,
190190
struct Blob *rows,
191191
void *opaque
192192
){
193193
INTER_BLOCK(ob);
194
- BLOB_APPEND_LITTERAL(ob, "<table>\n");
194
+ BLOB_APPEND_LITERAL(ob, "<table>\n");
195195
if( head_row && blob_size(head_row)>0 ){
196
- BLOB_APPEND_LITTERAL(ob, "<thead>\n");
196
+ BLOB_APPEND_LITERAL(ob, "<thead>\n");
197197
BLOB_APPEND_BLOB(ob, head_row);
198
- BLOB_APPEND_LITTERAL(ob, "</thead>\n<tbody>\n");
198
+ BLOB_APPEND_LITERAL(ob, "</thead>\n<tbody>\n");
199199
}
200200
if( rows ){
201201
BLOB_APPEND_BLOB(ob, rows);
202202
}
203203
if( head_row && blob_size(head_row)>0 ){
204
- BLOB_APPEND_LITTERAL(ob, "</tbody>\n");
204
+ BLOB_APPEND_LITERAL(ob, "</tbody>\n");
205205
}
206
- BLOB_APPEND_LITTERAL(ob, "</table>\n");
206
+ BLOB_APPEND_LITERAL(ob, "</table>\n");
207207
}
208208
209209
static void html_table_cell(
210210
struct Blob *ob,
211211
struct Blob *text,
212212
int flags,
213213
void *opaque
214214
){
215215
if( flags & MKD_CELL_HEAD ){
216
- BLOB_APPEND_LITTERAL(ob, " <th");
216
+ BLOB_APPEND_LITERAL(ob, " <th");
217217
}else{
218
- BLOB_APPEND_LITTERAL(ob, " <td");
218
+ BLOB_APPEND_LITERAL(ob, " <td");
219219
}
220220
switch( flags & MKD_CELL_ALIGN_MASK ){
221221
case MKD_CELL_ALIGN_LEFT: {
222
- BLOB_APPEND_LITTERAL(ob, " align=\"left\"");
222
+ BLOB_APPEND_LITERAL(ob, " align=\"left\"");
223223
break;
224224
}
225225
case MKD_CELL_ALIGN_RIGHT: {
226
- BLOB_APPEND_LITTERAL(ob, " align=\"right\"");
226
+ BLOB_APPEND_LITERAL(ob, " align=\"right\"");
227227
break;
228228
}
229229
case MKD_CELL_ALIGN_CENTER: {
230
- BLOB_APPEND_LITTERAL(ob, " align=\"center\"");
230
+ BLOB_APPEND_LITERAL(ob, " align=\"center\"");
231231
break;
232232
}
233233
}
234
- BLOB_APPEND_LITTERAL(ob, ">");
234
+ BLOB_APPEND_LITERAL(ob, ">");
235235
BLOB_APPEND_BLOB(ob, text);
236236
if( flags & MKD_CELL_HEAD ){
237
- BLOB_APPEND_LITTERAL(ob, "</th>\n");
237
+ BLOB_APPEND_LITERAL(ob, "</th>\n");
238238
}else{
239
- BLOB_APPEND_LITTERAL(ob, "</td>\n");
239
+ BLOB_APPEND_LITERAL(ob, "</td>\n");
240240
}
241241
}
242242
243243
static void html_table_row(
244244
struct Blob *ob,
245245
struct Blob *cells,
246246
int flags,
247247
void *opaque
248248
){
249
- BLOB_APPEND_LITTERAL(ob, " <tr>\n");
249
+ BLOB_APPEND_LITERAL(ob, " <tr>\n");
250250
BLOB_APPEND_BLOB(ob, cells);
251
- BLOB_APPEND_LITTERAL(ob, " </tr>\n");
251
+ BLOB_APPEND_LITERAL(ob, " </tr>\n");
252252
}
253253
254254
255255
256256
/* HTML span tags */
@@ -265,52 +265,52 @@
265265
struct Blob *link,
266266
enum mkd_autolink type,
267267
void *opaque
268268
){
269269
if( !link || blob_size(link)<=0 ) return 0;
270
- BLOB_APPEND_LITTERAL(ob, "<a href=\"");
271
- if( type==MKDA_IMPLICIT_EMAIL ) BLOB_APPEND_LITTERAL(ob, "mailto:");
270
+ BLOB_APPEND_LITERAL(ob, "<a href=\"");
271
+ if( type==MKDA_IMPLICIT_EMAIL ) BLOB_APPEND_LITERAL(ob, "mailto:");
272272
html_escape(ob, blob_buffer(link), blob_size(link));
273
- BLOB_APPEND_LITTERAL(ob, "\">");
273
+ BLOB_APPEND_LITERAL(ob, "\">");
274274
if( type==MKDA_EXPLICIT_EMAIL && blob_size(link)>7 ){
275275
/* remove "mailto:" from displayed text */
276276
html_escape(ob, blob_buffer(link)+7, blob_size(link)-7);
277277
}else{
278278
html_escape(ob, blob_buffer(link), blob_size(link));
279279
}
280
- BLOB_APPEND_LITTERAL(ob, "</a>");
280
+ BLOB_APPEND_LITERAL(ob, "</a>");
281281
return 1;
282282
}
283283
284284
static int html_code_span(struct Blob *ob, struct Blob *text, void *opaque){
285
- BLOB_APPEND_LITTERAL(ob, "<code>");
285
+ BLOB_APPEND_LITERAL(ob, "<code>");
286286
html_escape(ob, blob_buffer(text), blob_size(text));
287
- BLOB_APPEND_LITTERAL(ob, "</code>");
287
+ BLOB_APPEND_LITERAL(ob, "</code>");
288288
return 1;
289289
}
290290
291291
static int html_double_emphasis(
292292
struct Blob *ob,
293293
struct Blob *text,
294294
char c,
295295
void *opaque
296296
){
297
- BLOB_APPEND_LITTERAL(ob, "<strong>");
297
+ BLOB_APPEND_LITERAL(ob, "<strong>");
298298
BLOB_APPEND_BLOB(ob, text);
299
- BLOB_APPEND_LITTERAL(ob, "</strong>");
299
+ BLOB_APPEND_LITERAL(ob, "</strong>");
300300
return 1;
301301
}
302302
303303
static int html_emphasis(
304304
struct Blob *ob,
305305
struct Blob *text,
306306
char c,
307307
void *opaque
308308
){
309
- BLOB_APPEND_LITTERAL(ob, "<em>");
309
+ BLOB_APPEND_LITERAL(ob, "<em>");
310310
BLOB_APPEND_BLOB(ob, text);
311
- BLOB_APPEND_LITTERAL(ob, "</em>");
311
+ BLOB_APPEND_LITERAL(ob, "</em>");
312312
return 1;
313313
}
314314
315315
static int html_image(
316316
struct Blob *ob,
@@ -317,24 +317,24 @@
317317
struct Blob *link,
318318
struct Blob *title,
319319
struct Blob *alt,
320320
void *opaque
321321
){
322
- BLOB_APPEND_LITTERAL(ob, "<img src=\"");
322
+ BLOB_APPEND_LITERAL(ob, "<img src=\"");
323323
html_escape(ob, blob_buffer(link), blob_size(link));
324
- BLOB_APPEND_LITTERAL(ob, "\" alt=\"");
324
+ BLOB_APPEND_LITERAL(ob, "\" alt=\"");
325325
html_escape(ob, blob_buffer(alt), blob_size(alt));
326326
if( title && blob_size(title)>0 ){
327
- BLOB_APPEND_LITTERAL(ob, "\" title=\"");
327
+ BLOB_APPEND_LITERAL(ob, "\" title=\"");
328328
html_escape(ob, blob_buffer(title), blob_size(title));
329329
}
330
- BLOB_APPEND_LITTERAL(ob, "\" />");
330
+ BLOB_APPEND_LITERAL(ob, "\" />");
331331
return 1;
332332
}
333333
334334
static int html_line_break(struct Blob *ob, void *opaque){
335
- BLOB_APPEND_LITTERAL(ob, "<br />\n");
335
+ BLOB_APPEND_LITERAL(ob, "<br />\n");
336336
return 1;
337337
}
338338
339339
static int html_link(
340340
struct Blob *ob,
@@ -341,31 +341,31 @@
341341
struct Blob *link,
342342
struct Blob *title,
343343
struct Blob *content,
344344
void *opaque
345345
){
346
- BLOB_APPEND_LITTERAL(ob, "<a href=\"");
346
+ BLOB_APPEND_LITERAL(ob, "<a href=\"");
347347
html_escape(ob, blob_buffer(link), blob_size(link));
348348
if( title && blob_size(title)>0 ){
349
- BLOB_APPEND_LITTERAL(ob, "\" title=\"");
349
+ BLOB_APPEND_LITERAL(ob, "\" title=\"");
350350
html_escape(ob, blob_buffer(title), blob_size(title));
351351
}
352
- BLOB_APPEND_LITTERAL(ob, "\">");
352
+ BLOB_APPEND_LITERAL(ob, "\">");
353353
BLOB_APPEND_BLOB(ob, content);
354
- BLOB_APPEND_LITTERAL(ob, "</a>");
354
+ BLOB_APPEND_LITERAL(ob, "</a>");
355355
return 1;
356356
}
357357
358358
static int html_triple_emphasis(
359359
struct Blob *ob,
360360
struct Blob *text,
361361
char c,
362362
void *opaque
363363
){
364
- BLOB_APPEND_LITTERAL(ob, "<strong><em>");
364
+ BLOB_APPEND_LITERAL(ob, "<strong><em>");
365365
BLOB_APPEND_BLOB(ob, text);
366
- BLOB_APPEND_LITTERAL(ob, "</em></strong>");
366
+ BLOB_APPEND_LITERAL(ob, "</em></strong>");
367367
return 1;
368368
}
369369
370370
371371
static void html_normal_text(struct Blob *ob, struct Blob *text, void *opaque){
372372
--- src/markdown_html.c
+++ src/markdown_html.c
@@ -34,16 +34,16 @@
34
35 /* INTER_BLOCK -- skip a line between block level elements */
36 #define INTER_BLOCK(ob) \
37 do { if( blob_size(ob)>0 ) blob_append(ob, "\n", 1); } while (0)
38
39 /* BLOB_APPEND_LITTERAL -- append a string litteral to a blob */
40 #define BLOB_APPEND_LITTERAL(blob, litteral) \
41 blob_append((blob), "" litteral, (sizeof litteral)-1)
42 /*
43 * The empty string in the second argument leads to a syntax error
44 * when the macro is not used with a string litteral. Unfortunately
45 * the error is not overly explicit.
46 */
47
48 /* BLOB_APPEND_BLOB -- append blob contents to another */
49 #define BLOB_APPEND_BLOB(dest, src) \
@@ -65,17 +65,17 @@
65 i++;
66 }
67 blob_append(ob, data+beg, i-beg);
68 while( i<size ){
69 if( data[i]=='<' ){
70 BLOB_APPEND_LITTERAL(ob, "&lt;");
71 }else if( data[i]=='>' ){
72 BLOB_APPEND_LITTERAL(ob, "&gt;");
73 }else if( data[i]=='&' ){
74 BLOB_APPEND_LITTERAL(ob, "&amp;");
75 }else if( data[i]=='"' ){
76 BLOB_APPEND_LITTERAL(ob, "&quot;");
77 }else{
78 break;
79 }
80 i++;
81 }
@@ -88,41 +88,41 @@
88 /* Size of the prolog: "<div class='markdown'>\n" */
89 #define PROLOG_SIZE 23
90
91 static void html_prolog(struct Blob *ob, void *opaque){
92 INTER_BLOCK(ob);
93 BLOB_APPEND_LITTERAL(ob, "<div class=\"markdown\">\n");
94 assert( blob_size(ob)==PROLOG_SIZE );
95 }
96
97 static void html_epilog(struct Blob *ob, void *opaque){
98 INTER_BLOCK(ob);
99 BLOB_APPEND_LITTERAL(ob, "</div>\n");
100 }
101
102 static void html_raw_block(struct Blob *ob, struct Blob *text, void *opaque){
103 char *data = blob_buffer(text);
104 size_t first = 0, size = blob_size(text);
105 INTER_BLOCK(ob);
106 while( first<size && data[first]=='\n' ) first++;
107 while( size>first && data[size-1]=='\n' ) size--;
108 blob_append(ob, data+first, size-first);
109 BLOB_APPEND_LITTERAL(ob, "\n");
110 }
111
112 static void html_blockcode(struct Blob *ob, struct Blob *text, void *opaque){
113 INTER_BLOCK(ob);
114 BLOB_APPEND_LITTERAL(ob, "<pre><code>");
115 html_escape(ob, blob_buffer(text), blob_size(text));
116 BLOB_APPEND_LITTERAL(ob, "</code></pre>\n");
117 }
118
119 static void html_blockquote(struct Blob *ob, struct Blob *text, void *opaque){
120 INTER_BLOCK(ob);
121 BLOB_APPEND_LITTERAL(ob, "<blockquote>\n");
122 BLOB_APPEND_BLOB(ob, text);
123 BLOB_APPEND_LITTERAL(ob, "</blockquote>\n");
124 }
125
126 static void html_header(
127 struct Blob *ob,
128 struct Blob *text,
@@ -141,11 +141,11 @@
141 blob_appendf(ob, "</h%d>", level);
142 }
143
144 static void html_hrule(struct Blob *ob, void *opaque){
145 INTER_BLOCK(ob);
146 BLOB_APPEND_LITTERAL(ob, "<hr />\n");
147 }
148
149
150 static void html_list(
151 struct Blob *ob,
@@ -169,20 +169,20 @@
169 void *opaque
170 ){
171 char *text_data = blob_buffer(text);
172 size_t text_size = blob_size(text);
173 while( text_size>0 && text_data[text_size-1]=='\n' ) text_size--;
174 BLOB_APPEND_LITTERAL(ob, "<li>");
175 blob_append(ob, text_data, text_size);
176 BLOB_APPEND_LITTERAL(ob, "</li>\n");
177 }
178
179 static void html_paragraph(struct Blob *ob, struct Blob *text, void *opaque){
180 INTER_BLOCK(ob);
181 BLOB_APPEND_LITTERAL(ob, "<p>");
182 BLOB_APPEND_BLOB(ob, text);
183 BLOB_APPEND_LITTERAL(ob, "</p>\n");
184 }
185
186
187 static void html_table(
188 struct Blob *ob,
@@ -189,68 +189,68 @@
189 struct Blob *head_row,
190 struct Blob *rows,
191 void *opaque
192 ){
193 INTER_BLOCK(ob);
194 BLOB_APPEND_LITTERAL(ob, "<table>\n");
195 if( head_row && blob_size(head_row)>0 ){
196 BLOB_APPEND_LITTERAL(ob, "<thead>\n");
197 BLOB_APPEND_BLOB(ob, head_row);
198 BLOB_APPEND_LITTERAL(ob, "</thead>\n<tbody>\n");
199 }
200 if( rows ){
201 BLOB_APPEND_BLOB(ob, rows);
202 }
203 if( head_row && blob_size(head_row)>0 ){
204 BLOB_APPEND_LITTERAL(ob, "</tbody>\n");
205 }
206 BLOB_APPEND_LITTERAL(ob, "</table>\n");
207 }
208
209 static void html_table_cell(
210 struct Blob *ob,
211 struct Blob *text,
212 int flags,
213 void *opaque
214 ){
215 if( flags & MKD_CELL_HEAD ){
216 BLOB_APPEND_LITTERAL(ob, " <th");
217 }else{
218 BLOB_APPEND_LITTERAL(ob, " <td");
219 }
220 switch( flags & MKD_CELL_ALIGN_MASK ){
221 case MKD_CELL_ALIGN_LEFT: {
222 BLOB_APPEND_LITTERAL(ob, " align=\"left\"");
223 break;
224 }
225 case MKD_CELL_ALIGN_RIGHT: {
226 BLOB_APPEND_LITTERAL(ob, " align=\"right\"");
227 break;
228 }
229 case MKD_CELL_ALIGN_CENTER: {
230 BLOB_APPEND_LITTERAL(ob, " align=\"center\"");
231 break;
232 }
233 }
234 BLOB_APPEND_LITTERAL(ob, ">");
235 BLOB_APPEND_BLOB(ob, text);
236 if( flags & MKD_CELL_HEAD ){
237 BLOB_APPEND_LITTERAL(ob, "</th>\n");
238 }else{
239 BLOB_APPEND_LITTERAL(ob, "</td>\n");
240 }
241 }
242
243 static void html_table_row(
244 struct Blob *ob,
245 struct Blob *cells,
246 int flags,
247 void *opaque
248 ){
249 BLOB_APPEND_LITTERAL(ob, " <tr>\n");
250 BLOB_APPEND_BLOB(ob, cells);
251 BLOB_APPEND_LITTERAL(ob, " </tr>\n");
252 }
253
254
255
256 /* HTML span tags */
@@ -265,52 +265,52 @@
265 struct Blob *link,
266 enum mkd_autolink type,
267 void *opaque
268 ){
269 if( !link || blob_size(link)<=0 ) return 0;
270 BLOB_APPEND_LITTERAL(ob, "<a href=\"");
271 if( type==MKDA_IMPLICIT_EMAIL ) BLOB_APPEND_LITTERAL(ob, "mailto:");
272 html_escape(ob, blob_buffer(link), blob_size(link));
273 BLOB_APPEND_LITTERAL(ob, "\">");
274 if( type==MKDA_EXPLICIT_EMAIL && blob_size(link)>7 ){
275 /* remove "mailto:" from displayed text */
276 html_escape(ob, blob_buffer(link)+7, blob_size(link)-7);
277 }else{
278 html_escape(ob, blob_buffer(link), blob_size(link));
279 }
280 BLOB_APPEND_LITTERAL(ob, "</a>");
281 return 1;
282 }
283
284 static int html_code_span(struct Blob *ob, struct Blob *text, void *opaque){
285 BLOB_APPEND_LITTERAL(ob, "<code>");
286 html_escape(ob, blob_buffer(text), blob_size(text));
287 BLOB_APPEND_LITTERAL(ob, "</code>");
288 return 1;
289 }
290
291 static int html_double_emphasis(
292 struct Blob *ob,
293 struct Blob *text,
294 char c,
295 void *opaque
296 ){
297 BLOB_APPEND_LITTERAL(ob, "<strong>");
298 BLOB_APPEND_BLOB(ob, text);
299 BLOB_APPEND_LITTERAL(ob, "</strong>");
300 return 1;
301 }
302
303 static int html_emphasis(
304 struct Blob *ob,
305 struct Blob *text,
306 char c,
307 void *opaque
308 ){
309 BLOB_APPEND_LITTERAL(ob, "<em>");
310 BLOB_APPEND_BLOB(ob, text);
311 BLOB_APPEND_LITTERAL(ob, "</em>");
312 return 1;
313 }
314
315 static int html_image(
316 struct Blob *ob,
@@ -317,24 +317,24 @@
317 struct Blob *link,
318 struct Blob *title,
319 struct Blob *alt,
320 void *opaque
321 ){
322 BLOB_APPEND_LITTERAL(ob, "<img src=\"");
323 html_escape(ob, blob_buffer(link), blob_size(link));
324 BLOB_APPEND_LITTERAL(ob, "\" alt=\"");
325 html_escape(ob, blob_buffer(alt), blob_size(alt));
326 if( title && blob_size(title)>0 ){
327 BLOB_APPEND_LITTERAL(ob, "\" title=\"");
328 html_escape(ob, blob_buffer(title), blob_size(title));
329 }
330 BLOB_APPEND_LITTERAL(ob, "\" />");
331 return 1;
332 }
333
334 static int html_line_break(struct Blob *ob, void *opaque){
335 BLOB_APPEND_LITTERAL(ob, "<br />\n");
336 return 1;
337 }
338
339 static int html_link(
340 struct Blob *ob,
@@ -341,31 +341,31 @@
341 struct Blob *link,
342 struct Blob *title,
343 struct Blob *content,
344 void *opaque
345 ){
346 BLOB_APPEND_LITTERAL(ob, "<a href=\"");
347 html_escape(ob, blob_buffer(link), blob_size(link));
348 if( title && blob_size(title)>0 ){
349 BLOB_APPEND_LITTERAL(ob, "\" title=\"");
350 html_escape(ob, blob_buffer(title), blob_size(title));
351 }
352 BLOB_APPEND_LITTERAL(ob, "\">");
353 BLOB_APPEND_BLOB(ob, content);
354 BLOB_APPEND_LITTERAL(ob, "</a>");
355 return 1;
356 }
357
358 static int html_triple_emphasis(
359 struct Blob *ob,
360 struct Blob *text,
361 char c,
362 void *opaque
363 ){
364 BLOB_APPEND_LITTERAL(ob, "<strong><em>");
365 BLOB_APPEND_BLOB(ob, text);
366 BLOB_APPEND_LITTERAL(ob, "</em></strong>");
367 return 1;
368 }
369
370
371 static void html_normal_text(struct Blob *ob, struct Blob *text, void *opaque){
372
--- src/markdown_html.c
+++ src/markdown_html.c
@@ -34,16 +34,16 @@
34
35 /* INTER_BLOCK -- skip a line between block level elements */
36 #define INTER_BLOCK(ob) \
37 do { if( blob_size(ob)>0 ) blob_append(ob, "\n", 1); } while (0)
38
39 /* BLOB_APPEND_LITERAL -- append a string literal to a blob */
40 #define BLOB_APPEND_LITERAL(blob, literal) \
41 blob_append((blob), "" literal, (sizeof literal)-1)
42 /*
43 * The empty string in the second argument leads to a syntax error
44 * when the macro is not used with a string literal. Unfortunately
45 * the error is not overly explicit.
46 */
47
48 /* BLOB_APPEND_BLOB -- append blob contents to another */
49 #define BLOB_APPEND_BLOB(dest, src) \
@@ -65,17 +65,17 @@
65 i++;
66 }
67 blob_append(ob, data+beg, i-beg);
68 while( i<size ){
69 if( data[i]=='<' ){
70 BLOB_APPEND_LITERAL(ob, "&lt;");
71 }else if( data[i]=='>' ){
72 BLOB_APPEND_LITERAL(ob, "&gt;");
73 }else if( data[i]=='&' ){
74 BLOB_APPEND_LITERAL(ob, "&amp;");
75 }else if( data[i]=='"' ){
76 BLOB_APPEND_LITERAL(ob, "&quot;");
77 }else{
78 break;
79 }
80 i++;
81 }
@@ -88,41 +88,41 @@
88 /* Size of the prolog: "<div class='markdown'>\n" */
89 #define PROLOG_SIZE 23
90
91 static void html_prolog(struct Blob *ob, void *opaque){
92 INTER_BLOCK(ob);
93 BLOB_APPEND_LITERAL(ob, "<div class=\"markdown\">\n");
94 assert( blob_size(ob)==PROLOG_SIZE );
95 }
96
97 static void html_epilog(struct Blob *ob, void *opaque){
98 INTER_BLOCK(ob);
99 BLOB_APPEND_LITERAL(ob, "</div>\n");
100 }
101
102 static void html_raw_block(struct Blob *ob, struct Blob *text, void *opaque){
103 char *data = blob_buffer(text);
104 size_t first = 0, size = blob_size(text);
105 INTER_BLOCK(ob);
106 while( first<size && data[first]=='\n' ) first++;
107 while( size>first && data[size-1]=='\n' ) size--;
108 blob_append(ob, data+first, size-first);
109 BLOB_APPEND_LITERAL(ob, "\n");
110 }
111
112 static void html_blockcode(struct Blob *ob, struct Blob *text, void *opaque){
113 INTER_BLOCK(ob);
114 BLOB_APPEND_LITERAL(ob, "<pre><code>");
115 html_escape(ob, blob_buffer(text), blob_size(text));
116 BLOB_APPEND_LITERAL(ob, "</code></pre>\n");
117 }
118
119 static void html_blockquote(struct Blob *ob, struct Blob *text, void *opaque){
120 INTER_BLOCK(ob);
121 BLOB_APPEND_LITERAL(ob, "<blockquote>\n");
122 BLOB_APPEND_BLOB(ob, text);
123 BLOB_APPEND_LITERAL(ob, "</blockquote>\n");
124 }
125
126 static void html_header(
127 struct Blob *ob,
128 struct Blob *text,
@@ -141,11 +141,11 @@
141 blob_appendf(ob, "</h%d>", level);
142 }
143
144 static void html_hrule(struct Blob *ob, void *opaque){
145 INTER_BLOCK(ob);
146 BLOB_APPEND_LITERAL(ob, "<hr />\n");
147 }
148
149
150 static void html_list(
151 struct Blob *ob,
@@ -169,20 +169,20 @@
169 void *opaque
170 ){
171 char *text_data = blob_buffer(text);
172 size_t text_size = blob_size(text);
173 while( text_size>0 && text_data[text_size-1]=='\n' ) text_size--;
174 BLOB_APPEND_LITERAL(ob, "<li>");
175 blob_append(ob, text_data, text_size);
176 BLOB_APPEND_LITERAL(ob, "</li>\n");
177 }
178
179 static void html_paragraph(struct Blob *ob, struct Blob *text, void *opaque){
180 INTER_BLOCK(ob);
181 BLOB_APPEND_LITERAL(ob, "<p>");
182 BLOB_APPEND_BLOB(ob, text);
183 BLOB_APPEND_LITERAL(ob, "</p>\n");
184 }
185
186
187 static void html_table(
188 struct Blob *ob,
@@ -189,68 +189,68 @@
189 struct Blob *head_row,
190 struct Blob *rows,
191 void *opaque
192 ){
193 INTER_BLOCK(ob);
194 BLOB_APPEND_LITERAL(ob, "<table>\n");
195 if( head_row && blob_size(head_row)>0 ){
196 BLOB_APPEND_LITERAL(ob, "<thead>\n");
197 BLOB_APPEND_BLOB(ob, head_row);
198 BLOB_APPEND_LITERAL(ob, "</thead>\n<tbody>\n");
199 }
200 if( rows ){
201 BLOB_APPEND_BLOB(ob, rows);
202 }
203 if( head_row && blob_size(head_row)>0 ){
204 BLOB_APPEND_LITERAL(ob, "</tbody>\n");
205 }
206 BLOB_APPEND_LITERAL(ob, "</table>\n");
207 }
208
209 static void html_table_cell(
210 struct Blob *ob,
211 struct Blob *text,
212 int flags,
213 void *opaque
214 ){
215 if( flags & MKD_CELL_HEAD ){
216 BLOB_APPEND_LITERAL(ob, " <th");
217 }else{
218 BLOB_APPEND_LITERAL(ob, " <td");
219 }
220 switch( flags & MKD_CELL_ALIGN_MASK ){
221 case MKD_CELL_ALIGN_LEFT: {
222 BLOB_APPEND_LITERAL(ob, " align=\"left\"");
223 break;
224 }
225 case MKD_CELL_ALIGN_RIGHT: {
226 BLOB_APPEND_LITERAL(ob, " align=\"right\"");
227 break;
228 }
229 case MKD_CELL_ALIGN_CENTER: {
230 BLOB_APPEND_LITERAL(ob, " align=\"center\"");
231 break;
232 }
233 }
234 BLOB_APPEND_LITERAL(ob, ">");
235 BLOB_APPEND_BLOB(ob, text);
236 if( flags & MKD_CELL_HEAD ){
237 BLOB_APPEND_LITERAL(ob, "</th>\n");
238 }else{
239 BLOB_APPEND_LITERAL(ob, "</td>\n");
240 }
241 }
242
243 static void html_table_row(
244 struct Blob *ob,
245 struct Blob *cells,
246 int flags,
247 void *opaque
248 ){
249 BLOB_APPEND_LITERAL(ob, " <tr>\n");
250 BLOB_APPEND_BLOB(ob, cells);
251 BLOB_APPEND_LITERAL(ob, " </tr>\n");
252 }
253
254
255
256 /* HTML span tags */
@@ -265,52 +265,52 @@
265 struct Blob *link,
266 enum mkd_autolink type,
267 void *opaque
268 ){
269 if( !link || blob_size(link)<=0 ) return 0;
270 BLOB_APPEND_LITERAL(ob, "<a href=\"");
271 if( type==MKDA_IMPLICIT_EMAIL ) BLOB_APPEND_LITERAL(ob, "mailto:");
272 html_escape(ob, blob_buffer(link), blob_size(link));
273 BLOB_APPEND_LITERAL(ob, "\">");
274 if( type==MKDA_EXPLICIT_EMAIL && blob_size(link)>7 ){
275 /* remove "mailto:" from displayed text */
276 html_escape(ob, blob_buffer(link)+7, blob_size(link)-7);
277 }else{
278 html_escape(ob, blob_buffer(link), blob_size(link));
279 }
280 BLOB_APPEND_LITERAL(ob, "</a>");
281 return 1;
282 }
283
284 static int html_code_span(struct Blob *ob, struct Blob *text, void *opaque){
285 BLOB_APPEND_LITERAL(ob, "<code>");
286 html_escape(ob, blob_buffer(text), blob_size(text));
287 BLOB_APPEND_LITERAL(ob, "</code>");
288 return 1;
289 }
290
291 static int html_double_emphasis(
292 struct Blob *ob,
293 struct Blob *text,
294 char c,
295 void *opaque
296 ){
297 BLOB_APPEND_LITERAL(ob, "<strong>");
298 BLOB_APPEND_BLOB(ob, text);
299 BLOB_APPEND_LITERAL(ob, "</strong>");
300 return 1;
301 }
302
303 static int html_emphasis(
304 struct Blob *ob,
305 struct Blob *text,
306 char c,
307 void *opaque
308 ){
309 BLOB_APPEND_LITERAL(ob, "<em>");
310 BLOB_APPEND_BLOB(ob, text);
311 BLOB_APPEND_LITERAL(ob, "</em>");
312 return 1;
313 }
314
315 static int html_image(
316 struct Blob *ob,
@@ -317,24 +317,24 @@
317 struct Blob *link,
318 struct Blob *title,
319 struct Blob *alt,
320 void *opaque
321 ){
322 BLOB_APPEND_LITERAL(ob, "<img src=\"");
323 html_escape(ob, blob_buffer(link), blob_size(link));
324 BLOB_APPEND_LITERAL(ob, "\" alt=\"");
325 html_escape(ob, blob_buffer(alt), blob_size(alt));
326 if( title && blob_size(title)>0 ){
327 BLOB_APPEND_LITERAL(ob, "\" title=\"");
328 html_escape(ob, blob_buffer(title), blob_size(title));
329 }
330 BLOB_APPEND_LITERAL(ob, "\" />");
331 return 1;
332 }
333
334 static int html_line_break(struct Blob *ob, void *opaque){
335 BLOB_APPEND_LITERAL(ob, "<br />\n");
336 return 1;
337 }
338
339 static int html_link(
340 struct Blob *ob,
@@ -341,31 +341,31 @@
341 struct Blob *link,
342 struct Blob *title,
343 struct Blob *content,
344 void *opaque
345 ){
346 BLOB_APPEND_LITERAL(ob, "<a href=\"");
347 html_escape(ob, blob_buffer(link), blob_size(link));
348 if( title && blob_size(title)>0 ){
349 BLOB_APPEND_LITERAL(ob, "\" title=\"");
350 html_escape(ob, blob_buffer(title), blob_size(title));
351 }
352 BLOB_APPEND_LITERAL(ob, "\">");
353 BLOB_APPEND_BLOB(ob, content);
354 BLOB_APPEND_LITERAL(ob, "</a>");
355 return 1;
356 }
357
358 static int html_triple_emphasis(
359 struct Blob *ob,
360 struct Blob *text,
361 char c,
362 void *opaque
363 ){
364 BLOB_APPEND_LITERAL(ob, "<strong><em>");
365 BLOB_APPEND_BLOB(ob, text);
366 BLOB_APPEND_LITERAL(ob, "</em></strong>");
367 return 1;
368 }
369
370
371 static void html_normal_text(struct Blob *ob, struct Blob *text, void *opaque){
372
+28 -10
--- src/name.c
+++ src/name.c
@@ -1068,29 +1068,26 @@
10681068
10691069
/* Maximum number of collision examples to remember */
10701070
#define MAX_COLLIDE 25
10711071
10721072
/*
1073
-** WEBPAGE: hash-collisions
1074
-**
1075
-** Show the number of hash collisions for hash prefixes of various lengths.
1073
+** Generate a report on the number of collisions in SHA1 hashes
1074
+** generated by the SQL given in the argument.
10761075
*/
1077
-void hash_collisions_webpage(void){
1076
+static void collision_report(const char *zSql){
10781077
int i, j, kk;
10791078
int nHash = 0;
10801079
Stmt q;
10811080
char zPrev[UUID_SIZE+1];
10821081
struct {
10831082
int cnt;
10841083
char *azHit[MAX_COLLIDE];
10851084
char z[UUID_SIZE+1];
10861085
} aCollide[UUID_SIZE+1];
1087
- login_check_credentials();
1088
- if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
10891086
memset(aCollide, 0, sizeof(aCollide));
10901087
memset(zPrev, 0, sizeof(zPrev));
1091
- db_prepare(&q,"SELECT uuid FROM blob ORDER BY 1");
1088
+ db_prepare(&q,"%s",zSql/*safe-for-%s*/);
10921089
while( db_step(&q)==SQLITE_ROW ){
10931090
const char *zUuid = db_column_text(&q,0);
10941091
int n = db_column_bytes(&q,0);
10951092
int i;
10961093
nHash++;
@@ -1103,13 +1100,10 @@
11031100
if( aCollide[i].z[0]==0 ) memcpy(aCollide[i].z, zPrev, n+1);
11041101
}
11051102
memcpy(zPrev, zUuid, n+1);
11061103
}
11071104
db_finalize(&q);
1108
- style_header("SHA1 Prefix Collisions");
1109
- style_submenu_element("Activity Reports", 0, "reports");
1110
- style_submenu_element("Stats", 0, "stat");
11111105
@ <table border=1><thead>
11121106
@ <tr><th>Length<th>Instances<th>First Instance</tr>
11131107
@ </thead><tbody>
11141108
for(i=1; i<=UUID_SIZE; i++){
11151109
if( aCollide[i].cnt==0 ) continue;
@@ -1131,7 +1125,31 @@
11311125
char *zId = aCollide[i].azHit[j];
11321126
if( zId==0 ) continue;
11331127
@ %z(href("%R/whatis/%s",zId))%h(zId)</a>
11341128
}
11351129
}
1130
+ for(i=4; i<ArraySize(aCollide); i++){
1131
+ for(j=0; j<aCollide[i].cnt && j<MAX_COLLIDE; j++){
1132
+ fossil_free(aCollide[i].azHit[j]);
1133
+ }
1134
+ }
1135
+}
1136
+
1137
+/*
1138
+** WEBPAGE: hash-collisions
1139
+**
1140
+** Show the number of hash collisions for hash prefixes of various lengths.
1141
+*/
1142
+void hash_collisions_webpage(void){
1143
+ login_check_credentials();
1144
+ if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
1145
+ style_header("SHA1 Prefix Collisions");
1146
+ style_submenu_element("Activity Reports", 0, "reports");
1147
+ style_submenu_element("Stats", 0, "stat");
1148
+ @ <h1>Hash Prefix Collisions on Check-ins</h1>
1149
+ collision_report("SELECT (SELECT uuid FROM blob WHERE rid=objid)"
1150
+ " FROM event WHERE event.type='ci'"
1151
+ " ORDER BY 1");
1152
+ @ <h1>Hash Prefix Collisions on All Artifacts</h1>
1153
+ collision_report("SELECT uuid FROM blob ORDER BY 1");
11361154
style_footer();
11371155
}
11381156
11391157
ADDED src/piechart.c
--- src/name.c
+++ src/name.c
@@ -1068,29 +1068,26 @@
1068
1069 /* Maximum number of collision examples to remember */
1070 #define MAX_COLLIDE 25
1071
1072 /*
1073 ** WEBPAGE: hash-collisions
1074 **
1075 ** Show the number of hash collisions for hash prefixes of various lengths.
1076 */
1077 void hash_collisions_webpage(void){
1078 int i, j, kk;
1079 int nHash = 0;
1080 Stmt q;
1081 char zPrev[UUID_SIZE+1];
1082 struct {
1083 int cnt;
1084 char *azHit[MAX_COLLIDE];
1085 char z[UUID_SIZE+1];
1086 } aCollide[UUID_SIZE+1];
1087 login_check_credentials();
1088 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
1089 memset(aCollide, 0, sizeof(aCollide));
1090 memset(zPrev, 0, sizeof(zPrev));
1091 db_prepare(&q,"SELECT uuid FROM blob ORDER BY 1");
1092 while( db_step(&q)==SQLITE_ROW ){
1093 const char *zUuid = db_column_text(&q,0);
1094 int n = db_column_bytes(&q,0);
1095 int i;
1096 nHash++;
@@ -1103,13 +1100,10 @@
1103 if( aCollide[i].z[0]==0 ) memcpy(aCollide[i].z, zPrev, n+1);
1104 }
1105 memcpy(zPrev, zUuid, n+1);
1106 }
1107 db_finalize(&q);
1108 style_header("SHA1 Prefix Collisions");
1109 style_submenu_element("Activity Reports", 0, "reports");
1110 style_submenu_element("Stats", 0, "stat");
1111 @ <table border=1><thead>
1112 @ <tr><th>Length<th>Instances<th>First Instance</tr>
1113 @ </thead><tbody>
1114 for(i=1; i<=UUID_SIZE; i++){
1115 if( aCollide[i].cnt==0 ) continue;
@@ -1131,7 +1125,31 @@
1131 char *zId = aCollide[i].azHit[j];
1132 if( zId==0 ) continue;
1133 @ %z(href("%R/whatis/%s",zId))%h(zId)</a>
1134 }
1135 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1136 style_footer();
1137 }
1138
1139 DDED src/piechart.c
--- src/name.c
+++ src/name.c
@@ -1068,29 +1068,26 @@
1068
1069 /* Maximum number of collision examples to remember */
1070 #define MAX_COLLIDE 25
1071
1072 /*
1073 ** Generate a report on the number of collisions in SHA1 hashes
1074 ** generated by the SQL given in the argument.
 
1075 */
1076 static void collision_report(const char *zSql){
1077 int i, j, kk;
1078 int nHash = 0;
1079 Stmt q;
1080 char zPrev[UUID_SIZE+1];
1081 struct {
1082 int cnt;
1083 char *azHit[MAX_COLLIDE];
1084 char z[UUID_SIZE+1];
1085 } aCollide[UUID_SIZE+1];
 
 
1086 memset(aCollide, 0, sizeof(aCollide));
1087 memset(zPrev, 0, sizeof(zPrev));
1088 db_prepare(&q,"%s",zSql/*safe-for-%s*/);
1089 while( db_step(&q)==SQLITE_ROW ){
1090 const char *zUuid = db_column_text(&q,0);
1091 int n = db_column_bytes(&q,0);
1092 int i;
1093 nHash++;
@@ -1103,13 +1100,10 @@
1100 if( aCollide[i].z[0]==0 ) memcpy(aCollide[i].z, zPrev, n+1);
1101 }
1102 memcpy(zPrev, zUuid, n+1);
1103 }
1104 db_finalize(&q);
 
 
 
1105 @ <table border=1><thead>
1106 @ <tr><th>Length<th>Instances<th>First Instance</tr>
1107 @ </thead><tbody>
1108 for(i=1; i<=UUID_SIZE; i++){
1109 if( aCollide[i].cnt==0 ) continue;
@@ -1131,7 +1125,31 @@
1125 char *zId = aCollide[i].azHit[j];
1126 if( zId==0 ) continue;
1127 @ %z(href("%R/whatis/%s",zId))%h(zId)</a>
1128 }
1129 }
1130 for(i=4; i<ArraySize(aCollide); i++){
1131 for(j=0; j<aCollide[i].cnt && j<MAX_COLLIDE; j++){
1132 fossil_free(aCollide[i].azHit[j]);
1133 }
1134 }
1135 }
1136
1137 /*
1138 ** WEBPAGE: hash-collisions
1139 **
1140 ** Show the number of hash collisions for hash prefixes of various lengths.
1141 */
1142 void hash_collisions_webpage(void){
1143 login_check_credentials();
1144 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
1145 style_header("SHA1 Prefix Collisions");
1146 style_submenu_element("Activity Reports", 0, "reports");
1147 style_submenu_element("Stats", 0, "stat");
1148 @ <h1>Hash Prefix Collisions on Check-ins</h1>
1149 collision_report("SELECT (SELECT uuid FROM blob WHERE rid=objid)"
1150 " FROM event WHERE event.type='ci'"
1151 " ORDER BY 1");
1152 @ <h1>Hash Prefix Collisions on All Artifacts</h1>
1153 collision_report("SELECT uuid FROM blob ORDER BY 1");
1154 style_footer();
1155 }
1156
1157 DDED src/piechart.c
--- a/src/piechart.c
+++ b/src/piechart.c
@@ -0,0 +1,19 @@
1
+/*
2
+** Copyright (c) 2015 D. Richard Hipp
3
+**
4
+** This program is free software; you can redistribute it and/or
5
+** modify it under the terms o return;test_piecharpiechart_tes, q;
6
+ Bloblob_init(&all, zData, -1);
7
+ whif( blob_token(&line, &token1)==0 ) continue;
8
+ rAmt = atof(blob_str(&token1));
9
+ if( rAmt<=0.0 ) continue;
10
+ blob_tail(&line, &token2blob_str(&token2)n++ins);
11
+ blob_reset(&all);
12
+ if( n>0postOne slice per line. Value and then Label.<p>
13
+ @ <textarea name='data' rows='20' cohidden<input type='hiddenhr /><p>Previous Data:<rowid,");
14
+ while( ){
15
+ @ <tr><td>%d(db_column_int1))</td>
16
+ @ <td>%h(db_c. @ </table>
17
+ style_footer();
18
+}
19
+=
--- a/src/piechart.c
+++ b/src/piechart.c
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/src/piechart.c
+++ b/src/piechart.c
@@ -0,0 +1,19 @@
1 /*
2 ** Copyright (c) 2015 D. Richard Hipp
3 **
4 ** This program is free software; you can redistribute it and/or
5 ** modify it under the terms o return;test_piecharpiechart_tes, q;
6 Bloblob_init(&all, zData, -1);
7 whif( blob_token(&line, &token1)==0 ) continue;
8 rAmt = atof(blob_str(&token1));
9 if( rAmt<=0.0 ) continue;
10 blob_tail(&line, &token2blob_str(&token2)n++ins);
11 blob_reset(&all);
12 if( n>0postOne slice per line. Value and then Label.<p>
13 @ <textarea name='data' rows='20' cohidden<input type='hiddenhr /><p>Previous Data:<rowid,");
14 while( ){
15 @ <tr><td>%d(db_column_int1))</td>
16 @ <td>%h(db_c. @ </table>
17 style_footer();
18 }
19 =
+26 -20
--- src/rebuild.c
+++ src/rebuild.c
@@ -522,31 +522,32 @@
522522
** Reconstruct the named repository database from the core
523523
** records. Run this command after updating the fossil
524524
** executable in a way that changes the database schema.
525525
**
526526
** Options:
527
-** --analyze Run ANALYZE on the database after rebuilding
528
-** --cluster Compute clusters for unclustered artifacts
529
-** --compress Strive to make the database as small as possible
530
-** --deanalyze Remove ANALYZE tables from the database
531
-** --force Force the rebuild to complete even if errors are seen
532
-** --ifneeded Only do the rebuild if it would change the schema version
533
-** --index Always add in the full-text search index
534
-** --noverify Skip the verification of changes to the BLOB table
535
-** --noindex Always omit the full-text search index
536
-** --pagesize N Set the database pagesize to N. (512..65536 and power of 2)
537
-** --randomize Scan artifacts in a random order
538
-** --stats Show artifact statistics after rebuilding
539
-** --vacuum Run VACUUM on the database after rebuilding
540
-** --wal Set Write-Ahead-Log journalling mode on the database
527
+** --analyze Run ANALYZE on the database after rebuilding
528
+** --cluster Compute clusters for unclustered artifacts
529
+** --compress Strive to make the database as small as possible
530
+** --compress-only Skip the rebuilding step. Do --compress only
531
+** --deanalyze Remove ANALYZE tables from the database
532
+** --force Force the rebuild to complete even if errors are seen
533
+** --ifneeded Only do the rebuild if it would change the schema version
534
+** --index Always add in the full-text search index
535
+** --noverify Skip the verification of changes to the BLOB table
536
+** --noindex Always omit the full-text search index
537
+** --pagesize N Set the database pagesize to N. (512..65536 and power of 2)
538
+** --randomize Scan artifacts in a random order
539
+** --stats Show artifact statistics after rebuilding
540
+** --vacuum Run VACUUM on the database after rebuilding
541
+** --wal Set Write-Ahead-Log journalling mode on the database
541542
**
542543
** See also: deconstruct, reconstruct
543544
*/
544545
void rebuild_database(void){
545546
int forceFlag;
546547
int randomizeFlag;
547
- int errCnt;
548
+ int errCnt = 0;
548549
int omitVerify;
549550
int doClustering;
550551
const char *zPagesize;
551552
int newPagesize = 0;
552553
int activateWal;
@@ -557,10 +558,11 @@
557558
int showStats;
558559
int runReindex;
559560
int optNoIndex;
560561
int optIndex;
561562
int optIfNeeded;
563
+ int compressOnlyFlag;
562564
563565
omitVerify = find_option("noverify",0,0)!=0;
564566
forceFlag = find_option("force","f",0)!=0;
565567
randomizeFlag = find_option("randomize", 0, 0)!=0;
566568
doClustering = find_option("cluster", 0, 0)!=0;
@@ -571,10 +573,12 @@
571573
zPagesize = find_option("pagesize",0,1);
572574
showStats = find_option("stats",0,0)!=0;
573575
optIndex = find_option("index",0,0)!=0;
574576
optNoIndex = find_option("noindex",0,0)!=0;
575577
optIfNeeded = find_option("ifneeded",0,0)!=0;
578
+ compressOnlyFlag = find_option("compress-only",0,0)!=0;
579
+ if( compressOnlyFlag ) runCompress = runVacuum = 1;
576580
if( zPagesize ){
577581
newPagesize = atoi(zPagesize);
578582
if( newPagesize<512 || newPagesize>65536
579583
|| (newPagesize&(newPagesize-1))!=0
580584
){
@@ -590,11 +594,11 @@
590594
usage("?REPOSITORY-FILENAME?");
591595
}
592596
db_close(1);
593597
db_open_repository(g.zRepositoryName);
594598
}
595
- runReindex = search_index_exists();
599
+ runReindex = search_index_exists() && !compressOnlyFlag;
596600
if( optIndex ) runReindex = 1;
597601
if( optNoIndex ) runReindex = 0;
598602
if( optIfNeeded && fossil_strcmp(db_get("aux-schema",""),AUX_SCHEMA_MAX)==0 ){
599603
return;
600604
}
@@ -601,14 +605,16 @@
601605
602606
/* We should be done with options.. */
603607
verify_all_options();
604608
605609
db_begin_transaction();
606
- search_drop_index();
607
- ttyOutput = 1;
608
- errCnt = rebuild_db(randomizeFlag, 1, doClustering);
609
- reconstruct_private_table();
610
+ if( !compressOnlyFlag ){
611
+ search_drop_index();
612
+ ttyOutput = 1;
613
+ errCnt = rebuild_db(randomizeFlag, 1, doClustering);
614
+ reconstruct_private_table();
615
+ }
610616
db_multi_exec(
611617
"REPLACE INTO config(name,value,mtime) VALUES('content-schema',%Q,now());"
612618
"REPLACE INTO config(name,value,mtime) VALUES('aux-schema',%Q,now());"
613619
"REPLACE INTO config(name,value,mtime) VALUES('rebuilt',%Q,now());",
614620
CONTENT_SCHEMA, AUX_SCHEMA_MAX, get_version()
615621
--- src/rebuild.c
+++ src/rebuild.c
@@ -522,31 +522,32 @@
522 ** Reconstruct the named repository database from the core
523 ** records. Run this command after updating the fossil
524 ** executable in a way that changes the database schema.
525 **
526 ** Options:
527 ** --analyze Run ANALYZE on the database after rebuilding
528 ** --cluster Compute clusters for unclustered artifacts
529 ** --compress Strive to make the database as small as possible
530 ** --deanalyze Remove ANALYZE tables from the database
531 ** --force Force the rebuild to complete even if errors are seen
532 ** --ifneeded Only do the rebuild if it would change the schema version
533 ** --index Always add in the full-text search index
534 ** --noverify Skip the verification of changes to the BLOB table
535 ** --noindex Always omit the full-text search index
536 ** --pagesize N Set the database pagesize to N. (512..65536 and power of 2)
537 ** --randomize Scan artifacts in a random order
538 ** --stats Show artifact statistics after rebuilding
539 ** --vacuum Run VACUUM on the database after rebuilding
540 ** --wal Set Write-Ahead-Log journalling mode on the database
 
541 **
542 ** See also: deconstruct, reconstruct
543 */
544 void rebuild_database(void){
545 int forceFlag;
546 int randomizeFlag;
547 int errCnt;
548 int omitVerify;
549 int doClustering;
550 const char *zPagesize;
551 int newPagesize = 0;
552 int activateWal;
@@ -557,10 +558,11 @@
557 int showStats;
558 int runReindex;
559 int optNoIndex;
560 int optIndex;
561 int optIfNeeded;
 
562
563 omitVerify = find_option("noverify",0,0)!=0;
564 forceFlag = find_option("force","f",0)!=0;
565 randomizeFlag = find_option("randomize", 0, 0)!=0;
566 doClustering = find_option("cluster", 0, 0)!=0;
@@ -571,10 +573,12 @@
571 zPagesize = find_option("pagesize",0,1);
572 showStats = find_option("stats",0,0)!=0;
573 optIndex = find_option("index",0,0)!=0;
574 optNoIndex = find_option("noindex",0,0)!=0;
575 optIfNeeded = find_option("ifneeded",0,0)!=0;
 
 
576 if( zPagesize ){
577 newPagesize = atoi(zPagesize);
578 if( newPagesize<512 || newPagesize>65536
579 || (newPagesize&(newPagesize-1))!=0
580 ){
@@ -590,11 +594,11 @@
590 usage("?REPOSITORY-FILENAME?");
591 }
592 db_close(1);
593 db_open_repository(g.zRepositoryName);
594 }
595 runReindex = search_index_exists();
596 if( optIndex ) runReindex = 1;
597 if( optNoIndex ) runReindex = 0;
598 if( optIfNeeded && fossil_strcmp(db_get("aux-schema",""),AUX_SCHEMA_MAX)==0 ){
599 return;
600 }
@@ -601,14 +605,16 @@
601
602 /* We should be done with options.. */
603 verify_all_options();
604
605 db_begin_transaction();
606 search_drop_index();
607 ttyOutput = 1;
608 errCnt = rebuild_db(randomizeFlag, 1, doClustering);
609 reconstruct_private_table();
 
 
610 db_multi_exec(
611 "REPLACE INTO config(name,value,mtime) VALUES('content-schema',%Q,now());"
612 "REPLACE INTO config(name,value,mtime) VALUES('aux-schema',%Q,now());"
613 "REPLACE INTO config(name,value,mtime) VALUES('rebuilt',%Q,now());",
614 CONTENT_SCHEMA, AUX_SCHEMA_MAX, get_version()
615
--- src/rebuild.c
+++ src/rebuild.c
@@ -522,31 +522,32 @@
522 ** Reconstruct the named repository database from the core
523 ** records. Run this command after updating the fossil
524 ** executable in a way that changes the database schema.
525 **
526 ** Options:
527 ** --analyze Run ANALYZE on the database after rebuilding
528 ** --cluster Compute clusters for unclustered artifacts
529 ** --compress Strive to make the database as small as possible
530 ** --compress-only Skip the rebuilding step. Do --compress only
531 ** --deanalyze Remove ANALYZE tables from the database
532 ** --force Force the rebuild to complete even if errors are seen
533 ** --ifneeded Only do the rebuild if it would change the schema version
534 ** --index Always add in the full-text search index
535 ** --noverify Skip the verification of changes to the BLOB table
536 ** --noindex Always omit the full-text search index
537 ** --pagesize N Set the database pagesize to N. (512..65536 and power of 2)
538 ** --randomize Scan artifacts in a random order
539 ** --stats Show artifact statistics after rebuilding
540 ** --vacuum Run VACUUM on the database after rebuilding
541 ** --wal Set Write-Ahead-Log journalling mode on the database
542 **
543 ** See also: deconstruct, reconstruct
544 */
545 void rebuild_database(void){
546 int forceFlag;
547 int randomizeFlag;
548 int errCnt = 0;
549 int omitVerify;
550 int doClustering;
551 const char *zPagesize;
552 int newPagesize = 0;
553 int activateWal;
@@ -557,10 +558,11 @@
558 int showStats;
559 int runReindex;
560 int optNoIndex;
561 int optIndex;
562 int optIfNeeded;
563 int compressOnlyFlag;
564
565 omitVerify = find_option("noverify",0,0)!=0;
566 forceFlag = find_option("force","f",0)!=0;
567 randomizeFlag = find_option("randomize", 0, 0)!=0;
568 doClustering = find_option("cluster", 0, 0)!=0;
@@ -571,10 +573,12 @@
573 zPagesize = find_option("pagesize",0,1);
574 showStats = find_option("stats",0,0)!=0;
575 optIndex = find_option("index",0,0)!=0;
576 optNoIndex = find_option("noindex",0,0)!=0;
577 optIfNeeded = find_option("ifneeded",0,0)!=0;
578 compressOnlyFlag = find_option("compress-only",0,0)!=0;
579 if( compressOnlyFlag ) runCompress = runVacuum = 1;
580 if( zPagesize ){
581 newPagesize = atoi(zPagesize);
582 if( newPagesize<512 || newPagesize>65536
583 || (newPagesize&(newPagesize-1))!=0
584 ){
@@ -590,11 +594,11 @@
594 usage("?REPOSITORY-FILENAME?");
595 }
596 db_close(1);
597 db_open_repository(g.zRepositoryName);
598 }
599 runReindex = search_index_exists() && !compressOnlyFlag;
600 if( optIndex ) runReindex = 1;
601 if( optNoIndex ) runReindex = 0;
602 if( optIfNeeded && fossil_strcmp(db_get("aux-schema",""),AUX_SCHEMA_MAX)==0 ){
603 return;
604 }
@@ -601,14 +605,16 @@
605
606 /* We should be done with options.. */
607 verify_all_options();
608
609 db_begin_transaction();
610 if( !compressOnlyFlag ){
611 search_drop_index();
612 ttyOutput = 1;
613 errCnt = rebuild_db(randomizeFlag, 1, doClustering);
614 reconstruct_private_table();
615 }
616 db_multi_exec(
617 "REPLACE INTO config(name,value,mtime) VALUES('content-schema',%Q,now());"
618 "REPLACE INTO config(name,value,mtime) VALUES('aux-schema',%Q,now());"
619 "REPLACE INTO config(name,value,mtime) VALUES('rebuilt',%Q,now());",
620 CONTENT_SCHEMA, AUX_SCHEMA_MAX, get_version()
621
+1 -1
--- src/search.c
+++ src/search.c
@@ -102,11 +102,11 @@
102102
}
103103
104104
/*
105105
** Compile a search pattern
106106
*/
107
-Search *search_init(
107
+static Search *search_init(
108108
const char *zPattern, /* The search pattern */
109109
const char *zMarkBegin, /* Start of a match */
110110
const char *zMarkEnd, /* End of a match */
111111
const char *zMarkGap, /* A gap between two matches */
112112
unsigned fSrchFlg /* Flags */
113113
--- src/search.c
+++ src/search.c
@@ -102,11 +102,11 @@
102 }
103
104 /*
105 ** Compile a search pattern
106 */
107 Search *search_init(
108 const char *zPattern, /* The search pattern */
109 const char *zMarkBegin, /* Start of a match */
110 const char *zMarkEnd, /* End of a match */
111 const char *zMarkGap, /* A gap between two matches */
112 unsigned fSrchFlg /* Flags */
113
--- src/search.c
+++ src/search.c
@@ -102,11 +102,11 @@
102 }
103
104 /*
105 ** Compile a search pattern
106 */
107 static Search *search_init(
108 const char *zPattern, /* The search pattern */
109 const char *zMarkBegin, /* Start of a match */
110 const char *zMarkEnd, /* End of a match */
111 const char *zMarkGap, /* A gap between two matches */
112 unsigned fSrchFlg /* Flags */
113
+44 -18
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -1,8 +1,8 @@
11
/******************************************************************************
22
** This file is an amalgamation of many separate C source files from SQLite
3
-** version 3.8.10. By combining all the individual C code files into this
3
+** version 3.8.10.1. By combining all the individual C code files into this
44
** single large file, the entire code can be compiled as a single translation
55
** unit. This allows many compilers to do optimizations that would not be
66
** possible if the files were compiled separately. Performance improvements
77
** of 5% or more are commonly seen when SQLite is compiled as a single
88
** translation unit.
@@ -316,13 +316,13 @@
316316
**
317317
** See also: [sqlite3_libversion()],
318318
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
319319
** [sqlite_version()] and [sqlite_source_id()].
320320
*/
321
-#define SQLITE_VERSION "3.8.10"
321
+#define SQLITE_VERSION "3.8.10.1"
322322
#define SQLITE_VERSION_NUMBER 3008010
323
-#define SQLITE_SOURCE_ID "2015-05-07 11:53:08 cf975957b9ae671f34bb65f049acf351e650d437"
323
+#define SQLITE_SOURCE_ID "2015-05-09 12:14:55 05b4b1f2a937c06c90db70c09890038f6c98ec40"
324324
325325
/*
326326
** CAPI3REF: Run-Time Library Version Numbers
327327
** KEYWORDS: sqlite3_version, sqlite3_sourceid
328328
**
@@ -14123,10 +14123,13 @@
1412314123
#if SQLITE_ENABLE_CEROD
1412414124
"ENABLE_CEROD",
1412514125
#endif
1412614126
#if SQLITE_ENABLE_COLUMN_METADATA
1412714127
"ENABLE_COLUMN_METADATA",
14128
+#endif
14129
+#if SQLITE_ENABLE_DBSTAT_VTAB
14130
+ "ENABLE_DBSTAT_VTAB",
1412814131
#endif
1412914132
#if SQLITE_ENABLE_EXPENSIVE_ASSERT
1413014133
"ENABLE_EXPENSIVE_ASSERT",
1413114134
#endif
1413214135
#if SQLITE_ENABLE_FTS1
@@ -155331,10 +155334,11 @@
155331155334
};
155332155335
155333155336
struct StatTable {
155334155337
sqlite3_vtab base;
155335155338
sqlite3 *db;
155339
+ int iDb; /* Index of database to analyze */
155336155340
};
155337155341
155338155342
#ifndef get2byte
155339155343
# define get2byte(x) ((x)[0]<<8 | (x)[1])
155340155344
#endif
@@ -155349,11 +155353,21 @@
155349155353
sqlite3_vtab **ppVtab,
155350155354
char **pzErr
155351155355
){
155352155356
StatTable *pTab = 0;
155353155357
int rc = SQLITE_OK;
155358
+ int iDb;
155354155359
155360
+ if( argc>=4 ){
155361
+ iDb = sqlite3FindDbName(db, argv[3]);
155362
+ if( iDb<0 ){
155363
+ *pzErr = sqlite3_mprintf("no such database: %s", argv[3]);
155364
+ return SQLITE_ERROR;
155365
+ }
155366
+ }else{
155367
+ iDb = 0;
155368
+ }
155355155369
rc = sqlite3_declare_vtab(db, VTAB_SCHEMA);
155356155370
if( rc==SQLITE_OK ){
155357155371
pTab = (StatTable *)sqlite3_malloc64(sizeof(StatTable));
155358155372
if( pTab==0 ) rc = SQLITE_NOMEM;
155359155373
}
@@ -155360,10 +155374,11 @@
155360155374
155361155375
assert( rc==SQLITE_OK || pTab==0 );
155362155376
if( rc==SQLITE_OK ){
155363155377
memset(pTab, 0, sizeof(StatTable));
155364155378
pTab->db = db;
155379
+ pTab->iDb = iDb;
155365155380
}
155366155381
155367155382
*ppVtab = (sqlite3_vtab*)pTab;
155368155383
return rc;
155369155384
}
@@ -155414,20 +155429,26 @@
155414155429
155415155430
pCsr = (StatCursor *)sqlite3_malloc64(sizeof(StatCursor));
155416155431
if( pCsr==0 ){
155417155432
rc = SQLITE_NOMEM;
155418155433
}else{
155434
+ char *zSql;
155419155435
memset(pCsr, 0, sizeof(StatCursor));
155420155436
pCsr->base.pVtab = pVTab;
155421155437
155422
- rc = sqlite3_prepare_v2(pTab->db,
155438
+ zSql = sqlite3_mprintf(
155423155439
"SELECT 'sqlite_master' AS name, 1 AS rootpage, 'table' AS type"
155424155440
" UNION ALL "
155425
- "SELECT name, rootpage, type FROM sqlite_master WHERE rootpage!=0"
155426
- " ORDER BY name", -1,
155427
- &pCsr->pStmt, 0
155428
- );
155441
+ "SELECT name, rootpage, type"
155442
+ " FROM \"%w\".sqlite_master WHERE rootpage!=0"
155443
+ " ORDER BY name", pTab->db->aDb[pTab->iDb].zName);
155444
+ if( zSql==0 ){
155445
+ rc = SQLITE_NOMEM;
155446
+ }else{
155447
+ rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pCsr->pStmt, 0);
155448
+ sqlite3_free(zSql);
155449
+ }
155429155450
if( rc!=SQLITE_OK ){
155430155451
sqlite3_free(pCsr);
155431155452
pCsr = 0;
155432155453
}
155433155454
}
@@ -155589,11 +155610,11 @@
155589155610
** Populate the pCsr->iOffset and pCsr->szPage member variables. Based on
155590155611
** the current value of pCsr->iPageno.
155591155612
*/
155592155613
static void statSizeAndOffset(StatCursor *pCsr){
155593155614
StatTable *pTab = (StatTable *)((sqlite3_vtab_cursor *)pCsr)->pVtab;
155594
- Btree *pBt = pTab->db->aDb[0].pBt;
155615
+ Btree *pBt = pTab->db->aDb[pTab->iDb].pBt;
155595155616
Pager *pPager = sqlite3BtreePager(pBt);
155596155617
sqlite3_file *fd;
155597155618
sqlite3_int64 x[2];
155598155619
155599155620
/* The default page size and offset */
@@ -155603,11 +155624,11 @@
155603155624
/* If connected to a ZIPVFS backend, override the page size and
155604155625
** offset with actual values obtained from ZIPVFS.
155605155626
*/
155606155627
fd = sqlite3PagerFile(pPager);
155607155628
x[0] = pCsr->iPageno;
155608
- if( sqlite3OsFileControl(fd, 230440, &x)==SQLITE_OK ){
155629
+ if( fd->pMethods!=0 && sqlite3OsFileControl(fd, 230440, &x)==SQLITE_OK ){
155609155630
pCsr->iOffset = x[0];
155610155631
pCsr->szPage = (int)x[1];
155611155632
}
155612155633
}
155613155634
@@ -155615,13 +155636,14 @@
155615155636
** Move a statvfs cursor to the next entry in the file.
155616155637
*/
155617155638
static int statNext(sqlite3_vtab_cursor *pCursor){
155618155639
int rc;
155619155640
int nPayload;
155641
+ char *z;
155620155642
StatCursor *pCsr = (StatCursor *)pCursor;
155621155643
StatTable *pTab = (StatTable *)pCursor->pVtab;
155622
- Btree *pBt = pTab->db->aDb[0].pBt;
155644
+ Btree *pBt = pTab->db->aDb[pTab->iDb].pBt;
155623155645
Pager *pPager = sqlite3BtreePager(pBt);
155624155646
155625155647
sqlite3_free(pCsr->zPath);
155626155648
pCsr->zPath = 0;
155627155649
@@ -155637,12 +155659,13 @@
155637155659
return sqlite3_reset(pCsr->pStmt);
155638155660
}
155639155661
rc = sqlite3PagerGet(pPager, iRoot, &pCsr->aPage[0].pPg);
155640155662
pCsr->aPage[0].iPgno = iRoot;
155641155663
pCsr->aPage[0].iCell = 0;
155642
- pCsr->aPage[0].zPath = sqlite3_mprintf("/");
155664
+ pCsr->aPage[0].zPath = z = sqlite3_mprintf("/");
155643155665
pCsr->iPage = 0;
155666
+ if( z==0 ) rc = SQLITE_NOMEM;
155644155667
}else{
155645155668
pCsr->isEof = 1;
155646155669
return sqlite3_reset(pCsr->pStmt);
155647155670
}
155648155671
}else{
@@ -155661,11 +155684,11 @@
155661155684
pCsr->zName = (char *)sqlite3_column_text(pCsr->pStmt, 0);
155662155685
pCsr->iPageno = pCell->aOvfl[pCell->iOvfl];
155663155686
pCsr->zPagetype = "overflow";
155664155687
pCsr->nCell = 0;
155665155688
pCsr->nMxPayload = 0;
155666
- pCsr->zPath = sqlite3_mprintf(
155689
+ pCsr->zPath = z = sqlite3_mprintf(
155667155690
"%s%.3x+%.6x", p->zPath, p->iCell, pCell->iOvfl
155668155691
);
155669155692
if( pCell->iOvfl<pCell->nOvfl-1 ){
155670155693
pCsr->nUnused = 0;
155671155694
pCsr->nPayload = nUsable - 4;
@@ -155673,11 +155696,11 @@
155673155696
pCsr->nPayload = pCell->nLastOvfl;
155674155697
pCsr->nUnused = nUsable - 4 - pCsr->nPayload;
155675155698
}
155676155699
pCell->iOvfl++;
155677155700
statSizeAndOffset(pCsr);
155678
- return SQLITE_OK;
155701
+ return z==0 ? SQLITE_NOMEM : SQLITE_OK;
155679155702
}
155680155703
if( p->iRightChildPg ) break;
155681155704
p->iCell++;
155682155705
}
155683155706
@@ -155695,12 +155718,13 @@
155695155718
}else{
155696155719
p[1].iPgno = p->aCell[p->iCell].iChildPg;
155697155720
}
155698155721
rc = sqlite3PagerGet(pPager, p[1].iPgno, &p[1].pPg);
155699155722
p[1].iCell = 0;
155700
- p[1].zPath = sqlite3_mprintf("%s%.3x/", p->zPath, p->iCell);
155723
+ p[1].zPath = z = sqlite3_mprintf("%s%.3x/", p->zPath, p->iCell);
155701155724
p->iCell++;
155725
+ if( z==0 ) rc = SQLITE_NOMEM;
155702155726
}
155703155727
155704155728
155705155729
/* Populate the StatCursor fields with the values to be returned
155706155730
** by the xColumn() and xRowid() methods.
@@ -155729,11 +155753,12 @@
155729155753
break;
155730155754
}
155731155755
pCsr->nCell = p->nCell;
155732155756
pCsr->nUnused = p->nUnused;
155733155757
pCsr->nMxPayload = p->nMxPayload;
155734
- pCsr->zPath = sqlite3_mprintf("%s", p->zPath);
155758
+ pCsr->zPath = z = sqlite3_mprintf("%s", p->zPath);
155759
+ if( z==0 ) rc = SQLITE_NOMEM;
155735155760
nPayload = 0;
155736155761
for(i=0; i<p->nCell; i++){
155737155762
nPayload += p->aCell[i].nLocal;
155738155763
}
155739155764
pCsr->nPayload = nPayload;
@@ -155765,11 +155790,11 @@
155765155790
int i
155766155791
){
155767155792
StatCursor *pCsr = (StatCursor *)pCursor;
155768155793
switch( i ){
155769155794
case 0: /* name */
155770
- sqlite3_result_text(ctx, pCsr->zName, -1, SQLITE_STATIC);
155795
+ sqlite3_result_text(ctx, pCsr->zName, -1, SQLITE_TRANSIENT);
155771155796
break;
155772155797
case 1: /* path */
155773155798
sqlite3_result_text(ctx, pCsr->zPath, -1, SQLITE_TRANSIENT);
155774155799
break;
155775155800
case 2: /* pageno */
@@ -155791,11 +155816,12 @@
155791155816
sqlite3_result_int(ctx, pCsr->nMxPayload);
155792155817
break;
155793155818
case 8: /* pgoffset */
155794155819
sqlite3_result_int64(ctx, pCsr->iOffset);
155795155820
break;
155796
- case 9: /* pgsize */
155821
+ default: /* pgsize */
155822
+ assert( i==9 );
155797155823
sqlite3_result_int(ctx, pCsr->szPage);
155798155824
break;
155799155825
}
155800155826
return SQLITE_OK;
155801155827
}
155802155828
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -1,8 +1,8 @@
1 /******************************************************************************
2 ** This file is an amalgamation of many separate C source files from SQLite
3 ** version 3.8.10. By combining all the individual C code files into this
4 ** single large file, the entire code can be compiled as a single translation
5 ** unit. This allows many compilers to do optimizations that would not be
6 ** possible if the files were compiled separately. Performance improvements
7 ** of 5% or more are commonly seen when SQLite is compiled as a single
8 ** translation unit.
@@ -316,13 +316,13 @@
316 **
317 ** See also: [sqlite3_libversion()],
318 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
319 ** [sqlite_version()] and [sqlite_source_id()].
320 */
321 #define SQLITE_VERSION "3.8.10"
322 #define SQLITE_VERSION_NUMBER 3008010
323 #define SQLITE_SOURCE_ID "2015-05-07 11:53:08 cf975957b9ae671f34bb65f049acf351e650d437"
324
325 /*
326 ** CAPI3REF: Run-Time Library Version Numbers
327 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
328 **
@@ -14123,10 +14123,13 @@
14123 #if SQLITE_ENABLE_CEROD
14124 "ENABLE_CEROD",
14125 #endif
14126 #if SQLITE_ENABLE_COLUMN_METADATA
14127 "ENABLE_COLUMN_METADATA",
 
 
 
14128 #endif
14129 #if SQLITE_ENABLE_EXPENSIVE_ASSERT
14130 "ENABLE_EXPENSIVE_ASSERT",
14131 #endif
14132 #if SQLITE_ENABLE_FTS1
@@ -155331,10 +155334,11 @@
155331 };
155332
155333 struct StatTable {
155334 sqlite3_vtab base;
155335 sqlite3 *db;
 
155336 };
155337
155338 #ifndef get2byte
155339 # define get2byte(x) ((x)[0]<<8 | (x)[1])
155340 #endif
@@ -155349,11 +155353,21 @@
155349 sqlite3_vtab **ppVtab,
155350 char **pzErr
155351 ){
155352 StatTable *pTab = 0;
155353 int rc = SQLITE_OK;
 
155354
 
 
 
 
 
 
 
 
 
155355 rc = sqlite3_declare_vtab(db, VTAB_SCHEMA);
155356 if( rc==SQLITE_OK ){
155357 pTab = (StatTable *)sqlite3_malloc64(sizeof(StatTable));
155358 if( pTab==0 ) rc = SQLITE_NOMEM;
155359 }
@@ -155360,10 +155374,11 @@
155360
155361 assert( rc==SQLITE_OK || pTab==0 );
155362 if( rc==SQLITE_OK ){
155363 memset(pTab, 0, sizeof(StatTable));
155364 pTab->db = db;
 
155365 }
155366
155367 *ppVtab = (sqlite3_vtab*)pTab;
155368 return rc;
155369 }
@@ -155414,20 +155429,26 @@
155414
155415 pCsr = (StatCursor *)sqlite3_malloc64(sizeof(StatCursor));
155416 if( pCsr==0 ){
155417 rc = SQLITE_NOMEM;
155418 }else{
 
155419 memset(pCsr, 0, sizeof(StatCursor));
155420 pCsr->base.pVtab = pVTab;
155421
155422 rc = sqlite3_prepare_v2(pTab->db,
155423 "SELECT 'sqlite_master' AS name, 1 AS rootpage, 'table' AS type"
155424 " UNION ALL "
155425 "SELECT name, rootpage, type FROM sqlite_master WHERE rootpage!=0"
155426 " ORDER BY name", -1,
155427 &pCsr->pStmt, 0
155428 );
 
 
 
 
 
155429 if( rc!=SQLITE_OK ){
155430 sqlite3_free(pCsr);
155431 pCsr = 0;
155432 }
155433 }
@@ -155589,11 +155610,11 @@
155589 ** Populate the pCsr->iOffset and pCsr->szPage member variables. Based on
155590 ** the current value of pCsr->iPageno.
155591 */
155592 static void statSizeAndOffset(StatCursor *pCsr){
155593 StatTable *pTab = (StatTable *)((sqlite3_vtab_cursor *)pCsr)->pVtab;
155594 Btree *pBt = pTab->db->aDb[0].pBt;
155595 Pager *pPager = sqlite3BtreePager(pBt);
155596 sqlite3_file *fd;
155597 sqlite3_int64 x[2];
155598
155599 /* The default page size and offset */
@@ -155603,11 +155624,11 @@
155603 /* If connected to a ZIPVFS backend, override the page size and
155604 ** offset with actual values obtained from ZIPVFS.
155605 */
155606 fd = sqlite3PagerFile(pPager);
155607 x[0] = pCsr->iPageno;
155608 if( sqlite3OsFileControl(fd, 230440, &x)==SQLITE_OK ){
155609 pCsr->iOffset = x[0];
155610 pCsr->szPage = (int)x[1];
155611 }
155612 }
155613
@@ -155615,13 +155636,14 @@
155615 ** Move a statvfs cursor to the next entry in the file.
155616 */
155617 static int statNext(sqlite3_vtab_cursor *pCursor){
155618 int rc;
155619 int nPayload;
 
155620 StatCursor *pCsr = (StatCursor *)pCursor;
155621 StatTable *pTab = (StatTable *)pCursor->pVtab;
155622 Btree *pBt = pTab->db->aDb[0].pBt;
155623 Pager *pPager = sqlite3BtreePager(pBt);
155624
155625 sqlite3_free(pCsr->zPath);
155626 pCsr->zPath = 0;
155627
@@ -155637,12 +155659,13 @@
155637 return sqlite3_reset(pCsr->pStmt);
155638 }
155639 rc = sqlite3PagerGet(pPager, iRoot, &pCsr->aPage[0].pPg);
155640 pCsr->aPage[0].iPgno = iRoot;
155641 pCsr->aPage[0].iCell = 0;
155642 pCsr->aPage[0].zPath = sqlite3_mprintf("/");
155643 pCsr->iPage = 0;
 
155644 }else{
155645 pCsr->isEof = 1;
155646 return sqlite3_reset(pCsr->pStmt);
155647 }
155648 }else{
@@ -155661,11 +155684,11 @@
155661 pCsr->zName = (char *)sqlite3_column_text(pCsr->pStmt, 0);
155662 pCsr->iPageno = pCell->aOvfl[pCell->iOvfl];
155663 pCsr->zPagetype = "overflow";
155664 pCsr->nCell = 0;
155665 pCsr->nMxPayload = 0;
155666 pCsr->zPath = sqlite3_mprintf(
155667 "%s%.3x+%.6x", p->zPath, p->iCell, pCell->iOvfl
155668 );
155669 if( pCell->iOvfl<pCell->nOvfl-1 ){
155670 pCsr->nUnused = 0;
155671 pCsr->nPayload = nUsable - 4;
@@ -155673,11 +155696,11 @@
155673 pCsr->nPayload = pCell->nLastOvfl;
155674 pCsr->nUnused = nUsable - 4 - pCsr->nPayload;
155675 }
155676 pCell->iOvfl++;
155677 statSizeAndOffset(pCsr);
155678 return SQLITE_OK;
155679 }
155680 if( p->iRightChildPg ) break;
155681 p->iCell++;
155682 }
155683
@@ -155695,12 +155718,13 @@
155695 }else{
155696 p[1].iPgno = p->aCell[p->iCell].iChildPg;
155697 }
155698 rc = sqlite3PagerGet(pPager, p[1].iPgno, &p[1].pPg);
155699 p[1].iCell = 0;
155700 p[1].zPath = sqlite3_mprintf("%s%.3x/", p->zPath, p->iCell);
155701 p->iCell++;
 
155702 }
155703
155704
155705 /* Populate the StatCursor fields with the values to be returned
155706 ** by the xColumn() and xRowid() methods.
@@ -155729,11 +155753,12 @@
155729 break;
155730 }
155731 pCsr->nCell = p->nCell;
155732 pCsr->nUnused = p->nUnused;
155733 pCsr->nMxPayload = p->nMxPayload;
155734 pCsr->zPath = sqlite3_mprintf("%s", p->zPath);
 
155735 nPayload = 0;
155736 for(i=0; i<p->nCell; i++){
155737 nPayload += p->aCell[i].nLocal;
155738 }
155739 pCsr->nPayload = nPayload;
@@ -155765,11 +155790,11 @@
155765 int i
155766 ){
155767 StatCursor *pCsr = (StatCursor *)pCursor;
155768 switch( i ){
155769 case 0: /* name */
155770 sqlite3_result_text(ctx, pCsr->zName, -1, SQLITE_STATIC);
155771 break;
155772 case 1: /* path */
155773 sqlite3_result_text(ctx, pCsr->zPath, -1, SQLITE_TRANSIENT);
155774 break;
155775 case 2: /* pageno */
@@ -155791,11 +155816,12 @@
155791 sqlite3_result_int(ctx, pCsr->nMxPayload);
155792 break;
155793 case 8: /* pgoffset */
155794 sqlite3_result_int64(ctx, pCsr->iOffset);
155795 break;
155796 case 9: /* pgsize */
 
155797 sqlite3_result_int(ctx, pCsr->szPage);
155798 break;
155799 }
155800 return SQLITE_OK;
155801 }
155802
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -1,8 +1,8 @@
1 /******************************************************************************
2 ** This file is an amalgamation of many separate C source files from SQLite
3 ** version 3.8.10.1. By combining all the individual C code files into this
4 ** single large file, the entire code can be compiled as a single translation
5 ** unit. This allows many compilers to do optimizations that would not be
6 ** possible if the files were compiled separately. Performance improvements
7 ** of 5% or more are commonly seen when SQLite is compiled as a single
8 ** translation unit.
@@ -316,13 +316,13 @@
316 **
317 ** See also: [sqlite3_libversion()],
318 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
319 ** [sqlite_version()] and [sqlite_source_id()].
320 */
321 #define SQLITE_VERSION "3.8.10.1"
322 #define SQLITE_VERSION_NUMBER 3008010
323 #define SQLITE_SOURCE_ID "2015-05-09 12:14:55 05b4b1f2a937c06c90db70c09890038f6c98ec40"
324
325 /*
326 ** CAPI3REF: Run-Time Library Version Numbers
327 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
328 **
@@ -14123,10 +14123,13 @@
14123 #if SQLITE_ENABLE_CEROD
14124 "ENABLE_CEROD",
14125 #endif
14126 #if SQLITE_ENABLE_COLUMN_METADATA
14127 "ENABLE_COLUMN_METADATA",
14128 #endif
14129 #if SQLITE_ENABLE_DBSTAT_VTAB
14130 "ENABLE_DBSTAT_VTAB",
14131 #endif
14132 #if SQLITE_ENABLE_EXPENSIVE_ASSERT
14133 "ENABLE_EXPENSIVE_ASSERT",
14134 #endif
14135 #if SQLITE_ENABLE_FTS1
@@ -155331,10 +155334,11 @@
155334 };
155335
155336 struct StatTable {
155337 sqlite3_vtab base;
155338 sqlite3 *db;
155339 int iDb; /* Index of database to analyze */
155340 };
155341
155342 #ifndef get2byte
155343 # define get2byte(x) ((x)[0]<<8 | (x)[1])
155344 #endif
@@ -155349,11 +155353,21 @@
155353 sqlite3_vtab **ppVtab,
155354 char **pzErr
155355 ){
155356 StatTable *pTab = 0;
155357 int rc = SQLITE_OK;
155358 int iDb;
155359
155360 if( argc>=4 ){
155361 iDb = sqlite3FindDbName(db, argv[3]);
155362 if( iDb<0 ){
155363 *pzErr = sqlite3_mprintf("no such database: %s", argv[3]);
155364 return SQLITE_ERROR;
155365 }
155366 }else{
155367 iDb = 0;
155368 }
155369 rc = sqlite3_declare_vtab(db, VTAB_SCHEMA);
155370 if( rc==SQLITE_OK ){
155371 pTab = (StatTable *)sqlite3_malloc64(sizeof(StatTable));
155372 if( pTab==0 ) rc = SQLITE_NOMEM;
155373 }
@@ -155360,10 +155374,11 @@
155374
155375 assert( rc==SQLITE_OK || pTab==0 );
155376 if( rc==SQLITE_OK ){
155377 memset(pTab, 0, sizeof(StatTable));
155378 pTab->db = db;
155379 pTab->iDb = iDb;
155380 }
155381
155382 *ppVtab = (sqlite3_vtab*)pTab;
155383 return rc;
155384 }
@@ -155414,20 +155429,26 @@
155429
155430 pCsr = (StatCursor *)sqlite3_malloc64(sizeof(StatCursor));
155431 if( pCsr==0 ){
155432 rc = SQLITE_NOMEM;
155433 }else{
155434 char *zSql;
155435 memset(pCsr, 0, sizeof(StatCursor));
155436 pCsr->base.pVtab = pVTab;
155437
155438 zSql = sqlite3_mprintf(
155439 "SELECT 'sqlite_master' AS name, 1 AS rootpage, 'table' AS type"
155440 " UNION ALL "
155441 "SELECT name, rootpage, type"
155442 " FROM \"%w\".sqlite_master WHERE rootpage!=0"
155443 " ORDER BY name", pTab->db->aDb[pTab->iDb].zName);
155444 if( zSql==0 ){
155445 rc = SQLITE_NOMEM;
155446 }else{
155447 rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pCsr->pStmt, 0);
155448 sqlite3_free(zSql);
155449 }
155450 if( rc!=SQLITE_OK ){
155451 sqlite3_free(pCsr);
155452 pCsr = 0;
155453 }
155454 }
@@ -155589,11 +155610,11 @@
155610 ** Populate the pCsr->iOffset and pCsr->szPage member variables. Based on
155611 ** the current value of pCsr->iPageno.
155612 */
155613 static void statSizeAndOffset(StatCursor *pCsr){
155614 StatTable *pTab = (StatTable *)((sqlite3_vtab_cursor *)pCsr)->pVtab;
155615 Btree *pBt = pTab->db->aDb[pTab->iDb].pBt;
155616 Pager *pPager = sqlite3BtreePager(pBt);
155617 sqlite3_file *fd;
155618 sqlite3_int64 x[2];
155619
155620 /* The default page size and offset */
@@ -155603,11 +155624,11 @@
155624 /* If connected to a ZIPVFS backend, override the page size and
155625 ** offset with actual values obtained from ZIPVFS.
155626 */
155627 fd = sqlite3PagerFile(pPager);
155628 x[0] = pCsr->iPageno;
155629 if( fd->pMethods!=0 && sqlite3OsFileControl(fd, 230440, &x)==SQLITE_OK ){
155630 pCsr->iOffset = x[0];
155631 pCsr->szPage = (int)x[1];
155632 }
155633 }
155634
@@ -155615,13 +155636,14 @@
155636 ** Move a statvfs cursor to the next entry in the file.
155637 */
155638 static int statNext(sqlite3_vtab_cursor *pCursor){
155639 int rc;
155640 int nPayload;
155641 char *z;
155642 StatCursor *pCsr = (StatCursor *)pCursor;
155643 StatTable *pTab = (StatTable *)pCursor->pVtab;
155644 Btree *pBt = pTab->db->aDb[pTab->iDb].pBt;
155645 Pager *pPager = sqlite3BtreePager(pBt);
155646
155647 sqlite3_free(pCsr->zPath);
155648 pCsr->zPath = 0;
155649
@@ -155637,12 +155659,13 @@
155659 return sqlite3_reset(pCsr->pStmt);
155660 }
155661 rc = sqlite3PagerGet(pPager, iRoot, &pCsr->aPage[0].pPg);
155662 pCsr->aPage[0].iPgno = iRoot;
155663 pCsr->aPage[0].iCell = 0;
155664 pCsr->aPage[0].zPath = z = sqlite3_mprintf("/");
155665 pCsr->iPage = 0;
155666 if( z==0 ) rc = SQLITE_NOMEM;
155667 }else{
155668 pCsr->isEof = 1;
155669 return sqlite3_reset(pCsr->pStmt);
155670 }
155671 }else{
@@ -155661,11 +155684,11 @@
155684 pCsr->zName = (char *)sqlite3_column_text(pCsr->pStmt, 0);
155685 pCsr->iPageno = pCell->aOvfl[pCell->iOvfl];
155686 pCsr->zPagetype = "overflow";
155687 pCsr->nCell = 0;
155688 pCsr->nMxPayload = 0;
155689 pCsr->zPath = z = sqlite3_mprintf(
155690 "%s%.3x+%.6x", p->zPath, p->iCell, pCell->iOvfl
155691 );
155692 if( pCell->iOvfl<pCell->nOvfl-1 ){
155693 pCsr->nUnused = 0;
155694 pCsr->nPayload = nUsable - 4;
@@ -155673,11 +155696,11 @@
155696 pCsr->nPayload = pCell->nLastOvfl;
155697 pCsr->nUnused = nUsable - 4 - pCsr->nPayload;
155698 }
155699 pCell->iOvfl++;
155700 statSizeAndOffset(pCsr);
155701 return z==0 ? SQLITE_NOMEM : SQLITE_OK;
155702 }
155703 if( p->iRightChildPg ) break;
155704 p->iCell++;
155705 }
155706
@@ -155695,12 +155718,13 @@
155718 }else{
155719 p[1].iPgno = p->aCell[p->iCell].iChildPg;
155720 }
155721 rc = sqlite3PagerGet(pPager, p[1].iPgno, &p[1].pPg);
155722 p[1].iCell = 0;
155723 p[1].zPath = z = sqlite3_mprintf("%s%.3x/", p->zPath, p->iCell);
155724 p->iCell++;
155725 if( z==0 ) rc = SQLITE_NOMEM;
155726 }
155727
155728
155729 /* Populate the StatCursor fields with the values to be returned
155730 ** by the xColumn() and xRowid() methods.
@@ -155729,11 +155753,12 @@
155753 break;
155754 }
155755 pCsr->nCell = p->nCell;
155756 pCsr->nUnused = p->nUnused;
155757 pCsr->nMxPayload = p->nMxPayload;
155758 pCsr->zPath = z = sqlite3_mprintf("%s", p->zPath);
155759 if( z==0 ) rc = SQLITE_NOMEM;
155760 nPayload = 0;
155761 for(i=0; i<p->nCell; i++){
155762 nPayload += p->aCell[i].nLocal;
155763 }
155764 pCsr->nPayload = nPayload;
@@ -155765,11 +155790,11 @@
155790 int i
155791 ){
155792 StatCursor *pCsr = (StatCursor *)pCursor;
155793 switch( i ){
155794 case 0: /* name */
155795 sqlite3_result_text(ctx, pCsr->zName, -1, SQLITE_TRANSIENT);
155796 break;
155797 case 1: /* path */
155798 sqlite3_result_text(ctx, pCsr->zPath, -1, SQLITE_TRANSIENT);
155799 break;
155800 case 2: /* pageno */
@@ -155791,11 +155816,12 @@
155816 sqlite3_result_int(ctx, pCsr->nMxPayload);
155817 break;
155818 case 8: /* pgoffset */
155819 sqlite3_result_int64(ctx, pCsr->iOffset);
155820 break;
155821 default: /* pgsize */
155822 assert( i==9 );
155823 sqlite3_result_int(ctx, pCsr->szPage);
155824 break;
155825 }
155826 return SQLITE_OK;
155827 }
155828
+2 -2
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -109,13 +109,13 @@
109109
**
110110
** See also: [sqlite3_libversion()],
111111
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
112112
** [sqlite_version()] and [sqlite_source_id()].
113113
*/
114
-#define SQLITE_VERSION "3.8.10"
114
+#define SQLITE_VERSION "3.8.10.1"
115115
#define SQLITE_VERSION_NUMBER 3008010
116
-#define SQLITE_SOURCE_ID "2015-05-07 11:53:08 cf975957b9ae671f34bb65f049acf351e650d437"
116
+#define SQLITE_SOURCE_ID "2015-05-09 12:14:55 05b4b1f2a937c06c90db70c09890038f6c98ec40"
117117
118118
/*
119119
** CAPI3REF: Run-Time Library Version Numbers
120120
** KEYWORDS: sqlite3_version, sqlite3_sourceid
121121
**
122122
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -109,13 +109,13 @@
109 **
110 ** See also: [sqlite3_libversion()],
111 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
112 ** [sqlite_version()] and [sqlite_source_id()].
113 */
114 #define SQLITE_VERSION "3.8.10"
115 #define SQLITE_VERSION_NUMBER 3008010
116 #define SQLITE_SOURCE_ID "2015-05-07 11:53:08 cf975957b9ae671f34bb65f049acf351e650d437"
117
118 /*
119 ** CAPI3REF: Run-Time Library Version Numbers
120 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
121 **
122
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -109,13 +109,13 @@
109 **
110 ** See also: [sqlite3_libversion()],
111 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
112 ** [sqlite_version()] and [sqlite_source_id()].
113 */
114 #define SQLITE_VERSION "3.8.10.1"
115 #define SQLITE_VERSION_NUMBER 3008010
116 #define SQLITE_SOURCE_ID "2015-05-09 12:14:55 05b4b1f2a937c06c90db70c09890038f6c98ec40"
117
118 /*
119 ** CAPI3REF: Run-Time Library Version Numbers
120 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
121 **
122
+92
--- src/stat.c
+++ src/stat.c
@@ -36,10 +36,25 @@
3636
}else{
3737
sqlite3_snprintf(nOut, zOut, "%lld bytes (%.1fGB)",
3838
v, (double)v/1000000000.0);
3939
}
4040
}
41
+
42
+/*
43
+** Return the approximate size as KB, MB, GB, or TB.
44
+*/
45
+void approxSizeName(int nOut, char *zOut, sqlite3_int64 v){
46
+ if( v<1000 ){
47
+ sqlite3_snprintf(nOut, zOut, "%lld bytes", v);
48
+ }else if( v<1000000 ){
49
+ sqlite3_snprintf(nOut, zOut, "%.1fKB", (double)v/1000.0);
50
+ }else if( v<1000000000 ){
51
+ sqlite3_snprintf(nOut, zOut, "%.1fMB", (double)v/1000000.0);
52
+ }else{
53
+ sqlite3_snprintf(nOut, zOut, "%.1fGB", (double)v/1000000000.0);
54
+ }
55
+}
4156
4257
/*
4358
** WEBPAGE: stat
4459
**
4560
** Show statistics and global information about the repository.
@@ -63,10 +78,13 @@
6378
style_submenu_element("Schema", "Repository Schema", "repo_schema");
6479
style_submenu_element("Web-Cache", "Web-Cache Stats", "cachestat");
6580
}
6681
style_submenu_element("Activity Reports", 0, "reports");
6782
style_submenu_element("SHA1 Collisions", 0, "hash-collisions");
83
+ if( sqlite3_libversion_number()>=3008010 ){
84
+ style_submenu_element("Table Sizes", 0, "repo-tabsize");
85
+ }
6886
@ <table class="label-value">
6987
@ <tr><th>Repository&nbsp;Size:</th><td>
7088
fsize = file_size(g.zRepositoryName);
7189
bigSizeName(sizeof(zBuf), zBuf, fsize);
7290
@ %s(zBuf)
@@ -355,5 +373,79 @@
355373
}
356374
@ </pre>
357375
db_finalize(&q);
358376
style_footer();
359377
}
378
+
379
+/*
380
+** WEBPAGE: repo-tabsize
381
+**
382
+** Show relative sizes of tables in the repository database.
383
+*/
384
+void repo_tabsize_page(void){
385
+ int nPageFree;
386
+ sqlite3_int64 fsize;
387
+ char zBuf[100];
388
+
389
+ login_check_credentials();
390
+ if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
391
+ style_header("Repository Table Sizes");
392
+ style_adunit_config(ADUNIT_RIGHT_OK);
393
+ style_submenu_element("Stat", "Repository Stats", "stat");
394
+ db_multi_exec(
395
+ "CREATE VIRTUAL TABLE temp.dbx USING dbstat(%s);"
396
+ "CREATE TEMP TABLE trans(name TEXT PRIMARY KEY, tabname TEXT)WITHOUT ROWID;"
397
+ "INSERT INTO trans(name,tabname)"
398
+ " SELECT name, tbl_name FROM %s.sqlite_master;"
399
+ "CREATE TEMP TABLE piechart(amt REAL, label TEXT);"
400
+ "INSERT INTO piechart(amt,label)"
401
+ " SELECT count(*), "
402
+ " coalesce((SELECT tabname FROM trans WHERE trans.name=dbx.name),name)"
403
+ " FROM dbx"
404
+ " GROUP BY 2 ORDER BY 2;",
405
+ db_name("repository"), db_name("repository")
406
+ );
407
+ nPageFree = db_int(0, "PRAGMA \"%w\".freelist_count", db_name("repository"));
408
+ if( nPageFree>0 ){
409
+ db_multi_exec(
410
+ "INSERT INTO piechart(amt,label) VALUES(%d,'freelist')",
411
+ nPageFree
412
+ );
413
+ }
414
+ fsize = file_size(g.zRepositoryName);
415
+ approxSizeName(sizeof(zBuf), zBuf, fsize);
416
+ @ <h2>Repository Size: %s(zBuf)</h2>
417
+ @ <center><svg width='800' height='500'>
418
+ piechart_render(800,500,PIE_OTHER|PIE_PERCENT);
419
+ @ </svg></center>
420
+
421
+ if( g.localOpen ){
422
+ db_multi_exec(
423
+ "DROP TABLE temp.dbx;"
424
+ "CREATE VIRTUAL TABLE temp.dbx USING dbstat(%s);"
425
+ "DELETE FROM trans;"
426
+ "INSERT INTO trans(name,tabname)"
427
+ " SELECT name, tbl_name FROM %s.sqlite_master;"
428
+ "DELETE FROM piechart;"
429
+ "INSERT INTO piechart(amt,label)"
430
+ " SELECT count(*), "
431
+ " coalesce((SELECT tabname FROM trans WHERE trans.name=dbx.name),name)"
432
+ " FROM dbx"
433
+ " GROUP BY 2 ORDER BY 2;",
434
+ db_name("localdb"), db_name("localdb")
435
+ );
436
+ nPageFree = db_int(0, "PRAGMA \"%s\".freelist_count", db_name("localdb"));
437
+ if( nPageFree>0 ){
438
+ db_multi_exec(
439
+ "INSERT INTO piechart(amt,label) VALUES(%d,'freelist')",
440
+ nPageFree
441
+ );
442
+ }
443
+ fsize = file_size(g.zLocalDbName);
444
+ approxSizeName(sizeof(zBuf), zBuf, fsize);
445
+ @ <h2>%h(file_tail(g.zLocalDbName)) Size: %s(zBuf)</h2>
446
+ @ <center><svg width='800' height='500'>
447
+ piechart_render(800,500,PIE_OTHER|PIE_PERCENT);
448
+ @ </svg></center>
449
+ }
450
+ style_footer();
451
+}
360452
--- src/stat.c
+++ src/stat.c
@@ -36,10 +36,25 @@
36 }else{
37 sqlite3_snprintf(nOut, zOut, "%lld bytes (%.1fGB)",
38 v, (double)v/1000000000.0);
39 }
40 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
42 /*
43 ** WEBPAGE: stat
44 **
45 ** Show statistics and global information about the repository.
@@ -63,10 +78,13 @@
63 style_submenu_element("Schema", "Repository Schema", "repo_schema");
64 style_submenu_element("Web-Cache", "Web-Cache Stats", "cachestat");
65 }
66 style_submenu_element("Activity Reports", 0, "reports");
67 style_submenu_element("SHA1 Collisions", 0, "hash-collisions");
 
 
 
68 @ <table class="label-value">
69 @ <tr><th>Repository&nbsp;Size:</th><td>
70 fsize = file_size(g.zRepositoryName);
71 bigSizeName(sizeof(zBuf), zBuf, fsize);
72 @ %s(zBuf)
@@ -355,5 +373,79 @@
355 }
356 @ </pre>
357 db_finalize(&q);
358 style_footer();
359 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
360
--- src/stat.c
+++ src/stat.c
@@ -36,10 +36,25 @@
36 }else{
37 sqlite3_snprintf(nOut, zOut, "%lld bytes (%.1fGB)",
38 v, (double)v/1000000000.0);
39 }
40 }
41
42 /*
43 ** Return the approximate size as KB, MB, GB, or TB.
44 */
45 void approxSizeName(int nOut, char *zOut, sqlite3_int64 v){
46 if( v<1000 ){
47 sqlite3_snprintf(nOut, zOut, "%lld bytes", v);
48 }else if( v<1000000 ){
49 sqlite3_snprintf(nOut, zOut, "%.1fKB", (double)v/1000.0);
50 }else if( v<1000000000 ){
51 sqlite3_snprintf(nOut, zOut, "%.1fMB", (double)v/1000000.0);
52 }else{
53 sqlite3_snprintf(nOut, zOut, "%.1fGB", (double)v/1000000000.0);
54 }
55 }
56
57 /*
58 ** WEBPAGE: stat
59 **
60 ** Show statistics and global information about the repository.
@@ -63,10 +78,13 @@
78 style_submenu_element("Schema", "Repository Schema", "repo_schema");
79 style_submenu_element("Web-Cache", "Web-Cache Stats", "cachestat");
80 }
81 style_submenu_element("Activity Reports", 0, "reports");
82 style_submenu_element("SHA1 Collisions", 0, "hash-collisions");
83 if( sqlite3_libversion_number()>=3008010 ){
84 style_submenu_element("Table Sizes", 0, "repo-tabsize");
85 }
86 @ <table class="label-value">
87 @ <tr><th>Repository&nbsp;Size:</th><td>
88 fsize = file_size(g.zRepositoryName);
89 bigSizeName(sizeof(zBuf), zBuf, fsize);
90 @ %s(zBuf)
@@ -355,5 +373,79 @@
373 }
374 @ </pre>
375 db_finalize(&q);
376 style_footer();
377 }
378
379 /*
380 ** WEBPAGE: repo-tabsize
381 **
382 ** Show relative sizes of tables in the repository database.
383 */
384 void repo_tabsize_page(void){
385 int nPageFree;
386 sqlite3_int64 fsize;
387 char zBuf[100];
388
389 login_check_credentials();
390 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
391 style_header("Repository Table Sizes");
392 style_adunit_config(ADUNIT_RIGHT_OK);
393 style_submenu_element("Stat", "Repository Stats", "stat");
394 db_multi_exec(
395 "CREATE VIRTUAL TABLE temp.dbx USING dbstat(%s);"
396 "CREATE TEMP TABLE trans(name TEXT PRIMARY KEY, tabname TEXT)WITHOUT ROWID;"
397 "INSERT INTO trans(name,tabname)"
398 " SELECT name, tbl_name FROM %s.sqlite_master;"
399 "CREATE TEMP TABLE piechart(amt REAL, label TEXT);"
400 "INSERT INTO piechart(amt,label)"
401 " SELECT count(*), "
402 " coalesce((SELECT tabname FROM trans WHERE trans.name=dbx.name),name)"
403 " FROM dbx"
404 " GROUP BY 2 ORDER BY 2;",
405 db_name("repository"), db_name("repository")
406 );
407 nPageFree = db_int(0, "PRAGMA \"%w\".freelist_count", db_name("repository"));
408 if( nPageFree>0 ){
409 db_multi_exec(
410 "INSERT INTO piechart(amt,label) VALUES(%d,'freelist')",
411 nPageFree
412 );
413 }
414 fsize = file_size(g.zRepositoryName);
415 approxSizeName(sizeof(zBuf), zBuf, fsize);
416 @ <h2>Repository Size: %s(zBuf)</h2>
417 @ <center><svg width='800' height='500'>
418 piechart_render(800,500,PIE_OTHER|PIE_PERCENT);
419 @ </svg></center>
420
421 if( g.localOpen ){
422 db_multi_exec(
423 "DROP TABLE temp.dbx;"
424 "CREATE VIRTUAL TABLE temp.dbx USING dbstat(%s);"
425 "DELETE FROM trans;"
426 "INSERT INTO trans(name,tabname)"
427 " SELECT name, tbl_name FROM %s.sqlite_master;"
428 "DELETE FROM piechart;"
429 "INSERT INTO piechart(amt,label)"
430 " SELECT count(*), "
431 " coalesce((SELECT tabname FROM trans WHERE trans.name=dbx.name),name)"
432 " FROM dbx"
433 " GROUP BY 2 ORDER BY 2;",
434 db_name("localdb"), db_name("localdb")
435 );
436 nPageFree = db_int(0, "PRAGMA \"%s\".freelist_count", db_name("localdb"));
437 if( nPageFree>0 ){
438 db_multi_exec(
439 "INSERT INTO piechart(amt,label) VALUES(%d,'freelist')",
440 nPageFree
441 );
442 }
443 fsize = file_size(g.zLocalDbName);
444 approxSizeName(sizeof(zBuf), zBuf, fsize);
445 @ <h2>%h(file_tail(g.zLocalDbName)) Size: %s(zBuf)</h2>
446 @ <center><svg width='800' height='500'>
447 piechart_render(800,500,PIE_OTHER|PIE_PERCENT);
448 @ </svg></center>
449 }
450 style_footer();
451 }
452
+270 -264
--- src/statrep.c
+++ src/statrep.c
@@ -141,63 +141,10 @@
141141
default:
142142
return "all types";
143143
}
144144
}
145145
146
-/*
147
-** A helper for the /reports family of pages which prints out a menu
148
-** of links for the various type=XXX flags. zCurrentViewName must be
149
-** the name/value of the 'view' parameter which is in effect at the
150
-** time this is called. e.g. if called from the 'byuser' view then
151
-** zCurrentViewName must be "byuser". Any URL parameters which need to
152
-** be added to the generated URLs should be passed in zParam. The
153
-** caller is expected to have already encoded any zParam in the %T or
154
-** %t encoding. */
155
-static void stats_report_event_types_menu(const char *zCurrentViewName,
156
- const char *zParam){
157
- char *zTop;
158
- if(zParam && !*zParam){
159
- zParam = NULL;
160
- }
161
- zTop = mprintf("%s/reports?view=%s%s%s", g.zTop, zCurrentViewName,
162
- zParam ? "&" : "", zParam);
163
- cgi_printf("<div>");
164
- cgi_printf("<span>Types:</span> ");
165
- if('*' == statsReportType){
166
- cgi_printf(" <strong>all</strong>", zTop);
167
- }else{
168
- cgi_printf(" <a href='%s'>all</a>", zTop);
169
- }
170
- if('c' == statsReportType){
171
- cgi_printf(" <strong>check-ins</strong>", zTop);
172
- }else{
173
- cgi_printf(" <a href='%s&type=ci'>check-ins</a>", zTop);
174
- }
175
- if('e' == statsReportType){
176
- cgi_printf(" <strong>technotes</strong>", zTop);
177
- }else{
178
- cgi_printf(" <a href='%s&type=e'>technotes</a>", zTop);
179
- }
180
- if( 't' == statsReportType ){
181
- cgi_printf(" <strong>tickets</strong>", zTop);
182
- }else{
183
- cgi_printf(" <a href='%s&type=t'>tickets</a>", zTop);
184
- }
185
- if( 'g' == statsReportType ){
186
- cgi_printf(" <strong>tags</strong>", zTop);
187
- }else{
188
- cgi_printf(" <a href='%s&type=g'>tags</a>", zTop);
189
- }
190
- if( 'w' == statsReportType ){
191
- cgi_printf(" <strong>wiki</strong>", zTop);
192
- }else{
193
- cgi_printf(" <a href='%s&type=w'>wiki</a>", zTop);
194
- }
195
- fossil_free(zTop);
196
- cgi_printf("</div>");
197
-}
198
-
199146
200147
/*
201148
** Helper for stats_report_by_month_year(), which generates a list of
202149
** week numbers. zTimeframe should be either a timeframe in the form YYYY
203150
** or YYYY-MM.
@@ -227,23 +174,21 @@
227174
}
228175
229176
/*
230177
** Implements the "byyear" and "bymonth" reports for /reports.
231178
** If includeMonth is true then it generates the "bymonth" report,
232
-** else the "byyear" report. If zUserName is not NULL and not empty
233
-** then the report is restricted to events created by the named user
234
-** account.
179
+** else the "byyear" report. If zUserName is not NULL then the report is
180
+** restricted to events created by the named user account.
235181
*/
236182
static void stats_report_by_month_year(char includeMonth,
237183
char includeWeeks,
238184
const char *zUserName){
239185
Stmt query = empty_Stmt;
240186
int nRowNumber = 0; /* current TR number */
241187
int nEventTotal = 0; /* Total event count */
242188
int rowClass = 0; /* counter for alternating
243189
row colors */
244
- Blob sql = empty_blob; /* SQL */
245190
const char *zTimeLabel = includeMonth ? "Year/Month" : "Year";
246191
char zPrevYear[5] = {0}; /* For keeping track of when
247192
we change years while looping */
248193
int nEventsPerYear = 0; /* Total event count for the
249194
current year */
@@ -252,39 +197,37 @@
252197
Blob header = empty_blob; /* Page header text */
253198
int nMaxEvents = 1; /* for calculating length of graph
254199
bars. */
255200
int iterations = 0; /* number of weeks/months we iterate
256201
over */
202
+ Blob userFilter = empty_blob; /* Optional user=johndoe query string */
257203
stats_report_init_view();
258
- stats_report_event_types_menu( includeMonth ? "bymonth" : "byyear", NULL );
259
- blob_appendf(&header, "Timeline Events (%s) by year%s",
260
- stats_report_label_for_type(),
261
- (includeMonth ? "/month" : ""));
262
- blob_append_sql(&sql,
263
- "SELECT substr(date(mtime),1,%d) AS timeframe, "
264
- "count(*) AS eventCount "
265
- "FROM v_reports ",
266
- includeMonth ? 7 : 4);
267
- if(zUserName&&*zUserName){
268
- blob_append_sql(&sql, " WHERE user=%Q ", zUserName);
269
- blob_appendf(&header," for user %q", zUserName);
270
- }
271
- blob_append(&sql,
272
- " GROUP BY timeframe"
273
- " ORDER BY timeframe DESC",
274
- -1);
275
- db_prepare(&query, "%s", blob_sql_text(&sql));
276
- blob_reset(&sql);
277
- @ <h1>%b(&header)</h1>
204
+ if( zUserName ){
205
+ blob_appendf(&userFilter, "user=%s", zUserName);
206
+ }
207
+ blob_reset(&userFilter);
208
+ db_prepare(&query,
209
+ "SELECT substr(date(mtime),1,%d) AS timeframe,"
210
+ " count(*) AS eventCount"
211
+ " FROM v_reports"
212
+ " WHERE ifnull(coalesce(euser,user,'')=%Q,1)"
213
+ " GROUP BY timeframe"
214
+ " ORDER BY timeframe DESC",
215
+ includeMonth ? 7 : 4, zUserName);
216
+ @ <h1>Timeline Events (%s(stats_report_label_for_type()))
217
+ @ by year%s(includeMonth ? "/month" : "")
218
+ if( zUserName ){
219
+ @ for user %h(zUserName)
220
+ }
221
+ @ </h1>
278222
@ <table class='statistics-report-table-events' border='0' cellpadding='2'
279223
@ cellspacing='0' id='statsTable'>
280224
@ <thead>
281225
@ <th>%s(zTimeLabel)</th>
282226
@ <th>Events</th>
283227
@ <th width='90%%'><!-- relative commits graph --></th>
284228
@ </thead><tbody>
285
- blob_reset(&header);
286229
/*
287230
Run the query twice. The first time we calculate the maximum
288231
number of events for a given row. Maybe someone with better SQL
289232
Fu can re-implement this with a single query.
290233
*/
@@ -335,18 +278,18 @@
335278
zTimeframe, nCount,
336279
statsReportTimelineYFlag );
337280
/* Reminder: n=nCount is not actually correct for bymonth unless
338281
that was the only user who caused events.
339282
*/
340
- if( zUserName && *zUserName ){
283
+ if( zUserName ){
341284
cgi_printf("&u=%t", zUserName);
342285
}
343286
cgi_printf("' target='_new'>%s</a>",zTimeframe);
344287
}else {
345288
cgi_printf("<a href='?view=byweek&y=%s&type=%c",
346289
zTimeframe, (char)statsReportType);
347
- if(zUserName && *zUserName){
290
+ if( zUserName ){
348291
cgi_printf("&u=%t", zUserName);
349292
}
350293
cgi_printf("'>%s</a>", zTimeframe);
351294
}
352295
@ </td><td>%d(nCount)</td>
@@ -403,25 +346,34 @@
403346
int rowClass = 0; /* counter for alternating
404347
row colors */
405348
int nMaxEvents = 1; /* max number of events for
406349
all rows. */
407350
stats_report_init_view();
408
- stats_report_event_types_menu("byuser", NULL);
409
- db_prepare(&query,
410
- "SELECT user, "
411
- "COUNT(*) AS eventCount "
412
- "FROM v_reports "
413
- "GROUP BY user ORDER BY eventCount DESC");
414351
@ <h1>Timeline Events
415352
@ (%s(stats_report_label_for_type())) by User</h1>
353
+ db_multi_exec(
354
+ "CREATE TEMP TABLE piechart(amt,label);"
355
+ "INSERT INTO piechart SELECT count(*), ifnull(euser,user) FROM v_reports"
356
+ " GROUP BY ifnull(euser,user) ORDER BY count(*) DESC;"
357
+ );
358
+ if( db_int(0, "SELECT count(*) FROM piechart")>=2 ){
359
+ @ <center><svg width=700 height=400>
360
+ piechart_render(700, 400, PIE_OTHER|PIE_PERCENT);
361
+ @ </svg></centre><hr/>
362
+ }
416363
@ <table class='statistics-report-table-events' border='0'
417364
@ cellpadding='2' cellspacing='0' id='statsTable'>
418365
@ <thead><tr>
419366
@ <th>User</th>
420367
@ <th>Events</th>
421368
@ <th width='90%%'><!-- relative commits graph --></th>
422369
@ </tr></thead><tbody>
370
+ db_prepare(&query,
371
+ "SELECT ifnull(euser,user), "
372
+ "COUNT(*) AS eventCount "
373
+ "FROM v_reports "
374
+ "GROUP BY ifnull(euser,user) ORDER BY eventCount DESC");
423375
while( SQLITE_ROW == db_step(&query) ){
424376
const int nCount = db_column_int(&query, 1);
425377
if(nCount>nMaxEvents){
426378
nMaxEvents = nCount;
427379
}
@@ -428,20 +380,21 @@
428380
}
429381
db_reset(&query);
430382
while( SQLITE_ROW == db_step(&query) ){
431383
const char *zUser = db_column_text(&query, 0);
432384
const int nCount = db_column_int(&query, 1);
385
+ char y = (char)statsReportType;
433386
int nSize = nCount
434387
? (int)(100 * nCount / nMaxEvents)
435388
: 0;
436389
if(!nCount) continue /* arguable! Possible? */;
437390
else if(!nSize) nSize = 1;
438391
rowClass = ++nRowNumber % 2;
439392
nEventTotal += nCount;
440
- @<tr class='row%d(rowClass)'>
393
+ @ <tr class='row%d(rowClass)'>
441394
@ <td>
442
- @ <a href="?view=bymonth&user=%h(zUser)&type=%c((char)statsReportType)">%h(zUser)</a>
395
+ @ <a href="?view=bymonth&user=%h(zUser)&type=%c(y)">%h(zUser)</a>
443396
@ </td><td data-sortkey='%08x(-nCount)'>%d(nCount)</td>
444397
@ <td>
445398
@ <div class='statistics-report-graph-line'
446399
@ style='width:%d(nSize)%%;'>&nbsp;</div>
447400
@ </td>
@@ -455,30 +408,37 @@
455408
db_finalize(&query);
456409
output_table_sorting_javascript("statsTable","tkx",2);
457410
}
458411
459412
/*
460
-** Implements the "byfile" view for /reports.
413
+** Implements the "byfile" view for /reports. If zUserName is not NULL then the
414
+** report is restricted to events created by the named user account.
461415
*/
462
-static void stats_report_by_file(){
416
+static void stats_report_by_file(const char *zUserName){
463417
Stmt query;
464418
int mxEvent = 1; /* max number of events across all rows */
465419
int nRowNumber = 0;
466420
467421
db_multi_exec(
468422
"CREATE TEMP TABLE statrep(filename, cnt);"
469423
"INSERT INTO statrep(filename, cnt)"
470424
" SELECT filename.name, count(distinct mlink.mid)"
471
- " FROM filename, mlink"
425
+ " FROM filename, mlink, event"
472426
" WHERE filename.fnid=mlink.fnid"
473
- " GROUP BY 1"
427
+ " AND mlink.mid=event.objid"
428
+ " AND ifnull(coalesce(euser,user,'')=%Q,1)"
429
+ " GROUP BY 1", zUserName
474430
);
475431
db_prepare(&query,
476432
"SELECT filename, cnt FROM statrep ORDER BY cnt DESC, filename /*sort*/"
477433
);
478434
mxEvent = db_int(1, "SELECT max(cnt) FROM statrep");
479
- @ <h1>Check-ins Per File</h1>
435
+ @ <h1>Check-ins Per File
436
+ if( zUserName ){
437
+ @ for user %h(zUserName)
438
+ }
439
+ @ </h1>
480440
@ <table class='statistics-report-table-events' border='0'
481441
@ cellpadding='2' cellspacing='0' id='statsTable'>
482442
@ <thead><tr>
483443
@ <th>File</th>
484444
@ <th>Check-ins</th>
@@ -504,34 +464,62 @@
504464
db_finalize(&query);
505465
output_table_sorting_javascript("statsTable","tNx",2);
506466
}
507467
508468
/*
509
-** Implements the "byweekday" view for /reports.
469
+** Implements the "byweekday" view for /reports. If zUserName is not NULL then
470
+** the report is restricted to events created by the named user account.
510471
*/
511
-static void stats_report_day_of_week(){
472
+static void stats_report_day_of_week(const char *zUserName){
512473
Stmt query = empty_Stmt;
513474
int nRowNumber = 0; /* current TR number */
514475
int nEventTotal = 0; /* Total event count */
515476
int rowClass = 0; /* counter for alternating
516477
row colors */
517478
int nMaxEvents = 1; /* max number of events for
518479
all rows. */
480
+ Blob userFilter = empty_blob; /* Optional user=johndoe query string */
519481
static const char *const daysOfWeek[] = {
520482
"Monday", "Tuesday", "Wednesday", "Thursday",
521483
"Friday", "Saturday", "Sunday"
522484
};
523485
524486
stats_report_init_view();
525
- stats_report_event_types_menu("byweekday", NULL);
487
+ if( zUserName ){
488
+ blob_appendf(&userFilter, "user=%s", zUserName);
489
+ }
526490
db_prepare(&query,
527
- "SELECT cast(mtime %% 7 AS INTEGER) dow, "
528
- "COUNT(*) AS eventCount "
529
- "FROM v_reports "
530
- "GROUP BY dow ORDER BY dow");
531
- @ <h1>Timeline Events
532
- @ (%s(stats_report_label_for_type())) by Day of the Week</h1>
491
+ "SELECT cast(mtime %% 7 AS INTEGER) dow,"
492
+ " COUNT(*) AS eventCount"
493
+ " FROM v_reports"
494
+ " WHERE ifnull(coalesce(euser,user,'')=%Q,1)"
495
+ " GROUP BY dow ORDER BY dow", zUserName);
496
+ @ <h1>Timeline Events (%h(stats_report_label_for_type())) by Day of the Week
497
+ if( zUserName ){
498
+ @ for user %h(zUserName)
499
+ }
500
+ @ </h1>
501
+ db_multi_exec(
502
+ "CREATE TEMP TABLE piechart(amt,label);"
503
+ "INSERT INTO piechart"
504
+ " SELECT count(*), cast(mtime %% 7 AS INT) FROM v_reports"
505
+ " WHERE ifnull(coalesce(euser,user,'')=%Q,1)"
506
+ " GROUP BY 2 ORDER BY 2;"
507
+ "UPDATE piechart SET label = CASE label"
508
+ " WHEN 0 THEN 'Monday'"
509
+ " WHEN 1 THEN 'Tuesday'"
510
+ " WHEN 2 THEN 'Wednesday'"
511
+ " WHEN 3 THEN 'Thursday'"
512
+ " WHEN 4 THEN 'Friday'"
513
+ " WHEN 5 THEN 'Saturday'"
514
+ " ELSE 'Sunday' END;", zUserName
515
+ );
516
+ if( db_int(0, "SELECT count(*) FROM piechart")>=2 ){
517
+ @ <center><svg width=700 height=400>
518
+ piechart_render(700, 400, PIE_OTHER|PIE_PERCENT);
519
+ @ </svg></centre><hr/>
520
+ }
533521
@ <table class='statistics-report-table-events' border='0'
534522
@ cellpadding='2' cellspacing='0' id='statsTable'>
535523
@ <thead><tr>
536524
@ <th>DoW</th>
537525
@ <th>Day</th>
@@ -572,139 +560,114 @@
572560
573561
574562
/*
575563
** Helper for stats_report_by_month_year(), which generates a list of
576564
** week numbers. zTimeframe should be either a timeframe in the form YYYY
577
-** or YYYY-MM.
565
+** or YYYY-MM. If zUserName is not NULL then the report is restricted to events
566
+** created by the named user account.
578567
*/
579568
static void stats_report_year_weeks(const char *zUserName){
580
- const char *zYear = P("y");
581
- int nYear = zYear ? strlen(zYear) : 0;
569
+ const char *zYear = P("y"); /* Year for which report shown */
570
+ int isValidYear = 0; /* True if a valid year */
582571
int i = 0;
583
- Stmt qYears = empty_Stmt;
584
- char *zDefaultYear = NULL;
585
- Blob sql = empty_blob;
572
+ Stmt q;
586573
int nMaxEvents = 1; /* max number of events for
587574
all rows. */
588575
int iterations = 0; /* # of active time periods. */
589
- stats_report_init_view();
590
- if(4==nYear){
591
- Blob urlParams = empty_blob;
592
- blob_appendf(&urlParams, "y=%T", zYear);
593
- stats_report_event_types_menu("byweek", blob_str(&urlParams));
594
- blob_reset(&urlParams);
595
- }else{
596
- stats_report_event_types_menu("byweek", NULL);
597
- }
598
- blob_append(&sql,
599
- "SELECT DISTINCT substr(date(mtime),1,4) AS y "
600
- "FROM v_reports WHERE 1 ", -1);
601
- if(zUserName&&*zUserName){
602
- blob_append_sql(&sql,"AND user=%Q ", zUserName);
603
- }
604
- blob_append(&sql,"GROUP BY y ORDER BY y", -1);
605
- db_prepare(&qYears, "%s", blob_sql_text(&sql));
606
- blob_reset(&sql);
607
- cgi_printf("Select year: ");
608
- while( SQLITE_ROW == db_step(&qYears) ){
609
- const char *zT = db_column_text(&qYears, 0);
610
- if( i++ ){
611
- cgi_printf(" ");
612
- }
613
- cgi_printf("<a href='?view=byweek&y=%s&type=%c", zT,
614
- (char)statsReportType);
615
- if(zUserName && *zUserName){
616
- cgi_printf("&user=%t",zUserName);
617
- }
618
- cgi_printf("'>%s</a>",zT);
619
- }
620
- db_finalize(&qYears);
621
- cgi_printf("<br/>");
622
- if(!zYear || !*zYear){
623
- zDefaultYear = db_text("????", "SELECT strftime('%%Y')");
624
- zYear = zDefaultYear;
625
- nYear = 4;
626
- }
627
- if(4 == nYear){
628
- Stmt stWeek = empty_Stmt;
629
- int rowCount = 0;
630
- int total = 0;
631
- Blob header = empty_blob;
632
- blob_appendf(&header, "Timeline events (%s) for the calendar weeks "
633
- "of %h", stats_report_label_for_type(),
634
- zYear);
635
- blob_append_sql(&sql,
636
- "SELECT DISTINCT strftime('%%W',mtime) AS wk, "
637
- "count(*) AS n "
638
- "FROM v_reports "
639
- "WHERE %Q=substr(date(mtime),1,4) "
640
- "AND mtime < current_timestamp ",
641
- zYear);
642
- if(zUserName&&*zUserName){
643
- blob_append_sql(&sql, " AND user=%Q ", zUserName);
644
- blob_appendf(&header," for user %h", zUserName);
645
- }
646
- blob_append_sql(&sql, "GROUP BY wk ORDER BY wk DESC");
647
- cgi_printf("<h1>%h</h1>", blob_str(&header));
648
- blob_reset(&header);
649
- cgi_printf("<table class='statistics-report-table-events' "
650
- "border='0' cellpadding='2' width='100%%' "
651
- "cellspacing='0' id='statsTable'>");
652
- cgi_printf("<thead><tr>"
653
- "<th>Week</th>"
654
- "<th>Events</th>"
655
- "<th width='90%%'><!-- relative commits graph --></th>"
656
- "</tr></thead>"
657
- "<tbody>");
658
- db_prepare(&stWeek, "%s", blob_sql_text(&sql));
659
- blob_reset(&sql);
660
- while( SQLITE_ROW == db_step(&stWeek) ){
661
- const int nCount = db_column_int(&stWeek, 1);
662
- if(nCount>nMaxEvents){
663
- nMaxEvents = nCount;
664
- }
665
- ++iterations;
666
- }
667
- db_reset(&stWeek);
668
- while( SQLITE_ROW == db_step(&stWeek) ){
669
- const char *zWeek = db_column_text(&stWeek,0);
670
- const int nCount = db_column_int(&stWeek,1);
671
- int nSize = nCount
672
- ? (int)(100 * nCount / nMaxEvents)
673
- : 0;
674
- if(!nSize) nSize = 1;
675
- total += nCount;
676
- cgi_printf("<tr class='row%d'>", ++rowCount % 2 );
677
- cgi_printf("<td><a href='%R/timeline?yw=%t-%s&n=%d&y=%s",
678
- zYear, zWeek, nCount,
679
- statsReportTimelineYFlag);
680
- if(zUserName && *zUserName){
681
- cgi_printf("&u=%t",zUserName);
682
- }
683
- cgi_printf("'>%s</a></td>",zWeek);
684
-
685
- cgi_printf("<td>%d</td>",nCount);
686
- cgi_printf("<td>");
687
- if(nCount){
688
- cgi_printf("<div class='statistics-report-graph-line'"
689
- "style='width:%d%%;'>&nbsp;</div>",
690
- nSize);
691
- }
692
- cgi_printf("</td></tr>");
693
- }
694
- db_finalize(&stWeek);
695
- free(zDefaultYear);
696
- cgi_printf("</tbody></table>");
697
- if(total){
698
- int nAvg = iterations ? (total/iterations) : 0;
699
- cgi_printf("<br><div>Total events: %d<br>"
700
- "Average per active week: %d</div>",
701
- total, nAvg);
702
- }
703
- output_table_sorting_javascript("statsTable","tnx",-1);
704
- }
705
-}
576
+ int n = 0; /* Number of entries in azYear */
577
+ char **azYear = 0; /* Year dropdown menu */
578
+ int rowCount = 0;
579
+ int total = 0;
580
+
581
+ stats_report_init_view();
582
+ style_submenu_sql("y", "Year:",
583
+ "WITH RECURSIVE a(b) AS ("
584
+ " SELECT substr(date('now'),1,4) UNION ALL"
585
+ " SELECT b-1 FROM a"
586
+ " WHERE b>0+(SELECT substr(date(min(mtime)),1,4) FROM event)"
587
+ ") SELECT b, b FROM a ORDER BY b DESC");
588
+ if( zYear==0 || strlen(zYear)!=4 ){
589
+ zYear = db_text("1970","SELECT substr(date('now'),1,4);");
590
+ }
591
+ cgi_printf("<br/>");
592
+ db_prepare(&q,
593
+ "SELECT DISTINCT strftime('%%W',mtime) AS wk, "
594
+ " count(*) AS n "
595
+ " FROM v_reports "
596
+ " WHERE %Q=substr(date(mtime),1,4) "
597
+ " AND mtime < current_timestamp "
598
+ " AND ifnull(coalesce(euser,user,'')=%Q,1)"
599
+ " GROUP BY wk ORDER BY wk DESC", zYear, zUserName);
600
+ @ <h1>Timeline events (%h(stats_report_label_for_type()))
601
+ @ for the calendar weeks of %h(zYear)
602
+ if( zUserName ){
603
+ @ for user %h(zUserName)
604
+ }
605
+ @ </h1>
606
+ cgi_printf("<table class='statistics-report-table-events' "
607
+ "border='0' cellpadding='2' width='100%%' "
608
+ "cellspacing='0' id='statsTable'>");
609
+ cgi_printf("<thead><tr>"
610
+ "<th>Week</th>"
611
+ "<th>Events</th>"
612
+ "<th width='90%%'><!-- relative commits graph --></th>"
613
+ "</tr></thead>"
614
+ "<tbody>");
615
+ while( SQLITE_ROW == db_step(&q) ){
616
+ const int nCount = db_column_int(&q, 1);
617
+ if(nCount>nMaxEvents){
618
+ nMaxEvents = nCount;
619
+ }
620
+ ++iterations;
621
+ }
622
+ db_reset(&q);
623
+ while( SQLITE_ROW == db_step(&q) ){
624
+ const char *zWeek = db_column_text(&q,0);
625
+ const int nCount = db_column_int(&q,1);
626
+ int nSize = nCount
627
+ ? (int)(100 * nCount / nMaxEvents)
628
+ : 0;
629
+ if(!nSize) nSize = 1;
630
+ total += nCount;
631
+ cgi_printf("<tr class='row%d'>", ++rowCount % 2 );
632
+ cgi_printf("<td><a href='%R/timeline?yw=%t-%s&n=%d&y=%s",
633
+ zYear, zWeek, nCount,
634
+ statsReportTimelineYFlag);
635
+ if( zUserName ){
636
+ cgi_printf("&u=%t",zUserName);
637
+ }
638
+ cgi_printf("'>%s</a></td>",zWeek);
639
+
640
+ cgi_printf("<td>%d</td>",nCount);
641
+ cgi_printf("<td>");
642
+ if(nCount){
643
+ cgi_printf("<div class='statistics-report-graph-line'"
644
+ "style='width:%d%%;'>&nbsp;</div>",
645
+ nSize);
646
+ }
647
+ cgi_printf("</td></tr>");
648
+ }
649
+ db_finalize(&q);
650
+ cgi_printf("</tbody></table>");
651
+ if(total){
652
+ int nAvg = iterations ? (total/iterations) : 0;
653
+ cgi_printf("<br><div>Total events: %d<br>"
654
+ "Average per active week: %d</div>",
655
+ total, nAvg);
656
+ }
657
+ output_table_sorting_javascript("statsTable","tnx",-1);
658
+}
659
+
660
+/* Report types
661
+*/
662
+#define RPT_BYFILE 1
663
+#define RPT_BYMONTH 2
664
+#define RPT_BYUSER 3
665
+#define RPT_BYWEEK 4
666
+#define RPT_BYWEEKDAY 5
667
+#define RPT_BYYEAR 6
668
+#define RPT_NONE 0 /* None of the above */
706669
707670
/*
708671
** WEBPAGE: reports
709672
**
710673
** Shows activity reports for the repository.
@@ -724,51 +687,94 @@
724687
** y=YYYY The year to report (default is the server's
725688
** current year).
726689
*/
727690
void stats_report_page(){
728691
HQuery url; /* URL for various branch links */
729
- const char *zView = P("view"); /* Which view/report to show. */
730
- const char *zUserName = P("user");
731
-
692
+ const char *zView = P("view"); /* Which view/report to show. */
693
+ int eType = RPT_NONE; /* Numeric code for view/report to show */
694
+ int i; /* Loop counter */
695
+ const char *zUserName; /* Name of user */
696
+ const struct {
697
+ const char *zName; /* Name of view= screen type */
698
+ const char *zVal; /* Value of view= query parameter */
699
+ int eType; /* Corresponding RPT_* define */
700
+ } aViewType[] = {
701
+ { "File Changes","byfile", RPT_BYFILE },
702
+ { "By Month", "bymonth", RPT_BYMONTH },
703
+ { "By User", "byuser", RPT_BYUSER },
704
+ { "By Week", "byweek", RPT_BYWEEK },
705
+ { "By Weekday", "byweekday", RPT_BYWEEKDAY },
706
+ { "By Year", "byyear", RPT_BYYEAR },
707
+ };
708
+ const char *azType[] = {
709
+ "a", "All Changes",
710
+ "ci", "Check-ins",
711
+ "g", "Tags",
712
+ "e", "Tech Notes",
713
+ "t", "Tickets",
714
+ "w", "Wiki"
715
+ };
716
+
732717
login_check_credentials();
733718
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
734
- if(!zUserName) zUserName = P("u");
735
- url_initialize(&url, "reports");
736
- if(zUserName && *zUserName){
737
- url_add_parameter(&url,"user", zUserName);
738
- statrep_submenu(&url, "(Remove User Flag)", "view", zView, "user");
739
- }
740
- statrep_submenu(&url, "By Year", "view", "byyear", 0);
741
- statrep_submenu(&url, "By Month", "view", "bymonth", 0);
742
- statrep_submenu(&url, "By Week", "view", "byweek", 0);
743
- statrep_submenu(&url, "By Weekday", "view", "byweekday", 0);
744
- statrep_submenu(&url, "By User", "view", "byuser", "user");
745
- statrep_submenu(&url, "By File", "view", "byfile", "file");
719
+ zUserName = P("user");
720
+ if( zUserName==0 ) zUserName = P("u");
721
+ if( zUserName && zUserName[0]==0 ) zUserName = 0;
722
+ if( zView==0 ){
723
+ zView = "byuser";
724
+ cgi_replace_query_parameter("view","byuser");
725
+ }
726
+ for(i=0; i<ArraySize(aViewType); i++){
727
+ if( fossil_strcmp(zView, aViewType[i].zVal)==0 ){
728
+ eType = aViewType[i].eType;
729
+ break;
730
+ }
731
+ }
732
+ url_initialize(&url, "reports");
733
+ cgi_query_parameters_to_url(&url);
734
+ if( eType!=RPT_NONE ){
735
+ int nView = 0; /* Slots used in azView[] */
736
+ const char *azView[16]; /* Drop-down menu of view types */
737
+ for(i=0; i<ArraySize(aViewType); i++){
738
+ azView[nView++] = aViewType[i].zVal;
739
+ azView[nView++] = aViewType[i].zName;
740
+ }
741
+ if( eType!=RPT_BYFILE ){
742
+ style_submenu_multichoice("type", ArraySize(azType)/2, azType, 0);
743
+ }
744
+ style_submenu_multichoice("view", nView/2, azView, 0);
745
+ if( eType!=RPT_BYUSER ){
746
+ style_submenu_sql("u","User:",
747
+ "SELECT '', 'All Users' UNION ALL "
748
+ "SELECT x, x FROM ("
749
+ " SELECT DISTINCT trim(coalesce(euser,user)) AS x FROM event %s"
750
+ " ORDER BY 1 COLLATE nocase) WHERE x!=''",
751
+ eType==RPT_BYFILE ? "WHERE type='ci'" : ""
752
+ );
753
+ }
754
+ }
746755
style_submenu_element("Stats", "Stats", "%R/stat");
747756
url_reset(&url);
748757
style_header("Activity Reports");
749
- if(0==fossil_strcmp(zView,"byyear")){
750
- stats_report_by_month_year(0, 0, zUserName);
751
- }else if(0==fossil_strcmp(zView,"bymonth")){
752
- stats_report_by_month_year(1, 0, zUserName);
753
- }else if(0==fossil_strcmp(zView,"byweek")){
754
- stats_report_year_weeks(zUserName);
755
- }else if(0==fossil_strcmp(zView,"byuser")){
756
- stats_report_by_user();
757
- }else if(0==fossil_strcmp(zView,"byweekday")){
758
- stats_report_day_of_week();
759
- }else if(0==fossil_strcmp(zView,"byfile")){
760
- stats_report_by_file();
761
- }else{
762
- @ <h1>Activity Reports:</h1>
763
- @ <ul>
764
- @ <li>%z(href("?view=byyear"))Events by year</a></li>
765
- @ <li>%z(href("?view=bymonth"))Events by month</a></li>
766
- @ <li>%z(href("?view=byweek"))Events by calendar week</a></li>
767
- @ <li>%z(href("?view=byweekday"))Events by day of the week</a></li>
768
- @ <li>%z(href("?view=byuser"))Events by user</a></li>
769
- @ <li>%z(href("?view=byfile"))Events by file</a></li>
770
- @ </ul>
771
- }
772
-
758
+ switch( eType ){
759
+ case RPT_BYYEAR:
760
+ stats_report_by_month_year(0, 0, zUserName);
761
+ break;
762
+ case RPT_BYMONTH:
763
+ stats_report_by_month_year(1, 0, zUserName);
764
+ break;
765
+ case RPT_BYWEEK:
766
+ stats_report_year_weeks(zUserName);
767
+ break;
768
+ default:
769
+ case RPT_BYUSER:
770
+ stats_report_by_user();
771
+ break;
772
+ case RPT_BYWEEKDAY:
773
+ stats_report_day_of_week(zUserName);
774
+ break;
775
+ case RPT_BYFILE:
776
+ stats_report_by_file(zUserName);
777
+ break;
778
+ }
773779
style_footer();
774780
}
775781
--- src/statrep.c
+++ src/statrep.c
@@ -141,63 +141,10 @@
141 default:
142 return "all types";
143 }
144 }
145
146 /*
147 ** A helper for the /reports family of pages which prints out a menu
148 ** of links for the various type=XXX flags. zCurrentViewName must be
149 ** the name/value of the 'view' parameter which is in effect at the
150 ** time this is called. e.g. if called from the 'byuser' view then
151 ** zCurrentViewName must be "byuser". Any URL parameters which need to
152 ** be added to the generated URLs should be passed in zParam. The
153 ** caller is expected to have already encoded any zParam in the %T or
154 ** %t encoding. */
155 static void stats_report_event_types_menu(const char *zCurrentViewName,
156 const char *zParam){
157 char *zTop;
158 if(zParam && !*zParam){
159 zParam = NULL;
160 }
161 zTop = mprintf("%s/reports?view=%s%s%s", g.zTop, zCurrentViewName,
162 zParam ? "&" : "", zParam);
163 cgi_printf("<div>");
164 cgi_printf("<span>Types:</span> ");
165 if('*' == statsReportType){
166 cgi_printf(" <strong>all</strong>", zTop);
167 }else{
168 cgi_printf(" <a href='%s'>all</a>", zTop);
169 }
170 if('c' == statsReportType){
171 cgi_printf(" <strong>check-ins</strong>", zTop);
172 }else{
173 cgi_printf(" <a href='%s&type=ci'>check-ins</a>", zTop);
174 }
175 if('e' == statsReportType){
176 cgi_printf(" <strong>technotes</strong>", zTop);
177 }else{
178 cgi_printf(" <a href='%s&type=e'>technotes</a>", zTop);
179 }
180 if( 't' == statsReportType ){
181 cgi_printf(" <strong>tickets</strong>", zTop);
182 }else{
183 cgi_printf(" <a href='%s&type=t'>tickets</a>", zTop);
184 }
185 if( 'g' == statsReportType ){
186 cgi_printf(" <strong>tags</strong>", zTop);
187 }else{
188 cgi_printf(" <a href='%s&type=g'>tags</a>", zTop);
189 }
190 if( 'w' == statsReportType ){
191 cgi_printf(" <strong>wiki</strong>", zTop);
192 }else{
193 cgi_printf(" <a href='%s&type=w'>wiki</a>", zTop);
194 }
195 fossil_free(zTop);
196 cgi_printf("</div>");
197 }
198
199
200 /*
201 ** Helper for stats_report_by_month_year(), which generates a list of
202 ** week numbers. zTimeframe should be either a timeframe in the form YYYY
203 ** or YYYY-MM.
@@ -227,23 +174,21 @@
227 }
228
229 /*
230 ** Implements the "byyear" and "bymonth" reports for /reports.
231 ** If includeMonth is true then it generates the "bymonth" report,
232 ** else the "byyear" report. If zUserName is not NULL and not empty
233 ** then the report is restricted to events created by the named user
234 ** account.
235 */
236 static void stats_report_by_month_year(char includeMonth,
237 char includeWeeks,
238 const char *zUserName){
239 Stmt query = empty_Stmt;
240 int nRowNumber = 0; /* current TR number */
241 int nEventTotal = 0; /* Total event count */
242 int rowClass = 0; /* counter for alternating
243 row colors */
244 Blob sql = empty_blob; /* SQL */
245 const char *zTimeLabel = includeMonth ? "Year/Month" : "Year";
246 char zPrevYear[5] = {0}; /* For keeping track of when
247 we change years while looping */
248 int nEventsPerYear = 0; /* Total event count for the
249 current year */
@@ -252,39 +197,37 @@
252 Blob header = empty_blob; /* Page header text */
253 int nMaxEvents = 1; /* for calculating length of graph
254 bars. */
255 int iterations = 0; /* number of weeks/months we iterate
256 over */
 
257 stats_report_init_view();
258 stats_report_event_types_menu( includeMonth ? "bymonth" : "byyear", NULL );
259 blob_appendf(&header, "Timeline Events (%s) by year%s",
260 stats_report_label_for_type(),
261 (includeMonth ? "/month" : ""));
262 blob_append_sql(&sql,
263 "SELECT substr(date(mtime),1,%d) AS timeframe, "
264 "count(*) AS eventCount "
265 "FROM v_reports ",
266 includeMonth ? 7 : 4);
267 if(zUserName&&*zUserName){
268 blob_append_sql(&sql, " WHERE user=%Q ", zUserName);
269 blob_appendf(&header," for user %q", zUserName);
270 }
271 blob_append(&sql,
272 " GROUP BY timeframe"
273 " ORDER BY timeframe DESC",
274 -1);
275 db_prepare(&query, "%s", blob_sql_text(&sql));
276 blob_reset(&sql);
277 @ <h1>%b(&header)</h1>
278 @ <table class='statistics-report-table-events' border='0' cellpadding='2'
279 @ cellspacing='0' id='statsTable'>
280 @ <thead>
281 @ <th>%s(zTimeLabel)</th>
282 @ <th>Events</th>
283 @ <th width='90%%'><!-- relative commits graph --></th>
284 @ </thead><tbody>
285 blob_reset(&header);
286 /*
287 Run the query twice. The first time we calculate the maximum
288 number of events for a given row. Maybe someone with better SQL
289 Fu can re-implement this with a single query.
290 */
@@ -335,18 +278,18 @@
335 zTimeframe, nCount,
336 statsReportTimelineYFlag );
337 /* Reminder: n=nCount is not actually correct for bymonth unless
338 that was the only user who caused events.
339 */
340 if( zUserName && *zUserName ){
341 cgi_printf("&u=%t", zUserName);
342 }
343 cgi_printf("' target='_new'>%s</a>",zTimeframe);
344 }else {
345 cgi_printf("<a href='?view=byweek&y=%s&type=%c",
346 zTimeframe, (char)statsReportType);
347 if(zUserName && *zUserName){
348 cgi_printf("&u=%t", zUserName);
349 }
350 cgi_printf("'>%s</a>", zTimeframe);
351 }
352 @ </td><td>%d(nCount)</td>
@@ -403,25 +346,34 @@
403 int rowClass = 0; /* counter for alternating
404 row colors */
405 int nMaxEvents = 1; /* max number of events for
406 all rows. */
407 stats_report_init_view();
408 stats_report_event_types_menu("byuser", NULL);
409 db_prepare(&query,
410 "SELECT user, "
411 "COUNT(*) AS eventCount "
412 "FROM v_reports "
413 "GROUP BY user ORDER BY eventCount DESC");
414 @ <h1>Timeline Events
415 @ (%s(stats_report_label_for_type())) by User</h1>
 
 
 
 
 
 
 
 
 
 
416 @ <table class='statistics-report-table-events' border='0'
417 @ cellpadding='2' cellspacing='0' id='statsTable'>
418 @ <thead><tr>
419 @ <th>User</th>
420 @ <th>Events</th>
421 @ <th width='90%%'><!-- relative commits graph --></th>
422 @ </tr></thead><tbody>
 
 
 
 
 
423 while( SQLITE_ROW == db_step(&query) ){
424 const int nCount = db_column_int(&query, 1);
425 if(nCount>nMaxEvents){
426 nMaxEvents = nCount;
427 }
@@ -428,20 +380,21 @@
428 }
429 db_reset(&query);
430 while( SQLITE_ROW == db_step(&query) ){
431 const char *zUser = db_column_text(&query, 0);
432 const int nCount = db_column_int(&query, 1);
 
433 int nSize = nCount
434 ? (int)(100 * nCount / nMaxEvents)
435 : 0;
436 if(!nCount) continue /* arguable! Possible? */;
437 else if(!nSize) nSize = 1;
438 rowClass = ++nRowNumber % 2;
439 nEventTotal += nCount;
440 @<tr class='row%d(rowClass)'>
441 @ <td>
442 @ <a href="?view=bymonth&user=%h(zUser)&type=%c((char)statsReportType)">%h(zUser)</a>
443 @ </td><td data-sortkey='%08x(-nCount)'>%d(nCount)</td>
444 @ <td>
445 @ <div class='statistics-report-graph-line'
446 @ style='width:%d(nSize)%%;'>&nbsp;</div>
447 @ </td>
@@ -455,30 +408,37 @@
455 db_finalize(&query);
456 output_table_sorting_javascript("statsTable","tkx",2);
457 }
458
459 /*
460 ** Implements the "byfile" view for /reports.
 
461 */
462 static void stats_report_by_file(){
463 Stmt query;
464 int mxEvent = 1; /* max number of events across all rows */
465 int nRowNumber = 0;
466
467 db_multi_exec(
468 "CREATE TEMP TABLE statrep(filename, cnt);"
469 "INSERT INTO statrep(filename, cnt)"
470 " SELECT filename.name, count(distinct mlink.mid)"
471 " FROM filename, mlink"
472 " WHERE filename.fnid=mlink.fnid"
473 " GROUP BY 1"
 
 
474 );
475 db_prepare(&query,
476 "SELECT filename, cnt FROM statrep ORDER BY cnt DESC, filename /*sort*/"
477 );
478 mxEvent = db_int(1, "SELECT max(cnt) FROM statrep");
479 @ <h1>Check-ins Per File</h1>
 
 
 
 
480 @ <table class='statistics-report-table-events' border='0'
481 @ cellpadding='2' cellspacing='0' id='statsTable'>
482 @ <thead><tr>
483 @ <th>File</th>
484 @ <th>Check-ins</th>
@@ -504,34 +464,62 @@
504 db_finalize(&query);
505 output_table_sorting_javascript("statsTable","tNx",2);
506 }
507
508 /*
509 ** Implements the "byweekday" view for /reports.
 
510 */
511 static void stats_report_day_of_week(){
512 Stmt query = empty_Stmt;
513 int nRowNumber = 0; /* current TR number */
514 int nEventTotal = 0; /* Total event count */
515 int rowClass = 0; /* counter for alternating
516 row colors */
517 int nMaxEvents = 1; /* max number of events for
518 all rows. */
 
519 static const char *const daysOfWeek[] = {
520 "Monday", "Tuesday", "Wednesday", "Thursday",
521 "Friday", "Saturday", "Sunday"
522 };
523
524 stats_report_init_view();
525 stats_report_event_types_menu("byweekday", NULL);
 
 
526 db_prepare(&query,
527 "SELECT cast(mtime %% 7 AS INTEGER) dow, "
528 "COUNT(*) AS eventCount "
529 "FROM v_reports "
530 "GROUP BY dow ORDER BY dow");
531 @ <h1>Timeline Events
532 @ (%s(stats_report_label_for_type())) by Day of the Week</h1>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
533 @ <table class='statistics-report-table-events' border='0'
534 @ cellpadding='2' cellspacing='0' id='statsTable'>
535 @ <thead><tr>
536 @ <th>DoW</th>
537 @ <th>Day</th>
@@ -572,139 +560,114 @@
572
573
574 /*
575 ** Helper for stats_report_by_month_year(), which generates a list of
576 ** week numbers. zTimeframe should be either a timeframe in the form YYYY
577 ** or YYYY-MM.
 
578 */
579 static void stats_report_year_weeks(const char *zUserName){
580 const char *zYear = P("y");
581 int nYear = zYear ? strlen(zYear) : 0;
582 int i = 0;
583 Stmt qYears = empty_Stmt;
584 char *zDefaultYear = NULL;
585 Blob sql = empty_blob;
586 int nMaxEvents = 1; /* max number of events for
587 all rows. */
588 int iterations = 0; /* # of active time periods. */
589 stats_report_init_view();
590 if(4==nYear){
591 Blob urlParams = empty_blob;
592 blob_appendf(&urlParams, "y=%T", zYear);
593 stats_report_event_types_menu("byweek", blob_str(&urlParams));
594 blob_reset(&urlParams);
595 }else{
596 stats_report_event_types_menu("byweek", NULL);
597 }
598 blob_append(&sql,
599 "SELECT DISTINCT substr(date(mtime),1,4) AS y "
600 "FROM v_reports WHERE 1 ", -1);
601 if(zUserName&&*zUserName){
602 blob_append_sql(&sql,"AND user=%Q ", zUserName);
603 }
604 blob_append(&sql,"GROUP BY y ORDER BY y", -1);
605 db_prepare(&qYears, "%s", blob_sql_text(&sql));
606 blob_reset(&sql);
607 cgi_printf("Select year: ");
608 while( SQLITE_ROW == db_step(&qYears) ){
609 const char *zT = db_column_text(&qYears, 0);
610 if( i++ ){
611 cgi_printf(" ");
612 }
613 cgi_printf("<a href='?view=byweek&y=%s&type=%c", zT,
614 (char)statsReportType);
615 if(zUserName && *zUserName){
616 cgi_printf("&user=%t",zUserName);
617 }
618 cgi_printf("'>%s</a>",zT);
619 }
620 db_finalize(&qYears);
621 cgi_printf("<br/>");
622 if(!zYear || !*zYear){
623 zDefaultYear = db_text("????", "SELECT strftime('%%Y')");
624 zYear = zDefaultYear;
625 nYear = 4;
626 }
627 if(4 == nYear){
628 Stmt stWeek = empty_Stmt;
629 int rowCount = 0;
630 int total = 0;
631 Blob header = empty_blob;
632 blob_appendf(&header, "Timeline events (%s) for the calendar weeks "
633 "of %h", stats_report_label_for_type(),
634 zYear);
635 blob_append_sql(&sql,
636 "SELECT DISTINCT strftime('%%W',mtime) AS wk, "
637 "count(*) AS n "
638 "FROM v_reports "
639 "WHERE %Q=substr(date(mtime),1,4) "
640 "AND mtime < current_timestamp ",
641 zYear);
642 if(zUserName&&*zUserName){
643 blob_append_sql(&sql, " AND user=%Q ", zUserName);
644 blob_appendf(&header," for user %h", zUserName);
645 }
646 blob_append_sql(&sql, "GROUP BY wk ORDER BY wk DESC");
647 cgi_printf("<h1>%h</h1>", blob_str(&header));
648 blob_reset(&header);
649 cgi_printf("<table class='statistics-report-table-events' "
650 "border='0' cellpadding='2' width='100%%' "
651 "cellspacing='0' id='statsTable'>");
652 cgi_printf("<thead><tr>"
653 "<th>Week</th>"
654 "<th>Events</th>"
655 "<th width='90%%'><!-- relative commits graph --></th>"
656 "</tr></thead>"
657 "<tbody>");
658 db_prepare(&stWeek, "%s", blob_sql_text(&sql));
659 blob_reset(&sql);
660 while( SQLITE_ROW == db_step(&stWeek) ){
661 const int nCount = db_column_int(&stWeek, 1);
662 if(nCount>nMaxEvents){
663 nMaxEvents = nCount;
664 }
665 ++iterations;
666 }
667 db_reset(&stWeek);
668 while( SQLITE_ROW == db_step(&stWeek) ){
669 const char *zWeek = db_column_text(&stWeek,0);
670 const int nCount = db_column_int(&stWeek,1);
671 int nSize = nCount
672 ? (int)(100 * nCount / nMaxEvents)
673 : 0;
674 if(!nSize) nSize = 1;
675 total += nCount;
676 cgi_printf("<tr class='row%d'>", ++rowCount % 2 );
677 cgi_printf("<td><a href='%R/timeline?yw=%t-%s&n=%d&y=%s",
678 zYear, zWeek, nCount,
679 statsReportTimelineYFlag);
680 if(zUserName && *zUserName){
681 cgi_printf("&u=%t",zUserName);
682 }
683 cgi_printf("'>%s</a></td>",zWeek);
684
685 cgi_printf("<td>%d</td>",nCount);
686 cgi_printf("<td>");
687 if(nCount){
688 cgi_printf("<div class='statistics-report-graph-line'"
689 "style='width:%d%%;'>&nbsp;</div>",
690 nSize);
691 }
692 cgi_printf("</td></tr>");
693 }
694 db_finalize(&stWeek);
695 free(zDefaultYear);
696 cgi_printf("</tbody></table>");
697 if(total){
698 int nAvg = iterations ? (total/iterations) : 0;
699 cgi_printf("<br><div>Total events: %d<br>"
700 "Average per active week: %d</div>",
701 total, nAvg);
702 }
703 output_table_sorting_javascript("statsTable","tnx",-1);
704 }
705 }
706
707 /*
708 ** WEBPAGE: reports
709 **
710 ** Shows activity reports for the repository.
@@ -724,51 +687,94 @@
724 ** y=YYYY The year to report (default is the server's
725 ** current year).
726 */
727 void stats_report_page(){
728 HQuery url; /* URL for various branch links */
729 const char *zView = P("view"); /* Which view/report to show. */
730 const char *zUserName = P("user");
731
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
732 login_check_credentials();
733 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
734 if(!zUserName) zUserName = P("u");
735 url_initialize(&url, "reports");
736 if(zUserName && *zUserName){
737 url_add_parameter(&url,"user", zUserName);
738 statrep_submenu(&url, "(Remove User Flag)", "view", zView, "user");
739 }
740 statrep_submenu(&url, "By Year", "view", "byyear", 0);
741 statrep_submenu(&url, "By Month", "view", "bymonth", 0);
742 statrep_submenu(&url, "By Week", "view", "byweek", 0);
743 statrep_submenu(&url, "By Weekday", "view", "byweekday", 0);
744 statrep_submenu(&url, "By User", "view", "byuser", "user");
745 statrep_submenu(&url, "By File", "view", "byfile", "file");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
746 style_submenu_element("Stats", "Stats", "%R/stat");
747 url_reset(&url);
748 style_header("Activity Reports");
749 if(0==fossil_strcmp(zView,"byyear")){
750 stats_report_by_month_year(0, 0, zUserName);
751 }else if(0==fossil_strcmp(zView,"bymonth")){
752 stats_report_by_month_year(1, 0, zUserName);
753 }else if(0==fossil_strcmp(zView,"byweek")){
754 stats_report_year_weeks(zUserName);
755 }else if(0==fossil_strcmp(zView,"byuser")){
756 stats_report_by_user();
757 }else if(0==fossil_strcmp(zView,"byweekday")){
758 stats_report_day_of_week();
759 }else if(0==fossil_strcmp(zView,"byfile")){
760 stats_report_by_file();
761 }else{
762 @ <h1>Activity Reports:</h1>
763 @ <ul>
764 @ <li>%z(href("?view=byyear"))Events by year</a></li>
765 @ <li>%z(href("?view=bymonth"))Events by month</a></li>
766 @ <li>%z(href("?view=byweek"))Events by calendar week</a></li>
767 @ <li>%z(href("?view=byweekday"))Events by day of the week</a></li>
768 @ <li>%z(href("?view=byuser"))Events by user</a></li>
769 @ <li>%z(href("?view=byfile"))Events by file</a></li>
770 @ </ul>
771 }
772
773 style_footer();
774 }
775
--- src/statrep.c
+++ src/statrep.c
@@ -141,63 +141,10 @@
141 default:
142 return "all types";
143 }
144 }
145
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
146
147 /*
148 ** Helper for stats_report_by_month_year(), which generates a list of
149 ** week numbers. zTimeframe should be either a timeframe in the form YYYY
150 ** or YYYY-MM.
@@ -227,23 +174,21 @@
174 }
175
176 /*
177 ** Implements the "byyear" and "bymonth" reports for /reports.
178 ** If includeMonth is true then it generates the "bymonth" report,
179 ** else the "byyear" report. If zUserName is not NULL then the report is
180 ** restricted to events created by the named user account.
 
181 */
182 static void stats_report_by_month_year(char includeMonth,
183 char includeWeeks,
184 const char *zUserName){
185 Stmt query = empty_Stmt;
186 int nRowNumber = 0; /* current TR number */
187 int nEventTotal = 0; /* Total event count */
188 int rowClass = 0; /* counter for alternating
189 row colors */
 
190 const char *zTimeLabel = includeMonth ? "Year/Month" : "Year";
191 char zPrevYear[5] = {0}; /* For keeping track of when
192 we change years while looping */
193 int nEventsPerYear = 0; /* Total event count for the
194 current year */
@@ -252,39 +197,37 @@
197 Blob header = empty_blob; /* Page header text */
198 int nMaxEvents = 1; /* for calculating length of graph
199 bars. */
200 int iterations = 0; /* number of weeks/months we iterate
201 over */
202 Blob userFilter = empty_blob; /* Optional user=johndoe query string */
203 stats_report_init_view();
204 if( zUserName ){
205 blob_appendf(&userFilter, "user=%s", zUserName);
206 }
207 blob_reset(&userFilter);
208 db_prepare(&query,
209 "SELECT substr(date(mtime),1,%d) AS timeframe,"
210 " count(*) AS eventCount"
211 " FROM v_reports"
212 " WHERE ifnull(coalesce(euser,user,'')=%Q,1)"
213 " GROUP BY timeframe"
214 " ORDER BY timeframe DESC",
215 includeMonth ? 7 : 4, zUserName);
216 @ <h1>Timeline Events (%s(stats_report_label_for_type()))
217 @ by year%s(includeMonth ? "/month" : "")
218 if( zUserName ){
219 @ for user %h(zUserName)
220 }
221 @ </h1>
 
 
222 @ <table class='statistics-report-table-events' border='0' cellpadding='2'
223 @ cellspacing='0' id='statsTable'>
224 @ <thead>
225 @ <th>%s(zTimeLabel)</th>
226 @ <th>Events</th>
227 @ <th width='90%%'><!-- relative commits graph --></th>
228 @ </thead><tbody>
 
229 /*
230 Run the query twice. The first time we calculate the maximum
231 number of events for a given row. Maybe someone with better SQL
232 Fu can re-implement this with a single query.
233 */
@@ -335,18 +278,18 @@
278 zTimeframe, nCount,
279 statsReportTimelineYFlag );
280 /* Reminder: n=nCount is not actually correct for bymonth unless
281 that was the only user who caused events.
282 */
283 if( zUserName ){
284 cgi_printf("&u=%t", zUserName);
285 }
286 cgi_printf("' target='_new'>%s</a>",zTimeframe);
287 }else {
288 cgi_printf("<a href='?view=byweek&y=%s&type=%c",
289 zTimeframe, (char)statsReportType);
290 if( zUserName ){
291 cgi_printf("&u=%t", zUserName);
292 }
293 cgi_printf("'>%s</a>", zTimeframe);
294 }
295 @ </td><td>%d(nCount)</td>
@@ -403,25 +346,34 @@
346 int rowClass = 0; /* counter for alternating
347 row colors */
348 int nMaxEvents = 1; /* max number of events for
349 all rows. */
350 stats_report_init_view();
 
 
 
 
 
 
351 @ <h1>Timeline Events
352 @ (%s(stats_report_label_for_type())) by User</h1>
353 db_multi_exec(
354 "CREATE TEMP TABLE piechart(amt,label);"
355 "INSERT INTO piechart SELECT count(*), ifnull(euser,user) FROM v_reports"
356 " GROUP BY ifnull(euser,user) ORDER BY count(*) DESC;"
357 );
358 if( db_int(0, "SELECT count(*) FROM piechart")>=2 ){
359 @ <center><svg width=700 height=400>
360 piechart_render(700, 400, PIE_OTHER|PIE_PERCENT);
361 @ </svg></centre><hr/>
362 }
363 @ <table class='statistics-report-table-events' border='0'
364 @ cellpadding='2' cellspacing='0' id='statsTable'>
365 @ <thead><tr>
366 @ <th>User</th>
367 @ <th>Events</th>
368 @ <th width='90%%'><!-- relative commits graph --></th>
369 @ </tr></thead><tbody>
370 db_prepare(&query,
371 "SELECT ifnull(euser,user), "
372 "COUNT(*) AS eventCount "
373 "FROM v_reports "
374 "GROUP BY ifnull(euser,user) ORDER BY eventCount DESC");
375 while( SQLITE_ROW == db_step(&query) ){
376 const int nCount = db_column_int(&query, 1);
377 if(nCount>nMaxEvents){
378 nMaxEvents = nCount;
379 }
@@ -428,20 +380,21 @@
380 }
381 db_reset(&query);
382 while( SQLITE_ROW == db_step(&query) ){
383 const char *zUser = db_column_text(&query, 0);
384 const int nCount = db_column_int(&query, 1);
385 char y = (char)statsReportType;
386 int nSize = nCount
387 ? (int)(100 * nCount / nMaxEvents)
388 : 0;
389 if(!nCount) continue /* arguable! Possible? */;
390 else if(!nSize) nSize = 1;
391 rowClass = ++nRowNumber % 2;
392 nEventTotal += nCount;
393 @ <tr class='row%d(rowClass)'>
394 @ <td>
395 @ <a href="?view=bymonth&user=%h(zUser)&type=%c(y)">%h(zUser)</a>
396 @ </td><td data-sortkey='%08x(-nCount)'>%d(nCount)</td>
397 @ <td>
398 @ <div class='statistics-report-graph-line'
399 @ style='width:%d(nSize)%%;'>&nbsp;</div>
400 @ </td>
@@ -455,30 +408,37 @@
408 db_finalize(&query);
409 output_table_sorting_javascript("statsTable","tkx",2);
410 }
411
412 /*
413 ** Implements the "byfile" view for /reports. If zUserName is not NULL then the
414 ** report is restricted to events created by the named user account.
415 */
416 static void stats_report_by_file(const char *zUserName){
417 Stmt query;
418 int mxEvent = 1; /* max number of events across all rows */
419 int nRowNumber = 0;
420
421 db_multi_exec(
422 "CREATE TEMP TABLE statrep(filename, cnt);"
423 "INSERT INTO statrep(filename, cnt)"
424 " SELECT filename.name, count(distinct mlink.mid)"
425 " FROM filename, mlink, event"
426 " WHERE filename.fnid=mlink.fnid"
427 " AND mlink.mid=event.objid"
428 " AND ifnull(coalesce(euser,user,'')=%Q,1)"
429 " GROUP BY 1", zUserName
430 );
431 db_prepare(&query,
432 "SELECT filename, cnt FROM statrep ORDER BY cnt DESC, filename /*sort*/"
433 );
434 mxEvent = db_int(1, "SELECT max(cnt) FROM statrep");
435 @ <h1>Check-ins Per File
436 if( zUserName ){
437 @ for user %h(zUserName)
438 }
439 @ </h1>
440 @ <table class='statistics-report-table-events' border='0'
441 @ cellpadding='2' cellspacing='0' id='statsTable'>
442 @ <thead><tr>
443 @ <th>File</th>
444 @ <th>Check-ins</th>
@@ -504,34 +464,62 @@
464 db_finalize(&query);
465 output_table_sorting_javascript("statsTable","tNx",2);
466 }
467
468 /*
469 ** Implements the "byweekday" view for /reports. If zUserName is not NULL then
470 ** the report is restricted to events created by the named user account.
471 */
472 static void stats_report_day_of_week(const char *zUserName){
473 Stmt query = empty_Stmt;
474 int nRowNumber = 0; /* current TR number */
475 int nEventTotal = 0; /* Total event count */
476 int rowClass = 0; /* counter for alternating
477 row colors */
478 int nMaxEvents = 1; /* max number of events for
479 all rows. */
480 Blob userFilter = empty_blob; /* Optional user=johndoe query string */
481 static const char *const daysOfWeek[] = {
482 "Monday", "Tuesday", "Wednesday", "Thursday",
483 "Friday", "Saturday", "Sunday"
484 };
485
486 stats_report_init_view();
487 if( zUserName ){
488 blob_appendf(&userFilter, "user=%s", zUserName);
489 }
490 db_prepare(&query,
491 "SELECT cast(mtime %% 7 AS INTEGER) dow,"
492 " COUNT(*) AS eventCount"
493 " FROM v_reports"
494 " WHERE ifnull(coalesce(euser,user,'')=%Q,1)"
495 " GROUP BY dow ORDER BY dow", zUserName);
496 @ <h1>Timeline Events (%h(stats_report_label_for_type())) by Day of the Week
497 if( zUserName ){
498 @ for user %h(zUserName)
499 }
500 @ </h1>
501 db_multi_exec(
502 "CREATE TEMP TABLE piechart(amt,label);"
503 "INSERT INTO piechart"
504 " SELECT count(*), cast(mtime %% 7 AS INT) FROM v_reports"
505 " WHERE ifnull(coalesce(euser,user,'')=%Q,1)"
506 " GROUP BY 2 ORDER BY 2;"
507 "UPDATE piechart SET label = CASE label"
508 " WHEN 0 THEN 'Monday'"
509 " WHEN 1 THEN 'Tuesday'"
510 " WHEN 2 THEN 'Wednesday'"
511 " WHEN 3 THEN 'Thursday'"
512 " WHEN 4 THEN 'Friday'"
513 " WHEN 5 THEN 'Saturday'"
514 " ELSE 'Sunday' END;", zUserName
515 );
516 if( db_int(0, "SELECT count(*) FROM piechart")>=2 ){
517 @ <center><svg width=700 height=400>
518 piechart_render(700, 400, PIE_OTHER|PIE_PERCENT);
519 @ </svg></centre><hr/>
520 }
521 @ <table class='statistics-report-table-events' border='0'
522 @ cellpadding='2' cellspacing='0' id='statsTable'>
523 @ <thead><tr>
524 @ <th>DoW</th>
525 @ <th>Day</th>
@@ -572,139 +560,114 @@
560
561
562 /*
563 ** Helper for stats_report_by_month_year(), which generates a list of
564 ** week numbers. zTimeframe should be either a timeframe in the form YYYY
565 ** or YYYY-MM. If zUserName is not NULL then the report is restricted to events
566 ** created by the named user account.
567 */
568 static void stats_report_year_weeks(const char *zUserName){
569 const char *zYear = P("y"); /* Year for which report shown */
570 int isValidYear = 0; /* True if a valid year */
571 int i = 0;
572 Stmt q;
 
 
573 int nMaxEvents = 1; /* max number of events for
574 all rows. */
575 int iterations = 0; /* # of active time periods. */
576 int n = 0; /* Number of entries in azYear */
577 char **azYear = 0; /* Year dropdown menu */
578 int rowCount = 0;
579 int total = 0;
580
581 stats_report_init_view();
582 style_submenu_sql("y", "Year:",
583 "WITH RECURSIVE a(b) AS ("
584 " SELECT substr(date('now'),1,4) UNION ALL"
585 " SELECT b-1 FROM a"
586 " WHERE b>0+(SELECT substr(date(min(mtime)),1,4) FROM event)"
587 ") SELECT b, b FROM a ORDER BY b DESC");
588 if( zYear==0 || strlen(zYear)!=4 ){
589 zYear = db_text("1970","SELECT substr(date('now'),1,4);");
590 }
591 cgi_printf("<br/>");
592 db_prepare(&q,
593 "SELECT DISTINCT strftime('%%W',mtime) AS wk, "
594 " count(*) AS n "
595 " FROM v_reports "
596 " WHERE %Q=substr(date(mtime),1,4) "
597 " AND mtime < current_timestamp "
598 " AND ifnull(coalesce(euser,user,'')=%Q,1)"
599 " GROUP BY wk ORDER BY wk DESC", zYear, zUserName);
600 @ <h1>Timeline events (%h(stats_report_label_for_type()))
601 @ for the calendar weeks of %h(zYear)
602 if( zUserName ){
603 @ for user %h(zUserName)
604 }
605 @ </h1>
606 cgi_printf("<table class='statistics-report-table-events' "
607 "border='0' cellpadding='2' width='100%%' "
608 "cellspacing='0' id='statsTable'>");
609 cgi_printf("<thead><tr>"
610 "<th>Week</th>"
611 "<th>Events</th>"
612 "<th width='90%%'><!-- relative commits graph --></th>"
613 "</tr></thead>"
614 "<tbody>");
615 while( SQLITE_ROW == db_step(&q) ){
616 const int nCount = db_column_int(&q, 1);
617 if(nCount>nMaxEvents){
618 nMaxEvents = nCount;
619 }
620 ++iterations;
621 }
622 db_reset(&q);
623 while( SQLITE_ROW == db_step(&q) ){
624 const char *zWeek = db_column_text(&q,0);
625 const int nCount = db_column_int(&q,1);
626 int nSize = nCount
627 ? (int)(100 * nCount / nMaxEvents)
628 : 0;
629 if(!nSize) nSize = 1;
630 total += nCount;
631 cgi_printf("<tr class='row%d'>", ++rowCount % 2 );
632 cgi_printf("<td><a href='%R/timeline?yw=%t-%s&n=%d&y=%s",
633 zYear, zWeek, nCount,
634 statsReportTimelineYFlag);
635 if( zUserName ){
636 cgi_printf("&u=%t",zUserName);
637 }
638 cgi_printf("'>%s</a></td>",zWeek);
639
640 cgi_printf("<td>%d</td>",nCount);
641 cgi_printf("<td>");
642 if(nCount){
643 cgi_printf("<div class='statistics-report-graph-line'"
644 "style='width:%d%%;'>&nbsp;</div>",
645 nSize);
646 }
647 cgi_printf("</td></tr>");
648 }
649 db_finalize(&q);
650 cgi_printf("</tbody></table>");
651 if(total){
652 int nAvg = iterations ? (total/iterations) : 0;
653 cgi_printf("<br><div>Total events: %d<br>"
654 "Average per active week: %d</div>",
655 total, nAvg);
656 }
657 output_table_sorting_javascript("statsTable","tnx",-1);
658 }
659
660 /* Report types
661 */
662 #define RPT_BYFILE 1
663 #define RPT_BYMONTH 2
664 #define RPT_BYUSER 3
665 #define RPT_BYWEEK 4
666 #define RPT_BYWEEKDAY 5
667 #define RPT_BYYEAR 6
668 #define RPT_NONE 0 /* None of the above */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
669
670 /*
671 ** WEBPAGE: reports
672 **
673 ** Shows activity reports for the repository.
@@ -724,51 +687,94 @@
687 ** y=YYYY The year to report (default is the server's
688 ** current year).
689 */
690 void stats_report_page(){
691 HQuery url; /* URL for various branch links */
692 const char *zView = P("view"); /* Which view/report to show. */
693 int eType = RPT_NONE; /* Numeric code for view/report to show */
694 int i; /* Loop counter */
695 const char *zUserName; /* Name of user */
696 const struct {
697 const char *zName; /* Name of view= screen type */
698 const char *zVal; /* Value of view= query parameter */
699 int eType; /* Corresponding RPT_* define */
700 } aViewType[] = {
701 { "File Changes","byfile", RPT_BYFILE },
702 { "By Month", "bymonth", RPT_BYMONTH },
703 { "By User", "byuser", RPT_BYUSER },
704 { "By Week", "byweek", RPT_BYWEEK },
705 { "By Weekday", "byweekday", RPT_BYWEEKDAY },
706 { "By Year", "byyear", RPT_BYYEAR },
707 };
708 const char *azType[] = {
709 "a", "All Changes",
710 "ci", "Check-ins",
711 "g", "Tags",
712 "e", "Tech Notes",
713 "t", "Tickets",
714 "w", "Wiki"
715 };
716
717 login_check_credentials();
718 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
719 zUserName = P("user");
720 if( zUserName==0 ) zUserName = P("u");
721 if( zUserName && zUserName[0]==0 ) zUserName = 0;
722 if( zView==0 ){
723 zView = "byuser";
724 cgi_replace_query_parameter("view","byuser");
725 }
726 for(i=0; i<ArraySize(aViewType); i++){
727 if( fossil_strcmp(zView, aViewType[i].zVal)==0 ){
728 eType = aViewType[i].eType;
729 break;
730 }
731 }
732 url_initialize(&url, "reports");
733 cgi_query_parameters_to_url(&url);
734 if( eType!=RPT_NONE ){
735 int nView = 0; /* Slots used in azView[] */
736 const char *azView[16]; /* Drop-down menu of view types */
737 for(i=0; i<ArraySize(aViewType); i++){
738 azView[nView++] = aViewType[i].zVal;
739 azView[nView++] = aViewType[i].zName;
740 }
741 if( eType!=RPT_BYFILE ){
742 style_submenu_multichoice("type", ArraySize(azType)/2, azType, 0);
743 }
744 style_submenu_multichoice("view", nView/2, azView, 0);
745 if( eType!=RPT_BYUSER ){
746 style_submenu_sql("u","User:",
747 "SELECT '', 'All Users' UNION ALL "
748 "SELECT x, x FROM ("
749 " SELECT DISTINCT trim(coalesce(euser,user)) AS x FROM event %s"
750 " ORDER BY 1 COLLATE nocase) WHERE x!=''",
751 eType==RPT_BYFILE ? "WHERE type='ci'" : ""
752 );
753 }
754 }
755 style_submenu_element("Stats", "Stats", "%R/stat");
756 url_reset(&url);
757 style_header("Activity Reports");
758 switch( eType ){
759 case RPT_BYYEAR:
760 stats_report_by_month_year(0, 0, zUserName);
761 break;
762 case RPT_BYMONTH:
763 stats_report_by_month_year(1, 0, zUserName);
764 break;
765 case RPT_BYWEEK:
766 stats_report_year_weeks(zUserName);
767 break;
768 default:
769 case RPT_BYUSER:
770 stats_report_by_user();
771 break;
772 case RPT_BYWEEKDAY:
773 stats_report_day_of_week(zUserName);
774 break;
775 case RPT_BYFILE:
776 stats_report_by_file(zUserName);
777 break;
778 }
 
 
 
779 style_footer();
780 }
781
+162 -16
--- src/style.c
+++ src/style.c
@@ -285,11 +285,45 @@
285285
aSubmenuCtrl[nSubmenuCtrl].azChoice = azChoice;
286286
aSubmenuCtrl[nSubmenuCtrl].isDisabled = isDisabled;
287287
aSubmenuCtrl[nSubmenuCtrl].eType = FF_MULTI;
288288
nSubmenuCtrl++;
289289
}
290
+void style_submenu_sql(
291
+ const char *zName, /* Query parameter name */
292
+ const char *zLabel, /* Label on the control */
293
+ const char *zFormat, /* Format string for SQL command for choices */
294
+ ... /* Arguments to the format string */
295
+){
296
+ Stmt q;
297
+ int n = 0;
298
+ int nAlloc = 0;
299
+ char **az = 0;
300
+ va_list ap;
290301
302
+ va_start(ap, zFormat);
303
+ db_vprepare(&q, 0, zFormat, ap);
304
+ va_end(ap);
305
+ while( SQLITE_ROW==db_step(&q) ){
306
+ if( n+2>=nAlloc ){
307
+ nAlloc += nAlloc + 20;
308
+ az = fossil_realloc(az, sizeof(char*)*nAlloc);
309
+ }
310
+ az[n++] = fossil_strdup(db_column_text(&q,0));
311
+ az[n++] = fossil_strdup(db_column_text(&q,1));
312
+ }
313
+ db_finalize(&q);
314
+ if( n>0 ){
315
+ aSubmenuCtrl[nSubmenuCtrl].zName = zName;
316
+ aSubmenuCtrl[nSubmenuCtrl].zLabel = zLabel;
317
+ aSubmenuCtrl[nSubmenuCtrl].iSize = n/2;
318
+ aSubmenuCtrl[nSubmenuCtrl].azChoice = (const char**)az;
319
+ aSubmenuCtrl[nSubmenuCtrl].isDisabled = 0;
320
+ aSubmenuCtrl[nSubmenuCtrl].eType = FF_MULTI;
321
+ nSubmenuCtrl++;
322
+ }
323
+}
324
+
291325
292326
/*
293327
** Compare two submenu items for sorting purposes
294328
*/
295329
static int submenuCompare(const void *a, const void *b){
@@ -514,10 +548,13 @@
514548
break;
515549
}
516550
case FF_MULTI: {
517551
int j;
518552
const char *zVal = P(zQPN);
553
+ if( aSubmenuCtrl[i].zLabel ){
554
+ cgi_printf("&nbsp;%h", aSubmenuCtrl[i].zLabel);
555
+ }
519556
cgi_printf(
520557
"<select class='submenuctrl' size='1' name='%s'%s "
521558
"onchange='gebi(\"f01\").submit();'>\n",
522559
zQPN, zDisabled
523560
);
@@ -701,15 +738,108 @@
701738
@ vertical-align: top;
702739
@ text-align: right;
703740
@ white-space: nowrap;
704741
},
705742
{ "td.timelineGraph",
706
- "the format for the grap placeholder cells in timelines",
743
+ "the format for the graph placeholder cells in timelines",
707744
@ width: 20px;
708745
@ text-align: left;
709746
@ vertical-align: top;
710747
},
748
+ { ".tl-canvas",
749
+ "timeline graph canvas",
750
+ @ margin: 0 6px 0 10px;
751
+ },
752
+ { ".tl-rail",
753
+ "maximum rail spacing",
754
+ @ width: 18px;
755
+ },
756
+ { ".tl-mergeoffset",
757
+ "maximum spacing between merge risers and primary child risers",
758
+ @ width: 2px;
759
+ },
760
+ { ".tl-nodemark",
761
+ "adjusts the vertical position of graph nodes",
762
+ @ margin-top: 5px;
763
+ },
764
+ { ".tl-node",
765
+ "commit node",
766
+ @ width: 10px;
767
+ @ height: 10px;
768
+ @ border: 1px solid #000;
769
+ @ background: #fff;
770
+ @ cursor: pointer;
771
+ },
772
+ { ".tl-node.leaf:after",
773
+ "leaf commit marker",
774
+ @ content: '';
775
+ @ position: absolute;
776
+ @ top: 3px;
777
+ @ left: 3px;
778
+ @ width: 4px;
779
+ @ height: 4px;
780
+ @ background: #000;
781
+ },
782
+ { ".tl-node.sel:after",
783
+ "selected commit node marker",
784
+ @ content: '';
785
+ @ position: absolute;
786
+ @ top: 2px;
787
+ @ left: 2px;
788
+ @ width: 6px;
789
+ @ height: 6px;
790
+ @ background: red;
791
+ },
792
+ { ".tl-arrow",
793
+ "arrow",
794
+ @ width: 0;
795
+ @ height: 0;
796
+ @ transform: scale(.999);
797
+ @ border: 0 solid transparent;
798
+ },
799
+ { ".tl-arrow.u",
800
+ "up arrow",
801
+ @ margin-top: -1px;
802
+ @ border-width: 0 3px;
803
+ @ border-bottom: 7px solid #000;
804
+ },
805
+ { ".tl-arrow.u.sm",
806
+ "small up arrow",
807
+ @ border-bottom: 5px solid #000;
808
+ },
809
+ { ".tl-line",
810
+ "line",
811
+ @ background: #000;
812
+ @ width: 2px;
813
+ },
814
+ { ".tl-arrow.merge",
815
+ "merge arrow",
816
+ @ height: 1px;
817
+ @ border-width: 2px 0;
818
+ },
819
+ { ".tl-arrow.merge.l",
820
+ "left merge arrow",
821
+ @ border-right: 3px solid #000;
822
+ },
823
+ { ".tl-arrow.merge.r",
824
+ "right merge arrow",
825
+ @ border-left: 3px solid #000;
826
+ },
827
+ { ".tl-line.merge",
828
+ "merge line",
829
+ @ width: 1px;
830
+ },
831
+ { ".tl-arrow.warp",
832
+ "timewarp arrow",
833
+ @ margin-left: 1px;
834
+ @ border-width: 3px 0;
835
+ @ border-left: 7px solid #600000;
836
+ },
837
+ { ".tl-line.warp",
838
+ "timewarp line",
839
+ @ background: #600000;
840
+ },
711841
{ "a.tagLink",
712842
"the format for the tag links",
713843
@
714844
},
715845
{ "span.tagDsp",
@@ -1226,14 +1356,10 @@
12261356
},
12271357
{ "#usetupEditCapability",
12281358
"format for capabilities string, mentioned on the user edit page",
12291359
@ font-weight: bold;
12301360
},
1231
- { "#canvas", "timeline graph node colors",
1232
- @ color: black;
1233
- @ background-color: white;
1234
- },
12351361
{ "table.adminLogTable",
12361362
"Class for the /admin_log table",
12371363
@ text-align: left;
12381364
},
12391365
{ ".adminLogTable .adminTime",
@@ -1336,30 +1462,50 @@
13361462
}
13371463
}
13381464
}
13391465
13401466
/*
1341
-** Search string zHaystack for zNeedle. zNeedle must be an isolated
1342
-** word with space or punctuation on either size.
1467
+** Search string zCss for zSelector.
13431468
**
13441469
** Return true if found. Return false if not found
13451470
*/
1346
-static int containsString(const char *zHaystack, const char *zNeedle){
1347
- char *z;
1471
+static int containsSelector(const char *zCss, const char *zSelector){
1472
+ const char *z;
13481473
int n;
1474
+ int selectorLen = (int)strlen(zSelector);
13491475
1350
- while( zHaystack[0] ){
1351
- z = strstr(zHaystack, zNeedle);
1476
+ for(z=zCss; *z; z+=selectorLen){
1477
+ z = strstr(z, zSelector);
13521478
if( z==0 ) return 0;
1353
- n = (int)strlen(zNeedle);
1354
- if( (z==zHaystack || !fossil_isalnum(z[-1])) && !fossil_isalnum(z[n]) ){
1355
- return 1;
1479
+ if( z!=zCss ){
1480
+ for( n=-1; z+n!=zCss && fossil_isspace(z[n]); n--);
1481
+ if( z+n!=zCss && z[n]!=',' && z[n]!= '}' && z[n]!='/' ) continue;
13561482
}
1357
- zHaystack = z + n;
1483
+ for( n=selectorLen; z[n] && fossil_isspace(z[n]); n++ );
1484
+ if( z[n]==',' || z[n]=='{' || z[n]=='/' ) return 1;
13581485
}
13591486
return 0;
13601487
}
1488
+
1489
+/*
1490
+** COMMAND: test-contains-selector
1491
+**
1492
+** Usage: %fossil test-contains-selector FILENAME SELECTOR
1493
+**
1494
+** Determine if the CSS stylesheet FILENAME contains SELECTOR.
1495
+*/
1496
+void contains_selector_cmd(void){
1497
+ int found;
1498
+ char *zSelector;
1499
+ Blob css;
1500
+ if( g.argc!=4 ) usage("FILENAME SELECTOR");
1501
+ blob_read_from_file(&css, g.argv[2]);
1502
+ zSelector = g.argv[3];
1503
+ found = containsSelector(blob_str(&css), zSelector);
1504
+ fossil_print("%s %s\n", zSelector, found ? "found" : "not found");
1505
+ blob_reset(&css);
1506
+}
13611507
13621508
13631509
/*
13641510
** WEBPAGE: style.css
13651511
**
@@ -1373,11 +1519,11 @@
13731519
blob_init(&css,skin_get("css"),-1);
13741520
13751521
/* add special missing definitions */
13761522
for(i=1; cssDefaultList[i].elementClass; i++){
13771523
char *z = blob_str(&css);
1378
- if( !containsString(z, cssDefaultList[i].elementClass) ){
1524
+ if( !containsSelector(z, cssDefaultList[i].elementClass) ){
13791525
blob_appendf(&css, "/* %s */\n%s {\n%s}\n",
13801526
cssDefaultList[i].comment,
13811527
cssDefaultList[i].elementClass,
13821528
cssDefaultList[i].value);
13831529
}
13841530
--- src/style.c
+++ src/style.c
@@ -285,11 +285,45 @@
285 aSubmenuCtrl[nSubmenuCtrl].azChoice = azChoice;
286 aSubmenuCtrl[nSubmenuCtrl].isDisabled = isDisabled;
287 aSubmenuCtrl[nSubmenuCtrl].eType = FF_MULTI;
288 nSubmenuCtrl++;
289 }
 
 
 
 
 
 
 
 
 
 
 
290
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
291
292 /*
293 ** Compare two submenu items for sorting purposes
294 */
295 static int submenuCompare(const void *a, const void *b){
@@ -514,10 +548,13 @@
514 break;
515 }
516 case FF_MULTI: {
517 int j;
518 const char *zVal = P(zQPN);
 
 
 
519 cgi_printf(
520 "<select class='submenuctrl' size='1' name='%s'%s "
521 "onchange='gebi(\"f01\").submit();'>\n",
522 zQPN, zDisabled
523 );
@@ -701,15 +738,108 @@
701 @ vertical-align: top;
702 @ text-align: right;
703 @ white-space: nowrap;
704 },
705 { "td.timelineGraph",
706 "the format for the grap placeholder cells in timelines",
707 @ width: 20px;
708 @ text-align: left;
709 @ vertical-align: top;
710 },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
711 { "a.tagLink",
712 "the format for the tag links",
713 @
714 },
715 { "span.tagDsp",
@@ -1226,14 +1356,10 @@
1226 },
1227 { "#usetupEditCapability",
1228 "format for capabilities string, mentioned on the user edit page",
1229 @ font-weight: bold;
1230 },
1231 { "#canvas", "timeline graph node colors",
1232 @ color: black;
1233 @ background-color: white;
1234 },
1235 { "table.adminLogTable",
1236 "Class for the /admin_log table",
1237 @ text-align: left;
1238 },
1239 { ".adminLogTable .adminTime",
@@ -1336,30 +1462,50 @@
1336 }
1337 }
1338 }
1339
1340 /*
1341 ** Search string zHaystack for zNeedle. zNeedle must be an isolated
1342 ** word with space or punctuation on either size.
1343 **
1344 ** Return true if found. Return false if not found
1345 */
1346 static int containsString(const char *zHaystack, const char *zNeedle){
1347 char *z;
1348 int n;
 
1349
1350 while( zHaystack[0] ){
1351 z = strstr(zHaystack, zNeedle);
1352 if( z==0 ) return 0;
1353 n = (int)strlen(zNeedle);
1354 if( (z==zHaystack || !fossil_isalnum(z[-1])) && !fossil_isalnum(z[n]) ){
1355 return 1;
1356 }
1357 zHaystack = z + n;
 
1358 }
1359 return 0;
1360 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1361
1362
1363 /*
1364 ** WEBPAGE: style.css
1365 **
@@ -1373,11 +1519,11 @@
1373 blob_init(&css,skin_get("css"),-1);
1374
1375 /* add special missing definitions */
1376 for(i=1; cssDefaultList[i].elementClass; i++){
1377 char *z = blob_str(&css);
1378 if( !containsString(z, cssDefaultList[i].elementClass) ){
1379 blob_appendf(&css, "/* %s */\n%s {\n%s}\n",
1380 cssDefaultList[i].comment,
1381 cssDefaultList[i].elementClass,
1382 cssDefaultList[i].value);
1383 }
1384
--- src/style.c
+++ src/style.c
@@ -285,11 +285,45 @@
285 aSubmenuCtrl[nSubmenuCtrl].azChoice = azChoice;
286 aSubmenuCtrl[nSubmenuCtrl].isDisabled = isDisabled;
287 aSubmenuCtrl[nSubmenuCtrl].eType = FF_MULTI;
288 nSubmenuCtrl++;
289 }
290 void style_submenu_sql(
291 const char *zName, /* Query parameter name */
292 const char *zLabel, /* Label on the control */
293 const char *zFormat, /* Format string for SQL command for choices */
294 ... /* Arguments to the format string */
295 ){
296 Stmt q;
297 int n = 0;
298 int nAlloc = 0;
299 char **az = 0;
300 va_list ap;
301
302 va_start(ap, zFormat);
303 db_vprepare(&q, 0, zFormat, ap);
304 va_end(ap);
305 while( SQLITE_ROW==db_step(&q) ){
306 if( n+2>=nAlloc ){
307 nAlloc += nAlloc + 20;
308 az = fossil_realloc(az, sizeof(char*)*nAlloc);
309 }
310 az[n++] = fossil_strdup(db_column_text(&q,0));
311 az[n++] = fossil_strdup(db_column_text(&q,1));
312 }
313 db_finalize(&q);
314 if( n>0 ){
315 aSubmenuCtrl[nSubmenuCtrl].zName = zName;
316 aSubmenuCtrl[nSubmenuCtrl].zLabel = zLabel;
317 aSubmenuCtrl[nSubmenuCtrl].iSize = n/2;
318 aSubmenuCtrl[nSubmenuCtrl].azChoice = (const char**)az;
319 aSubmenuCtrl[nSubmenuCtrl].isDisabled = 0;
320 aSubmenuCtrl[nSubmenuCtrl].eType = FF_MULTI;
321 nSubmenuCtrl++;
322 }
323 }
324
325
326 /*
327 ** Compare two submenu items for sorting purposes
328 */
329 static int submenuCompare(const void *a, const void *b){
@@ -514,10 +548,13 @@
548 break;
549 }
550 case FF_MULTI: {
551 int j;
552 const char *zVal = P(zQPN);
553 if( aSubmenuCtrl[i].zLabel ){
554 cgi_printf("&nbsp;%h", aSubmenuCtrl[i].zLabel);
555 }
556 cgi_printf(
557 "<select class='submenuctrl' size='1' name='%s'%s "
558 "onchange='gebi(\"f01\").submit();'>\n",
559 zQPN, zDisabled
560 );
@@ -701,15 +738,108 @@
738 @ vertical-align: top;
739 @ text-align: right;
740 @ white-space: nowrap;
741 },
742 { "td.timelineGraph",
743 "the format for the graph placeholder cells in timelines",
744 @ width: 20px;
745 @ text-align: left;
746 @ vertical-align: top;
747 },
748 { ".tl-canvas",
749 "timeline graph canvas",
750 @ margin: 0 6px 0 10px;
751 },
752 { ".tl-rail",
753 "maximum rail spacing",
754 @ width: 18px;
755 },
756 { ".tl-mergeoffset",
757 "maximum spacing between merge risers and primary child risers",
758 @ width: 2px;
759 },
760 { ".tl-nodemark",
761 "adjusts the vertical position of graph nodes",
762 @ margin-top: 5px;
763 },
764 { ".tl-node",
765 "commit node",
766 @ width: 10px;
767 @ height: 10px;
768 @ border: 1px solid #000;
769 @ background: #fff;
770 @ cursor: pointer;
771 },
772 { ".tl-node.leaf:after",
773 "leaf commit marker",
774 @ content: '';
775 @ position: absolute;
776 @ top: 3px;
777 @ left: 3px;
778 @ width: 4px;
779 @ height: 4px;
780 @ background: #000;
781 },
782 { ".tl-node.sel:after",
783 "selected commit node marker",
784 @ content: '';
785 @ position: absolute;
786 @ top: 2px;
787 @ left: 2px;
788 @ width: 6px;
789 @ height: 6px;
790 @ background: red;
791 },
792 { ".tl-arrow",
793 "arrow",
794 @ width: 0;
795 @ height: 0;
796 @ transform: scale(.999);
797 @ border: 0 solid transparent;
798 },
799 { ".tl-arrow.u",
800 "up arrow",
801 @ margin-top: -1px;
802 @ border-width: 0 3px;
803 @ border-bottom: 7px solid #000;
804 },
805 { ".tl-arrow.u.sm",
806 "small up arrow",
807 @ border-bottom: 5px solid #000;
808 },
809 { ".tl-line",
810 "line",
811 @ background: #000;
812 @ width: 2px;
813 },
814 { ".tl-arrow.merge",
815 "merge arrow",
816 @ height: 1px;
817 @ border-width: 2px 0;
818 },
819 { ".tl-arrow.merge.l",
820 "left merge arrow",
821 @ border-right: 3px solid #000;
822 },
823 { ".tl-arrow.merge.r",
824 "right merge arrow",
825 @ border-left: 3px solid #000;
826 },
827 { ".tl-line.merge",
828 "merge line",
829 @ width: 1px;
830 },
831 { ".tl-arrow.warp",
832 "timewarp arrow",
833 @ margin-left: 1px;
834 @ border-width: 3px 0;
835 @ border-left: 7px solid #600000;
836 },
837 { ".tl-line.warp",
838 "timewarp line",
839 @ background: #600000;
840 },
841 { "a.tagLink",
842 "the format for the tag links",
843 @
844 },
845 { "span.tagDsp",
@@ -1226,14 +1356,10 @@
1356 },
1357 { "#usetupEditCapability",
1358 "format for capabilities string, mentioned on the user edit page",
1359 @ font-weight: bold;
1360 },
 
 
 
 
1361 { "table.adminLogTable",
1362 "Class for the /admin_log table",
1363 @ text-align: left;
1364 },
1365 { ".adminLogTable .adminTime",
@@ -1336,30 +1462,50 @@
1462 }
1463 }
1464 }
1465
1466 /*
1467 ** Search string zCss for zSelector.
 
1468 **
1469 ** Return true if found. Return false if not found
1470 */
1471 static int containsSelector(const char *zCss, const char *zSelector){
1472 const char *z;
1473 int n;
1474 int selectorLen = (int)strlen(zSelector);
1475
1476 for(z=zCss; *z; z+=selectorLen){
1477 z = strstr(z, zSelector);
1478 if( z==0 ) return 0;
1479 if( z!=zCss ){
1480 for( n=-1; z+n!=zCss && fossil_isspace(z[n]); n--);
1481 if( z+n!=zCss && z[n]!=',' && z[n]!= '}' && z[n]!='/' ) continue;
1482 }
1483 for( n=selectorLen; z[n] && fossil_isspace(z[n]); n++ );
1484 if( z[n]==',' || z[n]=='{' || z[n]=='/' ) return 1;
1485 }
1486 return 0;
1487 }
1488
1489 /*
1490 ** COMMAND: test-contains-selector
1491 **
1492 ** Usage: %fossil test-contains-selector FILENAME SELECTOR
1493 **
1494 ** Determine if the CSS stylesheet FILENAME contains SELECTOR.
1495 */
1496 void contains_selector_cmd(void){
1497 int found;
1498 char *zSelector;
1499 Blob css;
1500 if( g.argc!=4 ) usage("FILENAME SELECTOR");
1501 blob_read_from_file(&css, g.argv[2]);
1502 zSelector = g.argv[3];
1503 found = containsSelector(blob_str(&css), zSelector);
1504 fossil_print("%s %s\n", zSelector, found ? "found" : "not found");
1505 blob_reset(&css);
1506 }
1507
1508
1509 /*
1510 ** WEBPAGE: style.css
1511 **
@@ -1373,11 +1519,11 @@
1519 blob_init(&css,skin_get("css"),-1);
1520
1521 /* add special missing definitions */
1522 for(i=1; cssDefaultList[i].elementClass; i++){
1523 char *z = blob_str(&css);
1524 if( !containsSelector(z, cssDefaultList[i].elementClass) ){
1525 blob_appendf(&css, "/* %s */\n%s {\n%s}\n",
1526 cssDefaultList[i].comment,
1527 cssDefaultList[i].elementClass,
1528 cssDefaultList[i].value);
1529 }
1530
+245 -276
--- src/timeline.c
+++ src/timeline.c
@@ -241,23 +241,17 @@
241241
dateFormat = db_get_int("timeline-date-format", 0);
242242
zDateFmt = P("datefmt");
243243
if( zDateFmt ) dateFormat = atoi(zDateFmt);
244244
if( tmFlags & TIMELINE_GRAPH ){
245245
pGraph = graph_init();
246
- /* style is not moved to css, because this is
247
- ** a technical div for the timeline graph
248
- */
249
- @ <div id="canvas" style="position:relative;height:0px;width:0px;"
250
- @ onclick="clickOnGraph(event)"></div>
251246
}
252247
db_static_prepare(&qbranch,
253248
"SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0 AND rid=:rid",
254249
TAG_BRANCH
255250
);
256251
257
- @ <table id="timelineTable" class="timelineTable"
258
- @ onclick="clickOnGraph(event)">
252
+ @ <table id="timelineTable" class="timelineTable">
259253
blob_zero(&comment);
260254
while( db_step(pQuery)==SQLITE_ROW ){
261255
int rid = db_column_int(pQuery, 0);
262256
const char *zUuid = db_column_text(pQuery, 1);
263257
int isLeaf = db_column_int(pQuery, 5);
@@ -391,11 +385,11 @@
391385
}
392386
db_reset(&qparent);
393387
gidx = graph_add_row(pGraph, rid, nParent, aParent, zBr, zBgClr,
394388
zUuid, isLeaf);
395389
db_reset(&qbranch);
396
- @ <div id="m%d(gidx)"></div>
390
+ @ <div id="m%d(gidx)" class="tl-nodemark"></div>
397391
}
398392
@</td>
399393
if( zBgClr && zBgClr[0] && rid!=selectedRid ){
400394
@ <td class="timelineTableCell" style="background-color: %h(zBgClr);">
401395
}else{
@@ -589,18 +583,11 @@
589583
graph_finish(pGraph, (tmFlags & TIMELINE_DISJOINT)!=0);
590584
if( pGraph->nErr ){
591585
graph_free(pGraph);
592586
pGraph = 0;
593587
}else{
594
- int w;
595
- /* style is not moved to css, because this is
596
- ** a technical div for the timeline graph
597
- */
598
- w = pGraph->mxRail*pGraph->iRailPitch + 28;
599
- @ <tr class="timelineBottom"><td></td><td>
600
- @ <div id="grbtm" style="width:%d(w)px;"></div>
601
- @ </td><td></td></tr>
588
+ @ <tr class="timelineBottom"><td></td><td></td><td></td></tr>
602589
}
603590
}
604591
@ </table>
605592
if( fchngQueryInit ) db_finalize(&fchngQuery);
606593
timeline_output_graph_javascript(pGraph, (tmFlags & TIMELINE_DISJOINT)!=0, 0);
@@ -648,31 +635,34 @@
648635
){
649636
if( pGraph && pGraph->nErr==0 && pGraph->nRow>0 ){
650637
GraphRow *pRow;
651638
int i;
652639
char cSep;
653
- int mergeOffset; /* Pixel offset from rail to merge riser */
654640
int iRailPitch; /* Pixels between consecutive rails */
655641
int showArrowheads; /* True to draw arrowheads. False to omit. */
656642
int circleNodes; /* True for circle nodes. False for square nodes */
657643
int colorGraph; /* Use colors for graph lines */
658644
659
- iRailPitch = pGraph->iRailPitch;
645
+ iRailPitch = atoi(PD("railpitch","0"));
660646
showArrowheads = skin_detail_boolean("timeline-arrowheads");
661647
circleNodes = skin_detail_boolean("timeline-circle-nodes");
662648
colorGraph = skin_detail_boolean("timeline-color-graph-lines");
663649
664
- /* Number of pixels that the thin merge lines are offset from the
665
- ** the center of the think rail lines. If zero, then the vertical
666
- ** merge lines overlap with the thicker rail lines.
667
- */
668
- mergeOffset = iRailPitch>=14 ? 4 : iRailPitch>=13 ? 3 : 0;
669
- if( PB("nomo") ) mergeOffset = 0;
670
-
671
- @ <script>
672
- @ var railPitch=%d(iRailPitch);
673
-
650
+ @ <script>(function(){
651
+ @ "use strict";
652
+ @ var css = "";
653
+ if( circleNodes ){
654
+ @ css += ".tl-node, .tl-node:after { border-radius: 50%%; }";
655
+ }
656
+ if( !showArrowheads ){
657
+ @ css += ".tl-arrow.u { display: none; }";
658
+ }
659
+ @ if( css!=="" ){
660
+ @ var style = document.createElement("style");
661
+ @ style.textContent = css;
662
+ @ document.querySelector("head").appendChild(style);
663
+ @ }
674664
/* the rowinfo[] array contains all the information needed to generate
675665
** the graph. Each entry contains information for a single row:
676666
**
677667
** id: The id of the <div> element for the row. This is an integer.
678668
** to get an actual id, prepend "m" to the integer. The top node
@@ -680,13 +670,13 @@
680670
** bg: The background color for this row
681671
** r: The "rail" that the node for this row sits on. The left-most
682672
** rail is 0 and the number increases to the right.
683673
** d: True if there is a "descender" - an arrow coming from the bottom
684674
** of the page straight up to this node.
685
- ** mo: "merge-out". If non-zero, this is one more than the x-coordinate
675
+ ** mo: "merge-out". If non-negative, this is the rail position
686676
** for the upward portion of a merge arrow. The merge arrow goes up
687
- ** to the row identified by mu:. If this value is zero then
677
+ ** to the row identified by mu:. If this value is negative then
688678
** node has no merge children and no merge-out line is drawn.
689679
** mu: The id of the row which is the top of the merge-out arrow.
690680
** u: Draw a thick child-line out of the top of this node and up to
691681
** the node with an id equal to this value. 0 if it is straight to
692682
** the top of the page, -1 if there is no thick-line riser.
@@ -693,37 +683,25 @@
693683
** f: 0x01: a leaf node.
694684
** au: An array of integers that define thick-line risers for branches.
695685
** The integers are in pairs. For each pair, the first integer is
696686
** is the rail on which the riser should run and the second integer
697687
** is the id of the node upto which the riser should run.
698
- ** mi: "merge-in". An array of integer x-coordinates from which
688
+ ** mi: "merge-in". An array of integer rail positions from which
699689
** merge arrows should be drawn into this node. If the value is
700
- ** negative, then the x-coordinate is the absolute value of mi[]
690
+ ** negative, then the rail position is the absolute value of mi[]
701691
** and a thin merge-arrow descender is drawn to the bottom of
702692
** the screen.
703693
** h: The SHA1 hash of the object being graphed
704694
*/
705695
cgi_printf("var rowinfo = [\n");
706696
for(pRow=pGraph->pFirst; pRow; pRow=pRow->pNext){
707
- int mo = pRow->mergeOut;
708
- if( mo<0 ){
709
- mo = 0;
710
- }else{
711
- int x = (mo/4)*iRailPitch;
712
- switch( mo&3 ){
713
- case 0: x -= mergeOffset-2; break;
714
- case 1: x += 1; break;
715
- case 2: x += mergeOffset+1; break;
716
- }
717
- mo = x;
718
- }
719697
cgi_printf("{id:%d,bg:\"%s\",r:%d,d:%d,mo:%d,mu:%d,u:%d,f:%d,au:",
720698
pRow->idx, /* id */
721699
pRow->zBgClr, /* bg */
722700
pRow->iRail, /* r */
723701
pRow->bDescender, /* d */
724
- mo, /* mo */
702
+ pRow->mergeOut, /* mo */
725703
pRow->mergeUpto, /* mu */
726704
pRow->aiRiser[pRow->iRail], /* u */
727705
pRow->isLeaf ? 1 : 0 /* f */
728706
);
729707
/* u */
@@ -743,13 +721,11 @@
743721
/* mi */
744722
cgi_printf("mi:");
745723
cSep = '[';
746724
for(i=0; i<GR_MAX_RAIL; i++){
747725
if( pRow->mergeIn[i] ){
748
- int mi = i*iRailPitch;
749
- if( pRow->mergeIn[i]==1 ) mi -= mergeOffset-1;
750
- if( pRow->mergeIn[i]==3 ) mi += mergeOffset;
726
+ int mi = i;
751727
if( pRow->mergeDown & (1<<i) ) mi = -mi;
752728
cgi_printf("%c%d", cSep, mi);
753729
cSep = ',';
754730
}
755731
}
@@ -756,246 +732,238 @@
756732
if( cSep=='[' ) cgi_printf("[");
757733
cgi_printf("],h:\"%s\"}%s", pRow->zUuid, pRow->pNext ? ",\n" : "];\n");
758734
}
759735
cgi_printf("var nrail = %d\n", pGraph->mxRail+1);
760736
graph_free(pGraph);
761
- @ var cDiv = gebi("canvas");
762
- @ var csty = window.getComputedStyle && window.getComputedStyle(cDiv,null);
763
- @ var lineClr = (csty && csty.getPropertyValue('color')) || 'black';
764
- @ var bgClr = (csty && csty.getPropertyValue('background-color')) ||'white';
765
- @ if( bgClr=='transparent' ) bgClr = 'white';
766
- @ var boxColor = lineClr;
767
- @ function drawBox(color,x0,y0,x1,y1){
737
+ @ var canvasDiv;
738
+ @ var railPitch;
739
+ @ var mergeOffset;
740
+ @ var node, arrow, arrowSmall, line, mArrow, mLine, wArrow, wLine;
741
+ @ function initGraph(){
742
+ @ var parent = gebi("timelineTable").rows[0].cells[1];
743
+ @ parent.style.verticalAlign = "top";
744
+ @ canvasDiv = document.createElement("div");
745
+ @ canvasDiv.className = "tl-canvas";
746
+ @ canvasDiv.style.position = "absolute";
747
+ @ parent.appendChild(canvasDiv);
748
+ @
749
+ @ var elems = {};
750
+ @ var elemClasses = [
751
+ @ "rail", "mergeoffset", "node", "arrow u", "arrow u sm", "line",
752
+ @ "arrow merge r", "line merge", "arrow warp", "line warp"
753
+ @ ];
754
+ @ for( var i=0; i<elemClasses.length; i++ ){
755
+ @ var cls = elemClasses[i];
756
+ @ var elem = document.createElement("div");
757
+ @ elem.className = "tl-" + cls;
758
+ @ if( cls.indexOf("line")==0 ) elem.className += " v";
759
+ @ canvasDiv.appendChild(elem);
760
+ @ var k = cls.replace(/\s/g, "_");
761
+ @ var r = elem.getBoundingClientRect();
762
+ @ var w = Math.round(r.right - r.left);
763
+ @ var h = Math.round(r.bottom - r.top);
764
+ @ elems[k] = {w: w, h: h, cls: cls};
765
+ @ }
766
+ @ node = elems.node;
767
+ @ arrow = elems.arrow_u;
768
+ @ arrowSmall = elems.arrow_u_sm;
769
+ @ line = elems.line;
770
+ @ mArrow = elems.arrow_merge_r;
771
+ @ mLine = elems.line_merge;
772
+ @ wArrow = elems.arrow_warp;
773
+ @ wLine = elems.line_warp;
774
+ @
775
+ @ var minRailPitch = Math.ceil((node.w+line.w)/2 + mArrow.w + 1);
776
+ if( iRailPitch ){
777
+ @ railPitch = %d(iRailPitch);
778
+ }else{
779
+ @ railPitch = elems.rail.w;
780
+ @ railPitch -= Math.floor((nrail-1)*(railPitch-minRailPitch)/21);
781
+ }
782
+ @ railPitch = Math.max(railPitch, minRailPitch);
783
+ @
784
+ if( PB("nomo") ){
785
+ @ mergeOffset = 0;
786
+ }else{
787
+ @ mergeOffset = railPitch-minRailPitch-mLine.w;
788
+ @ mergeOffset = Math.min(mergeOffset, elems.mergeoffset.w);
789
+ @ mergeOffset = mergeOffset>0 ? mergeOffset + line.w/2 : 0;
790
+ }
791
+ @
792
+ @ var canvasWidth = (nrail-1)*railPitch + node.w;
793
+ @ canvasDiv.style.width = canvasWidth + "px";
794
+ @ canvasDiv.style.position = "relative";
795
+ @ }
796
+ @ function drawBox(cls,color,x0,y0,x1,y1){
768797
@ var n = document.createElement("div");
798
+ @ x0 = Math.floor(x0);
799
+ @ y0 = Math.floor(y0);
800
+ @ x1 = x1 || x1===0 ? Math.floor(x1) : x0;
801
+ @ y1 = y1 || y1===0 ? Math.floor(y1) : y0;
769802
@ if( x0>x1 ){ var t=x0; x0=x1; x1=t; }
770803
@ if( y0>y1 ){ var t=y0; y0=y1; y1=t; }
771
- @ var w = x1-x0+1;
772
- @ var h = y1-y0+1;
804
+ @ var w = x1-x0;
805
+ @ var h = y1-y0;
773806
@ n.style.position = "absolute";
774
- @ n.style.overflow = "hidden";
775807
@ n.style.left = x0+"px";
776808
@ n.style.top = y0+"px";
777
- @ n.style.width = w+"px";
778
- @ n.style.height = h+"px";
779
- @ n.style.backgroundColor = color;
780
- @ cDiv.appendChild(n);
809
+ @ if( w ) n.style.width = w+"px";
810
+ @ if( h ) n.style.height = h+"px";
811
+ @ if( color ) n.style.backgroundColor = color;
812
+ @ n.className = "tl-"+cls;
813
+ @ canvasDiv.appendChild(n);
781814
@ return n;
782815
@ }
783
- @ function absoluteY(id){
784
- @ var obj = gebi(id);
785
- @ if( !obj ) return;
816
+ @ function absoluteY(obj){
786817
@ var top = 0;
787818
@ if( obj.offsetParent ){
788819
@ do{
789820
@ top += obj.offsetTop;
790821
@ }while( obj = obj.offsetParent );
791822
@ }
792823
@ return top;
793824
@ }
794
- @ function absoluteX(id){
795
- @ var obj = gebi(id);
796
- @ if( !obj ) return;
797
- @ var left = 0;
798
- @ if( obj.offsetParent ){
799
- @ do{
800
- @ left += obj.offsetLeft;
801
- @ }while( obj = obj.offsetParent );
802
- @ }
803
- @ return left;
804
- @ }
805
- if( showArrowheads ){
806
- @ function drawUpArrow(x,y0,y1,clr){
807
- @ drawBox(clr,x,y0+4,x+1,y1);
808
- @ var n = document.createElement("div"),
809
- @ l = x-2,
810
- @ t = y0;
811
- @ n.style.position = "absolute";
812
- @ n.style.left = l+"px";
813
- @ n.style.top = t+"px";
814
- @ n.style.width = 0;
815
- @ n.style.height = 0;
816
- @ n.style.transform = "scale(.999)";
817
- @ n.style.borderWidth = 0;
818
- @ n.style.borderStyle = "solid";
819
- @ n.style.borderColor = "transparent";
820
- @ n.style.borderRightWidth = "3px";
821
- @ n.style.borderBottomColor = clr;
822
- @ n.style.borderLeftWidth = "3px";
823
- @ if( y0+10>=y1 ){
824
- @ n.style.borderBottomWidth = "5px";
825
- @ } else {
826
- @ n.style.borderBottomWidth = "7px";
827
- @ }
828
- @ cDiv.appendChild(n);
829
- @ }
830
- }else{
831
- @ function drawUpArrow(x,y0,y1,clr){
832
- @ drawBox(clr,x,y0+1,x+1,y1);
833
- @ }
834
- }
835
- @ function drawThinArrow(y,xFrom,xTo){
836
- @ var n = document.createElement("div"),
837
- @ t = y-2;
838
- @ n.style.position = "absolute";
839
- @ n.style.top = t+"px";
840
- @ n.style.width = 0;
841
- @ n.style.height = "1px";
842
- @ n.style.transform = "scale(.999)";
843
- @ n.style.borderWidth = 0;
844
- @ n.style.borderStyle = "solid";
845
- @ n.style.borderColor = "transparent";
846
- @ n.style.borderTopWidth = "2px";
847
- @ n.style.borderBottomWidth = "2px";
848
- @ if( xFrom<xTo ){
849
- @ drawBox(lineClr,xFrom,y,xTo-3,y);
850
- @ n.style.left = xTo-3+"px";
851
- @ n.style.borderLeftWidth = "3px";
852
- @ n.style.borderLeftColor = lineClr;
853
- @ }else{
854
- @ drawBox(lineClr,xTo+3,y,xFrom,y);
855
- @ n.style.left = xTo+1+"px";
856
- @ n.style.borderRightWidth = "3px";
857
- @ n.style.borderRightColor = lineClr;
858
- @ }
859
- @ cDiv.appendChild(n);
860
- @ }
861
- @ function drawThinLine(x0,y0,x1,y1){
862
- @ drawBox(lineClr,x0,y0,x1,y1);
863
- @ }
864
- @ function drawNodeBox(color,x0,y0,x1,y1){
865
- @ var n = drawBox(color,x0,y0,x1,y1);
866
- @ n.style.cursor = "pointer";
867
- if( circleNodes ){
868
- @ n.style.borderRadius = "6px";
869
- }
870
- @ }
871
- @ function drawNode(p, left, btm){
872
- @ drawNodeBox(boxColor,p.x-5,p.y-5,p.x+6,p.y+6);
873
- @ drawNodeBox(p.bg||bgClr,p.x-4,p.y-4,p.x+5,p.y+5);
874
- @ if( p.u>0 ) drawUpArrow(p.x,rowinfo[p.u-1].y+6,p.y-6,p.fg||lineClr);
875
- @ if( p.f&1 ) drawNodeBox(boxColor,p.x-1,p.y-1,p.x+2,p.y+2);
876
- if( !omitDescenders ){
877
- @ if( p.u==0 ) drawUpArrow(p.x,0,p.y-6,p.fg||lineClr);
878
- @ if( p.d ) drawUpArrow(p.x,p.y+6,btm,p.fg||lineClr);
879
- }
880
- @ if( p.mo>0 ){
881
- @ var x1 = p.mo + left - 1;
882
- @ var y1 = p.y-3;
883
- @ var x0 = x1>p.x ? p.x+7 : p.x-6;
884
- @ var u = rowinfo[p.mu-1];
885
- @ var y0 = u.y+5;
886
- @ if( x1>=p.x-5 && x1<=p.x+5 ){
887
- @ y1 = p.y-5;
888
- @ }else{
889
- @ drawThinLine(x0,y1,x1,y1);
890
- @ }
891
- if( mergeOffset==0 ) cgi_printf("if( p.mo!=p.u-1 ) ");
892
- @ drawThinLine(x1,y0,x1,y1);
893
- @ }
894
- @ var n = p.au.length;
895
- @ for(var i=0; i<n; i+=2){
896
- @ var x1 = p.au[i]*railPitch + left;
897
- @ var x0 = x1>p.x ? p.x+7 : p.x-6;
898
- @ var u = rowinfo[p.au[i+1]-1];
899
- @ if(u.id<p.id){
900
- @ drawBox(u.fg||lineClr,x0,p.y,x1+1,p.y+1);
901
- @ drawUpArrow(x1,u.y+6,p.y,u.fg||lineClr);
902
- @ }else{
903
- @ drawBox("#600000",x0,p.y,x1,p.y+1);
904
- @ drawBox("#600000",x1-1,p.y,x1,u.y+1);
905
- @ drawBox("#600000",x1,u.y,u.x-10,u.y+1);
906
- @ var n = document.createElement("div"),
907
- @ t = u.y-2,
908
- @ l = u.x-11;
909
- @ n.style.position = "absolute";
910
- @ n.style.top = t+"px";
911
- @ n.style.left = l+"px";
912
- @ n.style.width = 0;
913
- @ n.style.height = 0;
914
- @ n.style.transform = "scale(.999)";
915
- @ n.style.borderWidth = 0;
916
- @ n.style.borderStyle = "solid";
917
- @ n.style.borderColor = "transparent";
918
- @ n.style.borderTopWidth = "3px";
919
- @ n.style.borderBottomWidth = "3px";
920
- @ n.style.borderLeftWidth = "7px";
921
- @ n.style.borderLeftColor = "#600000";
922
- @ cDiv.appendChild(n);
923
- @ }
924
- @ }
925
- @ for(var j in p.mi){
926
- @ var y0 = p.y+5;
927
- @ var mx = p.mi[j];
928
- @ if( mx<0 ){
929
- @ mx = left-mx;
930
- @ drawThinLine(mx,y0,mx,btm);
931
- @ }else{
932
- @ mx += left;
933
- @ }
934
- @ if( mx>p.x ){
935
- @ drawThinArrow(y0,mx,p.x+6);
936
- @ }else{
937
- @ drawThinArrow(y0,mx,p.x-5);
938
- @ }
939
- @ }
940
- @ }
941
- @ var selBox = null;
942
- @ var selRow = null;
943
- @ function renderGraph(){
944
- @ var canvasDiv = gebi("canvas");
945
- @ while( canvasDiv.hasChildNodes() ){
946
- @ canvasDiv.removeChild(canvasDiv.firstChild);
947
- @ }
948
- @ var canvasY = absoluteY("timelineTable");
949
- @ var left = absoluteX("m"+rowinfo[0].id) - absoluteX("canvas") + 15;
950
- @ for(var i in rowinfo){
951
- @ rowinfo[i].y = absoluteY("m"+rowinfo[i].id) + 10 - canvasY;
952
- @ rowinfo[i].x = left + rowinfo[i].r*railPitch;
953
- @ }
954
- @ var btm = absoluteY("grbtm") + 10 - canvasY;
955
- @ for(var i in rowinfo){
956
- @ drawNode(rowinfo[i], left, btm);
957
- @ }
958
- @ if( selRow!=null ) clickOnRow(selRow);
959
- @ }
960
- @ function clickOnGraph(event){
961
- @ var x=event.clientX-absoluteX("canvas");
962
- @ var y=event.clientY-absoluteY("canvas");
963
- @ if(window.pageXOffset!=null){
964
- @ x += window.pageXOffset;
965
- @ y += window.pageYOffset;
966
- @ }else{
967
- @ var d = window.document.documentElement;
968
- @ if(document.compatMode!="CSS1Compat") d = d.body;
969
- @ x += d.scrollLeft;
970
- @ y += d.scrollTop;
971
- @ }
972
- if( P("clicktest")!=0 ){
973
- @ alert("click at "+x+","+y)
974
- }
975
- @ for(var i in rowinfo){
976
- @ p = rowinfo[i];
977
- @ if( p.y<y-11 ) continue;
978
- @ if( p.y>y+9 ) break;
979
- @ if( p.x>x-11 && p.x<x+9 ){
980
- @ clickOnRow(p);
981
- @ break;
982
- @ }
983
- @ }
984
- @ }
985
- @ function clickOnRow(p){
986
- @ if( selRow==null ){
987
- @ selBox = drawBox("red",p.x-2,p.y-2,p.x+3,p.y+3);
988
- if( circleNodes ){
989
- @ selBox.style.borderRadius="6px";
990
- }
991
- @ selRow = p;
992
- @ }else if( selRow==p ){
993
- @ var canvasDiv = gebi("canvas");
994
- @ canvasDiv.removeChild(selBox);
995
- @ selBox = null;
996
- @ selRow = null;
825
+ @ function miLineY(p){
826
+ @ return p.y + node.h - mLine.w - 1;
827
+ @ }
828
+ @ function drawLine(elem,color,x0,y0,x1,y1){
829
+ @ var cls = elem.cls + " ";
830
+ @ if( x1===null ){
831
+ @ x1 = x0+elem.w;
832
+ @ cls += "v";
833
+ @ }else{
834
+ @ y1 = y0+elem.w;
835
+ @ cls += "h";
836
+ @ }
837
+ @ drawBox(cls,color,x0,y0,x1,y1);
838
+ @ }
839
+ @ function drawUpArrow(from,to,color){
840
+ @ var y = to.y + node.h;
841
+ @ var arrowSpace = from.y - y + (!from.id || from.r!=to.r ? node.h/2 : 0);
842
+ @ var arw = arrowSpace < arrow.h*1.5 ? arrowSmall : arrow;
843
+ @ var x = to.x + (node.w-line.w)/2;
844
+ @ var y0 = from.y + node.h/2;
845
+ @ var y1 = Math.ceil(to.y + node.h + arw.h/2);
846
+ @ drawLine(line,color,x,y0,null,y1);
847
+ @ x = to.x + (node.w-arw.w)/2;
848
+ @ var n = drawBox(arw.cls,null,x,y);
849
+ @ n.style.borderBottomColor = color;
850
+ @ }
851
+ @ function drawMergeLine(x0,y0,x1,y1){
852
+ @ drawLine(mLine,null,x0,y0,x1,y1);
853
+ @ }
854
+ @ function drawMergeArrow(p,rail){
855
+ @ var x0 = rail*railPitch + node.w/2;
856
+ @ if( rail in mergeLines ){
857
+ @ x0 += mergeLines[rail];
858
+ @ if( p.r<rail ) x0 += mLine.w;
859
+ @ }else{
860
+ @ x0 += (p.r<rail ? -1 : 1)*line.w/2;
861
+ @ }
862
+ @ var x1 = mArrow.w ? mArrow.w/2 : -node.w/2;
863
+ @ x1 = p.x + (p.r<rail ? node.w + Math.ceil(x1) : -x1);
864
+ @ var y = miLineY(p);
865
+ @ drawMergeLine(x0,y,x1,null);
866
+ @ var x = p.x + (p.r<rail ? node.w : -mArrow.w);
867
+ @ var cls = "arrow merge " + (p.r<rail ? "l" : "r");
868
+ @ drawBox(cls,null,x,y+(mLine.w-mArrow.h)/2);
869
+ @ }
870
+ @ function drawNode(p, btm){
871
+ @ if( p.u>0 ) drawUpArrow(p,rowinfo[p.u-1],p.fg);
872
+ @ var cls = node.cls;
873
+ @ if( p.mi.length ) cls += " merge";
874
+ @ if( p.f&1 ) cls += " leaf";
875
+ @ var n = drawBox(cls,p.bg,p.x,p.y);
876
+ @ n.id = "tln"+p.id;
877
+ @ n.onclick = clickOnNode;
878
+ @ n.style.zIndex = 10;
879
+ if( !omitDescenders ){
880
+ @ if( p.u==0 ) drawUpArrow(p,{x: p.x, y: -node.h},p.fg);
881
+ @ if( p.d ) drawUpArrow({x: p.x, y: btm-node.h/2},p,p.fg);
882
+ }
883
+ @ if( p.mo>=0 ){
884
+ @ var x0 = p.x + node.w/2;
885
+ @ var x1 = p.mo*railPitch + node.w/2;
886
+ @ var u = rowinfo[p.mu-1];
887
+ @ var y1 = miLineY(u);
888
+ @ if( p.u<0 || p.mo!=p.r ){
889
+ @ x1 += mergeLines[p.mo] = -mLine.w/2;
890
+ @ var y0 = p.y+2;
891
+ @ if( p.r!=p.mo ) drawMergeLine(x0,y0,x1+(x0<x1 ? mLine.w : 0),null);
892
+ @ drawMergeLine(x1,y0+mLine.w,null,y1);
893
+ @ }else if( mergeOffset ){
894
+ @ mergeLines[p.mo] = u.r<p.r ? -mergeOffset-mLine.w : mergeOffset;
895
+ @ x1 += mergeLines[p.mo];
896
+ @ drawMergeLine(x1,p.y+node.h/2,null,y1);
897
+ @ }else{
898
+ @ delete mergeLines[p.mo];
899
+ @ }
900
+ @ }
901
+ @ for( var i=0; i<p.au.length; i+=2 ){
902
+ @ var rail = p.au[i];
903
+ @ var x0 = p.x + node.w/2;
904
+ @ var x1 = rail*railPitch + (node.w-line.w)/2;
905
+ @ if( x0<x1 ){
906
+ @ x0 = Math.ceil(x0);
907
+ @ x1 += line.w;
908
+ @ }
909
+ @ var y0 = p.y + (node.h-line.w)/2;
910
+ @ var u = rowinfo[p.au[i+1]-1];
911
+ @ if( u.id<p.id ){
912
+ @ drawLine(line,u.fg,x0,y0,x1,null);
913
+ @ drawUpArrow(p,u,u.fg);
914
+ @ }else{
915
+ @ var y1 = u.y + (node.h-line.w)/2;
916
+ @ drawLine(wLine,u.fg,x0,y0,x1,null);
917
+ @ drawLine(wLine,u.fg,x1-line.w,y0,null,y1+line.w);
918
+ @ drawLine(wLine,u.fg,x1,y1,u.x-wArrow.w/2,null);
919
+ @ var x = u.x-wArrow.w;
920
+ @ var y = u.y+(node.h-wArrow.h)/2;
921
+ @ var n = drawBox(wArrow.cls,null,x,y);
922
+ @ if( u.fg ) n.style.borderLeftColor = u.fg;
923
+ @ }
924
+ @ }
925
+ @ for( var i=0; i<p.mi.length; i++ ){
926
+ @ var rail = p.mi[i];
927
+ @ if( rail<0 ){
928
+ @ rail = -rail;
929
+ @ mergeLines[rail] = -mLine.w/2;
930
+ @ var x = rail*railPitch + (node.w-mLine.w)/2;
931
+ @ drawMergeLine(x,miLineY(p),null,btm);
932
+ @ }
933
+ @ drawMergeArrow(p,rail);
934
+ @ }
935
+ @ }
936
+ @ var mergeLines;
937
+ @ function renderGraph(){
938
+ @ mergeLines = {};
939
+ @ canvasDiv.innerHTML = "";
940
+ @ var canvasY = absoluteY(canvasDiv);
941
+ @ for( var i=0; i<rowinfo.length; i++ ){
942
+ @ rowinfo[i].y = absoluteY(gebi("m"+rowinfo[i].id)) - canvasY;
943
+ @ rowinfo[i].x = rowinfo[i].r*railPitch;
944
+ @ }
945
+ @ var tlBtm = document.querySelector(".timelineBottom");
946
+ @ if( tlBtm.offsetHeight<node.h ){
947
+ @ tlBtm.style.height = node.h + "px";
948
+ @ }
949
+ @ var btm = absoluteY(tlBtm) - canvasY + tlBtm.offsetHeight;
950
+ @ for( var i=rowinfo.length-1; i>=0; i-- ){
951
+ @ drawNode(rowinfo[i], btm);
952
+ @ }
953
+ @ }
954
+ @ var selRow;
955
+ @ function clickOnNode(){
956
+ @ var p = rowinfo[parseInt(this.id.match(/\d+$/)[0], 10)-1];
957
+ @ if( !selRow ){
958
+ @ selRow = p;
959
+ @ this.className += " sel";
960
+ @ canvasDiv.className += " sel";
961
+ @ }else if( selRow==p ){
962
+ @ selRow = null;
963
+ @ this.className = this.className.replace(" sel", "");
964
+ @ canvasDiv.className = canvasDiv.className.replace(" sel", "");
997965
@ }else{
998966
if( fileDiff ){
999967
@ location.href="%R/fdiff?v1="+selRow.h+"&v2="+p.h+"&sbs=1";
1000968
}else{
1001969
if( db_get_boolean("show-version-diffs", 0)==0 ){
@@ -1004,22 +972,23 @@
1004972
@ location.href="%R/vdiff?from="+selRow.h+"&to="+p.h+"&sbs=1";
1005973
}
1006974
}
1007975
@ }
1008976
@ }
1009
- @ var lastId = "m"+rowinfo[rowinfo.length-1].id;
977
+ @ var lastRow = gebi("m"+rowinfo[rowinfo.length-1].id);
1010978
@ var lastY = 0;
1011979
@ function checkHeight(){
1012
- @ var h = absoluteY(lastId);
980
+ @ var h = absoluteY(lastRow);
1013981
@ if( h!=lastY ){
1014982
@ renderGraph();
1015983
@ lastY = h;
1016984
@ }
1017
- @ setTimeout("checkHeight();", 1000);
985
+ @ setTimeout(checkHeight, 1000);
1018986
@ }
987
+ @ initGraph();
1019988
@ checkHeight();
1020
- @ </script>
989
+ @ }())</script>
1021990
}
1022991
}
1023992
1024993
/*
1025994
** Create a temporary table suitable for storing timeline data.
@@ -1308,24 +1277,24 @@
13081277
return;
13091278
}
13101279
url_initialize(&url, "timeline");
13111280
cgi_query_parameters_to_url(&url);
13121281
if( zTagName && g.perm.Read ){
1313
- tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname='sym-%q'", zTagName);
1282
+ tagid = db_int(-1,"SELECT tagid FROM tag WHERE tagname='sym-%q'",zTagName);
13141283
zThisTag = zTagName;
13151284
}else if( zBrName && g.perm.Read ){
1316
- tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname='sym-%q'",zBrName);
1285
+ tagid = db_int(-1,"SELECT tagid FROM tag WHERE tagname='sym-%q'",zBrName);
13171286
zThisTag = zBrName;
13181287
}else{
13191288
tagid = 0;
13201289
}
13211290
if( zMark && zMark[0]==0 ){
13221291
if( zAfter ) zMark = zAfter;
13231292
if( zBefore ) zMark = zBefore;
13241293
if( zCirca ) zMark = zCirca;
13251294
}
1326
- if( tagid>0
1295
+ if( tagid
13271296
&& db_int(0,"SELECT count(*) FROM tagxref WHERE tagid=%d",tagid)<=nEntry
13281297
){
13291298
nEntry = -1;
13301299
zCirca = 0;
13311300
}
@@ -1524,11 +1493,11 @@
15241493
}
15251494
else if( zYearWeek ){
15261495
blob_append_sql(&sql, " AND %Q=strftime('%%Y-%%W',event.mtime) ",
15271496
zYearWeek);
15281497
}
1529
- if( tagid>0 ){
1498
+ if( tagid ){
15301499
blob_append_sql(&sql,
15311500
" AND (EXISTS(SELECT 1 FROM tagxref"
15321501
" WHERE tagid=%d AND tagtype>0 AND rid=blob.rid)\n", tagid);
15331502
15341503
if( zBrName ){
15351504
--- src/timeline.c
+++ src/timeline.c
@@ -241,23 +241,17 @@
241 dateFormat = db_get_int("timeline-date-format", 0);
242 zDateFmt = P("datefmt");
243 if( zDateFmt ) dateFormat = atoi(zDateFmt);
244 if( tmFlags & TIMELINE_GRAPH ){
245 pGraph = graph_init();
246 /* style is not moved to css, because this is
247 ** a technical div for the timeline graph
248 */
249 @ <div id="canvas" style="position:relative;height:0px;width:0px;"
250 @ onclick="clickOnGraph(event)"></div>
251 }
252 db_static_prepare(&qbranch,
253 "SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0 AND rid=:rid",
254 TAG_BRANCH
255 );
256
257 @ <table id="timelineTable" class="timelineTable"
258 @ onclick="clickOnGraph(event)">
259 blob_zero(&comment);
260 while( db_step(pQuery)==SQLITE_ROW ){
261 int rid = db_column_int(pQuery, 0);
262 const char *zUuid = db_column_text(pQuery, 1);
263 int isLeaf = db_column_int(pQuery, 5);
@@ -391,11 +385,11 @@
391 }
392 db_reset(&qparent);
393 gidx = graph_add_row(pGraph, rid, nParent, aParent, zBr, zBgClr,
394 zUuid, isLeaf);
395 db_reset(&qbranch);
396 @ <div id="m%d(gidx)"></div>
397 }
398 @</td>
399 if( zBgClr && zBgClr[0] && rid!=selectedRid ){
400 @ <td class="timelineTableCell" style="background-color: %h(zBgClr);">
401 }else{
@@ -589,18 +583,11 @@
589 graph_finish(pGraph, (tmFlags & TIMELINE_DISJOINT)!=0);
590 if( pGraph->nErr ){
591 graph_free(pGraph);
592 pGraph = 0;
593 }else{
594 int w;
595 /* style is not moved to css, because this is
596 ** a technical div for the timeline graph
597 */
598 w = pGraph->mxRail*pGraph->iRailPitch + 28;
599 @ <tr class="timelineBottom"><td></td><td>
600 @ <div id="grbtm" style="width:%d(w)px;"></div>
601 @ </td><td></td></tr>
602 }
603 }
604 @ </table>
605 if( fchngQueryInit ) db_finalize(&fchngQuery);
606 timeline_output_graph_javascript(pGraph, (tmFlags & TIMELINE_DISJOINT)!=0, 0);
@@ -648,31 +635,34 @@
648 ){
649 if( pGraph && pGraph->nErr==0 && pGraph->nRow>0 ){
650 GraphRow *pRow;
651 int i;
652 char cSep;
653 int mergeOffset; /* Pixel offset from rail to merge riser */
654 int iRailPitch; /* Pixels between consecutive rails */
655 int showArrowheads; /* True to draw arrowheads. False to omit. */
656 int circleNodes; /* True for circle nodes. False for square nodes */
657 int colorGraph; /* Use colors for graph lines */
658
659 iRailPitch = pGraph->iRailPitch;
660 showArrowheads = skin_detail_boolean("timeline-arrowheads");
661 circleNodes = skin_detail_boolean("timeline-circle-nodes");
662 colorGraph = skin_detail_boolean("timeline-color-graph-lines");
663
664 /* Number of pixels that the thin merge lines are offset from the
665 ** the center of the think rail lines. If zero, then the vertical
666 ** merge lines overlap with the thicker rail lines.
667 */
668 mergeOffset = iRailPitch>=14 ? 4 : iRailPitch>=13 ? 3 : 0;
669 if( PB("nomo") ) mergeOffset = 0;
670
671 @ <script>
672 @ var railPitch=%d(iRailPitch);
673
 
 
 
 
674 /* the rowinfo[] array contains all the information needed to generate
675 ** the graph. Each entry contains information for a single row:
676 **
677 ** id: The id of the <div> element for the row. This is an integer.
678 ** to get an actual id, prepend "m" to the integer. The top node
@@ -680,13 +670,13 @@
680 ** bg: The background color for this row
681 ** r: The "rail" that the node for this row sits on. The left-most
682 ** rail is 0 and the number increases to the right.
683 ** d: True if there is a "descender" - an arrow coming from the bottom
684 ** of the page straight up to this node.
685 ** mo: "merge-out". If non-zero, this is one more than the x-coordinate
686 ** for the upward portion of a merge arrow. The merge arrow goes up
687 ** to the row identified by mu:. If this value is zero then
688 ** node has no merge children and no merge-out line is drawn.
689 ** mu: The id of the row which is the top of the merge-out arrow.
690 ** u: Draw a thick child-line out of the top of this node and up to
691 ** the node with an id equal to this value. 0 if it is straight to
692 ** the top of the page, -1 if there is no thick-line riser.
@@ -693,37 +683,25 @@
693 ** f: 0x01: a leaf node.
694 ** au: An array of integers that define thick-line risers for branches.
695 ** The integers are in pairs. For each pair, the first integer is
696 ** is the rail on which the riser should run and the second integer
697 ** is the id of the node upto which the riser should run.
698 ** mi: "merge-in". An array of integer x-coordinates from which
699 ** merge arrows should be drawn into this node. If the value is
700 ** negative, then the x-coordinate is the absolute value of mi[]
701 ** and a thin merge-arrow descender is drawn to the bottom of
702 ** the screen.
703 ** h: The SHA1 hash of the object being graphed
704 */
705 cgi_printf("var rowinfo = [\n");
706 for(pRow=pGraph->pFirst; pRow; pRow=pRow->pNext){
707 int mo = pRow->mergeOut;
708 if( mo<0 ){
709 mo = 0;
710 }else{
711 int x = (mo/4)*iRailPitch;
712 switch( mo&3 ){
713 case 0: x -= mergeOffset-2; break;
714 case 1: x += 1; break;
715 case 2: x += mergeOffset+1; break;
716 }
717 mo = x;
718 }
719 cgi_printf("{id:%d,bg:\"%s\",r:%d,d:%d,mo:%d,mu:%d,u:%d,f:%d,au:",
720 pRow->idx, /* id */
721 pRow->zBgClr, /* bg */
722 pRow->iRail, /* r */
723 pRow->bDescender, /* d */
724 mo, /* mo */
725 pRow->mergeUpto, /* mu */
726 pRow->aiRiser[pRow->iRail], /* u */
727 pRow->isLeaf ? 1 : 0 /* f */
728 );
729 /* u */
@@ -743,13 +721,11 @@
743 /* mi */
744 cgi_printf("mi:");
745 cSep = '[';
746 for(i=0; i<GR_MAX_RAIL; i++){
747 if( pRow->mergeIn[i] ){
748 int mi = i*iRailPitch;
749 if( pRow->mergeIn[i]==1 ) mi -= mergeOffset-1;
750 if( pRow->mergeIn[i]==3 ) mi += mergeOffset;
751 if( pRow->mergeDown & (1<<i) ) mi = -mi;
752 cgi_printf("%c%d", cSep, mi);
753 cSep = ',';
754 }
755 }
@@ -756,246 +732,238 @@
756 if( cSep=='[' ) cgi_printf("[");
757 cgi_printf("],h:\"%s\"}%s", pRow->zUuid, pRow->pNext ? ",\n" : "];\n");
758 }
759 cgi_printf("var nrail = %d\n", pGraph->mxRail+1);
760 graph_free(pGraph);
761 @ var cDiv = gebi("canvas");
762 @ var csty = window.getComputedStyle && window.getComputedStyle(cDiv,null);
763 @ var lineClr = (csty && csty.getPropertyValue('color')) || 'black';
764 @ var bgClr = (csty && csty.getPropertyValue('background-color')) ||'white';
765 @ if( bgClr=='transparent' ) bgClr = 'white';
766 @ var boxColor = lineClr;
767 @ function drawBox(color,x0,y0,x1,y1){
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
768 @ var n = document.createElement("div");
 
 
 
 
769 @ if( x0>x1 ){ var t=x0; x0=x1; x1=t; }
770 @ if( y0>y1 ){ var t=y0; y0=y1; y1=t; }
771 @ var w = x1-x0+1;
772 @ var h = y1-y0+1;
773 @ n.style.position = "absolute";
774 @ n.style.overflow = "hidden";
775 @ n.style.left = x0+"px";
776 @ n.style.top = y0+"px";
777 @ n.style.width = w+"px";
778 @ n.style.height = h+"px";
779 @ n.style.backgroundColor = color;
780 @ cDiv.appendChild(n);
 
781 @ return n;
782 @ }
783 @ function absoluteY(id){
784 @ var obj = gebi(id);
785 @ if( !obj ) return;
786 @ var top = 0;
787 @ if( obj.offsetParent ){
788 @ do{
789 @ top += obj.offsetTop;
790 @ }while( obj = obj.offsetParent );
791 @ }
792 @ return top;
793 @ }
794 @ function absoluteX(id){
795 @ var obj = gebi(id);
796 @ if( !obj ) return;
797 @ var left = 0;
798 @ if( obj.offsetParent ){
799 @ do{
800 @ left += obj.offsetLeft;
801 @ }while( obj = obj.offsetParent );
802 @ }
803 @ return left;
804 @ }
805 if( showArrowheads ){
806 @ function drawUpArrow(x,y0,y1,clr){
807 @ drawBox(clr,x,y0+4,x+1,y1);
808 @ var n = document.createElement("div"),
809 @ l = x-2,
810 @ t = y0;
811 @ n.style.position = "absolute";
812 @ n.style.left = l+"px";
813 @ n.style.top = t+"px";
814 @ n.style.width = 0;
815 @ n.style.height = 0;
816 @ n.style.transform = "scale(.999)";
817 @ n.style.borderWidth = 0;
818 @ n.style.borderStyle = "solid";
819 @ n.style.borderColor = "transparent";
820 @ n.style.borderRightWidth = "3px";
821 @ n.style.borderBottomColor = clr;
822 @ n.style.borderLeftWidth = "3px";
823 @ if( y0+10>=y1 ){
824 @ n.style.borderBottomWidth = "5px";
825 @ } else {
826 @ n.style.borderBottomWidth = "7px";
827 @ }
828 @ cDiv.appendChild(n);
829 @ }
830 }else{
831 @ function drawUpArrow(x,y0,y1,clr){
832 @ drawBox(clr,x,y0+1,x+1,y1);
833 @ }
834 }
835 @ function drawThinArrow(y,xFrom,xTo){
836 @ var n = document.createElement("div"),
837 @ t = y-2;
838 @ n.style.position = "absolute";
839 @ n.style.top = t+"px";
840 @ n.style.width = 0;
841 @ n.style.height = "1px";
842 @ n.style.transform = "scale(.999)";
843 @ n.style.borderWidth = 0;
844 @ n.style.borderStyle = "solid";
845 @ n.style.borderColor = "transparent";
846 @ n.style.borderTopWidth = "2px";
847 @ n.style.borderBottomWidth = "2px";
848 @ if( xFrom<xTo ){
849 @ drawBox(lineClr,xFrom,y,xTo-3,y);
850 @ n.style.left = xTo-3+"px";
851 @ n.style.borderLeftWidth = "3px";
852 @ n.style.borderLeftColor = lineClr;
853 @ }else{
854 @ drawBox(lineClr,xTo+3,y,xFrom,y);
855 @ n.style.left = xTo+1+"px";
856 @ n.style.borderRightWidth = "3px";
857 @ n.style.borderRightColor = lineClr;
858 @ }
859 @ cDiv.appendChild(n);
860 @ }
861 @ function drawThinLine(x0,y0,x1,y1){
862 @ drawBox(lineClr,x0,y0,x1,y1);
863 @ }
864 @ function drawNodeBox(color,x0,y0,x1,y1){
865 @ var n = drawBox(color,x0,y0,x1,y1);
866 @ n.style.cursor = "pointer";
867 if( circleNodes ){
868 @ n.style.borderRadius = "6px";
869 }
870 @ }
871 @ function drawNode(p, left, btm){
872 @ drawNodeBox(boxColor,p.x-5,p.y-5,p.x+6,p.y+6);
873 @ drawNodeBox(p.bg||bgClr,p.x-4,p.y-4,p.x+5,p.y+5);
874 @ if( p.u>0 ) drawUpArrow(p.x,rowinfo[p.u-1].y+6,p.y-6,p.fg||lineClr);
875 @ if( p.f&1 ) drawNodeBox(boxColor,p.x-1,p.y-1,p.x+2,p.y+2);
876 if( !omitDescenders ){
877 @ if( p.u==0 ) drawUpArrow(p.x,0,p.y-6,p.fg||lineClr);
878 @ if( p.d ) drawUpArrow(p.x,p.y+6,btm,p.fg||lineClr);
879 }
880 @ if( p.mo>0 ){
881 @ var x1 = p.mo + left - 1;
882 @ var y1 = p.y-3;
883 @ var x0 = x1>p.x ? p.x+7 : p.x-6;
884 @ var u = rowinfo[p.mu-1];
885 @ var y0 = u.y+5;
886 @ if( x1>=p.x-5 && x1<=p.x+5 ){
887 @ y1 = p.y-5;
888 @ }else{
889 @ drawThinLine(x0,y1,x1,y1);
890 @ }
891 if( mergeOffset==0 ) cgi_printf("if( p.mo!=p.u-1 ) ");
892 @ drawThinLine(x1,y0,x1,y1);
893 @ }
894 @ var n = p.au.length;
895 @ for(var i=0; i<n; i+=2){
896 @ var x1 = p.au[i]*railPitch + left;
897 @ var x0 = x1>p.x ? p.x+7 : p.x-6;
898 @ var u = rowinfo[p.au[i+1]-1];
899 @ if(u.id<p.id){
900 @ drawBox(u.fg||lineClr,x0,p.y,x1+1,p.y+1);
901 @ drawUpArrow(x1,u.y+6,p.y,u.fg||lineClr);
902 @ }else{
903 @ drawBox("#600000",x0,p.y,x1,p.y+1);
904 @ drawBox("#600000",x1-1,p.y,x1,u.y+1);
905 @ drawBox("#600000",x1,u.y,u.x-10,u.y+1);
906 @ var n = document.createElement("div"),
907 @ t = u.y-2,
908 @ l = u.x-11;
909 @ n.style.position = "absolute";
910 @ n.style.top = t+"px";
911 @ n.style.left = l+"px";
912 @ n.style.width = 0;
913 @ n.style.height = 0;
914 @ n.style.transform = "scale(.999)";
915 @ n.style.borderWidth = 0;
916 @ n.style.borderStyle = "solid";
917 @ n.style.borderColor = "transparent";
918 @ n.style.borderTopWidth = "3px";
919 @ n.style.borderBottomWidth = "3px";
920 @ n.style.borderLeftWidth = "7px";
921 @ n.style.borderLeftColor = "#600000";
922 @ cDiv.appendChild(n);
923 @ }
924 @ }
925 @ for(var j in p.mi){
926 @ var y0 = p.y+5;
927 @ var mx = p.mi[j];
928 @ if( mx<0 ){
929 @ mx = left-mx;
930 @ drawThinLine(mx,y0,mx,btm);
931 @ }else{
932 @ mx += left;
933 @ }
934 @ if( mx>p.x ){
935 @ drawThinArrow(y0,mx,p.x+6);
936 @ }else{
937 @ drawThinArrow(y0,mx,p.x-5);
938 @ }
939 @ }
940 @ }
941 @ var selBox = null;
942 @ var selRow = null;
943 @ function renderGraph(){
944 @ var canvasDiv = gebi("canvas");
945 @ while( canvasDiv.hasChildNodes() ){
946 @ canvasDiv.removeChild(canvasDiv.firstChild);
947 @ }
948 @ var canvasY = absoluteY("timelineTable");
949 @ var left = absoluteX("m"+rowinfo[0].id) - absoluteX("canvas") + 15;
950 @ for(var i in rowinfo){
951 @ rowinfo[i].y = absoluteY("m"+rowinfo[i].id) + 10 - canvasY;
952 @ rowinfo[i].x = left + rowinfo[i].r*railPitch;
953 @ }
954 @ var btm = absoluteY("grbtm") + 10 - canvasY;
955 @ for(var i in rowinfo){
956 @ drawNode(rowinfo[i], left, btm);
957 @ }
958 @ if( selRow!=null ) clickOnRow(selRow);
959 @ }
960 @ function clickOnGraph(event){
961 @ var x=event.clientX-absoluteX("canvas");
962 @ var y=event.clientY-absoluteY("canvas");
963 @ if(window.pageXOffset!=null){
964 @ x += window.pageXOffset;
965 @ y += window.pageYOffset;
966 @ }else{
967 @ var d = window.document.documentElement;
968 @ if(document.compatMode!="CSS1Compat") d = d.body;
969 @ x += d.scrollLeft;
970 @ y += d.scrollTop;
971 @ }
972 if( P("clicktest")!=0 ){
973 @ alert("click at "+x+","+y)
974 }
975 @ for(var i in rowinfo){
976 @ p = rowinfo[i];
977 @ if( p.y<y-11 ) continue;
978 @ if( p.y>y+9 ) break;
979 @ if( p.x>x-11 && p.x<x+9 ){
980 @ clickOnRow(p);
981 @ break;
982 @ }
983 @ }
984 @ }
985 @ function clickOnRow(p){
986 @ if( selRow==null ){
987 @ selBox = drawBox("red",p.x-2,p.y-2,p.x+3,p.y+3);
988 if( circleNodes ){
989 @ selBox.style.borderRadius="6px";
990 }
991 @ selRow = p;
992 @ }else if( selRow==p ){
993 @ var canvasDiv = gebi("canvas");
994 @ canvasDiv.removeChild(selBox);
995 @ selBox = null;
996 @ selRow = null;
997 @ }else{
998 if( fileDiff ){
999 @ location.href="%R/fdiff?v1="+selRow.h+"&v2="+p.h+"&sbs=1";
1000 }else{
1001 if( db_get_boolean("show-version-diffs", 0)==0 ){
@@ -1004,22 +972,23 @@
1004 @ location.href="%R/vdiff?from="+selRow.h+"&to="+p.h+"&sbs=1";
1005 }
1006 }
1007 @ }
1008 @ }
1009 @ var lastId = "m"+rowinfo[rowinfo.length-1].id;
1010 @ var lastY = 0;
1011 @ function checkHeight(){
1012 @ var h = absoluteY(lastId);
1013 @ if( h!=lastY ){
1014 @ renderGraph();
1015 @ lastY = h;
1016 @ }
1017 @ setTimeout("checkHeight();", 1000);
1018 @ }
 
1019 @ checkHeight();
1020 @ </script>
1021 }
1022 }
1023
1024 /*
1025 ** Create a temporary table suitable for storing timeline data.
@@ -1308,24 +1277,24 @@
1308 return;
1309 }
1310 url_initialize(&url, "timeline");
1311 cgi_query_parameters_to_url(&url);
1312 if( zTagName && g.perm.Read ){
1313 tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname='sym-%q'", zTagName);
1314 zThisTag = zTagName;
1315 }else if( zBrName && g.perm.Read ){
1316 tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname='sym-%q'",zBrName);
1317 zThisTag = zBrName;
1318 }else{
1319 tagid = 0;
1320 }
1321 if( zMark && zMark[0]==0 ){
1322 if( zAfter ) zMark = zAfter;
1323 if( zBefore ) zMark = zBefore;
1324 if( zCirca ) zMark = zCirca;
1325 }
1326 if( tagid>0
1327 && db_int(0,"SELECT count(*) FROM tagxref WHERE tagid=%d",tagid)<=nEntry
1328 ){
1329 nEntry = -1;
1330 zCirca = 0;
1331 }
@@ -1524,11 +1493,11 @@
1524 }
1525 else if( zYearWeek ){
1526 blob_append_sql(&sql, " AND %Q=strftime('%%Y-%%W',event.mtime) ",
1527 zYearWeek);
1528 }
1529 if( tagid>0 ){
1530 blob_append_sql(&sql,
1531 " AND (EXISTS(SELECT 1 FROM tagxref"
1532 " WHERE tagid=%d AND tagtype>0 AND rid=blob.rid)\n", tagid);
1533
1534 if( zBrName ){
1535
--- src/timeline.c
+++ src/timeline.c
@@ -241,23 +241,17 @@
241 dateFormat = db_get_int("timeline-date-format", 0);
242 zDateFmt = P("datefmt");
243 if( zDateFmt ) dateFormat = atoi(zDateFmt);
244 if( tmFlags & TIMELINE_GRAPH ){
245 pGraph = graph_init();
 
 
 
 
 
246 }
247 db_static_prepare(&qbranch,
248 "SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0 AND rid=:rid",
249 TAG_BRANCH
250 );
251
252 @ <table id="timelineTable" class="timelineTable">
 
253 blob_zero(&comment);
254 while( db_step(pQuery)==SQLITE_ROW ){
255 int rid = db_column_int(pQuery, 0);
256 const char *zUuid = db_column_text(pQuery, 1);
257 int isLeaf = db_column_int(pQuery, 5);
@@ -391,11 +385,11 @@
385 }
386 db_reset(&qparent);
387 gidx = graph_add_row(pGraph, rid, nParent, aParent, zBr, zBgClr,
388 zUuid, isLeaf);
389 db_reset(&qbranch);
390 @ <div id="m%d(gidx)" class="tl-nodemark"></div>
391 }
392 @</td>
393 if( zBgClr && zBgClr[0] && rid!=selectedRid ){
394 @ <td class="timelineTableCell" style="background-color: %h(zBgClr);">
395 }else{
@@ -589,18 +583,11 @@
583 graph_finish(pGraph, (tmFlags & TIMELINE_DISJOINT)!=0);
584 if( pGraph->nErr ){
585 graph_free(pGraph);
586 pGraph = 0;
587 }else{
588 @ <tr class="timelineBottom"><td></td><td></td><td></td></tr>
 
 
 
 
 
 
 
589 }
590 }
591 @ </table>
592 if( fchngQueryInit ) db_finalize(&fchngQuery);
593 timeline_output_graph_javascript(pGraph, (tmFlags & TIMELINE_DISJOINT)!=0, 0);
@@ -648,31 +635,34 @@
635 ){
636 if( pGraph && pGraph->nErr==0 && pGraph->nRow>0 ){
637 GraphRow *pRow;
638 int i;
639 char cSep;
 
640 int iRailPitch; /* Pixels between consecutive rails */
641 int showArrowheads; /* True to draw arrowheads. False to omit. */
642 int circleNodes; /* True for circle nodes. False for square nodes */
643 int colorGraph; /* Use colors for graph lines */
644
645 iRailPitch = atoi(PD("railpitch","0"));
646 showArrowheads = skin_detail_boolean("timeline-arrowheads");
647 circleNodes = skin_detail_boolean("timeline-circle-nodes");
648 colorGraph = skin_detail_boolean("timeline-color-graph-lines");
649
650 @ <script>(function(){
651 @ "use strict";
652 @ var css = "";
653 if( circleNodes ){
654 @ css += ".tl-node, .tl-node:after { border-radius: 50%%; }";
655 }
656 if( !showArrowheads ){
657 @ css += ".tl-arrow.u { display: none; }";
658 }
659 @ if( css!=="" ){
660 @ var style = document.createElement("style");
661 @ style.textContent = css;
662 @ document.querySelector("head").appendChild(style);
663 @ }
664 /* the rowinfo[] array contains all the information needed to generate
665 ** the graph. Each entry contains information for a single row:
666 **
667 ** id: The id of the <div> element for the row. This is an integer.
668 ** to get an actual id, prepend "m" to the integer. The top node
@@ -680,13 +670,13 @@
670 ** bg: The background color for this row
671 ** r: The "rail" that the node for this row sits on. The left-most
672 ** rail is 0 and the number increases to the right.
673 ** d: True if there is a "descender" - an arrow coming from the bottom
674 ** of the page straight up to this node.
675 ** mo: "merge-out". If non-negative, this is the rail position
676 ** for the upward portion of a merge arrow. The merge arrow goes up
677 ** to the row identified by mu:. If this value is negative then
678 ** node has no merge children and no merge-out line is drawn.
679 ** mu: The id of the row which is the top of the merge-out arrow.
680 ** u: Draw a thick child-line out of the top of this node and up to
681 ** the node with an id equal to this value. 0 if it is straight to
682 ** the top of the page, -1 if there is no thick-line riser.
@@ -693,37 +683,25 @@
683 ** f: 0x01: a leaf node.
684 ** au: An array of integers that define thick-line risers for branches.
685 ** The integers are in pairs. For each pair, the first integer is
686 ** is the rail on which the riser should run and the second integer
687 ** is the id of the node upto which the riser should run.
688 ** mi: "merge-in". An array of integer rail positions from which
689 ** merge arrows should be drawn into this node. If the value is
690 ** negative, then the rail position is the absolute value of mi[]
691 ** and a thin merge-arrow descender is drawn to the bottom of
692 ** the screen.
693 ** h: The SHA1 hash of the object being graphed
694 */
695 cgi_printf("var rowinfo = [\n");
696 for(pRow=pGraph->pFirst; pRow; pRow=pRow->pNext){
 
 
 
 
 
 
 
 
 
 
 
 
697 cgi_printf("{id:%d,bg:\"%s\",r:%d,d:%d,mo:%d,mu:%d,u:%d,f:%d,au:",
698 pRow->idx, /* id */
699 pRow->zBgClr, /* bg */
700 pRow->iRail, /* r */
701 pRow->bDescender, /* d */
702 pRow->mergeOut, /* mo */
703 pRow->mergeUpto, /* mu */
704 pRow->aiRiser[pRow->iRail], /* u */
705 pRow->isLeaf ? 1 : 0 /* f */
706 );
707 /* u */
@@ -743,13 +721,11 @@
721 /* mi */
722 cgi_printf("mi:");
723 cSep = '[';
724 for(i=0; i<GR_MAX_RAIL; i++){
725 if( pRow->mergeIn[i] ){
726 int mi = i;
 
 
727 if( pRow->mergeDown & (1<<i) ) mi = -mi;
728 cgi_printf("%c%d", cSep, mi);
729 cSep = ',';
730 }
731 }
@@ -756,246 +732,238 @@
732 if( cSep=='[' ) cgi_printf("[");
733 cgi_printf("],h:\"%s\"}%s", pRow->zUuid, pRow->pNext ? ",\n" : "];\n");
734 }
735 cgi_printf("var nrail = %d\n", pGraph->mxRail+1);
736 graph_free(pGraph);
737 @ var canvasDiv;
738 @ var railPitch;
739 @ var mergeOffset;
740 @ var node, arrow, arrowSmall, line, mArrow, mLine, wArrow, wLine;
741 @ function initGraph(){
742 @ var parent = gebi("timelineTable").rows[0].cells[1];
743 @ parent.style.verticalAlign = "top";
744 @ canvasDiv = document.createElement("div");
745 @ canvasDiv.className = "tl-canvas";
746 @ canvasDiv.style.position = "absolute";
747 @ parent.appendChild(canvasDiv);
748 @
749 @ var elems = {};
750 @ var elemClasses = [
751 @ "rail", "mergeoffset", "node", "arrow u", "arrow u sm", "line",
752 @ "arrow merge r", "line merge", "arrow warp", "line warp"
753 @ ];
754 @ for( var i=0; i<elemClasses.length; i++ ){
755 @ var cls = elemClasses[i];
756 @ var elem = document.createElement("div");
757 @ elem.className = "tl-" + cls;
758 @ if( cls.indexOf("line")==0 ) elem.className += " v";
759 @ canvasDiv.appendChild(elem);
760 @ var k = cls.replace(/\s/g, "_");
761 @ var r = elem.getBoundingClientRect();
762 @ var w = Math.round(r.right - r.left);
763 @ var h = Math.round(r.bottom - r.top);
764 @ elems[k] = {w: w, h: h, cls: cls};
765 @ }
766 @ node = elems.node;
767 @ arrow = elems.arrow_u;
768 @ arrowSmall = elems.arrow_u_sm;
769 @ line = elems.line;
770 @ mArrow = elems.arrow_merge_r;
771 @ mLine = elems.line_merge;
772 @ wArrow = elems.arrow_warp;
773 @ wLine = elems.line_warp;
774 @
775 @ var minRailPitch = Math.ceil((node.w+line.w)/2 + mArrow.w + 1);
776 if( iRailPitch ){
777 @ railPitch = %d(iRailPitch);
778 }else{
779 @ railPitch = elems.rail.w;
780 @ railPitch -= Math.floor((nrail-1)*(railPitch-minRailPitch)/21);
781 }
782 @ railPitch = Math.max(railPitch, minRailPitch);
783 @
784 if( PB("nomo") ){
785 @ mergeOffset = 0;
786 }else{
787 @ mergeOffset = railPitch-minRailPitch-mLine.w;
788 @ mergeOffset = Math.min(mergeOffset, elems.mergeoffset.w);
789 @ mergeOffset = mergeOffset>0 ? mergeOffset + line.w/2 : 0;
790 }
791 @
792 @ var canvasWidth = (nrail-1)*railPitch + node.w;
793 @ canvasDiv.style.width = canvasWidth + "px";
794 @ canvasDiv.style.position = "relative";
795 @ }
796 @ function drawBox(cls,color,x0,y0,x1,y1){
797 @ var n = document.createElement("div");
798 @ x0 = Math.floor(x0);
799 @ y0 = Math.floor(y0);
800 @ x1 = x1 || x1===0 ? Math.floor(x1) : x0;
801 @ y1 = y1 || y1===0 ? Math.floor(y1) : y0;
802 @ if( x0>x1 ){ var t=x0; x0=x1; x1=t; }
803 @ if( y0>y1 ){ var t=y0; y0=y1; y1=t; }
804 @ var w = x1-x0;
805 @ var h = y1-y0;
806 @ n.style.position = "absolute";
 
807 @ n.style.left = x0+"px";
808 @ n.style.top = y0+"px";
809 @ if( w ) n.style.width = w+"px";
810 @ if( h ) n.style.height = h+"px";
811 @ if( color ) n.style.backgroundColor = color;
812 @ n.className = "tl-"+cls;
813 @ canvasDiv.appendChild(n);
814 @ return n;
815 @ }
816 @ function absoluteY(obj){
 
 
817 @ var top = 0;
818 @ if( obj.offsetParent ){
819 @ do{
820 @ top += obj.offsetTop;
821 @ }while( obj = obj.offsetParent );
822 @ }
823 @ return top;
824 @ }
825 @ function miLineY(p){
826 @ return p.y + node.h - mLine.w - 1;
827 @ }
828 @ function drawLine(elem,color,x0,y0,x1,y1){
829 @ var cls = elem.cls + " ";
830 @ if( x1===null ){
831 @ x1 = x0+elem.w;
832 @ cls += "v";
833 @ }else{
834 @ y1 = y0+elem.w;
835 @ cls += "h";
836 @ }
837 @ drawBox(cls,color,x0,y0,x1,y1);
838 @ }
839 @ function drawUpArrow(from,to,color){
840 @ var y = to.y + node.h;
841 @ var arrowSpace = from.y - y + (!from.id || from.r!=to.r ? node.h/2 : 0);
842 @ var arw = arrowSpace < arrow.h*1.5 ? arrowSmall : arrow;
843 @ var x = to.x + (node.w-line.w)/2;
844 @ var y0 = from.y + node.h/2;
845 @ var y1 = Math.ceil(to.y + node.h + arw.h/2);
846 @ drawLine(line,color,x,y0,null,y1);
847 @ x = to.x + (node.w-arw.w)/2;
848 @ var n = drawBox(arw.cls,null,x,y);
849 @ n.style.borderBottomColor = color;
850 @ }
851 @ function drawMergeLine(x0,y0,x1,y1){
852 @ drawLine(mLine,null,x0,y0,x1,y1);
853 @ }
854 @ function drawMergeArrow(p,rail){
855 @ var x0 = rail*railPitch + node.w/2;
856 @ if( rail in mergeLines ){
857 @ x0 += mergeLines[rail];
858 @ if( p.r<rail ) x0 += mLine.w;
859 @ }else{
860 @ x0 += (p.r<rail ? -1 : 1)*line.w/2;
861 @ }
862 @ var x1 = mArrow.w ? mArrow.w/2 : -node.w/2;
863 @ x1 = p.x + (p.r<rail ? node.w + Math.ceil(x1) : -x1);
864 @ var y = miLineY(p);
865 @ drawMergeLine(x0,y,x1,null);
866 @ var x = p.x + (p.r<rail ? node.w : -mArrow.w);
867 @ var cls = "arrow merge " + (p.r<rail ? "l" : "r");
868 @ drawBox(cls,null,x,y+(mLine.w-mArrow.h)/2);
869 @ }
870 @ function drawNode(p, btm){
871 @ if( p.u>0 ) drawUpArrow(p,rowinfo[p.u-1],p.fg);
872 @ var cls = node.cls;
873 @ if( p.mi.length ) cls += " merge";
874 @ if( p.f&1 ) cls += " leaf";
875 @ var n = drawBox(cls,p.bg,p.x,p.y);
876 @ n.id = "tln"+p.id;
877 @ n.onclick = clickOnNode;
878 @ n.style.zIndex = 10;
879 if( !omitDescenders ){
880 @ if( p.u==0 ) drawUpArrow(p,{x: p.x, y: -node.h},p.fg);
881 @ if( p.d ) drawUpArrow({x: p.x, y: btm-node.h/2},p,p.fg);
882 }
883 @ if( p.mo>=0 ){
884 @ var x0 = p.x + node.w/2;
885 @ var x1 = p.mo*railPitch + node.w/2;
886 @ var u = rowinfo[p.mu-1];
887 @ var y1 = miLineY(u);
888 @ if( p.u<0 || p.mo!=p.r ){
889 @ x1 += mergeLines[p.mo] = -mLine.w/2;
890 @ var y0 = p.y+2;
891 @ if( p.r!=p.mo ) drawMergeLine(x0,y0,x1+(x0<x1 ? mLine.w : 0),null);
892 @ drawMergeLine(x1,y0+mLine.w,null,y1);
893 @ }else if( mergeOffset ){
894 @ mergeLines[p.mo] = u.r<p.r ? -mergeOffset-mLine.w : mergeOffset;
895 @ x1 += mergeLines[p.mo];
896 @ drawMergeLine(x1,p.y+node.h/2,null,y1);
897 @ }else{
898 @ delete mergeLines[p.mo];
899 @ }
900 @ }
901 @ for( var i=0; i<p.au.length; i+=2 ){
902 @ var rail = p.au[i];
903 @ var x0 = p.x + node.w/2;
904 @ var x1 = rail*railPitch + (node.w-line.w)/2;
905 @ if( x0<x1 ){
906 @ x0 = Math.ceil(x0);
907 @ x1 += line.w;
908 @ }
909 @ var y0 = p.y + (node.h-line.w)/2;
910 @ var u = rowinfo[p.au[i+1]-1];
911 @ if( u.id<p.id ){
912 @ drawLine(line,u.fg,x0,y0,x1,null);
913 @ drawUpArrow(p,u,u.fg);
914 @ }else{
915 @ var y1 = u.y + (node.h-line.w)/2;
916 @ drawLine(wLine,u.fg,x0,y0,x1,null);
917 @ drawLine(wLine,u.fg,x1-line.w,y0,null,y1+line.w);
918 @ drawLine(wLine,u.fg,x1,y1,u.x-wArrow.w/2,null);
919 @ var x = u.x-wArrow.w;
920 @ var y = u.y+(node.h-wArrow.h)/2;
921 @ var n = drawBox(wArrow.cls,null,x,y);
922 @ if( u.fg ) n.style.borderLeftColor = u.fg;
923 @ }
924 @ }
925 @ for( var i=0; i<p.mi.length; i++ ){
926 @ var rail = p.mi[i];
927 @ if( rail<0 ){
928 @ rail = -rail;
929 @ mergeLines[rail] = -mLine.w/2;
930 @ var x = rail*railPitch + (node.w-mLine.w)/2;
931 @ drawMergeLine(x,miLineY(p),null,btm);
932 @ }
933 @ drawMergeArrow(p,rail);
934 @ }
935 @ }
936 @ var mergeLines;
937 @ function renderGraph(){
938 @ mergeLines = {};
939 @ canvasDiv.innerHTML = "";
940 @ var canvasY = absoluteY(canvasDiv);
941 @ for( var i=0; i<rowinfo.length; i++ ){
942 @ rowinfo[i].y = absoluteY(gebi("m"+rowinfo[i].id)) - canvasY;
943 @ rowinfo[i].x = rowinfo[i].r*railPitch;
944 @ }
945 @ var tlBtm = document.querySelector(".timelineBottom");
946 @ if( tlBtm.offsetHeight<node.h ){
947 @ tlBtm.style.height = node.h + "px";
948 @ }
949 @ var btm = absoluteY(tlBtm) - canvasY + tlBtm.offsetHeight;
950 @ for( var i=rowinfo.length-1; i>=0; i-- ){
951 @ drawNode(rowinfo[i], btm);
952 @ }
953 @ }
954 @ var selRow;
955 @ function clickOnNode(){
956 @ var p = rowinfo[parseInt(this.id.match(/\d+$/)[0], 10)-1];
957 @ if( !selRow ){
958 @ selRow = p;
959 @ this.className += " sel";
960 @ canvasDiv.className += " sel";
961 @ }else if( selRow==p ){
962 @ selRow = null;
963 @ this.className = this.className.replace(" sel", "");
964 @ canvasDiv.className = canvasDiv.className.replace(" sel", "");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
965 @ }else{
966 if( fileDiff ){
967 @ location.href="%R/fdiff?v1="+selRow.h+"&v2="+p.h+"&sbs=1";
968 }else{
969 if( db_get_boolean("show-version-diffs", 0)==0 ){
@@ -1004,22 +972,23 @@
972 @ location.href="%R/vdiff?from="+selRow.h+"&to="+p.h+"&sbs=1";
973 }
974 }
975 @ }
976 @ }
977 @ var lastRow = gebi("m"+rowinfo[rowinfo.length-1].id);
978 @ var lastY = 0;
979 @ function checkHeight(){
980 @ var h = absoluteY(lastRow);
981 @ if( h!=lastY ){
982 @ renderGraph();
983 @ lastY = h;
984 @ }
985 @ setTimeout(checkHeight, 1000);
986 @ }
987 @ initGraph();
988 @ checkHeight();
989 @ }())</script>
990 }
991 }
992
993 /*
994 ** Create a temporary table suitable for storing timeline data.
@@ -1308,24 +1277,24 @@
1277 return;
1278 }
1279 url_initialize(&url, "timeline");
1280 cgi_query_parameters_to_url(&url);
1281 if( zTagName && g.perm.Read ){
1282 tagid = db_int(-1,"SELECT tagid FROM tag WHERE tagname='sym-%q'",zTagName);
1283 zThisTag = zTagName;
1284 }else if( zBrName && g.perm.Read ){
1285 tagid = db_int(-1,"SELECT tagid FROM tag WHERE tagname='sym-%q'",zBrName);
1286 zThisTag = zBrName;
1287 }else{
1288 tagid = 0;
1289 }
1290 if( zMark && zMark[0]==0 ){
1291 if( zAfter ) zMark = zAfter;
1292 if( zBefore ) zMark = zBefore;
1293 if( zCirca ) zMark = zCirca;
1294 }
1295 if( tagid
1296 && db_int(0,"SELECT count(*) FROM tagxref WHERE tagid=%d",tagid)<=nEntry
1297 ){
1298 nEntry = -1;
1299 zCirca = 0;
1300 }
@@ -1524,11 +1493,11 @@
1493 }
1494 else if( zYearWeek ){
1495 blob_append_sql(&sql, " AND %Q=strftime('%%Y-%%W',event.mtime) ",
1496 zYearWeek);
1497 }
1498 if( tagid ){
1499 blob_append_sql(&sql,
1500 " AND (EXISTS(SELECT 1 FROM tagxref"
1501 " WHERE tagid=%d AND tagtype>0 AND rid=blob.rid)\n", tagid);
1502
1503 if( zBrName ){
1504
+5 -5
--- src/translate.c
+++ src/translate.c
@@ -40,15 +40,15 @@
4040
** rather than text that is to be output via cgi_printf(). Render it
4141
** as such.
4242
**
4343
** Enhancement #2:
4444
**
45
-** Comments of the form: "/* @-comment: CC" cause CC to become a
46
-** comment character for the @-substitution. Typical values for CC are
47
-** "--" (for SQL text) or "#" (for Tcl script) or "//" (for C++ code).
48
-** Lines of subsequent @-blocks that begin with CC are omitted from the
49
-** output.
45
+** Comments of the form: "|* @-comment: CC" (where "|" is really "/")
46
+** cause CC to become a comment character for the @-substitution.
47
+** Typical values for CC are "--" (for SQL text) or "#" (for Tcl script)
48
+** or "//" (for C++ code). Lines of subsequent @-blocks that begin with
49
+** CC are omitted from the output.
5050
**
5151
*/
5252
#include <stdio.h>
5353
#include <ctype.h>
5454
#include <stdlib.h>
5555
--- src/translate.c
+++ src/translate.c
@@ -40,15 +40,15 @@
40 ** rather than text that is to be output via cgi_printf(). Render it
41 ** as such.
42 **
43 ** Enhancement #2:
44 **
45 ** Comments of the form: "/* @-comment: CC" cause CC to become a
46 ** comment character for the @-substitution. Typical values for CC are
47 ** "--" (for SQL text) or "#" (for Tcl script) or "//" (for C++ code).
48 ** Lines of subsequent @-blocks that begin with CC are omitted from the
49 ** output.
50 **
51 */
52 #include <stdio.h>
53 #include <ctype.h>
54 #include <stdlib.h>
55
--- src/translate.c
+++ src/translate.c
@@ -40,15 +40,15 @@
40 ** rather than text that is to be output via cgi_printf(). Render it
41 ** as such.
42 **
43 ** Enhancement #2:
44 **
45 ** Comments of the form: "|* @-comment: CC" (where "|" is really "/")
46 ** cause CC to become a comment character for the @-substitution.
47 ** Typical values for CC are "--" (for SQL text) or "#" (for Tcl script)
48 ** or "//" (for C++ code). Lines of subsequent @-blocks that begin with
49 ** CC are omitted from the output.
50 **
51 */
52 #include <stdio.h>
53 #include <ctype.h>
54 #include <stdlib.h>
55
+16 -24
--- src/update.c
+++ src/update.c
@@ -586,43 +586,32 @@
586586
db_end_transaction(0);
587587
}
588588
}
589589
590590
/*
591
-** Make sure empty directories are created
591
+** Create empty directories specified by the empty-dirs setting.
592592
*/
593593
void ensure_empty_dirs_created(void){
594
- /* Make empty directories? */
595594
char *zEmptyDirs = db_get("empty-dirs", 0);
596595
if( zEmptyDirs!=0 ){
597
- char *bc;
596
+ int i;
598597
Blob dirName;
599598
Blob dirsList;
600599
601
- blob_zero(&dirsList);
602
- blob_init(&dirsList, zEmptyDirs, strlen(zEmptyDirs));
603
- /* Replace commas by spaces */
604
- bc = blob_str(&dirsList);
605
- while( (*bc)!='\0' ){
606
- if( (*bc)==',' ) { *bc = ' '; }
607
- ++bc;
608
- }
609
- /* Make directories */
610
- blob_zero(&dirName);
600
+ zEmptyDirs = fossil_strdup(zEmptyDirs);
601
+ for(i=0; zEmptyDirs[i]; i++){
602
+ if( zEmptyDirs[i]==',' ) zEmptyDirs[i] = ' ';
603
+ }
604
+ blob_init(&dirsList, zEmptyDirs, -1);
611605
while( blob_token(&dirsList, &dirName) ){
612
- const char *zDir = blob_str(&dirName);
613
- /* Make full pathname of the directory */
614
- Blob path;
615
- const char *zPath;
616
-
617
- blob_zero(&path);
618
- blob_appendf(&path, "%s/%s", g.zLocalRoot, zDir);
619
- zPath = blob_str(&path);
620
- /* Handle various cases of existence of the directory */
606
+ char *zDir = blob_str(&dirName);
607
+ char *zPath = mprintf("%s/%s", g.zLocalRoot, zDir);
621608
switch( file_wd_isdir(zPath) ){
622609
case 0: { /* doesn't exist */
623
- if( file_mkdir(zPath, 0)!=0 ) {
610
+ fossil_free(zPath);
611
+ zPath = mprintf("%s/%s/x", g.zLocalRoot, zDir);
612
+ if( file_mkfolder(zPath, 0, 1)!=0 ) {
624613
fossil_warning("couldn't create directory %s as "
625614
"required by empty-dirs setting", zDir);
626615
}
627616
break;
628617
}
@@ -633,12 +622,15 @@
633622
case 2: { /* exists, but isn't a directory */
634623
fossil_warning("file %s found, but a directory is required "
635624
"by empty-dirs setting", zDir);
636625
}
637626
}
638
- blob_reset(&path);
627
+ fossil_free(zPath);
628
+ blob_reset(&dirName);
639629
}
630
+ blob_reset(&dirsList);
631
+ fossil_free(zEmptyDirs);
640632
}
641633
}
642634
643635
644636
/*
645637
--- src/update.c
+++ src/update.c
@@ -586,43 +586,32 @@
586 db_end_transaction(0);
587 }
588 }
589
590 /*
591 ** Make sure empty directories are created
592 */
593 void ensure_empty_dirs_created(void){
594 /* Make empty directories? */
595 char *zEmptyDirs = db_get("empty-dirs", 0);
596 if( zEmptyDirs!=0 ){
597 char *bc;
598 Blob dirName;
599 Blob dirsList;
600
601 blob_zero(&dirsList);
602 blob_init(&dirsList, zEmptyDirs, strlen(zEmptyDirs));
603 /* Replace commas by spaces */
604 bc = blob_str(&dirsList);
605 while( (*bc)!='\0' ){
606 if( (*bc)==',' ) { *bc = ' '; }
607 ++bc;
608 }
609 /* Make directories */
610 blob_zero(&dirName);
611 while( blob_token(&dirsList, &dirName) ){
612 const char *zDir = blob_str(&dirName);
613 /* Make full pathname of the directory */
614 Blob path;
615 const char *zPath;
616
617 blob_zero(&path);
618 blob_appendf(&path, "%s/%s", g.zLocalRoot, zDir);
619 zPath = blob_str(&path);
620 /* Handle various cases of existence of the directory */
621 switch( file_wd_isdir(zPath) ){
622 case 0: { /* doesn't exist */
623 if( file_mkdir(zPath, 0)!=0 ) {
 
 
624 fossil_warning("couldn't create directory %s as "
625 "required by empty-dirs setting", zDir);
626 }
627 break;
628 }
@@ -633,12 +622,15 @@
633 case 2: { /* exists, but isn't a directory */
634 fossil_warning("file %s found, but a directory is required "
635 "by empty-dirs setting", zDir);
636 }
637 }
638 blob_reset(&path);
 
639 }
 
 
640 }
641 }
642
643
644 /*
645
--- src/update.c
+++ src/update.c
@@ -586,43 +586,32 @@
586 db_end_transaction(0);
587 }
588 }
589
590 /*
591 ** Create empty directories specified by the empty-dirs setting.
592 */
593 void ensure_empty_dirs_created(void){
 
594 char *zEmptyDirs = db_get("empty-dirs", 0);
595 if( zEmptyDirs!=0 ){
596 int i;
597 Blob dirName;
598 Blob dirsList;
599
600 zEmptyDirs = fossil_strdup(zEmptyDirs);
601 for(i=0; zEmptyDirs[i]; i++){
602 if( zEmptyDirs[i]==',' ) zEmptyDirs[i] = ' ';
603 }
604 blob_init(&dirsList, zEmptyDirs, -1);
 
 
 
 
 
605 while( blob_token(&dirsList, &dirName) ){
606 char *zDir = blob_str(&dirName);
607 char *zPath = mprintf("%s/%s", g.zLocalRoot, zDir);
 
 
 
 
 
 
 
608 switch( file_wd_isdir(zPath) ){
609 case 0: { /* doesn't exist */
610 fossil_free(zPath);
611 zPath = mprintf("%s/%s/x", g.zLocalRoot, zDir);
612 if( file_mkfolder(zPath, 0, 1)!=0 ) {
613 fossil_warning("couldn't create directory %s as "
614 "required by empty-dirs setting", zDir);
615 }
616 break;
617 }
@@ -633,12 +622,15 @@
622 case 2: { /* exists, but isn't a directory */
623 fossil_warning("file %s found, but a directory is required "
624 "by empty-dirs setting", zDir);
625 }
626 }
627 fossil_free(zPath);
628 blob_reset(&dirName);
629 }
630 blob_reset(&dirsList);
631 fossil_free(zEmptyDirs);
632 }
633 }
634
635
636 /*
637
+6 -4
--- src/url.c
+++ src/url.c
@@ -454,12 +454,12 @@
454454
** Resets the given URL object, deallocating any memory
455455
** it uses.
456456
*/
457457
void url_reset(HQuery *p){
458458
blob_reset(&p->url);
459
- fossil_free(p->azName);
460
- fossil_free(p->azValue);
459
+ fossil_free((void *)p->azName);
460
+ fossil_free((void *)p->azValue);
461461
url_initialize(p, p->zBase);
462462
}
463463
464464
/*
465465
** Add a fixed parameter to an HQuery. Or remove the parameters if zValue==0.
@@ -480,12 +480,14 @@
480480
}
481481
assert( i==p->nParam );
482482
if( zValue==0 ) return;
483483
if( i>=p->nAlloc ){
484484
p->nAlloc = p->nAlloc*2 + 10;
485
- p->azName = fossil_realloc(p->azName, sizeof(p->azName[0])*p->nAlloc);
486
- p->azValue = fossil_realloc(p->azValue, sizeof(p->azValue[0])*p->nAlloc);
485
+ p->azName = fossil_realloc((void *)p->azName,
486
+ sizeof(p->azName[0])*p->nAlloc);
487
+ p->azValue = fossil_realloc((void *)p->azValue,
488
+ sizeof(p->azValue[0])*p->nAlloc);
487489
}
488490
p->azName[i] = zName;
489491
p->azValue[i] = zValue;
490492
p->nParam++;
491493
}
492494
--- src/url.c
+++ src/url.c
@@ -454,12 +454,12 @@
454 ** Resets the given URL object, deallocating any memory
455 ** it uses.
456 */
457 void url_reset(HQuery *p){
458 blob_reset(&p->url);
459 fossil_free(p->azName);
460 fossil_free(p->azValue);
461 url_initialize(p, p->zBase);
462 }
463
464 /*
465 ** Add a fixed parameter to an HQuery. Or remove the parameters if zValue==0.
@@ -480,12 +480,14 @@
480 }
481 assert( i==p->nParam );
482 if( zValue==0 ) return;
483 if( i>=p->nAlloc ){
484 p->nAlloc = p->nAlloc*2 + 10;
485 p->azName = fossil_realloc(p->azName, sizeof(p->azName[0])*p->nAlloc);
486 p->azValue = fossil_realloc(p->azValue, sizeof(p->azValue[0])*p->nAlloc);
 
 
487 }
488 p->azName[i] = zName;
489 p->azValue[i] = zValue;
490 p->nParam++;
491 }
492
--- src/url.c
+++ src/url.c
@@ -454,12 +454,12 @@
454 ** Resets the given URL object, deallocating any memory
455 ** it uses.
456 */
457 void url_reset(HQuery *p){
458 blob_reset(&p->url);
459 fossil_free((void *)p->azName);
460 fossil_free((void *)p->azValue);
461 url_initialize(p, p->zBase);
462 }
463
464 /*
465 ** Add a fixed parameter to an HQuery. Or remove the parameters if zValue==0.
@@ -480,12 +480,14 @@
480 }
481 assert( i==p->nParam );
482 if( zValue==0 ) return;
483 if( i>=p->nAlloc ){
484 p->nAlloc = p->nAlloc*2 + 10;
485 p->azName = fossil_realloc((void *)p->azName,
486 sizeof(p->azName[0])*p->nAlloc);
487 p->azValue = fossil_realloc((void *)p->azValue,
488 sizeof(p->azValue[0])*p->nAlloc);
489 }
490 p->azName[i] = zName;
491 p->azValue[i] = zValue;
492 p->nParam++;
493 }
494
+35 -7
--- src/vfile.c
+++ src/vfile.c
@@ -136,15 +136,22 @@
136136
#define CKSIG_SETMTIME 0x004 /* Set mtime to last check-out time */
137137
138138
#endif /* INTERFACE */
139139
140140
/*
141
-** Look at every VFILE entry with the given vid and update
142
-** VFILE.CHNGED field according to whether or not
143
-** the file has changed. 0 means no change. 1 means edited. 2 means
144
-** the file has changed due to a merge. 3 means the file was added
145
-** by a merge.
141
+** Look at every VFILE entry with the given vid and update VFILE.CHNGED field
142
+** according to whether or not the file has changed.
143
+** - 0 means no change.
144
+** - 1 means edited.
145
+** - 2 means changed due to a merge.
146
+** - 3 means added by a merge.
147
+** - 4 means changed due to an integrate merge.
148
+** - 5 means added by an integrate merge.
149
+** - 6 means became executable but has unmodified contents.
150
+** - 7 means became a symlink whose target equals its old contents.
151
+** - 8 means lost executable status but has unmodified contents.
152
+** - 9 means lost symlink status and has contents equal to its old target.
146153
**
147154
** If VFILE.DELETED is true or if VFILE.RID is zero, then the file was either
148155
** removed from configuration management via "fossil rm" or added via
149156
** "fossil add", respectively, and in both cases we always know that
150157
** the file has changed without having the check the size, mtime,
@@ -170,18 +177,22 @@
170177
int useMtime = (cksigFlags & CKSIG_SHA1)==0
171178
&& db_get_boolean("mtime-changes", 1);
172179
173180
db_begin_transaction();
174181
db_prepare(&q, "SELECT id, %Q || pathname,"
175
- " vfile.mrid, deleted, chnged, uuid, size, mtime"
182
+ " vfile.mrid, deleted, chnged, uuid, size, mtime,"
183
+ " CASE WHEN isexe THEN %d WHEN islink THEN %d ELSE %d END"
176184
" FROM vfile LEFT JOIN blob ON vfile.mrid=blob.rid"
177
- " WHERE vid=%d ", g.zLocalRoot, vid);
185
+ " WHERE vid=%d ", g.zLocalRoot, PERM_EXE, PERM_LNK, PERM_REG,
186
+ vid);
178187
while( db_step(&q)==SQLITE_ROW ){
179188
int id, rid, isDeleted;
180189
const char *zName;
181190
int chnged = 0;
182191
int oldChnged;
192
+ int origPerm;
193
+ int currentPerm;
183194
i64 oldMtime;
184195
i64 currentMtime;
185196
i64 origSize;
186197
i64 currentSize;
187198
@@ -192,10 +203,12 @@
192203
oldChnged = chnged = db_column_int(&q, 4);
193204
oldMtime = db_column_int64(&q, 7);
194205
origSize = db_column_int64(&q, 6);
195206
currentSize = file_wd_size(zName);
196207
currentMtime = file_wd_mtime(0);
208
+ origPerm = db_column_int(&q, 8);
209
+ currentPerm = file_wd_perm(zName);
197210
if( chnged==0 && (isDeleted || rid==0) ){
198211
/* "fossil rm" or "fossil add" always change the file */
199212
chnged = 1;
200213
}else if( !file_wd_isfile_or_link(0) && currentSize>=0 ){
201214
if( cksigFlags & CKSIG_ENOTFILE ){
@@ -245,10 +258,25 @@
245258
file_set_mtime(zName, desiredMtime);
246259
currentMtime = file_wd_mtime(zName);
247260
}
248261
}
249262
}
263
+#ifndef _WIN32
264
+ if( chnged==0 || chnged==6 || chnged==7 || chnged==8 || chnged==9 ){
265
+ if( origPerm == currentPerm ){
266
+ chnged = 0;
267
+ }else if( currentPerm == PERM_EXE ){
268
+ chnged = 6;
269
+ }else if( currentPerm == PERM_LNK ){
270
+ chnged = 7;
271
+ }else if( origPerm == PERM_EXE ){
272
+ chnged = 8;
273
+ }else if( origPerm == PERM_LNK ){
274
+ chnged = 9;
275
+ }
276
+ }
277
+#endif
250278
if( currentMtime!=oldMtime || chnged!=oldChnged ){
251279
db_multi_exec("UPDATE vfile SET mtime=%lld, chnged=%d WHERE id=%d",
252280
currentMtime, chnged, id);
253281
}
254282
}
255283
--- src/vfile.c
+++ src/vfile.c
@@ -136,15 +136,22 @@
136 #define CKSIG_SETMTIME 0x004 /* Set mtime to last check-out time */
137
138 #endif /* INTERFACE */
139
140 /*
141 ** Look at every VFILE entry with the given vid and update
142 ** VFILE.CHNGED field according to whether or not
143 ** the file has changed. 0 means no change. 1 means edited. 2 means
144 ** the file has changed due to a merge. 3 means the file was added
145 ** by a merge.
 
 
 
 
 
 
 
146 **
147 ** If VFILE.DELETED is true or if VFILE.RID is zero, then the file was either
148 ** removed from configuration management via "fossil rm" or added via
149 ** "fossil add", respectively, and in both cases we always know that
150 ** the file has changed without having the check the size, mtime,
@@ -170,18 +177,22 @@
170 int useMtime = (cksigFlags & CKSIG_SHA1)==0
171 && db_get_boolean("mtime-changes", 1);
172
173 db_begin_transaction();
174 db_prepare(&q, "SELECT id, %Q || pathname,"
175 " vfile.mrid, deleted, chnged, uuid, size, mtime"
 
176 " FROM vfile LEFT JOIN blob ON vfile.mrid=blob.rid"
177 " WHERE vid=%d ", g.zLocalRoot, vid);
 
178 while( db_step(&q)==SQLITE_ROW ){
179 int id, rid, isDeleted;
180 const char *zName;
181 int chnged = 0;
182 int oldChnged;
 
 
183 i64 oldMtime;
184 i64 currentMtime;
185 i64 origSize;
186 i64 currentSize;
187
@@ -192,10 +203,12 @@
192 oldChnged = chnged = db_column_int(&q, 4);
193 oldMtime = db_column_int64(&q, 7);
194 origSize = db_column_int64(&q, 6);
195 currentSize = file_wd_size(zName);
196 currentMtime = file_wd_mtime(0);
 
 
197 if( chnged==0 && (isDeleted || rid==0) ){
198 /* "fossil rm" or "fossil add" always change the file */
199 chnged = 1;
200 }else if( !file_wd_isfile_or_link(0) && currentSize>=0 ){
201 if( cksigFlags & CKSIG_ENOTFILE ){
@@ -245,10 +258,25 @@
245 file_set_mtime(zName, desiredMtime);
246 currentMtime = file_wd_mtime(zName);
247 }
248 }
249 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
250 if( currentMtime!=oldMtime || chnged!=oldChnged ){
251 db_multi_exec("UPDATE vfile SET mtime=%lld, chnged=%d WHERE id=%d",
252 currentMtime, chnged, id);
253 }
254 }
255
--- src/vfile.c
+++ src/vfile.c
@@ -136,15 +136,22 @@
136 #define CKSIG_SETMTIME 0x004 /* Set mtime to last check-out time */
137
138 #endif /* INTERFACE */
139
140 /*
141 ** Look at every VFILE entry with the given vid and update VFILE.CHNGED field
142 ** according to whether or not the file has changed.
143 ** - 0 means no change.
144 ** - 1 means edited.
145 ** - 2 means changed due to a merge.
146 ** - 3 means added by a merge.
147 ** - 4 means changed due to an integrate merge.
148 ** - 5 means added by an integrate merge.
149 ** - 6 means became executable but has unmodified contents.
150 ** - 7 means became a symlink whose target equals its old contents.
151 ** - 8 means lost executable status but has unmodified contents.
152 ** - 9 means lost symlink status and has contents equal to its old target.
153 **
154 ** If VFILE.DELETED is true or if VFILE.RID is zero, then the file was either
155 ** removed from configuration management via "fossil rm" or added via
156 ** "fossil add", respectively, and in both cases we always know that
157 ** the file has changed without having the check the size, mtime,
@@ -170,18 +177,22 @@
177 int useMtime = (cksigFlags & CKSIG_SHA1)==0
178 && db_get_boolean("mtime-changes", 1);
179
180 db_begin_transaction();
181 db_prepare(&q, "SELECT id, %Q || pathname,"
182 " vfile.mrid, deleted, chnged, uuid, size, mtime,"
183 " CASE WHEN isexe THEN %d WHEN islink THEN %d ELSE %d END"
184 " FROM vfile LEFT JOIN blob ON vfile.mrid=blob.rid"
185 " WHERE vid=%d ", g.zLocalRoot, PERM_EXE, PERM_LNK, PERM_REG,
186 vid);
187 while( db_step(&q)==SQLITE_ROW ){
188 int id, rid, isDeleted;
189 const char *zName;
190 int chnged = 0;
191 int oldChnged;
192 int origPerm;
193 int currentPerm;
194 i64 oldMtime;
195 i64 currentMtime;
196 i64 origSize;
197 i64 currentSize;
198
@@ -192,10 +203,12 @@
203 oldChnged = chnged = db_column_int(&q, 4);
204 oldMtime = db_column_int64(&q, 7);
205 origSize = db_column_int64(&q, 6);
206 currentSize = file_wd_size(zName);
207 currentMtime = file_wd_mtime(0);
208 origPerm = db_column_int(&q, 8);
209 currentPerm = file_wd_perm(zName);
210 if( chnged==0 && (isDeleted || rid==0) ){
211 /* "fossil rm" or "fossil add" always change the file */
212 chnged = 1;
213 }else if( !file_wd_isfile_or_link(0) && currentSize>=0 ){
214 if( cksigFlags & CKSIG_ENOTFILE ){
@@ -245,10 +258,25 @@
258 file_set_mtime(zName, desiredMtime);
259 currentMtime = file_wd_mtime(zName);
260 }
261 }
262 }
263 #ifndef _WIN32
264 if( chnged==0 || chnged==6 || chnged==7 || chnged==8 || chnged==9 ){
265 if( origPerm == currentPerm ){
266 chnged = 0;
267 }else if( currentPerm == PERM_EXE ){
268 chnged = 6;
269 }else if( currentPerm == PERM_LNK ){
270 chnged = 7;
271 }else if( origPerm == PERM_EXE ){
272 chnged = 8;
273 }else if( origPerm == PERM_LNK ){
274 chnged = 9;
275 }
276 }
277 #endif
278 if( currentMtime!=oldMtime || chnged!=oldChnged ){
279 db_multi_exec("UPDATE vfile SET mtime=%lld, chnged=%d WHERE id=%d",
280 currentMtime, chnged, id);
281 }
282 }
283
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -1151,11 +1151,13 @@
11511151
return zTarget+5;
11521152
}
11531153
if( strcmp(zTarget, "Sandbox")==0 ) return zTarget;
11541154
if( wiki_name_is_wellformed((const unsigned char *)zTarget)
11551155
&& ((p->state & WIKI_NOBADLINKS)==0 ||
1156
- db_exists("SELECT 1 FROM tag WHERE tagname GLOB 'wiki-%q'", zTarget))
1156
+ db_exists("SELECT 1 FROM tag WHERE tagname GLOB 'wiki-%q'"
1157
+ " AND (SELECT value FROM tagxref WHERE tagid=tag.tagid"
1158
+ " ORDER BY mtime DESC LIMIT 1) > 0", zTarget))
11571159
){
11581160
return zTarget;
11591161
}
11601162
return 0;
11611163
}
11621164
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -1151,11 +1151,13 @@
1151 return zTarget+5;
1152 }
1153 if( strcmp(zTarget, "Sandbox")==0 ) return zTarget;
1154 if( wiki_name_is_wellformed((const unsigned char *)zTarget)
1155 && ((p->state & WIKI_NOBADLINKS)==0 ||
1156 db_exists("SELECT 1 FROM tag WHERE tagname GLOB 'wiki-%q'", zTarget))
 
 
1157 ){
1158 return zTarget;
1159 }
1160 return 0;
1161 }
1162
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -1151,11 +1151,13 @@
1151 return zTarget+5;
1152 }
1153 if( strcmp(zTarget, "Sandbox")==0 ) return zTarget;
1154 if( wiki_name_is_wellformed((const unsigned char *)zTarget)
1155 && ((p->state & WIKI_NOBADLINKS)==0 ||
1156 db_exists("SELECT 1 FROM tag WHERE tagname GLOB 'wiki-%q'"
1157 " AND (SELECT value FROM tagxref WHERE tagid=tag.tagid"
1158 " ORDER BY mtime DESC LIMIT 1) > 0", zTarget))
1159 ){
1160 return zTarget;
1161 }
1162 return 0;
1163 }
1164
+1 -1
--- src/xfer.c
+++ src/xfer.c
@@ -1973,10 +1973,10 @@
19731973
manifest_crosslink_end(MC_PERMIT_HOOKS);
19741974
content_enable_dephantomize(1);
19751975
db_end_transaction(0);
19761976
}
19771977
if( (syncFlags & SYNC_CLONE)==0 && g.rcvid && fossil_any_has_fork(g.rcvid) ){
1978
- fossil_warning("***** WARNING: multiple leaves on the same branch are formed *****\n"
1978
+ fossil_warning("***** WARNING: a fork has occurred *****\n"
19791979
"use \"fossil info\" for more details.");
19801980
}
19811981
return nErr;
19821982
}
19831983
19841984
ADDED test/contains-selector.test
--- src/xfer.c
+++ src/xfer.c
@@ -1973,10 +1973,10 @@
1973 manifest_crosslink_end(MC_PERMIT_HOOKS);
1974 content_enable_dephantomize(1);
1975 db_end_transaction(0);
1976 }
1977 if( (syncFlags & SYNC_CLONE)==0 && g.rcvid && fossil_any_has_fork(g.rcvid) ){
1978 fossil_warning("***** WARNING: multiple leaves on the same branch are formed *****\n"
1979 "use \"fossil info\" for more details.");
1980 }
1981 return nErr;
1982 }
1983
1984 DDED test/contains-selector.test
--- src/xfer.c
+++ src/xfer.c
@@ -1973,10 +1973,10 @@
1973 manifest_crosslink_end(MC_PERMIT_HOOKS);
1974 content_enable_dephantomize(1);
1975 db_end_transaction(0);
1976 }
1977 if( (syncFlags & SYNC_CLONE)==0 && g.rcvid && fossil_any_has_fork(g.rcvid) ){
1978 fossil_warning("***** WARNING: a fork has occurred *****\n"
1979 "use \"fossil info\" for more details.");
1980 }
1981 return nErr;
1982 }
1983
1984 DDED test/contains-selector.test
+1 -1
--- src/xfer.c
+++ src/xfer.c
@@ -1973,10 +1973,10 @@
19731973
manifest_crosslink_end(MC_PERMIT_HOOKS);
19741974
content_enable_dephantomize(1);
19751975
db_end_transaction(0);
19761976
}
19771977
if( (syncFlags & SYNC_CLONE)==0 && g.rcvid && fossil_any_has_fork(g.rcvid) ){
1978
- fossil_warning("***** WARNING: multiple leaves on the same branch are formed *****\n"
1978
+ fossil_warning("***** WARNING: a fork has occurred *****\n"
19791979
"use \"fossil info\" for more details.");
19801980
}
19811981
return nErr;
19821982
}
19831983
19841984
ADDED test/contains-selector.test
--- src/xfer.c
+++ src/xfer.c
@@ -1973,10 +1973,10 @@
1973 manifest_crosslink_end(MC_PERMIT_HOOKS);
1974 content_enable_dephantomize(1);
1975 db_end_transaction(0);
1976 }
1977 if( (syncFlags & SYNC_CLONE)==0 && g.rcvid && fossil_any_has_fork(g.rcvid) ){
1978 fossil_warning("***** WARNING: multiple leaves on the same branch are formed *****\n"
1979 "use \"fossil info\" for more details.");
1980 }
1981 return nErr;
1982 }
1983
1984 DDED test/contains-selector.test
--- src/xfer.c
+++ src/xfer.c
@@ -1973,10 +1973,10 @@
1973 manifest_crosslink_end(MC_PERMIT_HOOKS);
1974 content_enable_dephantomize(1);
1975 db_end_transaction(0);
1976 }
1977 if( (syncFlags & SYNC_CLONE)==0 && g.rcvid && fossil_any_has_fork(g.rcvid) ){
1978 fossil_warning("***** WARNING: a fork has occurred *****\n"
1979 "use \"fossil info\" for more details.");
1980 }
1981 return nErr;
1982 }
1983
1984 DDED test/contains-selector.test
--- a/test/contains-selector.test
+++ b/test/contains-selector.test
@@ -0,0 +1,43 @@
1
+#
2
+# Copyright (c) 2015 D. Richard Hipp
3
+#
4
+# This program is free software; you can redistribute it and/or
5
+# modify it under the terms of the Simplified BSD License (also
6
+# known as the "2-Clause License" or "FreeBSD License".)
7
+#
8
+# This program is distributed in the hope that it will be useful,
9
+# but without any warranty; without even the implied warranty of
10
+# merchantability or fitness for a particular purpose.
11
+#
12
+# Author contact information:
13
+# [email protected]
14
+# http://www.hwaci.com/drh/
15
+#
16
+############################################################################
17
+#
18
+# Test containsSelector() proc contains-selector {testId css selectorResultMap} {
19
+ set css [string trim $css]
20
+ set filename [file join $::tempPath compare-selector.css]
21
+ set fh [open $filename w]
22
+ puts -nonewline $fh $css
23
+ close $fh
24
+ foreach {selector found} $selectorResultMap {
25
+ set expected "$selector [expr {$found ? "found" : "not found"}]"
26
+ set result [fossil test-contains-selector $filename $selector]
27
+ test "contains-selector $testId $selector" {$result eq $expected}
28
+ }
29
+ file delete $filename
30
+}
31
+
32
+contains-selector 1 {
33
+ .a.b {}
34
+ .c .de {}
35
+ /* comment */
36
+ .c .d, .e /* comment */ {}
37
+} {
38
+ .a 0
39
+ .b 0
40
+ .a.b 1
41
+ .c 0
42
+ .d 0
43
+ {.c
--- a/test/contains-selector.test
+++ b/test/contains-selector.test
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/test/contains-selector.test
+++ b/test/contains-selector.test
@@ -0,0 +1,43 @@
1 #
2 # Copyright (c) 2015 D. Richard Hipp
3 #
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the Simplified BSD License (also
6 # known as the "2-Clause License" or "FreeBSD License".)
7 #
8 # This program is distributed in the hope that it will be useful,
9 # but without any warranty; without even the implied warranty of
10 # merchantability or fitness for a particular purpose.
11 #
12 # Author contact information:
13 # [email protected]
14 # http://www.hwaci.com/drh/
15 #
16 ############################################################################
17 #
18 # Test containsSelector() proc contains-selector {testId css selectorResultMap} {
19 set css [string trim $css]
20 set filename [file join $::tempPath compare-selector.css]
21 set fh [open $filename w]
22 puts -nonewline $fh $css
23 close $fh
24 foreach {selector found} $selectorResultMap {
25 set expected "$selector [expr {$found ? "found" : "not found"}]"
26 set result [fossil test-contains-selector $filename $selector]
27 test "contains-selector $testId $selector" {$result eq $expected}
28 }
29 file delete $filename
30 }
31
32 contains-selector 1 {
33 .a.b {}
34 .c .de {}
35 /* comment */
36 .c .d, .e /* comment */ {}
37 } {
38 .a 0
39 .b 0
40 .a.b 1
41 .c 0
42 .d 0
43 {.c
--- win/Makefile.PellesCGMake
+++ win/Makefile.PellesCGMake
@@ -83,11 +83,11 @@
8383
8484
# define the SQLite files, which need special flags on compile
8585
SQLITESRC=sqlite3.c
8686
ORIGSQLITESRC=$(foreach sf,$(SQLITESRC),$(SRCDIR)$(sf))
8787
SQLITEOBJ=$(foreach sf,$(SQLITESRC),$(sf:.c=.obj))
88
-SQLITEDEFINES=-DNDEBUG=1 -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_OMIT_DEPRECATED -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS3_PARENTHESIS -DSQLITE_WIN32_NO_ANSI
88
+SQLITEDEFINES=-DNDEBUG=1 -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_OMIT_DEPRECATED -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS3_PARENTHESIS -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_WIN32_NO_ANSI
8989
9090
# define the SQLite shell files, which need special flags on compile
9191
SQLITESHELLSRC=shell.c
9292
ORIGSQLITESHELLSRC=$(foreach sf,$(SQLITESHELLSRC),$(SRCDIR)$(sf))
9393
SQLITESHELLOBJ=$(foreach sf,$(SQLITESHELLSRC),$(sf:.c=.obj))
9494
--- win/Makefile.PellesCGMake
+++ win/Makefile.PellesCGMake
@@ -83,11 +83,11 @@
83
84 # define the SQLite files, which need special flags on compile
85 SQLITESRC=sqlite3.c
86 ORIGSQLITESRC=$(foreach sf,$(SQLITESRC),$(SRCDIR)$(sf))
87 SQLITEOBJ=$(foreach sf,$(SQLITESRC),$(sf:.c=.obj))
88 SQLITEDEFINES=-DNDEBUG=1 -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_OMIT_DEPRECATED -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS3_PARENTHESIS -DSQLITE_WIN32_NO_ANSI
89
90 # define the SQLite shell files, which need special flags on compile
91 SQLITESHELLSRC=shell.c
92 ORIGSQLITESHELLSRC=$(foreach sf,$(SQLITESHELLSRC),$(SRCDIR)$(sf))
93 SQLITESHELLOBJ=$(foreach sf,$(SQLITESHELLSRC),$(sf:.c=.obj))
94
--- win/Makefile.PellesCGMake
+++ win/Makefile.PellesCGMake
@@ -83,11 +83,11 @@
83
84 # define the SQLite files, which need special flags on compile
85 SQLITESRC=sqlite3.c
86 ORIGSQLITESRC=$(foreach sf,$(SQLITESRC),$(SRCDIR)$(sf))
87 SQLITEOBJ=$(foreach sf,$(SQLITESRC),$(sf:.c=.obj))
88 SQLITEDEFINES=-DNDEBUG=1 -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_OMIT_DEPRECATED -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS3_PARENTHESIS -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_WIN32_NO_ANSI
89
90 # define the SQLite shell files, which need special flags on compile
91 SQLITESHELLSRC=shell.c
92 ORIGSQLITESHELLSRC=$(foreach sf,$(SQLITESHELLSRC),$(SRCDIR)$(sf))
93 SQLITESHELLOBJ=$(foreach sf,$(SQLITESHELLSRC),$(sf:.c=.obj))
94
+11 -5
--- win/Makefile.dmc
+++ win/Makefile.dmc
@@ -24,17 +24,17 @@
2424
CFLAGS = -o
2525
BCC = $(DMDIR)\bin\dmc $(CFLAGS)
2626
TCC = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(SSL) $(INCL)
2727
LIBS = $(DMDIR)\extra\lib\ zlib wsock32 advapi32
2828
29
-SQLITE_OPTIONS = -DNDEBUG=1 -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_OMIT_DEPRECATED -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS3_PARENTHESIS
29
+SQLITE_OPTIONS = -DNDEBUG=1 -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_OMIT_DEPRECATED -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS3_PARENTHESIS -DSQLITE_ENABLE_DBSTAT_VTAB
3030
3131
SHELL_OPTIONS = -Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 -DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) -DSQLITE_SHELL_DBNAME_PROC=fossil_open -Daccess=file_access -Dsystem=fossil_system -Dgetenv=fossil_getenv -Dfopen=fossil_fopen
3232
33
-SRC = add_.c allrepo_.c attach_.c bag_.c bisect_.c blob_.c branch_.c browse_.c builtin_.c bundle_.c cache_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.c delta_.c deltacmd_.c descendants_.c diff_.c diffcmd_.c doc_.c encode_.c event_.c export_.c file_.c finfo_.c foci_.c fusefs_.c glob_.c graph_.c gzip_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c json_.c json_artifact_.c json_branch_.c json_config_.c json_diff_.c json_dir_.c json_finfo_.c json_login_.c json_query_.c json_report_.c json_status_.c json_tag_.c json_timeline_.c json_user_.c json_wiki_.c leaf_.c loadctrl_.c login_.c lookslike_.c main_.c manifest_.c markdown_.c markdown_html_.c md5_.c merge_.c merge3_.c moderate_.c name_.c path_.c pivot_.c popen_.c pqueue_.c printf_.c publish_.c purge_.c rebuild_.c regexp_.c report_.c rss_.c schema_.c search_.c setup_.c sha1_.c shun_.c sitemap_.c skins_.c sqlcmd_.c stash_.c stat_.c statrep_.c style_.c sync_.c tag_.c tar_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c unicode_.c update_.c url_.c user_.c utf8_.c util_.c verify_.c vfile_.c wiki_.c wikiformat_.c winfile_.c winhttp_.c wysiwyg_.c xfer_.c xfersetup_.c zip_.c
33
+SRC = add_.c allrepo_.c attach_.c bag_.c bisect_.c blob_.c branch_.c browse_.c builtin_.c bundle_.c cache_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.c delta_.c deltacmd_.c descendants_.c diff_.c diffcmd_.c doc_.c encode_.c event_.c export_.c file_.c finfo_.c foci_.c fusefs_.c glob_.c graph_.c gzip_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c json_.c json_artifact_.c json_branch_.c json_config_.c json_diff_.c json_dir_.c json_finfo_.c json_login_.c json_query_.c json_report_.c json_status_.c json_tag_.c json_timeline_.c json_user_.c json_wiki_.c leaf_.c loadctrl_.c login_.c lookslike_.c main_.c manifest_.c markdown_.c markdown_html_.c md5_.c merge_.c merge3_.c moderate_.c name_.c path_.c piechart_.c pivot_.c popen_.c pqueue_.c printf_.c publish_.c purge_.c rebuild_.c regexp_.c report_.c rss_.c schema_.c search_.c setup_.c sha1_.c shun_.c sitemap_.c skins_.c sqlcmd_.c stash_.c stat_.c statrep_.c style_.c sync_.c tag_.c tar_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c unicode_.c update_.c url_.c user_.c utf8_.c util_.c verify_.c vfile_.c wiki_.c wikiformat_.c winfile_.c winhttp_.c wysiwyg_.c xfer_.c xfersetup_.c zip_.c
3434
35
-OBJ = $(OBJDIR)\add$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\bag$O $(OBJDIR)\bisect$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\builtin$O $(OBJDIR)\bundle$O $(OBJDIR)\cache$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\db$O $(OBJDIR)\delta$O $(OBJDIR)\deltacmd$O $(OBJDIR)\descendants$O $(OBJDIR)\diff$O $(OBJDIR)\diffcmd$O $(OBJDIR)\doc$O $(OBJDIR)\encode$O $(OBJDIR)\event$O $(OBJDIR)\export$O $(OBJDIR)\file$O $(OBJDIR)\finfo$O $(OBJDIR)\foci$O $(OBJDIR)\fusefs$O $(OBJDIR)\glob$O $(OBJDIR)\graph$O $(OBJDIR)\gzip$O $(OBJDIR)\http$O $(OBJDIR)\http_socket$O $(OBJDIR)\http_ssl$O $(OBJDIR)\http_transport$O $(OBJDIR)\import$O $(OBJDIR)\info$O $(OBJDIR)\json$O $(OBJDIR)\json_artifact$O $(OBJDIR)\json_branch$O $(OBJDIR)\json_config$O $(OBJDIR)\json_diff$O $(OBJDIR)\json_dir$O $(OBJDIR)\json_finfo$O $(OBJDIR)\json_login$O $(OBJDIR)\json_query$O $(OBJDIR)\json_report$O $(OBJDIR)\json_status$O $(OBJDIR)\json_tag$O $(OBJDIR)\json_timeline$O $(OBJDIR)\json_user$O $(OBJDIR)\json_wiki$O $(OBJDIR)\leaf$O $(OBJDIR)\loadctrl$O $(OBJDIR)\login$O $(OBJDIR)\lookslike$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\markdown$O $(OBJDIR)\markdown_html$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\moderate$O $(OBJDIR)\name$O $(OBJDIR)\path$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\publish$O $(OBJDIR)\purge$O $(OBJDIR)\rebuild$O $(OBJDIR)\regexp$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\setup$O $(OBJDIR)\sha1$O $(OBJDIR)\shun$O $(OBJDIR)\sitemap$O $(OBJDIR)\skins$O $(OBJDIR)\sqlcmd$O $(OBJDIR)\stash$O $(OBJDIR)\stat$O $(OBJDIR)\statrep$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\tar$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\unicode$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\utf8$O $(OBJDIR)\util$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winfile$O $(OBJDIR)\winhttp$O $(OBJDIR)\wysiwyg$O $(OBJDIR)\xfer$O $(OBJDIR)\xfersetup$O $(OBJDIR)\zip$O $(OBJDIR)\shell$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O
35
+OBJ = $(OBJDIR)\add$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\bag$O $(OBJDIR)\bisect$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\builtin$O $(OBJDIR)\bundle$O $(OBJDIR)\cache$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\db$O $(OBJDIR)\delta$O $(OBJDIR)\deltacmd$O $(OBJDIR)\descendants$O $(OBJDIR)\diff$O $(OBJDIR)\diffcmd$O $(OBJDIR)\doc$O $(OBJDIR)\encode$O $(OBJDIR)\event$O $(OBJDIR)\export$O $(OBJDIR)\file$O $(OBJDIR)\finfo$O $(OBJDIR)\foci$O $(OBJDIR)\fusefs$O $(OBJDIR)\glob$O $(OBJDIR)\graph$O $(OBJDIR)\gzip$O $(OBJDIR)\http$O $(OBJDIR)\http_socket$O $(OBJDIR)\http_ssl$O $(OBJDIR)\http_transport$O $(OBJDIR)\import$O $(OBJDIR)\info$O $(OBJDIR)\json$O $(OBJDIR)\json_artifact$O $(OBJDIR)\json_branch$O $(OBJDIR)\json_config$O $(OBJDIR)\json_diff$O $(OBJDIR)\json_dir$O $(OBJDIR)\json_finfo$O $(OBJDIR)\json_login$O $(OBJDIR)\json_query$O $(OBJDIR)\json_report$O $(OBJDIR)\json_status$O $(OBJDIR)\json_tag$O $(OBJDIR)\json_timeline$O $(OBJDIR)\json_user$O $(OBJDIR)\json_wiki$O $(OBJDIR)\leaf$O $(OBJDIR)\loadctrl$O $(OBJDIR)\login$O $(OBJDIR)\lookslike$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\markdown$O $(OBJDIR)\markdown_html$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\moderate$O $(OBJDIR)\name$O $(OBJDIR)\path$O $(OBJDIR)\piechart$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\publish$O $(OBJDIR)\purge$O $(OBJDIR)\rebuild$O $(OBJDIR)\regexp$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\setup$O $(OBJDIR)\sha1$O $(OBJDIR)\shun$O $(OBJDIR)\sitemap$O $(OBJDIR)\skins$O $(OBJDIR)\sqlcmd$O $(OBJDIR)\stash$O $(OBJDIR)\stat$O $(OBJDIR)\statrep$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\tar$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\unicode$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\utf8$O $(OBJDIR)\util$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winfile$O $(OBJDIR)\winhttp$O $(OBJDIR)\wysiwyg$O $(OBJDIR)\xfer$O $(OBJDIR)\xfersetup$O $(OBJDIR)\zip$O $(OBJDIR)\shell$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O
3636
3737
3838
RC=$(DMDIR)\bin\rcc
3939
RCFLAGS=-32 -w1 -I$(SRCDIR) /D__DMC__
4040
@@ -49,11 +49,11 @@
4949
5050
$(OBJDIR)\fossil.res: $B\win\fossil.rc
5151
$(RC) $(RCFLAGS) -o$@ $**
5252
5353
$(OBJDIR)\link: $B\win\Makefile.dmc $(OBJDIR)\fossil.res
54
- +echo add allrepo attach bag bisect blob branch browse builtin bundle cache captcha cgi checkin checkout clearsign clone comformat configure content db delta deltacmd descendants diff diffcmd doc encode event export file finfo foci fusefs glob graph gzip http http_socket http_ssl http_transport import info json json_artifact json_branch json_config json_diff json_dir json_finfo json_login json_query json_report json_status json_tag json_timeline json_user json_wiki leaf loadctrl login lookslike main manifest markdown markdown_html md5 merge merge3 moderate name path pivot popen pqueue printf publish purge rebuild regexp report rss schema search setup sha1 shun sitemap skins sqlcmd stash stat statrep style sync tag tar th_main timeline tkt tktsetup undo unicode update url user utf8 util verify vfile wiki wikiformat winfile winhttp wysiwyg xfer xfersetup zip shell sqlite3 th th_lang > $@
54
+ +echo add allrepo attach bag bisect blob branch browse builtin bundle cache captcha cgi checkin checkout clearsign clone comformat configure content db delta deltacmd descendants diff diffcmd doc encode event export file finfo foci fusefs glob graph gzip http http_socket http_ssl http_transport import info json json_artifact json_branch json_config json_diff json_dir json_finfo json_login json_query json_report json_status json_tag json_timeline json_user json_wiki leaf loadctrl login lookslike main manifest markdown markdown_html md5 merge merge3 moderate name path piechart pivot popen pqueue printf publish purge rebuild regexp report rss schema search setup sha1 shun sitemap skins sqlcmd stash stat statrep style sync tag tar th_main timeline tkt tktsetup undo unicode update url user utf8 util verify vfile wiki wikiformat winfile winhttp wysiwyg xfer xfersetup zip shell sqlite3 th th_lang > $@
5555
+echo fossil >> $@
5656
+echo fossil >> $@
5757
+echo $(LIBS) >> $@
5858
+echo. >> $@
5959
+echo fossil >> $@
@@ -554,10 +554,16 @@
554554
$(OBJDIR)\path$O : path_.c path.h
555555
$(TCC) -o$@ -c path_.c
556556
557557
path_.c : $(SRCDIR)\path.c
558558
+translate$E $** > $@
559
+
560
+$(OBJDIR)\piechart$O : piechart_.c piechart.h
561
+ $(TCC) -o$@ -c piechart_.c
562
+
563
+piechart_.c : $(SRCDIR)\piechart.c
564
+ +translate$E $** > $@
559565
560566
$(OBJDIR)\pivot$O : pivot_.c pivot.h
561567
$(TCC) -o$@ -c pivot_.c
562568
563569
pivot_.c : $(SRCDIR)\pivot.c
@@ -832,7 +838,7 @@
832838
833839
zip_.c : $(SRCDIR)\zip.c
834840
+translate$E $** > $@
835841
836842
headers: makeheaders$E page_index.h builtin_data.h VERSION.h
837
- +makeheaders$E add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h builtin_.c:builtin.h bundle_.c:bundle.h cache_.c:cache.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h event_.c:event.h export_.c:export.h file_.c:file.h finfo_.c:finfo.h foci_.c:foci.h fusefs_.c:fusefs.h glob_.c:glob.h graph_.c:graph.h gzip_.c:gzip.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h import_.c:import.h info_.c:info.h json_.c:json.h json_artifact_.c:json_artifact.h json_branch_.c:json_branch.h json_config_.c:json_config.h json_diff_.c:json_diff.h json_dir_.c:json_dir.h json_finfo_.c:json_finfo.h json_login_.c:json_login.h json_query_.c:json_query.h json_report_.c:json_report.h json_status_.c:json_status.h json_tag_.c:json_tag.h json_timeline_.c:json_timeline.h json_user_.c:json_user.h json_wiki_.c:json_wiki.h leaf_.c:leaf.h loadctrl_.c:loadctrl.h login_.c:login.h lookslike_.c:lookslike.h main_.c:main.h manifest_.c:manifest.h markdown_.c:markdown.h markdown_html_.c:markdown_html.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h moderate_.c:moderate.h name_.c:name.h path_.c:path.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h publish_.c:publish.h purge_.c:purge.h rebuild_.c:rebuild.h regexp_.c:regexp.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h sitemap_.c:sitemap.h skins_.c:skins.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.h statrep_.c:statrep.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tar_.c:tar.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h unicode_.c:unicode.h update_.c:update.h url_.c:url.h user_.c:user.h utf8_.c:utf8.h util_.c:util.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winfile_.c:winfile.h winhttp_.c:winhttp.h wysiwyg_.c:wysiwyg.h xfer_.c:xfer.h xfersetup_.c:xfersetup.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h $(SRCDIR)\cson_amalgamation.h
843
+ +makeheaders$E add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h builtin_.c:builtin.h bundle_.c:bundle.h cache_.c:cache.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h event_.c:event.h export_.c:export.h file_.c:file.h finfo_.c:finfo.h foci_.c:foci.h fusefs_.c:fusefs.h glob_.c:glob.h graph_.c:graph.h gzip_.c:gzip.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h import_.c:import.h info_.c:info.h json_.c:json.h json_artifact_.c:json_artifact.h json_branch_.c:json_branch.h json_config_.c:json_config.h json_diff_.c:json_diff.h json_dir_.c:json_dir.h json_finfo_.c:json_finfo.h json_login_.c:json_login.h json_query_.c:json_query.h json_report_.c:json_report.h json_status_.c:json_status.h json_tag_.c:json_tag.h json_timeline_.c:json_timeline.h json_user_.c:json_user.h json_wiki_.c:json_wiki.h leaf_.c:leaf.h loadctrl_.c:loadctrl.h login_.c:login.h lookslike_.c:lookslike.h main_.c:main.h manifest_.c:manifest.h markdown_.c:markdown.h markdown_html_.c:markdown_html.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h moderate_.c:moderate.h name_.c:name.h path_.c:path.h piechart_.c:piechart.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h publish_.c:publish.h purge_.c:purge.h rebuild_.c:rebuild.h regexp_.c:regexp.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h sitemap_.c:sitemap.h skins_.c:skins.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.h statrep_.c:statrep.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tar_.c:tar.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h unicode_.c:unicode.h update_.c:update.h url_.c:url.h user_.c:user.h utf8_.c:utf8.h util_.c:util.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winfile_.c:winfile.h winhttp_.c:winhttp.h wysiwyg_.c:wysiwyg.h xfer_.c:xfer.h xfersetup_.c:xfersetup.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h $(SRCDIR)\cson_amalgamation.h
838844
@copy /Y nul: headers
839845
--- win/Makefile.dmc
+++ win/Makefile.dmc
@@ -24,17 +24,17 @@
24 CFLAGS = -o
25 BCC = $(DMDIR)\bin\dmc $(CFLAGS)
26 TCC = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(SSL) $(INCL)
27 LIBS = $(DMDIR)\extra\lib\ zlib wsock32 advapi32
28
29 SQLITE_OPTIONS = -DNDEBUG=1 -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_OMIT_DEPRECATED -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS3_PARENTHESIS
30
31 SHELL_OPTIONS = -Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 -DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) -DSQLITE_SHELL_DBNAME_PROC=fossil_open -Daccess=file_access -Dsystem=fossil_system -Dgetenv=fossil_getenv -Dfopen=fossil_fopen
32
33 SRC = add_.c allrepo_.c attach_.c bag_.c bisect_.c blob_.c branch_.c browse_.c builtin_.c bundle_.c cache_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.c delta_.c deltacmd_.c descendants_.c diff_.c diffcmd_.c doc_.c encode_.c event_.c export_.c file_.c finfo_.c foci_.c fusefs_.c glob_.c graph_.c gzip_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c json_.c json_artifact_.c json_branch_.c json_config_.c json_diff_.c json_dir_.c json_finfo_.c json_login_.c json_query_.c json_report_.c json_status_.c json_tag_.c json_timeline_.c json_user_.c json_wiki_.c leaf_.c loadctrl_.c login_.c lookslike_.c main_.c manifest_.c markdown_.c markdown_html_.c md5_.c merge_.c merge3_.c moderate_.c name_.c path_.c pivot_.c popen_.c pqueue_.c printf_.c publish_.c purge_.c rebuild_.c regexp_.c report_.c rss_.c schema_.c search_.c setup_.c sha1_.c shun_.c sitemap_.c skins_.c sqlcmd_.c stash_.c stat_.c statrep_.c style_.c sync_.c tag_.c tar_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c unicode_.c update_.c url_.c user_.c utf8_.c util_.c verify_.c vfile_.c wiki_.c wikiformat_.c winfile_.c winhttp_.c wysiwyg_.c xfer_.c xfersetup_.c zip_.c
34
35 OBJ = $(OBJDIR)\add$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\bag$O $(OBJDIR)\bisect$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\builtin$O $(OBJDIR)\bundle$O $(OBJDIR)\cache$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\db$O $(OBJDIR)\delta$O $(OBJDIR)\deltacmd$O $(OBJDIR)\descendants$O $(OBJDIR)\diff$O $(OBJDIR)\diffcmd$O $(OBJDIR)\doc$O $(OBJDIR)\encode$O $(OBJDIR)\event$O $(OBJDIR)\export$O $(OBJDIR)\file$O $(OBJDIR)\finfo$O $(OBJDIR)\foci$O $(OBJDIR)\fusefs$O $(OBJDIR)\glob$O $(OBJDIR)\graph$O $(OBJDIR)\gzip$O $(OBJDIR)\http$O $(OBJDIR)\http_socket$O $(OBJDIR)\http_ssl$O $(OBJDIR)\http_transport$O $(OBJDIR)\import$O $(OBJDIR)\info$O $(OBJDIR)\json$O $(OBJDIR)\json_artifact$O $(OBJDIR)\json_branch$O $(OBJDIR)\json_config$O $(OBJDIR)\json_diff$O $(OBJDIR)\json_dir$O $(OBJDIR)\json_finfo$O $(OBJDIR)\json_login$O $(OBJDIR)\json_query$O $(OBJDIR)\json_report$O $(OBJDIR)\json_status$O $(OBJDIR)\json_tag$O $(OBJDIR)\json_timeline$O $(OBJDIR)\json_user$O $(OBJDIR)\json_wiki$O $(OBJDIR)\leaf$O $(OBJDIR)\loadctrl$O $(OBJDIR)\login$O $(OBJDIR)\lookslike$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\markdown$O $(OBJDIR)\markdown_html$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\moderate$O $(OBJDIR)\name$O $(OBJDIR)\path$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\publish$O $(OBJDIR)\purge$O $(OBJDIR)\rebuild$O $(OBJDIR)\regexp$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\setup$O $(OBJDIR)\sha1$O $(OBJDIR)\shun$O $(OBJDIR)\sitemap$O $(OBJDIR)\skins$O $(OBJDIR)\sqlcmd$O $(OBJDIR)\stash$O $(OBJDIR)\stat$O $(OBJDIR)\statrep$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\tar$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\unicode$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\utf8$O $(OBJDIR)\util$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winfile$O $(OBJDIR)\winhttp$O $(OBJDIR)\wysiwyg$O $(OBJDIR)\xfer$O $(OBJDIR)\xfersetup$O $(OBJDIR)\zip$O $(OBJDIR)\shell$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O
36
37
38 RC=$(DMDIR)\bin\rcc
39 RCFLAGS=-32 -w1 -I$(SRCDIR) /D__DMC__
40
@@ -49,11 +49,11 @@
49
50 $(OBJDIR)\fossil.res: $B\win\fossil.rc
51 $(RC) $(RCFLAGS) -o$@ $**
52
53 $(OBJDIR)\link: $B\win\Makefile.dmc $(OBJDIR)\fossil.res
54 +echo add allrepo attach bag bisect blob branch browse builtin bundle cache captcha cgi checkin checkout clearsign clone comformat configure content db delta deltacmd descendants diff diffcmd doc encode event export file finfo foci fusefs glob graph gzip http http_socket http_ssl http_transport import info json json_artifact json_branch json_config json_diff json_dir json_finfo json_login json_query json_report json_status json_tag json_timeline json_user json_wiki leaf loadctrl login lookslike main manifest markdown markdown_html md5 merge merge3 moderate name path pivot popen pqueue printf publish purge rebuild regexp report rss schema search setup sha1 shun sitemap skins sqlcmd stash stat statrep style sync tag tar th_main timeline tkt tktsetup undo unicode update url user utf8 util verify vfile wiki wikiformat winfile winhttp wysiwyg xfer xfersetup zip shell sqlite3 th th_lang > $@
55 +echo fossil >> $@
56 +echo fossil >> $@
57 +echo $(LIBS) >> $@
58 +echo. >> $@
59 +echo fossil >> $@
@@ -554,10 +554,16 @@
554 $(OBJDIR)\path$O : path_.c path.h
555 $(TCC) -o$@ -c path_.c
556
557 path_.c : $(SRCDIR)\path.c
558 +translate$E $** > $@
 
 
 
 
 
 
559
560 $(OBJDIR)\pivot$O : pivot_.c pivot.h
561 $(TCC) -o$@ -c pivot_.c
562
563 pivot_.c : $(SRCDIR)\pivot.c
@@ -832,7 +838,7 @@
832
833 zip_.c : $(SRCDIR)\zip.c
834 +translate$E $** > $@
835
836 headers: makeheaders$E page_index.h builtin_data.h VERSION.h
837 +makeheaders$E add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h builtin_.c:builtin.h bundle_.c:bundle.h cache_.c:cache.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h event_.c:event.h export_.c:export.h file_.c:file.h finfo_.c:finfo.h foci_.c:foci.h fusefs_.c:fusefs.h glob_.c:glob.h graph_.c:graph.h gzip_.c:gzip.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h import_.c:import.h info_.c:info.h json_.c:json.h json_artifact_.c:json_artifact.h json_branch_.c:json_branch.h json_config_.c:json_config.h json_diff_.c:json_diff.h json_dir_.c:json_dir.h json_finfo_.c:json_finfo.h json_login_.c:json_login.h json_query_.c:json_query.h json_report_.c:json_report.h json_status_.c:json_status.h json_tag_.c:json_tag.h json_timeline_.c:json_timeline.h json_user_.c:json_user.h json_wiki_.c:json_wiki.h leaf_.c:leaf.h loadctrl_.c:loadctrl.h login_.c:login.h lookslike_.c:lookslike.h main_.c:main.h manifest_.c:manifest.h markdown_.c:markdown.h markdown_html_.c:markdown_html.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h moderate_.c:moderate.h name_.c:name.h path_.c:path.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h publish_.c:publish.h purge_.c:purge.h rebuild_.c:rebuild.h regexp_.c:regexp.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h sitemap_.c:sitemap.h skins_.c:skins.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.h statrep_.c:statrep.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tar_.c:tar.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h unicode_.c:unicode.h update_.c:update.h url_.c:url.h user_.c:user.h utf8_.c:utf8.h util_.c:util.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winfile_.c:winfile.h winhttp_.c:winhttp.h wysiwyg_.c:wysiwyg.h xfer_.c:xfer.h xfersetup_.c:xfersetup.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h $(SRCDIR)\cson_amalgamation.h
838 @copy /Y nul: headers
839
--- win/Makefile.dmc
+++ win/Makefile.dmc
@@ -24,17 +24,17 @@
24 CFLAGS = -o
25 BCC = $(DMDIR)\bin\dmc $(CFLAGS)
26 TCC = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(SSL) $(INCL)
27 LIBS = $(DMDIR)\extra\lib\ zlib wsock32 advapi32
28
29 SQLITE_OPTIONS = -DNDEBUG=1 -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_OMIT_DEPRECATED -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS3_PARENTHESIS -DSQLITE_ENABLE_DBSTAT_VTAB
30
31 SHELL_OPTIONS = -Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 -DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) -DSQLITE_SHELL_DBNAME_PROC=fossil_open -Daccess=file_access -Dsystem=fossil_system -Dgetenv=fossil_getenv -Dfopen=fossil_fopen
32
33 SRC = add_.c allrepo_.c attach_.c bag_.c bisect_.c blob_.c branch_.c browse_.c builtin_.c bundle_.c cache_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.c delta_.c deltacmd_.c descendants_.c diff_.c diffcmd_.c doc_.c encode_.c event_.c export_.c file_.c finfo_.c foci_.c fusefs_.c glob_.c graph_.c gzip_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c json_.c json_artifact_.c json_branch_.c json_config_.c json_diff_.c json_dir_.c json_finfo_.c json_login_.c json_query_.c json_report_.c json_status_.c json_tag_.c json_timeline_.c json_user_.c json_wiki_.c leaf_.c loadctrl_.c login_.c lookslike_.c main_.c manifest_.c markdown_.c markdown_html_.c md5_.c merge_.c merge3_.c moderate_.c name_.c path_.c piechart_.c pivot_.c popen_.c pqueue_.c printf_.c publish_.c purge_.c rebuild_.c regexp_.c report_.c rss_.c schema_.c search_.c setup_.c sha1_.c shun_.c sitemap_.c skins_.c sqlcmd_.c stash_.c stat_.c statrep_.c style_.c sync_.c tag_.c tar_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c unicode_.c update_.c url_.c user_.c utf8_.c util_.c verify_.c vfile_.c wiki_.c wikiformat_.c winfile_.c winhttp_.c wysiwyg_.c xfer_.c xfersetup_.c zip_.c
34
35 OBJ = $(OBJDIR)\add$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\bag$O $(OBJDIR)\bisect$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\builtin$O $(OBJDIR)\bundle$O $(OBJDIR)\cache$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\db$O $(OBJDIR)\delta$O $(OBJDIR)\deltacmd$O $(OBJDIR)\descendants$O $(OBJDIR)\diff$O $(OBJDIR)\diffcmd$O $(OBJDIR)\doc$O $(OBJDIR)\encode$O $(OBJDIR)\event$O $(OBJDIR)\export$O $(OBJDIR)\file$O $(OBJDIR)\finfo$O $(OBJDIR)\foci$O $(OBJDIR)\fusefs$O $(OBJDIR)\glob$O $(OBJDIR)\graph$O $(OBJDIR)\gzip$O $(OBJDIR)\http$O $(OBJDIR)\http_socket$O $(OBJDIR)\http_ssl$O $(OBJDIR)\http_transport$O $(OBJDIR)\import$O $(OBJDIR)\info$O $(OBJDIR)\json$O $(OBJDIR)\json_artifact$O $(OBJDIR)\json_branch$O $(OBJDIR)\json_config$O $(OBJDIR)\json_diff$O $(OBJDIR)\json_dir$O $(OBJDIR)\json_finfo$O $(OBJDIR)\json_login$O $(OBJDIR)\json_query$O $(OBJDIR)\json_report$O $(OBJDIR)\json_status$O $(OBJDIR)\json_tag$O $(OBJDIR)\json_timeline$O $(OBJDIR)\json_user$O $(OBJDIR)\json_wiki$O $(OBJDIR)\leaf$O $(OBJDIR)\loadctrl$O $(OBJDIR)\login$O $(OBJDIR)\lookslike$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\markdown$O $(OBJDIR)\markdown_html$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\moderate$O $(OBJDIR)\name$O $(OBJDIR)\path$O $(OBJDIR)\piechart$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\publish$O $(OBJDIR)\purge$O $(OBJDIR)\rebuild$O $(OBJDIR)\regexp$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\setup$O $(OBJDIR)\sha1$O $(OBJDIR)\shun$O $(OBJDIR)\sitemap$O $(OBJDIR)\skins$O $(OBJDIR)\sqlcmd$O $(OBJDIR)\stash$O $(OBJDIR)\stat$O $(OBJDIR)\statrep$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\tar$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\unicode$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\utf8$O $(OBJDIR)\util$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winfile$O $(OBJDIR)\winhttp$O $(OBJDIR)\wysiwyg$O $(OBJDIR)\xfer$O $(OBJDIR)\xfersetup$O $(OBJDIR)\zip$O $(OBJDIR)\shell$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O
36
37
38 RC=$(DMDIR)\bin\rcc
39 RCFLAGS=-32 -w1 -I$(SRCDIR) /D__DMC__
40
@@ -49,11 +49,11 @@
49
50 $(OBJDIR)\fossil.res: $B\win\fossil.rc
51 $(RC) $(RCFLAGS) -o$@ $**
52
53 $(OBJDIR)\link: $B\win\Makefile.dmc $(OBJDIR)\fossil.res
54 +echo add allrepo attach bag bisect blob branch browse builtin bundle cache captcha cgi checkin checkout clearsign clone comformat configure content db delta deltacmd descendants diff diffcmd doc encode event export file finfo foci fusefs glob graph gzip http http_socket http_ssl http_transport import info json json_artifact json_branch json_config json_diff json_dir json_finfo json_login json_query json_report json_status json_tag json_timeline json_user json_wiki leaf loadctrl login lookslike main manifest markdown markdown_html md5 merge merge3 moderate name path piechart pivot popen pqueue printf publish purge rebuild regexp report rss schema search setup sha1 shun sitemap skins sqlcmd stash stat statrep style sync tag tar th_main timeline tkt tktsetup undo unicode update url user utf8 util verify vfile wiki wikiformat winfile winhttp wysiwyg xfer xfersetup zip shell sqlite3 th th_lang > $@
55 +echo fossil >> $@
56 +echo fossil >> $@
57 +echo $(LIBS) >> $@
58 +echo. >> $@
59 +echo fossil >> $@
@@ -554,10 +554,16 @@
554 $(OBJDIR)\path$O : path_.c path.h
555 $(TCC) -o$@ -c path_.c
556
557 path_.c : $(SRCDIR)\path.c
558 +translate$E $** > $@
559
560 $(OBJDIR)\piechart$O : piechart_.c piechart.h
561 $(TCC) -o$@ -c piechart_.c
562
563 piechart_.c : $(SRCDIR)\piechart.c
564 +translate$E $** > $@
565
566 $(OBJDIR)\pivot$O : pivot_.c pivot.h
567 $(TCC) -o$@ -c pivot_.c
568
569 pivot_.c : $(SRCDIR)\pivot.c
@@ -832,7 +838,7 @@
838
839 zip_.c : $(SRCDIR)\zip.c
840 +translate$E $** > $@
841
842 headers: makeheaders$E page_index.h builtin_data.h VERSION.h
843 +makeheaders$E add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h builtin_.c:builtin.h bundle_.c:bundle.h cache_.c:cache.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h event_.c:event.h export_.c:export.h file_.c:file.h finfo_.c:finfo.h foci_.c:foci.h fusefs_.c:fusefs.h glob_.c:glob.h graph_.c:graph.h gzip_.c:gzip.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h import_.c:import.h info_.c:info.h json_.c:json.h json_artifact_.c:json_artifact.h json_branch_.c:json_branch.h json_config_.c:json_config.h json_diff_.c:json_diff.h json_dir_.c:json_dir.h json_finfo_.c:json_finfo.h json_login_.c:json_login.h json_query_.c:json_query.h json_report_.c:json_report.h json_status_.c:json_status.h json_tag_.c:json_tag.h json_timeline_.c:json_timeline.h json_user_.c:json_user.h json_wiki_.c:json_wiki.h leaf_.c:leaf.h loadctrl_.c:loadctrl.h login_.c:login.h lookslike_.c:lookslike.h main_.c:main.h manifest_.c:manifest.h markdown_.c:markdown.h markdown_html_.c:markdown_html.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h moderate_.c:moderate.h name_.c:name.h path_.c:path.h piechart_.c:piechart.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h publish_.c:publish.h purge_.c:purge.h rebuild_.c:rebuild.h regexp_.c:regexp.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h sitemap_.c:sitemap.h skins_.c:skins.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.h statrep_.c:statrep.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tar_.c:tar.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h unicode_.c:unicode.h update_.c:update.h url_.c:url.h user_.c:user.h utf8_.c:utf8.h util_.c:util.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winfile_.c:winfile.h winhttp_.c:winhttp.h wysiwyg_.c:wysiwyg.h xfer_.c:xfer.h xfersetup_.c:xfersetup.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h $(SRCDIR)\cson_amalgamation.h
844 @copy /Y nul: headers
845
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -447,10 +447,11 @@
447447
$(SRCDIR)/merge.c \
448448
$(SRCDIR)/merge3.c \
449449
$(SRCDIR)/moderate.c \
450450
$(SRCDIR)/name.c \
451451
$(SRCDIR)/path.c \
452
+ $(SRCDIR)/piechart.c \
452453
$(SRCDIR)/pivot.c \
453454
$(SRCDIR)/popen.c \
454455
$(SRCDIR)/pqueue.c \
455456
$(SRCDIR)/printf.c \
456457
$(SRCDIR)/publish.c \
@@ -618,10 +619,11 @@
618619
$(OBJDIR)/merge_.c \
619620
$(OBJDIR)/merge3_.c \
620621
$(OBJDIR)/moderate_.c \
621622
$(OBJDIR)/name_.c \
622623
$(OBJDIR)/path_.c \
624
+ $(OBJDIR)/piechart_.c \
623625
$(OBJDIR)/pivot_.c \
624626
$(OBJDIR)/popen_.c \
625627
$(OBJDIR)/pqueue_.c \
626628
$(OBJDIR)/printf_.c \
627629
$(OBJDIR)/publish_.c \
@@ -738,10 +740,11 @@
738740
$(OBJDIR)/merge.o \
739741
$(OBJDIR)/merge3.o \
740742
$(OBJDIR)/moderate.o \
741743
$(OBJDIR)/name.o \
742744
$(OBJDIR)/path.o \
745
+ $(OBJDIR)/piechart.o \
743746
$(OBJDIR)/pivot.o \
744747
$(OBJDIR)/popen.o \
745748
$(OBJDIR)/pqueue.o \
746749
$(OBJDIR)/printf.o \
747750
$(OBJDIR)/publish.o \
@@ -1051,10 +1054,11 @@
10511054
$(OBJDIR)/merge_.c:$(OBJDIR)/merge.h \
10521055
$(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h \
10531056
$(OBJDIR)/moderate_.c:$(OBJDIR)/moderate.h \
10541057
$(OBJDIR)/name_.c:$(OBJDIR)/name.h \
10551058
$(OBJDIR)/path_.c:$(OBJDIR)/path.h \
1059
+ $(OBJDIR)/piechart_.c:$(OBJDIR)/piechart.h \
10561060
$(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h \
10571061
$(OBJDIR)/popen_.c:$(OBJDIR)/popen.h \
10581062
$(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h \
10591063
$(OBJDIR)/printf_.c:$(OBJDIR)/printf.h \
10601064
$(OBJDIR)/publish_.c:$(OBJDIR)/publish.h \
@@ -1681,10 +1685,18 @@
16811685
16821686
$(OBJDIR)/path.o: $(OBJDIR)/path_.c $(OBJDIR)/path.h $(SRCDIR)/config.h
16831687
$(XTCC) -o $(OBJDIR)/path.o -c $(OBJDIR)/path_.c
16841688
16851689
$(OBJDIR)/path.h: $(OBJDIR)/headers
1690
+
1691
+$(OBJDIR)/piechart_.c: $(SRCDIR)/piechart.c $(TRANSLATE)
1692
+ $(TRANSLATE) $(SRCDIR)/piechart.c >$@
1693
+
1694
+$(OBJDIR)/piechart.o: $(OBJDIR)/piechart_.c $(OBJDIR)/piechart.h $(SRCDIR)/config.h
1695
+ $(XTCC) -o $(OBJDIR)/piechart.o -c $(OBJDIR)/piechart_.c
1696
+
1697
+$(OBJDIR)/piechart.h: $(OBJDIR)/headers
16861698
16871699
$(OBJDIR)/pivot_.c: $(SRCDIR)/pivot.c $(TRANSLATE)
16881700
$(TRANSLATE) $(SRCDIR)/pivot.c >$@
16891701
16901702
$(OBJDIR)/pivot.o: $(OBJDIR)/pivot_.c $(OBJDIR)/pivot.h $(SRCDIR)/config.h
@@ -2059,10 +2071,11 @@
20592071
-DSQLITE_DEFAULT_FILE_FORMAT=4 \
20602072
-DSQLITE_OMIT_DEPRECATED \
20612073
-DSQLITE_ENABLE_EXPLAIN_COMMENTS \
20622074
-DSQLITE_ENABLE_FTS4 \
20632075
-DSQLITE_ENABLE_FTS3_PARENTHESIS \
2076
+ -DSQLITE_ENABLE_DBSTAT_VTAB \
20642077
-DSQLITE_WIN32_NO_ANSI \
20652078
-D_HAVE__MINGW_H \
20662079
-DSQLITE_USE_MALLOC_H \
20672080
-DSQLITE_USE_MSIZE
20682081
20692082
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -447,10 +447,11 @@
447 $(SRCDIR)/merge.c \
448 $(SRCDIR)/merge3.c \
449 $(SRCDIR)/moderate.c \
450 $(SRCDIR)/name.c \
451 $(SRCDIR)/path.c \
 
452 $(SRCDIR)/pivot.c \
453 $(SRCDIR)/popen.c \
454 $(SRCDIR)/pqueue.c \
455 $(SRCDIR)/printf.c \
456 $(SRCDIR)/publish.c \
@@ -618,10 +619,11 @@
618 $(OBJDIR)/merge_.c \
619 $(OBJDIR)/merge3_.c \
620 $(OBJDIR)/moderate_.c \
621 $(OBJDIR)/name_.c \
622 $(OBJDIR)/path_.c \
 
623 $(OBJDIR)/pivot_.c \
624 $(OBJDIR)/popen_.c \
625 $(OBJDIR)/pqueue_.c \
626 $(OBJDIR)/printf_.c \
627 $(OBJDIR)/publish_.c \
@@ -738,10 +740,11 @@
738 $(OBJDIR)/merge.o \
739 $(OBJDIR)/merge3.o \
740 $(OBJDIR)/moderate.o \
741 $(OBJDIR)/name.o \
742 $(OBJDIR)/path.o \
 
743 $(OBJDIR)/pivot.o \
744 $(OBJDIR)/popen.o \
745 $(OBJDIR)/pqueue.o \
746 $(OBJDIR)/printf.o \
747 $(OBJDIR)/publish.o \
@@ -1051,10 +1054,11 @@
1051 $(OBJDIR)/merge_.c:$(OBJDIR)/merge.h \
1052 $(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h \
1053 $(OBJDIR)/moderate_.c:$(OBJDIR)/moderate.h \
1054 $(OBJDIR)/name_.c:$(OBJDIR)/name.h \
1055 $(OBJDIR)/path_.c:$(OBJDIR)/path.h \
 
1056 $(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h \
1057 $(OBJDIR)/popen_.c:$(OBJDIR)/popen.h \
1058 $(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h \
1059 $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h \
1060 $(OBJDIR)/publish_.c:$(OBJDIR)/publish.h \
@@ -1681,10 +1685,18 @@
1681
1682 $(OBJDIR)/path.o: $(OBJDIR)/path_.c $(OBJDIR)/path.h $(SRCDIR)/config.h
1683 $(XTCC) -o $(OBJDIR)/path.o -c $(OBJDIR)/path_.c
1684
1685 $(OBJDIR)/path.h: $(OBJDIR)/headers
 
 
 
 
 
 
 
 
1686
1687 $(OBJDIR)/pivot_.c: $(SRCDIR)/pivot.c $(TRANSLATE)
1688 $(TRANSLATE) $(SRCDIR)/pivot.c >$@
1689
1690 $(OBJDIR)/pivot.o: $(OBJDIR)/pivot_.c $(OBJDIR)/pivot.h $(SRCDIR)/config.h
@@ -2059,10 +2071,11 @@
2059 -DSQLITE_DEFAULT_FILE_FORMAT=4 \
2060 -DSQLITE_OMIT_DEPRECATED \
2061 -DSQLITE_ENABLE_EXPLAIN_COMMENTS \
2062 -DSQLITE_ENABLE_FTS4 \
2063 -DSQLITE_ENABLE_FTS3_PARENTHESIS \
 
2064 -DSQLITE_WIN32_NO_ANSI \
2065 -D_HAVE__MINGW_H \
2066 -DSQLITE_USE_MALLOC_H \
2067 -DSQLITE_USE_MSIZE
2068
2069
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -447,10 +447,11 @@
447 $(SRCDIR)/merge.c \
448 $(SRCDIR)/merge3.c \
449 $(SRCDIR)/moderate.c \
450 $(SRCDIR)/name.c \
451 $(SRCDIR)/path.c \
452 $(SRCDIR)/piechart.c \
453 $(SRCDIR)/pivot.c \
454 $(SRCDIR)/popen.c \
455 $(SRCDIR)/pqueue.c \
456 $(SRCDIR)/printf.c \
457 $(SRCDIR)/publish.c \
@@ -618,10 +619,11 @@
619 $(OBJDIR)/merge_.c \
620 $(OBJDIR)/merge3_.c \
621 $(OBJDIR)/moderate_.c \
622 $(OBJDIR)/name_.c \
623 $(OBJDIR)/path_.c \
624 $(OBJDIR)/piechart_.c \
625 $(OBJDIR)/pivot_.c \
626 $(OBJDIR)/popen_.c \
627 $(OBJDIR)/pqueue_.c \
628 $(OBJDIR)/printf_.c \
629 $(OBJDIR)/publish_.c \
@@ -738,10 +740,11 @@
740 $(OBJDIR)/merge.o \
741 $(OBJDIR)/merge3.o \
742 $(OBJDIR)/moderate.o \
743 $(OBJDIR)/name.o \
744 $(OBJDIR)/path.o \
745 $(OBJDIR)/piechart.o \
746 $(OBJDIR)/pivot.o \
747 $(OBJDIR)/popen.o \
748 $(OBJDIR)/pqueue.o \
749 $(OBJDIR)/printf.o \
750 $(OBJDIR)/publish.o \
@@ -1051,10 +1054,11 @@
1054 $(OBJDIR)/merge_.c:$(OBJDIR)/merge.h \
1055 $(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h \
1056 $(OBJDIR)/moderate_.c:$(OBJDIR)/moderate.h \
1057 $(OBJDIR)/name_.c:$(OBJDIR)/name.h \
1058 $(OBJDIR)/path_.c:$(OBJDIR)/path.h \
1059 $(OBJDIR)/piechart_.c:$(OBJDIR)/piechart.h \
1060 $(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h \
1061 $(OBJDIR)/popen_.c:$(OBJDIR)/popen.h \
1062 $(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h \
1063 $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h \
1064 $(OBJDIR)/publish_.c:$(OBJDIR)/publish.h \
@@ -1681,10 +1685,18 @@
1685
1686 $(OBJDIR)/path.o: $(OBJDIR)/path_.c $(OBJDIR)/path.h $(SRCDIR)/config.h
1687 $(XTCC) -o $(OBJDIR)/path.o -c $(OBJDIR)/path_.c
1688
1689 $(OBJDIR)/path.h: $(OBJDIR)/headers
1690
1691 $(OBJDIR)/piechart_.c: $(SRCDIR)/piechart.c $(TRANSLATE)
1692 $(TRANSLATE) $(SRCDIR)/piechart.c >$@
1693
1694 $(OBJDIR)/piechart.o: $(OBJDIR)/piechart_.c $(OBJDIR)/piechart.h $(SRCDIR)/config.h
1695 $(XTCC) -o $(OBJDIR)/piechart.o -c $(OBJDIR)/piechart_.c
1696
1697 $(OBJDIR)/piechart.h: $(OBJDIR)/headers
1698
1699 $(OBJDIR)/pivot_.c: $(SRCDIR)/pivot.c $(TRANSLATE)
1700 $(TRANSLATE) $(SRCDIR)/pivot.c >$@
1701
1702 $(OBJDIR)/pivot.o: $(OBJDIR)/pivot_.c $(OBJDIR)/pivot.h $(SRCDIR)/config.h
@@ -2059,10 +2071,11 @@
2071 -DSQLITE_DEFAULT_FILE_FORMAT=4 \
2072 -DSQLITE_OMIT_DEPRECATED \
2073 -DSQLITE_ENABLE_EXPLAIN_COMMENTS \
2074 -DSQLITE_ENABLE_FTS4 \
2075 -DSQLITE_ENABLE_FTS3_PARENTHESIS \
2076 -DSQLITE_ENABLE_DBSTAT_VTAB \
2077 -DSQLITE_WIN32_NO_ANSI \
2078 -D_HAVE__MINGW_H \
2079 -DSQLITE_USE_MALLOC_H \
2080 -DSQLITE_USE_MSIZE
2081
2082
--- win/Makefile.mingw.mistachkin
+++ win/Makefile.mingw.mistachkin
@@ -447,10 +447,11 @@
447447
$(SRCDIR)/merge.c \
448448
$(SRCDIR)/merge3.c \
449449
$(SRCDIR)/moderate.c \
450450
$(SRCDIR)/name.c \
451451
$(SRCDIR)/path.c \
452
+ $(SRCDIR)/piechart.c \
452453
$(SRCDIR)/pivot.c \
453454
$(SRCDIR)/popen.c \
454455
$(SRCDIR)/pqueue.c \
455456
$(SRCDIR)/printf.c \
456457
$(SRCDIR)/publish.c \
@@ -618,10 +619,11 @@
618619
$(OBJDIR)/merge_.c \
619620
$(OBJDIR)/merge3_.c \
620621
$(OBJDIR)/moderate_.c \
621622
$(OBJDIR)/name_.c \
622623
$(OBJDIR)/path_.c \
624
+ $(OBJDIR)/piechart_.c \
623625
$(OBJDIR)/pivot_.c \
624626
$(OBJDIR)/popen_.c \
625627
$(OBJDIR)/pqueue_.c \
626628
$(OBJDIR)/printf_.c \
627629
$(OBJDIR)/publish_.c \
@@ -738,10 +740,11 @@
738740
$(OBJDIR)/merge.o \
739741
$(OBJDIR)/merge3.o \
740742
$(OBJDIR)/moderate.o \
741743
$(OBJDIR)/name.o \
742744
$(OBJDIR)/path.o \
745
+ $(OBJDIR)/piechart.o \
743746
$(OBJDIR)/pivot.o \
744747
$(OBJDIR)/popen.o \
745748
$(OBJDIR)/pqueue.o \
746749
$(OBJDIR)/printf.o \
747750
$(OBJDIR)/publish.o \
@@ -1051,10 +1054,11 @@
10511054
$(OBJDIR)/merge_.c:$(OBJDIR)/merge.h \
10521055
$(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h \
10531056
$(OBJDIR)/moderate_.c:$(OBJDIR)/moderate.h \
10541057
$(OBJDIR)/name_.c:$(OBJDIR)/name.h \
10551058
$(OBJDIR)/path_.c:$(OBJDIR)/path.h \
1059
+ $(OBJDIR)/piechart_.c:$(OBJDIR)/piechart.h \
10561060
$(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h \
10571061
$(OBJDIR)/popen_.c:$(OBJDIR)/popen.h \
10581062
$(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h \
10591063
$(OBJDIR)/printf_.c:$(OBJDIR)/printf.h \
10601064
$(OBJDIR)/publish_.c:$(OBJDIR)/publish.h \
@@ -1681,10 +1685,18 @@
16811685
16821686
$(OBJDIR)/path.o: $(OBJDIR)/path_.c $(OBJDIR)/path.h $(SRCDIR)/config.h
16831687
$(XTCC) -o $(OBJDIR)/path.o -c $(OBJDIR)/path_.c
16841688
16851689
$(OBJDIR)/path.h: $(OBJDIR)/headers
1690
+
1691
+$(OBJDIR)/piechart_.c: $(SRCDIR)/piechart.c $(TRANSLATE)
1692
+ $(TRANSLATE) $(SRCDIR)/piechart.c >$@
1693
+
1694
+$(OBJDIR)/piechart.o: $(OBJDIR)/piechart_.c $(OBJDIR)/piechart.h $(SRCDIR)/config.h
1695
+ $(XTCC) -o $(OBJDIR)/piechart.o -c $(OBJDIR)/piechart_.c
1696
+
1697
+$(OBJDIR)/piechart.h: $(OBJDIR)/headers
16861698
16871699
$(OBJDIR)/pivot_.c: $(SRCDIR)/pivot.c $(TRANSLATE)
16881700
$(TRANSLATE) $(SRCDIR)/pivot.c >$@
16891701
16901702
$(OBJDIR)/pivot.o: $(OBJDIR)/pivot_.c $(OBJDIR)/pivot.h $(SRCDIR)/config.h
@@ -2059,10 +2071,11 @@
20592071
-DSQLITE_DEFAULT_FILE_FORMAT=4 \
20602072
-DSQLITE_OMIT_DEPRECATED \
20612073
-DSQLITE_ENABLE_EXPLAIN_COMMENTS \
20622074
-DSQLITE_ENABLE_FTS4 \
20632075
-DSQLITE_ENABLE_FTS3_PARENTHESIS \
2076
+ -DSQLITE_ENABLE_DBSTAT_VTAB \
20642077
-DSQLITE_WIN32_NO_ANSI \
20652078
-D_HAVE__MINGW_H \
20662079
-DSQLITE_USE_MALLOC_H \
20672080
-DSQLITE_USE_MSIZE
20682081
20692082
--- win/Makefile.mingw.mistachkin
+++ win/Makefile.mingw.mistachkin
@@ -447,10 +447,11 @@
447 $(SRCDIR)/merge.c \
448 $(SRCDIR)/merge3.c \
449 $(SRCDIR)/moderate.c \
450 $(SRCDIR)/name.c \
451 $(SRCDIR)/path.c \
 
452 $(SRCDIR)/pivot.c \
453 $(SRCDIR)/popen.c \
454 $(SRCDIR)/pqueue.c \
455 $(SRCDIR)/printf.c \
456 $(SRCDIR)/publish.c \
@@ -618,10 +619,11 @@
618 $(OBJDIR)/merge_.c \
619 $(OBJDIR)/merge3_.c \
620 $(OBJDIR)/moderate_.c \
621 $(OBJDIR)/name_.c \
622 $(OBJDIR)/path_.c \
 
623 $(OBJDIR)/pivot_.c \
624 $(OBJDIR)/popen_.c \
625 $(OBJDIR)/pqueue_.c \
626 $(OBJDIR)/printf_.c \
627 $(OBJDIR)/publish_.c \
@@ -738,10 +740,11 @@
738 $(OBJDIR)/merge.o \
739 $(OBJDIR)/merge3.o \
740 $(OBJDIR)/moderate.o \
741 $(OBJDIR)/name.o \
742 $(OBJDIR)/path.o \
 
743 $(OBJDIR)/pivot.o \
744 $(OBJDIR)/popen.o \
745 $(OBJDIR)/pqueue.o \
746 $(OBJDIR)/printf.o \
747 $(OBJDIR)/publish.o \
@@ -1051,10 +1054,11 @@
1051 $(OBJDIR)/merge_.c:$(OBJDIR)/merge.h \
1052 $(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h \
1053 $(OBJDIR)/moderate_.c:$(OBJDIR)/moderate.h \
1054 $(OBJDIR)/name_.c:$(OBJDIR)/name.h \
1055 $(OBJDIR)/path_.c:$(OBJDIR)/path.h \
 
1056 $(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h \
1057 $(OBJDIR)/popen_.c:$(OBJDIR)/popen.h \
1058 $(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h \
1059 $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h \
1060 $(OBJDIR)/publish_.c:$(OBJDIR)/publish.h \
@@ -1681,10 +1685,18 @@
1681
1682 $(OBJDIR)/path.o: $(OBJDIR)/path_.c $(OBJDIR)/path.h $(SRCDIR)/config.h
1683 $(XTCC) -o $(OBJDIR)/path.o -c $(OBJDIR)/path_.c
1684
1685 $(OBJDIR)/path.h: $(OBJDIR)/headers
 
 
 
 
 
 
 
 
1686
1687 $(OBJDIR)/pivot_.c: $(SRCDIR)/pivot.c $(TRANSLATE)
1688 $(TRANSLATE) $(SRCDIR)/pivot.c >$@
1689
1690 $(OBJDIR)/pivot.o: $(OBJDIR)/pivot_.c $(OBJDIR)/pivot.h $(SRCDIR)/config.h
@@ -2059,10 +2071,11 @@
2059 -DSQLITE_DEFAULT_FILE_FORMAT=4 \
2060 -DSQLITE_OMIT_DEPRECATED \
2061 -DSQLITE_ENABLE_EXPLAIN_COMMENTS \
2062 -DSQLITE_ENABLE_FTS4 \
2063 -DSQLITE_ENABLE_FTS3_PARENTHESIS \
 
2064 -DSQLITE_WIN32_NO_ANSI \
2065 -D_HAVE__MINGW_H \
2066 -DSQLITE_USE_MALLOC_H \
2067 -DSQLITE_USE_MSIZE
2068
2069
--- win/Makefile.mingw.mistachkin
+++ win/Makefile.mingw.mistachkin
@@ -447,10 +447,11 @@
447 $(SRCDIR)/merge.c \
448 $(SRCDIR)/merge3.c \
449 $(SRCDIR)/moderate.c \
450 $(SRCDIR)/name.c \
451 $(SRCDIR)/path.c \
452 $(SRCDIR)/piechart.c \
453 $(SRCDIR)/pivot.c \
454 $(SRCDIR)/popen.c \
455 $(SRCDIR)/pqueue.c \
456 $(SRCDIR)/printf.c \
457 $(SRCDIR)/publish.c \
@@ -618,10 +619,11 @@
619 $(OBJDIR)/merge_.c \
620 $(OBJDIR)/merge3_.c \
621 $(OBJDIR)/moderate_.c \
622 $(OBJDIR)/name_.c \
623 $(OBJDIR)/path_.c \
624 $(OBJDIR)/piechart_.c \
625 $(OBJDIR)/pivot_.c \
626 $(OBJDIR)/popen_.c \
627 $(OBJDIR)/pqueue_.c \
628 $(OBJDIR)/printf_.c \
629 $(OBJDIR)/publish_.c \
@@ -738,10 +740,11 @@
740 $(OBJDIR)/merge.o \
741 $(OBJDIR)/merge3.o \
742 $(OBJDIR)/moderate.o \
743 $(OBJDIR)/name.o \
744 $(OBJDIR)/path.o \
745 $(OBJDIR)/piechart.o \
746 $(OBJDIR)/pivot.o \
747 $(OBJDIR)/popen.o \
748 $(OBJDIR)/pqueue.o \
749 $(OBJDIR)/printf.o \
750 $(OBJDIR)/publish.o \
@@ -1051,10 +1054,11 @@
1054 $(OBJDIR)/merge_.c:$(OBJDIR)/merge.h \
1055 $(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h \
1056 $(OBJDIR)/moderate_.c:$(OBJDIR)/moderate.h \
1057 $(OBJDIR)/name_.c:$(OBJDIR)/name.h \
1058 $(OBJDIR)/path_.c:$(OBJDIR)/path.h \
1059 $(OBJDIR)/piechart_.c:$(OBJDIR)/piechart.h \
1060 $(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h \
1061 $(OBJDIR)/popen_.c:$(OBJDIR)/popen.h \
1062 $(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h \
1063 $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h \
1064 $(OBJDIR)/publish_.c:$(OBJDIR)/publish.h \
@@ -1681,10 +1685,18 @@
1685
1686 $(OBJDIR)/path.o: $(OBJDIR)/path_.c $(OBJDIR)/path.h $(SRCDIR)/config.h
1687 $(XTCC) -o $(OBJDIR)/path.o -c $(OBJDIR)/path_.c
1688
1689 $(OBJDIR)/path.h: $(OBJDIR)/headers
1690
1691 $(OBJDIR)/piechart_.c: $(SRCDIR)/piechart.c $(TRANSLATE)
1692 $(TRANSLATE) $(SRCDIR)/piechart.c >$@
1693
1694 $(OBJDIR)/piechart.o: $(OBJDIR)/piechart_.c $(OBJDIR)/piechart.h $(SRCDIR)/config.h
1695 $(XTCC) -o $(OBJDIR)/piechart.o -c $(OBJDIR)/piechart_.c
1696
1697 $(OBJDIR)/piechart.h: $(OBJDIR)/headers
1698
1699 $(OBJDIR)/pivot_.c: $(SRCDIR)/pivot.c $(TRANSLATE)
1700 $(TRANSLATE) $(SRCDIR)/pivot.c >$@
1701
1702 $(OBJDIR)/pivot.o: $(OBJDIR)/pivot_.c $(OBJDIR)/pivot.h $(SRCDIR)/config.h
@@ -2059,10 +2071,11 @@
2071 -DSQLITE_DEFAULT_FILE_FORMAT=4 \
2072 -DSQLITE_OMIT_DEPRECATED \
2073 -DSQLITE_ENABLE_EXPLAIN_COMMENTS \
2074 -DSQLITE_ENABLE_FTS4 \
2075 -DSQLITE_ENABLE_FTS3_PARENTHESIS \
2076 -DSQLITE_ENABLE_DBSTAT_VTAB \
2077 -DSQLITE_WIN32_NO_ANSI \
2078 -D_HAVE__MINGW_H \
2079 -DSQLITE_USE_MALLOC_H \
2080 -DSQLITE_USE_MSIZE
2081
2082
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -199,10 +199,11 @@
199199
/DSQLITE_DEFAULT_FILE_FORMAT=4 \
200200
/DSQLITE_OMIT_DEPRECATED \
201201
/DSQLITE_ENABLE_EXPLAIN_COMMENTS \
202202
/DSQLITE_ENABLE_FTS4 \
203203
/DSQLITE_ENABLE_FTS3_PARENTHESIS \
204
+ /DSQLITE_ENABLE_DBSTAT_VTAB \
204205
/DSQLITE_WIN32_NO_ANSI
205206
206207
SHELL_OPTIONS = /Dmain=sqlite3_shell \
207208
/DSQLITE_OMIT_LOAD_EXTENSION=1 \
208209
/DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) \
@@ -286,10 +287,11 @@
286287
merge_.c \
287288
merge3_.c \
288289
moderate_.c \
289290
name_.c \
290291
path_.c \
292
+ piechart_.c \
291293
pivot_.c \
292294
popen_.c \
293295
pqueue_.c \
294296
printf_.c \
295297
publish_.c \
@@ -456,10 +458,11 @@
456458
$(OX)\merge$O \
457459
$(OX)\merge3$O \
458460
$(OX)\moderate$O \
459461
$(OX)\name$O \
460462
$(OX)\path$O \
463
+ $(OX)\piechart$O \
461464
$(OX)\pivot$O \
462465
$(OX)\popen$O \
463466
$(OX)\pqueue$O \
464467
$(OX)\printf$O \
465468
$(OX)\publish$O \
@@ -631,10 +634,11 @@
631634
echo $(OX)\merge.obj >> $@
632635
echo $(OX)\merge3.obj >> $@
633636
echo $(OX)\moderate.obj >> $@
634637
echo $(OX)\name.obj >> $@
635638
echo $(OX)\path.obj >> $@
639
+ echo $(OX)\piechart.obj >> $@
636640
echo $(OX)\pivot.obj >> $@
637641
echo $(OX)\popen.obj >> $@
638642
echo $(OX)\pqueue.obj >> $@
639643
echo $(OX)\printf.obj >> $@
640644
echo $(OX)\publish.obj >> $@
@@ -1212,10 +1216,16 @@
12121216
$(OX)\path$O : path_.c path.h
12131217
$(TCC) /Fo$@ -c path_.c
12141218
12151219
path_.c : $(SRCDIR)\path.c
12161220
translate$E $** > $@
1221
+
1222
+$(OX)\piechart$O : piechart_.c piechart.h
1223
+ $(TCC) /Fo$@ -c piechart_.c
1224
+
1225
+piechart_.c : $(SRCDIR)\piechart.c
1226
+ translate$E $** > $@
12171227
12181228
$(OX)\pivot$O : pivot_.c pivot.h
12191229
$(TCC) /Fo$@ -c pivot_.c
12201230
12211231
pivot_.c : $(SRCDIR)\pivot.c
@@ -1565,10 +1575,11 @@
15651575
merge_.c:merge.h \
15661576
merge3_.c:merge3.h \
15671577
moderate_.c:moderate.h \
15681578
name_.c:name.h \
15691579
path_.c:path.h \
1580
+ piechart_.c:piechart.h \
15701581
pivot_.c:pivot.h \
15711582
popen_.c:popen.h \
15721583
pqueue_.c:pqueue.h \
15731584
printf_.c:printf.h \
15741585
publish_.c:publish.h \
15751586
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -199,10 +199,11 @@
199 /DSQLITE_DEFAULT_FILE_FORMAT=4 \
200 /DSQLITE_OMIT_DEPRECATED \
201 /DSQLITE_ENABLE_EXPLAIN_COMMENTS \
202 /DSQLITE_ENABLE_FTS4 \
203 /DSQLITE_ENABLE_FTS3_PARENTHESIS \
 
204 /DSQLITE_WIN32_NO_ANSI
205
206 SHELL_OPTIONS = /Dmain=sqlite3_shell \
207 /DSQLITE_OMIT_LOAD_EXTENSION=1 \
208 /DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) \
@@ -286,10 +287,11 @@
286 merge_.c \
287 merge3_.c \
288 moderate_.c \
289 name_.c \
290 path_.c \
 
291 pivot_.c \
292 popen_.c \
293 pqueue_.c \
294 printf_.c \
295 publish_.c \
@@ -456,10 +458,11 @@
456 $(OX)\merge$O \
457 $(OX)\merge3$O \
458 $(OX)\moderate$O \
459 $(OX)\name$O \
460 $(OX)\path$O \
 
461 $(OX)\pivot$O \
462 $(OX)\popen$O \
463 $(OX)\pqueue$O \
464 $(OX)\printf$O \
465 $(OX)\publish$O \
@@ -631,10 +634,11 @@
631 echo $(OX)\merge.obj >> $@
632 echo $(OX)\merge3.obj >> $@
633 echo $(OX)\moderate.obj >> $@
634 echo $(OX)\name.obj >> $@
635 echo $(OX)\path.obj >> $@
 
636 echo $(OX)\pivot.obj >> $@
637 echo $(OX)\popen.obj >> $@
638 echo $(OX)\pqueue.obj >> $@
639 echo $(OX)\printf.obj >> $@
640 echo $(OX)\publish.obj >> $@
@@ -1212,10 +1216,16 @@
1212 $(OX)\path$O : path_.c path.h
1213 $(TCC) /Fo$@ -c path_.c
1214
1215 path_.c : $(SRCDIR)\path.c
1216 translate$E $** > $@
 
 
 
 
 
 
1217
1218 $(OX)\pivot$O : pivot_.c pivot.h
1219 $(TCC) /Fo$@ -c pivot_.c
1220
1221 pivot_.c : $(SRCDIR)\pivot.c
@@ -1565,10 +1575,11 @@
1565 merge_.c:merge.h \
1566 merge3_.c:merge3.h \
1567 moderate_.c:moderate.h \
1568 name_.c:name.h \
1569 path_.c:path.h \
 
1570 pivot_.c:pivot.h \
1571 popen_.c:popen.h \
1572 pqueue_.c:pqueue.h \
1573 printf_.c:printf.h \
1574 publish_.c:publish.h \
1575
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -199,10 +199,11 @@
199 /DSQLITE_DEFAULT_FILE_FORMAT=4 \
200 /DSQLITE_OMIT_DEPRECATED \
201 /DSQLITE_ENABLE_EXPLAIN_COMMENTS \
202 /DSQLITE_ENABLE_FTS4 \
203 /DSQLITE_ENABLE_FTS3_PARENTHESIS \
204 /DSQLITE_ENABLE_DBSTAT_VTAB \
205 /DSQLITE_WIN32_NO_ANSI
206
207 SHELL_OPTIONS = /Dmain=sqlite3_shell \
208 /DSQLITE_OMIT_LOAD_EXTENSION=1 \
209 /DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) \
@@ -286,10 +287,11 @@
287 merge_.c \
288 merge3_.c \
289 moderate_.c \
290 name_.c \
291 path_.c \
292 piechart_.c \
293 pivot_.c \
294 popen_.c \
295 pqueue_.c \
296 printf_.c \
297 publish_.c \
@@ -456,10 +458,11 @@
458 $(OX)\merge$O \
459 $(OX)\merge3$O \
460 $(OX)\moderate$O \
461 $(OX)\name$O \
462 $(OX)\path$O \
463 $(OX)\piechart$O \
464 $(OX)\pivot$O \
465 $(OX)\popen$O \
466 $(OX)\pqueue$O \
467 $(OX)\printf$O \
468 $(OX)\publish$O \
@@ -631,10 +634,11 @@
634 echo $(OX)\merge.obj >> $@
635 echo $(OX)\merge3.obj >> $@
636 echo $(OX)\moderate.obj >> $@
637 echo $(OX)\name.obj >> $@
638 echo $(OX)\path.obj >> $@
639 echo $(OX)\piechart.obj >> $@
640 echo $(OX)\pivot.obj >> $@
641 echo $(OX)\popen.obj >> $@
642 echo $(OX)\pqueue.obj >> $@
643 echo $(OX)\printf.obj >> $@
644 echo $(OX)\publish.obj >> $@
@@ -1212,10 +1216,16 @@
1216 $(OX)\path$O : path_.c path.h
1217 $(TCC) /Fo$@ -c path_.c
1218
1219 path_.c : $(SRCDIR)\path.c
1220 translate$E $** > $@
1221
1222 $(OX)\piechart$O : piechart_.c piechart.h
1223 $(TCC) /Fo$@ -c piechart_.c
1224
1225 piechart_.c : $(SRCDIR)\piechart.c
1226 translate$E $** > $@
1227
1228 $(OX)\pivot$O : pivot_.c pivot.h
1229 $(TCC) /Fo$@ -c pivot_.c
1230
1231 pivot_.c : $(SRCDIR)\pivot.c
@@ -1565,10 +1575,11 @@
1575 merge_.c:merge.h \
1576 merge3_.c:merge3.h \
1577 moderate_.c:moderate.h \
1578 name_.c:name.h \
1579 path_.c:path.h \
1580 piechart_.c:piechart.h \
1581 pivot_.c:pivot.h \
1582 popen_.c:popen.h \
1583 pqueue_.c:pqueue.h \
1584 printf_.c:printf.h \
1585 publish_.c:publish.h \
1586
+33 -14
--- www/build.wiki
+++ www/build.wiki
@@ -26,39 +26,39 @@
2626
<p><hr>
2727
2828
<h2>1.0 Obtaining The Source Code</h2>
2929
3030
<p>Fossil is self-hosting, so you can obtain a ZIP archive or tarball
31
-containing a snapshot of the <em>latest</em> version directly from
32
-Fossil's own fossil repository. Additionally, source archives of
31
+containing a snapshot of the <em>latest</em> version directly from
32
+Fossil's own fossil repository. Additionally, source archives of
3333
<em>released</em> versions of
3434
fossil are available from the <a href="http://www.fossil-scm.org/download.html">downloads page</a>.
3535
To obtain a development version of fossil, follow these steps:</p>
3636
3737
<ol>
3838
<li><p>Point your web browser to
3939
<a href="http://www.fossil-scm.org/">
4040
http://www.fossil-scm.org/</a>.</p></li>
4141
42
-<li><p>Click on the
43
-<a href="http://www.fossil-scm.org/fossil/timeline">Timeline</a>
42
+<li><p>Click on the
43
+<a href="http://www.fossil-scm.org/fossil/timeline">Timeline</a>
4444
link at the top of the page.</p></li>
4545
4646
<li><p>Select a version of of Fossil you want to download. The latest
4747
version on the trunk branch is usually a good choice. Click on its
4848
link.</p></li>
4949
5050
<li><p>Finally, click on one of the
5151
"Zip Archive" or "Tarball" links, according to your preference.
52
-These link will build a ZIP archive or a gzip-compressed tarball of the
52
+These link will build a ZIP archive or a gzip-compressed tarball of the
5353
complete source code and download it to your computer.
5454
</ol>
5555
5656
<h2>Aside: Is it really safe to use an unreleased development version of
5757
the Fossil source code?</h2>
5858
59
-Yes! Any check-in on the
59
+Yes! Any check-in on the
6060
[/timeline?t=trunk | trunk branch] of the Fossil
6161
[http://fossil-scm.org/fossil/timeline | Fossil self-hosting repository]
6262
will work fine. (Dodgy code is always on a branch.) In the unlikely
6363
event that you pick a version with a serious bug, it still won't
6464
clobber your files. Fossil uses several
@@ -90,10 +90,14 @@
9090
9191
<li><p>
9292
To build a statically linked binary (suitable for use inside a chroot
9393
jail) add the <b>--static</b> option.
9494
95
+<li><p>
96
+To enable the native [./th1.md#tclEval | Tcl integration feature] feature,
97
+add the <b>--with-tcl=1</b> and <b>--with-tcl-private-stubs=1</b> options.
98
+
9599
<li><p>
96100
Other configuration options can be seen by running
97101
<b>./configure --help</b>
98102
</ol>
99103
@@ -102,20 +106,26 @@
102106
103107
<ol type="a">
104108
<li><p><i>Unix</i> → the configure-generated Makefile should work on
105109
all Unix and Unix-like systems. Simply type "<b>make</b>".
106110
107
-<li><p><i>Unix without running "configure"</i> → if you prefer to avoid running configure, you
108
-can also use: <b>make -f Makefile.classic</b>. You may want to make minor
109
-edits to Makefile.classic to configure the build for your system.
111
+<li><p><i>Unix without running "configure"</i> → if you prefer to avoid
112
+running configure, you can also use: <b>make -f Makefile.classic</b>. You may
113
+want to make minor edits to Makefile.classic to configure the build for your
114
+system.
110115
111116
<li><p><i>MinGW3.x (not 4.0)/MinGW-w64</i> → Use the mingw makefile:
112117
"<b>make -f win/Makefile.mingw</b>". On a Windows box you will
113118
need either Cygwin or Msys as build environment. On Cygwin, Linux
114119
or Darwin you may want to make minor edits to win/Makefile.mingw
115120
to configure the cross-compile environment.
116121
122
+To enable the native [./th1.md#tclEval | Tcl integration feature], use a
123
+command line like the following (all on one line):
124
+
125
+<b>make -f win/Makefile.mingw FOSSIL_ENABLE_TCL=1 FOSSIL_ENABLE_TCL_STUBS=1 FOSSIL_ENABLE_TCL_PRIVATE_STUBS=1</b>
126
+
117127
Hint: don't use MinGW-4.0, it will compile but fossil won't work correctly, see
118128
<a href="https://www.fossil-scm.org/index.html/tktview/18cff45a4e210430e24c">https://www.fossil-scm.org/index.html/tktview/18cff45a4e210430e24c</a>.
119129
120130
<li><p><i>MSVC</i> → Use the MSVC makefile. First
121131
change to the "win/" subdirectory ("<b>cd win</b>") then run
@@ -134,10 +144,19 @@
134144
nmake /f Makefile.msc FOSSIL_ENABLE_SSL=1 FOSSIL_BUILD_SSL=1 PERLDIR=C:\full\path\to\Perl\bin
135145
</pre></blockquote>
136146
<blockquote><pre>
137147
buildmsvc.bat FOSSIL_ENABLE_SSL=1 FOSSIL_BUILD_SSL=1 PERLDIR=C:\full\path\to\Perl\bin
138148
</pre></blockquote>
149
+To enable the optional native [./th1.md#tclEval | Tcl integration feature],
150
+run one of the following commands or add the &quot;FOSSIL_ENABLE_TCL=1&quot;
151
+argument to one of the other NMAKE command lines:
152
+<blockquote><pre>
153
+nmake /f Makefile.msc FOSSIL_ENABLE_TCL=1
154
+</pre></blockquote>
155
+<blockquote><pre>
156
+buildmsvc.bat FOSSIL_ENABLE_TCL=1
157
+</pre></blockquote>
139158
140159
<li><p><i>Cygwin</i> → The same as other Unix-like systems. It is
141160
recommended to configure using: "<b>configure --disable-internal-sqlite</b>",
142161
making sure you have the "libsqlite3-devel" , "zlib-devel" and
143162
"openssl-devel" packages installed first.
@@ -146,12 +165,12 @@
146165
147166
<h2>3.0 Installing</h2>
148167
149168
<ol>
150169
<li value="8">
151
-<p>The finished binary is named "fossil" (or "fossil.exe" on Windows).
152
-Put this binary in a
170
+<p>The finished binary is named "fossil" (or "fossil.exe" on Windows).
171
+Put this binary in a
153172
directory that is somewhere on your PATH environment variable.
154173
It does not matter where.</p>
155174
156175
<li>
157176
<p><b>(Optional:)</b>
@@ -167,14 +186,14 @@
167186
Fossil manually, then refer to the
168187
[./makefile.wiki | Fossil Build Process] document which describes
169188
in detail what the makefiles do behind the scenes.
170189
171190
<li><p>
172
- The fossil executable is self-contained and stand-alone and usually
173
- requires no special libraries or other software to be installed. However,
191
+ The fossil executable is self-contained and stand-alone and usually
192
+ requires no special libraries or other software to be installed. However,
174193
the "--tk" option to the [/help/diff|diff command] requires that Tcl/Tk
175
- be installed on the local machine. You can get Tcl/Tk from
194
+ be installed on the local machine. You can get Tcl/Tk from
176195
[http://www.activestate.com/activetcl|ActiveState].
177196
178197
<li><p>
179198
To build on older Macs (circa 2002, MacOS 10.2) edit the Makefile
180199
generated by configure to add the following lines:
181200
--- www/build.wiki
+++ www/build.wiki
@@ -26,39 +26,39 @@
26 <p><hr>
27
28 <h2>1.0 Obtaining The Source Code</h2>
29
30 <p>Fossil is self-hosting, so you can obtain a ZIP archive or tarball
31 containing a snapshot of the <em>latest</em> version directly from
32 Fossil's own fossil repository. Additionally, source archives of
33 <em>released</em> versions of
34 fossil are available from the <a href="http://www.fossil-scm.org/download.html">downloads page</a>.
35 To obtain a development version of fossil, follow these steps:</p>
36
37 <ol>
38 <li><p>Point your web browser to
39 <a href="http://www.fossil-scm.org/">
40 http://www.fossil-scm.org/</a>.</p></li>
41
42 <li><p>Click on the
43 <a href="http://www.fossil-scm.org/fossil/timeline">Timeline</a>
44 link at the top of the page.</p></li>
45
46 <li><p>Select a version of of Fossil you want to download. The latest
47 version on the trunk branch is usually a good choice. Click on its
48 link.</p></li>
49
50 <li><p>Finally, click on one of the
51 "Zip Archive" or "Tarball" links, according to your preference.
52 These link will build a ZIP archive or a gzip-compressed tarball of the
53 complete source code and download it to your computer.
54 </ol>
55
56 <h2>Aside: Is it really safe to use an unreleased development version of
57 the Fossil source code?</h2>
58
59 Yes! Any check-in on the
60 [/timeline?t=trunk | trunk branch] of the Fossil
61 [http://fossil-scm.org/fossil/timeline | Fossil self-hosting repository]
62 will work fine. (Dodgy code is always on a branch.) In the unlikely
63 event that you pick a version with a serious bug, it still won't
64 clobber your files. Fossil uses several
@@ -90,10 +90,14 @@
90
91 <li><p>
92 To build a statically linked binary (suitable for use inside a chroot
93 jail) add the <b>--static</b> option.
94
 
 
 
 
95 <li><p>
96 Other configuration options can be seen by running
97 <b>./configure --help</b>
98 </ol>
99
@@ -102,20 +106,26 @@
102
103 <ol type="a">
104 <li><p><i>Unix</i> → the configure-generated Makefile should work on
105 all Unix and Unix-like systems. Simply type "<b>make</b>".
106
107 <li><p><i>Unix without running "configure"</i> → if you prefer to avoid running configure, you
108 can also use: <b>make -f Makefile.classic</b>. You may want to make minor
109 edits to Makefile.classic to configure the build for your system.
 
110
111 <li><p><i>MinGW3.x (not 4.0)/MinGW-w64</i> → Use the mingw makefile:
112 "<b>make -f win/Makefile.mingw</b>". On a Windows box you will
113 need either Cygwin or Msys as build environment. On Cygwin, Linux
114 or Darwin you may want to make minor edits to win/Makefile.mingw
115 to configure the cross-compile environment.
116
 
 
 
 
 
117 Hint: don't use MinGW-4.0, it will compile but fossil won't work correctly, see
118 <a href="https://www.fossil-scm.org/index.html/tktview/18cff45a4e210430e24c">https://www.fossil-scm.org/index.html/tktview/18cff45a4e210430e24c</a>.
119
120 <li><p><i>MSVC</i> → Use the MSVC makefile. First
121 change to the "win/" subdirectory ("<b>cd win</b>") then run
@@ -134,10 +144,19 @@
134 nmake /f Makefile.msc FOSSIL_ENABLE_SSL=1 FOSSIL_BUILD_SSL=1 PERLDIR=C:\full\path\to\Perl\bin
135 </pre></blockquote>
136 <blockquote><pre>
137 buildmsvc.bat FOSSIL_ENABLE_SSL=1 FOSSIL_BUILD_SSL=1 PERLDIR=C:\full\path\to\Perl\bin
138 </pre></blockquote>
 
 
 
 
 
 
 
 
 
139
140 <li><p><i>Cygwin</i> → The same as other Unix-like systems. It is
141 recommended to configure using: "<b>configure --disable-internal-sqlite</b>",
142 making sure you have the "libsqlite3-devel" , "zlib-devel" and
143 "openssl-devel" packages installed first.
@@ -146,12 +165,12 @@
146
147 <h2>3.0 Installing</h2>
148
149 <ol>
150 <li value="8">
151 <p>The finished binary is named "fossil" (or "fossil.exe" on Windows).
152 Put this binary in a
153 directory that is somewhere on your PATH environment variable.
154 It does not matter where.</p>
155
156 <li>
157 <p><b>(Optional:)</b>
@@ -167,14 +186,14 @@
167 Fossil manually, then refer to the
168 [./makefile.wiki | Fossil Build Process] document which describes
169 in detail what the makefiles do behind the scenes.
170
171 <li><p>
172 The fossil executable is self-contained and stand-alone and usually
173 requires no special libraries or other software to be installed. However,
174 the "--tk" option to the [/help/diff|diff command] requires that Tcl/Tk
175 be installed on the local machine. You can get Tcl/Tk from
176 [http://www.activestate.com/activetcl|ActiveState].
177
178 <li><p>
179 To build on older Macs (circa 2002, MacOS 10.2) edit the Makefile
180 generated by configure to add the following lines:
181
--- www/build.wiki
+++ www/build.wiki
@@ -26,39 +26,39 @@
26 <p><hr>
27
28 <h2>1.0 Obtaining The Source Code</h2>
29
30 <p>Fossil is self-hosting, so you can obtain a ZIP archive or tarball
31 containing a snapshot of the <em>latest</em> version directly from
32 Fossil's own fossil repository. Additionally, source archives of
33 <em>released</em> versions of
34 fossil are available from the <a href="http://www.fossil-scm.org/download.html">downloads page</a>.
35 To obtain a development version of fossil, follow these steps:</p>
36
37 <ol>
38 <li><p>Point your web browser to
39 <a href="http://www.fossil-scm.org/">
40 http://www.fossil-scm.org/</a>.</p></li>
41
42 <li><p>Click on the
43 <a href="http://www.fossil-scm.org/fossil/timeline">Timeline</a>
44 link at the top of the page.</p></li>
45
46 <li><p>Select a version of of Fossil you want to download. The latest
47 version on the trunk branch is usually a good choice. Click on its
48 link.</p></li>
49
50 <li><p>Finally, click on one of the
51 "Zip Archive" or "Tarball" links, according to your preference.
52 These link will build a ZIP archive or a gzip-compressed tarball of the
53 complete source code and download it to your computer.
54 </ol>
55
56 <h2>Aside: Is it really safe to use an unreleased development version of
57 the Fossil source code?</h2>
58
59 Yes! Any check-in on the
60 [/timeline?t=trunk | trunk branch] of the Fossil
61 [http://fossil-scm.org/fossil/timeline | Fossil self-hosting repository]
62 will work fine. (Dodgy code is always on a branch.) In the unlikely
63 event that you pick a version with a serious bug, it still won't
64 clobber your files. Fossil uses several
@@ -90,10 +90,14 @@
90
91 <li><p>
92 To build a statically linked binary (suitable for use inside a chroot
93 jail) add the <b>--static</b> option.
94
95 <li><p>
96 To enable the native [./th1.md#tclEval | Tcl integration feature] feature,
97 add the <b>--with-tcl=1</b> and <b>--with-tcl-private-stubs=1</b> options.
98
99 <li><p>
100 Other configuration options can be seen by running
101 <b>./configure --help</b>
102 </ol>
103
@@ -102,20 +106,26 @@
106
107 <ol type="a">
108 <li><p><i>Unix</i> → the configure-generated Makefile should work on
109 all Unix and Unix-like systems. Simply type "<b>make</b>".
110
111 <li><p><i>Unix without running "configure"</i> → if you prefer to avoid
112 running configure, you can also use: <b>make -f Makefile.classic</b>. You may
113 want to make minor edits to Makefile.classic to configure the build for your
114 system.
115
116 <li><p><i>MinGW3.x (not 4.0)/MinGW-w64</i> → Use the mingw makefile:
117 "<b>make -f win/Makefile.mingw</b>". On a Windows box you will
118 need either Cygwin or Msys as build environment. On Cygwin, Linux
119 or Darwin you may want to make minor edits to win/Makefile.mingw
120 to configure the cross-compile environment.
121
122 To enable the native [./th1.md#tclEval | Tcl integration feature], use a
123 command line like the following (all on one line):
124
125 <b>make -f win/Makefile.mingw FOSSIL_ENABLE_TCL=1 FOSSIL_ENABLE_TCL_STUBS=1 FOSSIL_ENABLE_TCL_PRIVATE_STUBS=1</b>
126
127 Hint: don't use MinGW-4.0, it will compile but fossil won't work correctly, see
128 <a href="https://www.fossil-scm.org/index.html/tktview/18cff45a4e210430e24c">https://www.fossil-scm.org/index.html/tktview/18cff45a4e210430e24c</a>.
129
130 <li><p><i>MSVC</i> → Use the MSVC makefile. First
131 change to the "win/" subdirectory ("<b>cd win</b>") then run
@@ -134,10 +144,19 @@
144 nmake /f Makefile.msc FOSSIL_ENABLE_SSL=1 FOSSIL_BUILD_SSL=1 PERLDIR=C:\full\path\to\Perl\bin
145 </pre></blockquote>
146 <blockquote><pre>
147 buildmsvc.bat FOSSIL_ENABLE_SSL=1 FOSSIL_BUILD_SSL=1 PERLDIR=C:\full\path\to\Perl\bin
148 </pre></blockquote>
149 To enable the optional native [./th1.md#tclEval | Tcl integration feature],
150 run one of the following commands or add the &quot;FOSSIL_ENABLE_TCL=1&quot;
151 argument to one of the other NMAKE command lines:
152 <blockquote><pre>
153 nmake /f Makefile.msc FOSSIL_ENABLE_TCL=1
154 </pre></blockquote>
155 <blockquote><pre>
156 buildmsvc.bat FOSSIL_ENABLE_TCL=1
157 </pre></blockquote>
158
159 <li><p><i>Cygwin</i> → The same as other Unix-like systems. It is
160 recommended to configure using: "<b>configure --disable-internal-sqlite</b>",
161 making sure you have the "libsqlite3-devel" , "zlib-devel" and
162 "openssl-devel" packages installed first.
@@ -146,12 +165,12 @@
165
166 <h2>3.0 Installing</h2>
167
168 <ol>
169 <li value="8">
170 <p>The finished binary is named "fossil" (or "fossil.exe" on Windows).
171 Put this binary in a
172 directory that is somewhere on your PATH environment variable.
173 It does not matter where.</p>
174
175 <li>
176 <p><b>(Optional:)</b>
@@ -167,14 +186,14 @@
186 Fossil manually, then refer to the
187 [./makefile.wiki | Fossil Build Process] document which describes
188 in detail what the makefiles do behind the scenes.
189
190 <li><p>
191 The fossil executable is self-contained and stand-alone and usually
192 requires no special libraries or other software to be installed. However,
193 the "--tk" option to the [/help/diff|diff command] requires that Tcl/Tk
194 be installed on the local machine. You can get Tcl/Tk from
195 [http://www.activestate.com/activetcl|ActiveState].
196
197 <li><p>
198 To build on older Macs (circa 2002, MacOS 10.2) edit the Makefile
199 generated by configure to add the following lines:
200
+35 -2
--- www/changes.wiki
+++ www/changes.wiki
@@ -1,22 +1,55 @@
11
<title>Change Log</title>
22
33
<h2>Changes for Version 1.33 (not released yet)</h2>
4
+ * Improved fork detection on [/help?cmd=update|fossil update],
5
+ [/help?cmd=status|fossil status] and related commands.
6
+ * Change the default skin to what used to be called "San Francisco Modern".
7
+ * Add the [/repo-tabsize] web page
48
* Add [/help?cmd=import|fossil import --svn], for importing a subversion
59
repository into fossil which was exported using "svnadmin dump".
10
+ * Add the "--compress-only" option to [/help?cmd=rebuild|fossil rebuild].
11
+ * Use a pie chart on the [/reports?view=byuser] page.
12
+ * Enhanced [/help?cmd=clean|fossil clean --verily] so that it ignores
13
+ keep-glob and ignore-glob settings. Added the -x alias for --verily.
14
+ * Add the --soft and --hard options to [/help?cmd=rm|fossil rm] and
15
+ [/help?cmd=mv|fossil mv]. The default is still --soft, but that is
16
+ now configurable at compile-time or by the mv-rm-files setting.
17
+ * Improved ability to [./customgraph.md|customize the timelime graph].
18
+ * Improvements to the [/sitemap] page.
19
+ * Automatically adjust the [/help?cmd=timeline|CLI timeline] to the terminal
20
+ width on Linux.
621
* Added <nowiki>[info commands] and [info vars]</nowiki> commands to TH1.
722
These commands perform the same function as their Tcl counterparts,
823
except they do not accept a pattern argument.
924
* Fix some obscure issues with TH1 expression processing.
1025
* Fix titles in search results for documents that are not wiki, markdown,
1126
or HTML.
1227
* Formally translate TH1 to Tcl return codes and vice-versa, where
1328
necessary, in the Tcl integration subsystem.
14
- * Better fork detection on [/help?cmd=update|fossil update],
15
- [/help?cmd=status|fossil status] and related commands.
1629
* Add [/help?cmd=leaves|fossil leaves -multiple], for finding multiple
1730
leaves on the same branch.
31
+ * Added the "Blitz" skin option.
32
+ * Removed the ".fossil-settings/keep-glob" file. It should not have been
33
+ checked into the repository.
34
+ * Update the built-in SQLite to version 3.8.10.1.
35
+ * Make [/help?cmd=open|fossil open] honor ".fossil-settings/allow-symlinks".
36
+ * Allow [/help?cmd=add|fossil add] to be used on symlinks to nonexistent or
37
+ unreadable files in the same way as [/help?cmd=addremove|fossil addremove].
38
+ * Added fork warning to be issued if sync produced a fork
39
+ * Update the [/help?cmd=/info|info] page to report when a file becomes a
40
+ symlink. Additionally show the UUID for files whose types have changed
41
+ without changing contents or symlink target.
42
+ * Have [/help?cmd=changes|fossil changes] and
43
+ [/help?cmd=status|fossil status] report when executable or symlink status
44
+ changes on otherwise unmodified files.
45
+ * Permit filtering weekday and file [/help?cmd=/reports|reports] by user.
46
+ Also ensure the user parameter is preserved when changing types. Add a
47
+ field for direct entry of the user name to each applicable report.
48
+ * Create parent directories of [/help?cmd=settings|empty-dirs] if they don't
49
+ already exist.
50
+ * Inhibit timeline links to wiki pages that have been deleted.
1851
1952
<h2>Changes for Version 1.32 (2015-03-14)</h2>
2053
* When creating a new repository using [/help?cmd=init|fossil init], ensure
2154
that the new repository is fully compatible with historical versions of
2255
Fossil by having a valid manifest as RID 1.
2356
2457
ADDED www/customgraph.md
--- www/changes.wiki
+++ www/changes.wiki
@@ -1,22 +1,55 @@
1 <title>Change Log</title>
2
3 <h2>Changes for Version 1.33 (not released yet)</h2>
 
 
 
 
4 * Add [/help?cmd=import|fossil import --svn], for importing a subversion
5 repository into fossil which was exported using "svnadmin dump".
 
 
 
 
 
 
 
 
 
 
 
6 * Added <nowiki>[info commands] and [info vars]</nowiki> commands to TH1.
7 These commands perform the same function as their Tcl counterparts,
8 except they do not accept a pattern argument.
9 * Fix some obscure issues with TH1 expression processing.
10 * Fix titles in search results for documents that are not wiki, markdown,
11 or HTML.
12 * Formally translate TH1 to Tcl return codes and vice-versa, where
13 necessary, in the Tcl integration subsystem.
14 * Better fork detection on [/help?cmd=update|fossil update],
15 [/help?cmd=status|fossil status] and related commands.
16 * Add [/help?cmd=leaves|fossil leaves -multiple], for finding multiple
17 leaves on the same branch.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
19 <h2>Changes for Version 1.32 (2015-03-14)</h2>
20 * When creating a new repository using [/help?cmd=init|fossil init], ensure
21 that the new repository is fully compatible with historical versions of
22 Fossil by having a valid manifest as RID 1.
23
24 DDED www/customgraph.md
--- www/changes.wiki
+++ www/changes.wiki
@@ -1,22 +1,55 @@
1 <title>Change Log</title>
2
3 <h2>Changes for Version 1.33 (not released yet)</h2>
4 * Improved fork detection on [/help?cmd=update|fossil update],
5 [/help?cmd=status|fossil status] and related commands.
6 * Change the default skin to what used to be called "San Francisco Modern".
7 * Add the [/repo-tabsize] web page
8 * Add [/help?cmd=import|fossil import --svn], for importing a subversion
9 repository into fossil which was exported using "svnadmin dump".
10 * Add the "--compress-only" option to [/help?cmd=rebuild|fossil rebuild].
11 * Use a pie chart on the [/reports?view=byuser] page.
12 * Enhanced [/help?cmd=clean|fossil clean --verily] so that it ignores
13 keep-glob and ignore-glob settings. Added the -x alias for --verily.
14 * Add the --soft and --hard options to [/help?cmd=rm|fossil rm] and
15 [/help?cmd=mv|fossil mv]. The default is still --soft, but that is
16 now configurable at compile-time or by the mv-rm-files setting.
17 * Improved ability to [./customgraph.md|customize the timelime graph].
18 * Improvements to the [/sitemap] page.
19 * Automatically adjust the [/help?cmd=timeline|CLI timeline] to the terminal
20 width on Linux.
21 * Added <nowiki>[info commands] and [info vars]</nowiki> commands to TH1.
22 These commands perform the same function as their Tcl counterparts,
23 except they do not accept a pattern argument.
24 * Fix some obscure issues with TH1 expression processing.
25 * Fix titles in search results for documents that are not wiki, markdown,
26 or HTML.
27 * Formally translate TH1 to Tcl return codes and vice-versa, where
28 necessary, in the Tcl integration subsystem.
 
 
29 * Add [/help?cmd=leaves|fossil leaves -multiple], for finding multiple
30 leaves on the same branch.
31 * Added the "Blitz" skin option.
32 * Removed the ".fossil-settings/keep-glob" file. It should not have been
33 checked into the repository.
34 * Update the built-in SQLite to version 3.8.10.1.
35 * Make [/help?cmd=open|fossil open] honor ".fossil-settings/allow-symlinks".
36 * Allow [/help?cmd=add|fossil add] to be used on symlinks to nonexistent or
37 unreadable files in the same way as [/help?cmd=addremove|fossil addremove].
38 * Added fork warning to be issued if sync produced a fork
39 * Update the [/help?cmd=/info|info] page to report when a file becomes a
40 symlink. Additionally show the UUID for files whose types have changed
41 without changing contents or symlink target.
42 * Have [/help?cmd=changes|fossil changes] and
43 [/help?cmd=status|fossil status] report when executable or symlink status
44 changes on otherwise unmodified files.
45 * Permit filtering weekday and file [/help?cmd=/reports|reports] by user.
46 Also ensure the user parameter is preserved when changing types. Add a
47 field for direct entry of the user name to each applicable report.
48 * Create parent directories of [/help?cmd=settings|empty-dirs] if they don't
49 already exist.
50 * Inhibit timeline links to wiki pages that have been deleted.
51
52 <h2>Changes for Version 1.32 (2015-03-14)</h2>
53 * When creating a new repository using [/help?cmd=init|fossil init], ensure
54 that the new repository is fully compatible with historical versions of
55 Fossil by having a valid manifest as RID 1.
56
57 DDED www/customgraph.md
--- a/www/customgraph.md
+++ b/www/customgraph.md
@@ -0,0 +1,144 @@
1
+# Customizing the Timeline Graph
2
+
3
+Beginning with version 1.33, Fossil gives users and skin authors significantly
4
+more control over the look and feel of the timeline graph.
5
+
6
+## <a id="basic-style"></a>Basic Style Options
7
+
8
+Fossil includes several options for changing the graph's style without having
9
+to delve into CSS. These can be found in the details.txt file of your skin or
10
+under Admin/Skins/D###`timeline-arrowheads`
11
+
12
+ Set this to `0` to hide arrowheads on primary child lines.
13
+
14
+* ### Set this to `node s`**
15
+
16
+ Set this to `1` to### `timeline-color-graph-line`
17
+
18
+ Set this to `1` to colorize### `white-foreground`
19
+
20
+ Set this to `round`**
21
+
22
+ Seses white (or any light color) text.
23
+ This tells Fossil to generate darker background colors for branches.
24
+
25
+
26
+## <a id="adv-style"></a>Advanced Styling
27
+
28
+If the above options aren't enough for you, it's time to get your hands dirty
29
+with CSS. To get started, I recommend first copying all the [graph-related CSS
30
+rules](#default-css) to your stylesheet. Then it's simply a matter of making
31
+the necessary changes to achieve the look you want. So, next, let's look at the
32
+various graph elements and what purpose they serve.
33
+
34
+Each element used to construct the timeline graph falls into one of two
35
+categories: visible elements and positioning elements. We'll start with the
36
+latter, less obvious type.
37
+
38
+## <a id="pos-elems"></a>Positioning Elements
39
+
40
+These elements aren't intended to be seen. They're only used to h### <a id="
41
+
42
+ Set the left and right margins on this class to give the desired amount
43
+ of space between tunt
44
+ of space between the graph and its adjacent columns in the timeline.
45
+
46
+ #### Ad ditional Classes
47
+ **Additional Classes**
48
+
49
+ * `.sel`: See [`.tl-node`](#tl-node) ### <a id="tl-rail"></a>`.tl-rail`tl-rail"></a>**`.tl-rail`**
50
+
51
+ Think of rails as invisibl Think of rails as invisible vertical lines o placed. The more simultaneous branches in a graph, the more rails required
52
+ to draw it. Setting the `width` property on this class determines the
53
+ maximum spacing between rails. This spacing is automatically reduced as
54
+ the number of rails increases. If you change the `width` of `.tl-node`
55
+ elements, you'll probably need to ch###ing the Timeline Graph
56
+
57
+Begi# Customizing theoreground`**
58
+
59
+ Set this to `1` if your skin uses white (or any light color) text.
60
+ T`
61
+
62
+ Set this to `round`**
63
+
64
+ Set this to `1` if your skin uses white (or any light color) text.
65
+ This tells Fossil to generate darker background colors for branches.
66
+
67
+
68
+## <a id="adv-style"></a>Advanced Styling
69
+
70
+If the above options aren't enough for you, it's time to get your hands dirty
71
+with CSS. To get started, I recommend first copying all the [graph-related CSS
72
+rules](#default-css) to yourcessary changes to achieve the look you want. So, next, let's look at the
73
+various graph elements and what purpose they serve.
74
+
75
+Each element used to construct the timeline graph falls into one of two
76
+categories: visible elements and positioning elements. We'll start with the
77
+latter, less obvious type.
78
+
79
+## <a id="pos-elems"></a>Positioning Elements
80
+
81
+These elements aren't intended to be seen. They're only used to h### <a id="
82
+
83
+ Set the left and right margins on this class to give the desired amount
84
+ of space between the graph and its adjaidth` of `.tl-node`
85
+ elements, you'll probably need to ch###ing the Timeline Graph
86
+
87
+Begi# Customizing theoreground`**
88
+
89
+ Set this to ` Think of rails as invisibl node`](#tl-node) ### <a id="tl-rail"></a>`.tl-rail`tl-rail"></a>**`.tl-rail`**
90
+
91
+ Thin more simultaneous branches in a graph, the more rails required
92
+ to draw it. Setting the `width` property on this class determines the
93
+ maximum spacing between rails. This spacing is automatically reduced as
94
+ the number of rails increases. If you change the `width` of `.tl-node`
95
+ elements, you'll probably need to ch###ing the Timeline Graph
96
+
97
+Begi# Customizing theoreground`**
98
+
99
+ Set this to `1` if your skin uses white (or any light color) text.
100
+ T`
101
+
102
+ Set this to `round`**
103
+
104
+ Set this to `1` if your skin uses white (or any light color) text.
105
+ This tells Fossil to generate darker background colors for branches.
106
+
107
+
108
+## <a id="adv-style"></a>Advanced Styling
109
+
110
+If the above options ar round: transparent;
111
+ border: 0 dotted #000;
112
+ }
113
+ . d #000;
114
+ }
115
+ .tl-line.merge.h {
116
+ border-top-width: 1px;
117
+ -#### Additional Classesl-node) for more infasses**
118
+
119
+ * `.merge`: A merge line.
120
+
121
+ * skin authors significantly
122
+more# Customizing the Timeline Graph
123
+
124
+Beginning with version 1.33, Fossil gives users and skin authors significantly
125
+more control over the look and feel of the timeline graph.
126
+
127
+## <a id="basic-style"></a>Basic Sty skin authors significantly
128
+more control over the look and feel of the timeline graph.
129
+
130
+## <a id="basic-style"></a>Basic Style Options
131
+
132
+Fossil includes several options for changing the graph's style without having
133
+to delve into CSS. These can be found in the details.txt file of your skin or
134
+under Admin/Skins/D###`timeline-arrowheads`
135
+
136
+ Set this to `0` to hide arrowheads on primary child lines.
137
+
138
+* ### Set this to `nodes`**
139
+
140
+ Set this to `1` to### `timeline-color-graph-line`
141
+
142
+ Set this to `1` to colorize### `white-foreground`
143
+
144
+ Set this to `round`**
--- a/www/customgraph.md
+++ b/www/customgraph.md
@@ -0,0 +1,144 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/www/customgraph.md
+++ b/www/customgraph.md
@@ -0,0 +1,144 @@
1 # Customizing the Timeline Graph
2
3 Beginning with version 1.33, Fossil gives users and skin authors significantly
4 more control over the look and feel of the timeline graph.
5
6 ## <a id="basic-style"></a>Basic Style Options
7
8 Fossil includes several options for changing the graph's style without having
9 to delve into CSS. These can be found in the details.txt file of your skin or
10 under Admin/Skins/D###`timeline-arrowheads`
11
12 Set this to `0` to hide arrowheads on primary child lines.
13
14 * ### Set this to `node s`**
15
16 Set this to `1` to### `timeline-color-graph-line`
17
18 Set this to `1` to colorize### `white-foreground`
19
20 Set this to `round`**
21
22 Seses white (or any light color) text.
23 This tells Fossil to generate darker background colors for branches.
24
25
26 ## <a id="adv-style"></a>Advanced Styling
27
28 If the above options aren't enough for you, it's time to get your hands dirty
29 with CSS. To get started, I recommend first copying all the [graph-related CSS
30 rules](#default-css) to your stylesheet. Then it's simply a matter of making
31 the necessary changes to achieve the look you want. So, next, let's look at the
32 various graph elements and what purpose they serve.
33
34 Each element used to construct the timeline graph falls into one of two
35 categories: visible elements and positioning elements. We'll start with the
36 latter, less obvious type.
37
38 ## <a id="pos-elems"></a>Positioning Elements
39
40 These elements aren't intended to be seen. They're only used to h### <a id="
41
42 Set the left and right margins on this class to give the desired amount
43 of space between tunt
44 of space between the graph and its adjacent columns in the timeline.
45
46 #### Ad ditional Classes
47 **Additional Classes**
48
49 * `.sel`: See [`.tl-node`](#tl-node) ### <a id="tl-rail"></a>`.tl-rail`tl-rail"></a>**`.tl-rail`**
50
51 Think of rails as invisibl Think of rails as invisible vertical lines o placed. The more simultaneous branches in a graph, the more rails required
52 to draw it. Setting the `width` property on this class determines the
53 maximum spacing between rails. This spacing is automatically reduced as
54 the number of rails increases. If you change the `width` of `.tl-node`
55 elements, you'll probably need to ch###ing the Timeline Graph
56
57 Begi# Customizing theoreground`**
58
59 Set this to `1` if your skin uses white (or any light color) text.
60 T`
61
62 Set this to `round`**
63
64 Set this to `1` if your skin uses white (or any light color) text.
65 This tells Fossil to generate darker background colors for branches.
66
67
68 ## <a id="adv-style"></a>Advanced Styling
69
70 If the above options aren't enough for you, it's time to get your hands dirty
71 with CSS. To get started, I recommend first copying all the [graph-related CSS
72 rules](#default-css) to yourcessary changes to achieve the look you want. So, next, let's look at the
73 various graph elements and what purpose they serve.
74
75 Each element used to construct the timeline graph falls into one of two
76 categories: visible elements and positioning elements. We'll start with the
77 latter, less obvious type.
78
79 ## <a id="pos-elems"></a>Positioning Elements
80
81 These elements aren't intended to be seen. They're only used to h### <a id="
82
83 Set the left and right margins on this class to give the desired amount
84 of space between the graph and its adjaidth` of `.tl-node`
85 elements, you'll probably need to ch###ing the Timeline Graph
86
87 Begi# Customizing theoreground`**
88
89 Set this to ` Think of rails as invisibl node`](#tl-node) ### <a id="tl-rail"></a>`.tl-rail`tl-rail"></a>**`.tl-rail`**
90
91 Thin more simultaneous branches in a graph, the more rails required
92 to draw it. Setting the `width` property on this class determines the
93 maximum spacing between rails. This spacing is automatically reduced as
94 the number of rails increases. If you change the `width` of `.tl-node`
95 elements, you'll probably need to ch###ing the Timeline Graph
96
97 Begi# Customizing theoreground`**
98
99 Set this to `1` if your skin uses white (or any light color) text.
100 T`
101
102 Set this to `round`**
103
104 Set this to `1` if your skin uses white (or any light color) text.
105 This tells Fossil to generate darker background colors for branches.
106
107
108 ## <a id="adv-style"></a>Advanced Styling
109
110 If the above options ar round: transparent;
111 border: 0 dotted #000;
112 }
113 . d #000;
114 }
115 .tl-line.merge.h {
116 border-top-width: 1px;
117 -#### Additional Classesl-node) for more infasses**
118
119 * `.merge`: A merge line.
120
121 * skin authors significantly
122 more# Customizing the Timeline Graph
123
124 Beginning with version 1.33, Fossil gives users and skin authors significantly
125 more control over the look and feel of the timeline graph.
126
127 ## <a id="basic-style"></a>Basic Sty skin authors significantly
128 more control over the look and feel of the timeline graph.
129
130 ## <a id="basic-style"></a>Basic Style Options
131
132 Fossil includes several options for changing the graph's style without having
133 to delve into CSS. These can be found in the details.txt file of your skin or
134 under Admin/Skins/D###`timeline-arrowheads`
135
136 Set this to `0` to hide arrowheads on primary child lines.
137
138 * ### Set this to `nodes`**
139
140 Set this to `1` to### `timeline-color-graph-line`
141
142 Set this to `1` to colorize### `white-foreground`
143
144 Set this to `round`**
--- www/customskin.md
+++ www/customskin.md
@@ -232,5 +232,10 @@
232232
233233
4. Copy/paste the resulting css.txt, details.txt,
234234
header.txt, and footer.txt files
235235
into the CSS, details, header, and footer configuration screens
236236
under the Admin/Skins menu.
237
+
238
+See Also
239
+--------
240
+
241
+* [Customizing the Timeline Graph](customgraph.md)
237242
--- www/customskin.md
+++ www/customskin.md
@@ -232,5 +232,10 @@
232
233 4. Copy/paste the resulting css.txt, details.txt,
234 header.txt, and footer.txt files
235 into the CSS, details, header, and footer configuration screens
236 under the Admin/Skins menu.
 
 
 
 
 
237
--- www/customskin.md
+++ www/customskin.md
@@ -232,5 +232,10 @@
232
233 4. Copy/paste the resulting css.txt, details.txt,
234 header.txt, and footer.txt files
235 into the CSS, details, header, and footer configuration screens
236 under the Admin/Skins menu.
237
238 See Also
239 --------
240
241 * [Customizing the Timeline Graph](customgraph.md)
242
--- www/mkindex.tcl
+++ www/mkindex.tcl
@@ -17,10 +17,11 @@
1717
checkin.wiki {Check-in Checklist}
1818
changes.wiki {Fossil Changelog}
1919
copyright-release.html {Contributor License Agreement}
2020
concepts.wiki {Fossil Core Concepts}
2121
contribute.wiki {Contributing Code or Documentation To The Fossil Project}
22
+ customgraph.md {Theming: Customizing the Timeline Graph}
2223
customskin.md {Theming: Customizing The Appearance of Web Pages}
2324
custom_ticket.wiki {Customizing The Ticket System}
2425
delta_encoder_algorithm.wiki {Fossil Delta Encoding Algorithm}
2526
delta_format.wiki {Fossil Delta Format}
2627
embeddeddoc.wiki {Embedded Project Documentation}
2728
--- www/mkindex.tcl
+++ www/mkindex.tcl
@@ -17,10 +17,11 @@
17 checkin.wiki {Check-in Checklist}
18 changes.wiki {Fossil Changelog}
19 copyright-release.html {Contributor License Agreement}
20 concepts.wiki {Fossil Core Concepts}
21 contribute.wiki {Contributing Code or Documentation To The Fossil Project}
 
22 customskin.md {Theming: Customizing The Appearance of Web Pages}
23 custom_ticket.wiki {Customizing The Ticket System}
24 delta_encoder_algorithm.wiki {Fossil Delta Encoding Algorithm}
25 delta_format.wiki {Fossil Delta Format}
26 embeddeddoc.wiki {Embedded Project Documentation}
27
--- www/mkindex.tcl
+++ www/mkindex.tcl
@@ -17,10 +17,11 @@
17 checkin.wiki {Check-in Checklist}
18 changes.wiki {Fossil Changelog}
19 copyright-release.html {Contributor License Agreement}
20 concepts.wiki {Fossil Core Concepts}
21 contribute.wiki {Contributing Code or Documentation To The Fossil Project}
22 customgraph.md {Theming: Customizing the Timeline Graph}
23 customskin.md {Theming: Customizing The Appearance of Web Pages}
24 custom_ticket.wiki {Customizing The Ticket System}
25 delta_encoder_algorithm.wiki {Fossil Delta Encoding Algorithm}
26 delta_format.wiki {Fossil Delta Format}
27 embeddeddoc.wiki {Embedded Project Documentation}
28
--- www/permutedindex.html
+++ www/permutedindex.html
@@ -34,12 +34,12 @@
3434
<li><a href="private.wiki">Branches &mdash; Creating, Syncing, and Deleting Private</a></li>
3535
<li><a href="branching.wiki">Branching, Forking, Merging, and Tagging</a></li>
3636
<li><a href="bugtheory.wiki">Bug Tracking In Fossil</a></li>
3737
<li><a href="makefile.wiki">Build Process &mdash; The Fossil</a></li>
3838
<li><a href="changes.wiki">Changelog &mdash; Fossil</a></li>
39
-<li><a href="checkin.wiki">Check-in Checklist</a></li>
4039
<li><a href="checkin_names.wiki">Check-in And Version Names</a></li>
40
+<li><a href="checkin.wiki">Check-in Checklist</a></li>
4141
<li><a href="checkin.wiki">Checklist &mdash; Check-in</a></li>
4242
<li><a href="../test/release-checklist.wiki">Checklist &mdash; Pre-Release Testing</a></li>
4343
<li><a href="foss-cklist.wiki">Checklist For Successful Open-Source Projects</a></li>
4444
<li><a href="selfcheck.wiki">Checks &mdash; Fossil Repository Integrity Self</a></li>
4545
<li><a href="contribute.wiki">Code or Documentation To The Fossil Project &mdash; Contributing</a></li>
@@ -54,10 +54,11 @@
5454
<li><a href="newrepo.wiki">Create A New Fossil Repository &mdash; How To</a></li>
5555
<li><a href="private.wiki">Creating, Syncing, and Deleting Private Branches</a></li>
5656
<li><a href="qandc.wiki">Criticisms &mdash; Questions And</a></li>
5757
<li><a href="customskin.md">Customizing The Appearance of Web Pages &mdash; Theming:</a></li>
5858
<li><a href="custom_ticket.wiki">Customizing The Ticket System</a></li>
59
+<li><a href="customgraph.md">Customizing the Timeline Graph &mdash; Theming:</a></li>
5960
<li><a href="tech_overview.wiki">Databases Used By Fossil &mdash; SQLite</a></li>
6061
<li><a href="antibot.wiki">Defense against Spiders and Bots</a></li>
6162
<li><a href="shunning.wiki">Deleting Content From Fossil &mdash; Shunning:</a></li>
6263
<li><a href="private.wiki">Deleting Private Branches &mdash; Creating, Syncing, and</a></li>
6364
<li><a href="delta_encoder_algorithm.wiki">Delta Encoding Algorithm &mdash; Fossil</a></li>
@@ -95,10 +96,11 @@
9596
<li><a href="inout.wiki">From Git &mdash; Import And Export To And</a></li>
9697
<li><a href="quotes.wiki">General &mdash; Quotes: What People Are Saying About Fossil, Git, and DVCSes in</a></li>
9798
<li><a href="fossil-v-git.wiki">Git &mdash; Fossil Versus</a></li>
9899
<li><a href="inout.wiki">Git &mdash; Import And Export To And From</a></li>
99100
<li><a href="quotes.wiki">Git, and DVCSes in General &mdash; Quotes: What People Are Saying About Fossil,</a></li>
101
+<li><a href="customgraph.md">Graph &mdash; Theming: Customizing the Timeline</a></li>
100102
<li><a href="quickstart.wiki">Guide &mdash; Fossil Quick Start</a></li>
101103
<li><a href="style.wiki">Guidelines &mdash; Source Code Style</a></li>
102104
<li><a href="hacker-howto.wiki">Hacker How-To</a></li>
103105
<li><a href="adding_code.wiki">Hacking Fossil</a></li>
104106
<li><a href="hints.wiki">Hints &mdash; Fossil Tips And Usage</a></li>
@@ -176,13 +178,15 @@
176178
<li><a href="sync.wiki">The Fossil Sync Protocol</a></li>
177179
<li><a href="tickets.wiki">The Fossil Ticket System</a></li>
178180
<li><a href="webui.wiki">The Fossil Web Interface</a></li>
179181
<li><a href="th1.md">The TH1 Scripting Language</a></li>
180182
<li><a href="customskin.md">Theming: Customizing The Appearance of Web Pages</a></li>
183
+<li><a href="customgraph.md">Theming: Customizing the Timeline Graph</a></li>
181184
<li><a href="theory1.wiki">Thoughts On The Design Of The Fossil DVCS</a></li>
182185
<li><a href="custom_ticket.wiki">Ticket System &mdash; Customizing The</a></li>
183186
<li><a href="tickets.wiki">Ticket System &mdash; The Fossil</a></li>
187
+<li><a href="customgraph.md">Timeline Graph &mdash; Theming: Customizing the</a></li>
184188
<li><a href="hints.wiki">Tips And Usage Hints &mdash; Fossil</a></li>
185189
<li><a href="bugtheory.wiki">Tracking In Fossil &mdash; Bug</a></li>
186190
<li><a href="fiveminutes.wiki">Update and Running in 5 Minutes as a Single User</a></li>
187191
<li><a href="hints.wiki">Usage Hints &mdash; Fossil Tips And</a></li>
188192
<li><a href="fiveminutes.wiki">User &mdash; Update and Running in 5 Minutes as a Single</a></li>
189193
--- www/permutedindex.html
+++ www/permutedindex.html
@@ -34,12 +34,12 @@
34 <li><a href="private.wiki">Branches &mdash; Creating, Syncing, and Deleting Private</a></li>
35 <li><a href="branching.wiki">Branching, Forking, Merging, and Tagging</a></li>
36 <li><a href="bugtheory.wiki">Bug Tracking In Fossil</a></li>
37 <li><a href="makefile.wiki">Build Process &mdash; The Fossil</a></li>
38 <li><a href="changes.wiki">Changelog &mdash; Fossil</a></li>
39 <li><a href="checkin.wiki">Check-in Checklist</a></li>
40 <li><a href="checkin_names.wiki">Check-in And Version Names</a></li>
 
41 <li><a href="checkin.wiki">Checklist &mdash; Check-in</a></li>
42 <li><a href="../test/release-checklist.wiki">Checklist &mdash; Pre-Release Testing</a></li>
43 <li><a href="foss-cklist.wiki">Checklist For Successful Open-Source Projects</a></li>
44 <li><a href="selfcheck.wiki">Checks &mdash; Fossil Repository Integrity Self</a></li>
45 <li><a href="contribute.wiki">Code or Documentation To The Fossil Project &mdash; Contributing</a></li>
@@ -54,10 +54,11 @@
54 <li><a href="newrepo.wiki">Create A New Fossil Repository &mdash; How To</a></li>
55 <li><a href="private.wiki">Creating, Syncing, and Deleting Private Branches</a></li>
56 <li><a href="qandc.wiki">Criticisms &mdash; Questions And</a></li>
57 <li><a href="customskin.md">Customizing The Appearance of Web Pages &mdash; Theming:</a></li>
58 <li><a href="custom_ticket.wiki">Customizing The Ticket System</a></li>
 
59 <li><a href="tech_overview.wiki">Databases Used By Fossil &mdash; SQLite</a></li>
60 <li><a href="antibot.wiki">Defense against Spiders and Bots</a></li>
61 <li><a href="shunning.wiki">Deleting Content From Fossil &mdash; Shunning:</a></li>
62 <li><a href="private.wiki">Deleting Private Branches &mdash; Creating, Syncing, and</a></li>
63 <li><a href="delta_encoder_algorithm.wiki">Delta Encoding Algorithm &mdash; Fossil</a></li>
@@ -95,10 +96,11 @@
95 <li><a href="inout.wiki">From Git &mdash; Import And Export To And</a></li>
96 <li><a href="quotes.wiki">General &mdash; Quotes: What People Are Saying About Fossil, Git, and DVCSes in</a></li>
97 <li><a href="fossil-v-git.wiki">Git &mdash; Fossil Versus</a></li>
98 <li><a href="inout.wiki">Git &mdash; Import And Export To And From</a></li>
99 <li><a href="quotes.wiki">Git, and DVCSes in General &mdash; Quotes: What People Are Saying About Fossil,</a></li>
 
100 <li><a href="quickstart.wiki">Guide &mdash; Fossil Quick Start</a></li>
101 <li><a href="style.wiki">Guidelines &mdash; Source Code Style</a></li>
102 <li><a href="hacker-howto.wiki">Hacker How-To</a></li>
103 <li><a href="adding_code.wiki">Hacking Fossil</a></li>
104 <li><a href="hints.wiki">Hints &mdash; Fossil Tips And Usage</a></li>
@@ -176,13 +178,15 @@
176 <li><a href="sync.wiki">The Fossil Sync Protocol</a></li>
177 <li><a href="tickets.wiki">The Fossil Ticket System</a></li>
178 <li><a href="webui.wiki">The Fossil Web Interface</a></li>
179 <li><a href="th1.md">The TH1 Scripting Language</a></li>
180 <li><a href="customskin.md">Theming: Customizing The Appearance of Web Pages</a></li>
 
181 <li><a href="theory1.wiki">Thoughts On The Design Of The Fossil DVCS</a></li>
182 <li><a href="custom_ticket.wiki">Ticket System &mdash; Customizing The</a></li>
183 <li><a href="tickets.wiki">Ticket System &mdash; The Fossil</a></li>
 
184 <li><a href="hints.wiki">Tips And Usage Hints &mdash; Fossil</a></li>
185 <li><a href="bugtheory.wiki">Tracking In Fossil &mdash; Bug</a></li>
186 <li><a href="fiveminutes.wiki">Update and Running in 5 Minutes as a Single User</a></li>
187 <li><a href="hints.wiki">Usage Hints &mdash; Fossil Tips And</a></li>
188 <li><a href="fiveminutes.wiki">User &mdash; Update and Running in 5 Minutes as a Single</a></li>
189
--- www/permutedindex.html
+++ www/permutedindex.html
@@ -34,12 +34,12 @@
34 <li><a href="private.wiki">Branches &mdash; Creating, Syncing, and Deleting Private</a></li>
35 <li><a href="branching.wiki">Branching, Forking, Merging, and Tagging</a></li>
36 <li><a href="bugtheory.wiki">Bug Tracking In Fossil</a></li>
37 <li><a href="makefile.wiki">Build Process &mdash; The Fossil</a></li>
38 <li><a href="changes.wiki">Changelog &mdash; Fossil</a></li>
 
39 <li><a href="checkin_names.wiki">Check-in And Version Names</a></li>
40 <li><a href="checkin.wiki">Check-in Checklist</a></li>
41 <li><a href="checkin.wiki">Checklist &mdash; Check-in</a></li>
42 <li><a href="../test/release-checklist.wiki">Checklist &mdash; Pre-Release Testing</a></li>
43 <li><a href="foss-cklist.wiki">Checklist For Successful Open-Source Projects</a></li>
44 <li><a href="selfcheck.wiki">Checks &mdash; Fossil Repository Integrity Self</a></li>
45 <li><a href="contribute.wiki">Code or Documentation To The Fossil Project &mdash; Contributing</a></li>
@@ -54,10 +54,11 @@
54 <li><a href="newrepo.wiki">Create A New Fossil Repository &mdash; How To</a></li>
55 <li><a href="private.wiki">Creating, Syncing, and Deleting Private Branches</a></li>
56 <li><a href="qandc.wiki">Criticisms &mdash; Questions And</a></li>
57 <li><a href="customskin.md">Customizing The Appearance of Web Pages &mdash; Theming:</a></li>
58 <li><a href="custom_ticket.wiki">Customizing The Ticket System</a></li>
59 <li><a href="customgraph.md">Customizing the Timeline Graph &mdash; Theming:</a></li>
60 <li><a href="tech_overview.wiki">Databases Used By Fossil &mdash; SQLite</a></li>
61 <li><a href="antibot.wiki">Defense against Spiders and Bots</a></li>
62 <li><a href="shunning.wiki">Deleting Content From Fossil &mdash; Shunning:</a></li>
63 <li><a href="private.wiki">Deleting Private Branches &mdash; Creating, Syncing, and</a></li>
64 <li><a href="delta_encoder_algorithm.wiki">Delta Encoding Algorithm &mdash; Fossil</a></li>
@@ -95,10 +96,11 @@
96 <li><a href="inout.wiki">From Git &mdash; Import And Export To And</a></li>
97 <li><a href="quotes.wiki">General &mdash; Quotes: What People Are Saying About Fossil, Git, and DVCSes in</a></li>
98 <li><a href="fossil-v-git.wiki">Git &mdash; Fossil Versus</a></li>
99 <li><a href="inout.wiki">Git &mdash; Import And Export To And From</a></li>
100 <li><a href="quotes.wiki">Git, and DVCSes in General &mdash; Quotes: What People Are Saying About Fossil,</a></li>
101 <li><a href="customgraph.md">Graph &mdash; Theming: Customizing the Timeline</a></li>
102 <li><a href="quickstart.wiki">Guide &mdash; Fossil Quick Start</a></li>
103 <li><a href="style.wiki">Guidelines &mdash; Source Code Style</a></li>
104 <li><a href="hacker-howto.wiki">Hacker How-To</a></li>
105 <li><a href="adding_code.wiki">Hacking Fossil</a></li>
106 <li><a href="hints.wiki">Hints &mdash; Fossil Tips And Usage</a></li>
@@ -176,13 +178,15 @@
178 <li><a href="sync.wiki">The Fossil Sync Protocol</a></li>
179 <li><a href="tickets.wiki">The Fossil Ticket System</a></li>
180 <li><a href="webui.wiki">The Fossil Web Interface</a></li>
181 <li><a href="th1.md">The TH1 Scripting Language</a></li>
182 <li><a href="customskin.md">Theming: Customizing The Appearance of Web Pages</a></li>
183 <li><a href="customgraph.md">Theming: Customizing the Timeline Graph</a></li>
184 <li><a href="theory1.wiki">Thoughts On The Design Of The Fossil DVCS</a></li>
185 <li><a href="custom_ticket.wiki">Ticket System &mdash; Customizing The</a></li>
186 <li><a href="tickets.wiki">Ticket System &mdash; The Fossil</a></li>
187 <li><a href="customgraph.md">Timeline Graph &mdash; Theming: Customizing the</a></li>
188 <li><a href="hints.wiki">Tips And Usage Hints &mdash; Fossil</a></li>
189 <li><a href="bugtheory.wiki">Tracking In Fossil &mdash; Bug</a></li>
190 <li><a href="fiveminutes.wiki">Update and Running in 5 Minutes as a Single User</a></li>
191 <li><a href="hints.wiki">Usage Hints &mdash; Fossil Tips And</a></li>
192 <li><a href="fiveminutes.wiki">User &mdash; Update and Running in 5 Minutes as a Single</a></li>
193
+78 -39
--- www/th1.md
+++ www/th1.md
@@ -166,90 +166,90 @@
166166
All commands starting with "tcl", with the exception of "tclReady",
167167
require the Tcl integration subsystem be included at compile-time.
168168
Additionally, the "tcl" repository setting must be enabled at runtime
169169
in order to successfully make use of these commands.
170170
171
-TH1 anoncap Command
--------------------
171
+<a name="anoncap"></a>TH1 anoncap Command
172
+-----------------------------------------
172173
173174
* anoncap STRING...
174175
175176
Returns true if the anonymous user has all of the capabilities listed
176177
in STRING.
177178
178
-TH1 anycap Command
-------------------
179
+<a name="anycap"></a>TH1 anycap Command
180
+---------------------------------------
179181
180182
* anycap STRING
181183
182184
Returns true if the current user user has any one of the capabilities
183185
listed in STRING.
184186
185
-TH1 artifact Command
---------------------
187
+<a name="artifact"></a>TH1 artifact Command
188
+-------------------------------------------
186189
187190
* artifact ID ?FILENAME?
188191
189192
Attempts to locate the specified artifact and return its contents. An
190193
error is generated if the repository is not open or the artifact cannot
191194
be found.
192195
193
-TH1 checkout Command
---------------------
196
+<a name="checkout"></a>TH1 checkout Command
197
+-------------------------------------------
194198
195199
* checkout ?BOOLEAN?
196200
197201
Return the fully qualified directory name of the current checkout or an
198202
empty string if it is not available. Optionally, it will attempt to find
199203
the current checkout, opening the configuration ("user") database and the
200204
repository as necessary, if the boolean argument is non-zero.
201205
202
-TH1 combobox Command
---------------------
206
+<a name="combobox"></a>TH1 combobox Command
207
+-------------------------------------------
203208
204209
* combobox NAME TEXT-LIST NUMLINES
205210
206211
Generates and emits an HTML combobox. NAME is both the name of the
207212
CGI parameter and the name of a variable that contains the currently
208213
selected value. TEXT-LIST is a list of possible values for the
209214
combobox. NUMLINES is 1 for a true combobox. If NUMLINES is greater
210215
than one then the display is a listbox with the number of lines given.
211216
212
-TH1 date Command
-----------------
217
+<a name="date"></a>TH1 date Command
218
+-----------------------------------
213219
214220
* date ?-local?
215221
216222
Return a strings which is the current time and date. If the -local
217223
option is used, the date appears using localtime instead of UTC.
218224
219
-TH1 decorate Command
---------------------
225
+<a name="decorate"></a>TH1 decorate Command
226
+-------------------------------------------
220227
221228
* decorate STRING
222229
223230
Renders STRING as wiki content; however, only links are handled. No
224231
other markup is processed.
225232
226
-TH1 enable_output Command
--------------------------
233
+<a name="enable_output"></a>TH1 enable_output Command
234
+-----------------------------------------------------
227235
228236
* enable_output BOOLEAN
229237
230238
Enable or disable sending output when the combobox, puts, or wiki
231239
commands are used.
232240
233
-TH1 getParameter Command
-------------------------
241
+<a name="getParameter"></a>TH1 getParameter Command
242
+---------------------------------------------------
234243
235244
* getParameter NAME ?DEFAULT?
236245
237246
Returns the value of the specified query parameter or the specified
238247
default value when there is no matching query parameter.
239248
240
-TH1 globalState Command
------------------------
249
+<a name="globalState"></a>TH1 globalState Command
250
+-------------------------------------------------
241251
242252
* globalState NAME ?DEFAULT?
243253
244254
Returns a string containing the value of the specified global state
245255
variable -OR- the specified default value. The supported items are:
@@ -266,20 +266,20 @@
266266
267267
Attempts to query for unsupported global state variables will result
268268
in a script error. Additional global state variables may be exposed
269269
in the future.
270270
271
-TH1 hascap Command
-------------------
271
+<a name="hascap"></a>TH1 hascap Command
272
+---------------------------------------
272273
273274
* hascap STRING...
274275
275276
Returns true if the current user has all of the capabilities listed
276277
in STRING.
277278
278
-TH1 hasfeature Command
-----------------------
279
+<a name="hasfeature"></a>TH1 hasfeature Command
280
+-----------------------------------------------
279281
280282
* hasfeature STRING
281283
282284
Returns true if the binary has the given compile-time feature enabled.
283285
The possible features are:
@@ -294,27 +294,27 @@
294294
1. **tclPrivateStubs** -- _Uses Tcl private stubs (i.e. header-only)._
295295
1. **json** -- _Support for the JSON APIs._
296296
1. **markdown** -- _Support for Markdown documentation format._
297297
1. **unicodeCmdLine** -- _The command line arguments are Unicode._
298298
299
-TH1 html Command
-----------------
299
+<a name="html"></a>TH1 html Command
300
+-----------------------------------
300301
301302
* html STRING
302303
303304
Outputs the STRING escaped for HTML.
304305
305
-TH1 htmlize Command
--------------------
306
+<a name="htmlize"></a>TH1 htmlize Command
307
+-----------------------------------------
306308
307309
* htmlize STRING
308310
309311
Escape all characters of STRING which have special meaning in HTML.
310312
Returns the escaped string.
311313
312
-TH1 http Command
-----------------
314
+<a name="http"></a>TH1 http Command
315
+-----------------------------------
313316
314317
* http ?-asynchronous? ?--? url ?payload?
315318
316319
Performs an HTTP or HTTPS request for the specified URL. If a
317320
payload is present, it will be interpreted as text/plain and
@@ -322,35 +322,35 @@
322322
be used. Upon success, if the -asynchronous option is used, an
323323
empty string is returned as the result; otherwise, the response
324324
from the server is returned as the result. Synchronous requests
325325
are not currently implemented.
326326
327
-TH1 httpize Command
--------------------
327
+<a name="httpize"></a>TH1 httpize Command
328
+-----------------------------------------
328329
329330
* httpize STRING
330331
331332
Escape all characters of STRING which have special meaning in URI
332333
components. Returns the escaped string.
333334
334
-TH1 linecount Command
----------------------
335
+<a name="linecount"></a>TH1 linecount Command
336
+---------------------------------------------
335337
336338
* linecount STRING MAX MIN
337339
338340
Returns one more than the number of \n characters in STRING. But
339341
never returns less than MIN or more than MAX.
340342
341
-TH1 puts Command
-----------------
343
+<a name="puts"></a>TH1 puts Command
344
+-----------------------------------
342345
343346
* puts STRING
344347
345348
Outputs the STRING unchanged.
346349
347
-TH1 query Command
------------------
350
+<a name="query"></a>TH1 query Command
351
+-------------------------------------
348352
349353
* query SQL CODE
350354
351355
Runs the SQL query given by the SQL argument. For each row in the result
352356
set, run CODE.
@@ -357,52 +357,52 @@
357357
358358
In SQL, parameters such as $var are filled in using the value of variable
359359
"var". Result values are stored in variables with the column name prior
360360
to each invocation of CODE.
361361
362
-TH1 randhex Command
--------------------
362
+<a name="randhex"></a>TH1 randhex Command
363
+-----------------------------------------
363364
364365
* randhex N
365366
366367
Returns a string of N*2 random hexadecimal digits with N<50. If N is
367368
omitted, use a value of 10.
368369
369
-TH1 regexp Command
-------------------
370
+<a name="regexp"></a>TH1 regexp Command
371
+---------------------------------------
370372
371373
* regexp ?-nocase? ?--? exp string
372374
373375
Checks the string against the specified regular expression and returns
374376
non-zero if it matches. If the regular expression is invalid or cannot
375377
be compiled, an error will be generated.
376378
377
-TH1 reinitialize Command
-------------------------
379
+<a name="reinitialize"></a>TH1 reinitialize Command
380
+---------------------------------------------------
378381
379382
* reinitialize ?FLAGS?
380383
381384
Reinitializes the TH1 interpreter using the specified flags.
382385
383
-TH1 render Command
-------------------
386
+<a name="render"></a>TH1 render Command
387
+---------------------------------------
384388
385389
* render STRING
386390
387391
Renders the TH1 template and writes the results.
388392
389
-TH1 repository Command
-----------------------
393
+<a name="repository"></a>TH1 repository Command
394
+-----------------------------------------------
390395
391396
* repository ?BOOLEAN?
392397
393398
Returns the fully qualified file name of the open repository or an empty
394399
string if one is not currently open. Optionally, it will attempt to open
395400
the repository if the boolean argument is non-zero.
396401
397
-TH1 searchable Command
-----------------------
402
+<a name="searchable"></a>TH1 searchable Command
403
+-----------------------------------------------
398404
399405
* searchable STRING...
400406
401407
Return true if searching in any of the document classes identified
402408
by STRING is enabled for the repository and user has the necessary
@@ -426,104 +426,104 @@
426426
if {[searchable cdtw]} {...}
427427
428428
This command is useful for enabling or disabling a "Search" entry on the
429429
menu bar.
430430
431
-TH1 setParameter Command
-------------------------
431
+<a name="setParameter"></a>TH1 setParameter Command
432
+---------------------------------------------------
432433
433434
* setParameter NAME VALUE
434435
435436
Sets the value of the specified query parameter.
436437
437
-TH1 setting Command
--------------------
438
+<a name="setting"></a>TH1 setting Command
439
+-----------------------------------------
438440
439441
* setting name
440442
441443
Gets and returns the value of the specified setting.
442444
443
-TH1 styleHeader Command
------------------------
445
+<a name="styleHeader"></a>TH1 styleHeader Command
446
+-------------------------------------------------
444447
445448
* styleHeader TITLE
446449
447450
Render the configured style header.
448451
449
-TH1 styleFooter Command
------------------------
452
+<a name="styleFooter"></a>TH1 styleFooter Command
453
+-------------------------------------------------
450454
451455
* styleFooter
452456
453457
Render the configured style footer.
454458
455
-TH1 tclEval Command
--------------------
459
+<a name="tclEval"></a>TH1 tclEval Command
460
+-----------------------------------------
456461
457462
**This command requires the Tcl integration feature.**
458463
459464
* tclEval arg ?arg ...?
460465
461466
Evaluates the Tcl script and returns its result verbatim. If a Tcl script
462467
error is generated, it will be transformed into a TH1 script error. A Tcl
463468
interpreter will be created automatically if it has not been already.
464469
465
-TH1 tclExpr Command
--------------------
470
+<a name="tclExpr"></a>TH1 tclExpr Command
471
+-----------------------------------------
466472
467473
**This command requires the Tcl integration feature.**
468474
469475
* tclExpr arg ?arg ...?
470476
471477
Evaluates the Tcl expression and returns its result verbatim. If a Tcl
472478
script error is generated, it will be transformed into a TH1 script error.
473479
A Tcl interpreter will be created automatically if it has not been already.
474480
475
-TH1 tclInvoke Command
----------------------
481
+<a name="tclInvoke"></a>TH1 tclInvoke Command
482
+---------------------------------------------
476483
477484
**This command requires the Tcl integration feature.**
478485
479486
* tclInvoke command ?arg ...?
480487
481488
Invokes the Tcl command using the supplied arguments. No additional
482489
substitutions are performed on the arguments. A Tcl interpreter will
483490
be created automatically if it has not been already.
484491
485
-TH1 tclReady Command
---------------------
492
+<a name="tclReady"></a>TH1 tclReady Command
493
+-------------------------------------------
486494
487495
* tclReady
488496
489497
Returns true if the binary has the Tcl integration feature enabled and it
490498
is currently available for use by TH1 scripts.
491499
492
-TH1 trace Command
------------------
500
+<a name="trace"></a>TH1 trace Command
501
+-------------------------------------
493502
494503
* trace STRING
495504
496505
Generates a TH1 trace message if TH1 tracing is enabled.
497506
498
-TH1 stime Command
------------------
507
+<a name="stime"></a>TH1 stime Command
508
+-------------------------------------
499509
500510
* stime
501511
502512
Returns the number of microseconds of CPU time consumed by the current
503513
process in system space.
504514
505
-TH1 utime Command
------------------
515
+<a name="utime"></a>TH1 utime Command
516
+-------------------------------------
506517
507518
* utime
508519
509520
Returns the number of microseconds of CPU time consumed by the current
510521
process in user space.
511522
512
-TH1 wiki Command
-----------------
523
+<a name="wiki"></a>TH1 wiki Command
524
+-----------------------------------
513525
514526
* wiki STRING
515527
516528
Renders STRING as wiki content.
517529
@@ -536,22 +536,22 @@
536536
Tcl commands:
537537
538538
* th1Eval
539539
* th1Expr
540540
541
-Tcl th1Eval Command
--------------------
541
+<a name="th1Eval"></a>Tcl th1Eval Command
542
+-----------------------------------------
542543
543544
**This command requires the Tcl integration feature.**
544545
545546
* th1Eval arg
546547
547548
Evaluates the TH1 script and returns its result verbatim. If a TH1 script
548549
error is generated, it will be transformed into a Tcl script error.
549550
550
-Tcl th1Expr Command
--------------------
551
+<a name="th1Expr"></a>Tcl th1Expr Command
552
+-----------------------------------------
551553
552554
**This command requires the Tcl integration feature.**
553555
554556
* th1Expr arg
555557
556558
--- www/th1.md
+++ www/th1.md
@@ -166,90 +166,90 @@
166 All commands starting with "tcl", with the exception of "tclReady",
167 require the Tcl integration subsystem be included at compile-time.
168 Additionally, the "tcl" repository setting must be enabled at runtime
169 in order to successfully make use of these commands.
170
171 TH1 anoncap Command
--------------------
 
 
172
173 * anoncap STRING...
174
175 Returns true if the anonymous user has all of the capabilities listed
176 in STRING.
177
178 TH1 anycap Command
-------------------
 
 
179
180 * anycap STRING
181
182 Returns true if the current user user has any one of the capabilities
183 listed in STRING.
184
185 TH1 artifact Command
---------------------
 
 
186
187 * artifact ID ?FILENAME?
188
189 Attempts to locate the specified artifact and return its contents. An
190 error is generated if the repository is not open or the artifact cannot
191 be found.
192
193 TH1 checkout Command
---------------------
 
 
194
195 * checkout ?BOOLEAN?
196
197 Return the fully qualified directory name of the current checkout or an
198 empty string if it is not available. Optionally, it will attempt to find
199 the current checkout, opening the configuration ("user") database and the
200 repository as necessary, if the boolean argument is non-zero.
201
202 TH1 combobox Command
---------------------
 
 
203
204 * combobox NAME TEXT-LIST NUMLINES
205
206 Generates and emits an HTML combobox. NAME is both the name of the
207 CGI parameter and the name of a variable that contains the currently
208 selected value. TEXT-LIST is a list of possible values for the
209 combobox. NUMLINES is 1 for a true combobox. If NUMLINES is greater
210 than one then the display is a listbox with the number of lines given.
211
212 TH1 date Command
-----------------
 
 
213
214 * date ?-local?
215
216 Return a strings which is the current time and date. If the -local
217 option is used, the date appears using localtime instead of UTC.
218
219 TH1 decorate Command
---------------------
 
 
220
221 * decorate STRING
222
223 Renders STRING as wiki content; however, only links are handled. No
224 other markup is processed.
225
226 TH1 enable_output Command
--------------------------
 
 
227
228 * enable_output BOOLEAN
229
230 Enable or disable sending output when the combobox, puts, or wiki
231 commands are used.
232
233 TH1 getParameter Command
-------------------------
 
 
234
235 * getParameter NAME ?DEFAULT?
236
237 Returns the value of the specified query parameter or the specified
238 default value when there is no matching query parameter.
239
240 TH1 globalState Command
------------------------
 
 
241
242 * globalState NAME ?DEFAULT?
243
244 Returns a string containing the value of the specified global state
245 variable -OR- the specified default value. The supported items are:
@@ -266,20 +266,20 @@
266
267 Attempts to query for unsupported global state variables will result
268 in a script error. Additional global state variables may be exposed
269 in the future.
270
271 TH1 hascap Command
-------------------
 
 
272
273 * hascap STRING...
274
275 Returns true if the current user has all of the capabilities listed
276 in STRING.
277
278 TH1 hasfeature Command
-----------------------
 
 
279
280 * hasfeature STRING
281
282 Returns true if the binary has the given compile-time feature enabled.
283 The possible features are:
@@ -294,27 +294,27 @@
294 1. **tclPrivateStubs** -- _Uses Tcl private stubs (i.e. header-only)._
295 1. **json** -- _Support for the JSON APIs._
296 1. **markdown** -- _Support for Markdown documentation format._
297 1. **unicodeCmdLine** -- _The command line arguments are Unicode._
298
299 TH1 html Command
-----------------
 
 
300
301 * html STRING
302
303 Outputs the STRING escaped for HTML.
304
305 TH1 htmlize Command
--------------------
 
 
306
307 * htmlize STRING
308
309 Escape all characters of STRING which have special meaning in HTML.
310 Returns the escaped string.
311
312 TH1 http Command
-----------------
 
 
313
314 * http ?-asynchronous? ?--? url ?payload?
315
316 Performs an HTTP or HTTPS request for the specified URL. If a
317 payload is present, it will be interpreted as text/plain and
@@ -322,35 +322,35 @@
322 be used. Upon success, if the -asynchronous option is used, an
323 empty string is returned as the result; otherwise, the response
324 from the server is returned as the result. Synchronous requests
325 are not currently implemented.
326
327 TH1 httpize Command
--------------------
 
 
328
329 * httpize STRING
330
331 Escape all characters of STRING which have special meaning in URI
332 components. Returns the escaped string.
333
334 TH1 linecount Command
----------------------
 
 
335
336 * linecount STRING MAX MIN
337
338 Returns one more than the number of \n characters in STRING. But
339 never returns less than MIN or more than MAX.
340
341 TH1 puts Command
-----------------
 
 
342
343 * puts STRING
344
345 Outputs the STRING unchanged.
346
347 TH1 query Command
------------------
 
 
348
349 * query SQL CODE
350
351 Runs the SQL query given by the SQL argument. For each row in the result
352 set, run CODE.
@@ -357,52 +357,52 @@
357
358 In SQL, parameters such as $var are filled in using the value of variable
359 "var". Result values are stored in variables with the column name prior
360 to each invocation of CODE.
361
362 TH1 randhex Command
--------------------
 
 
363
364 * randhex N
365
366 Returns a string of N*2 random hexadecimal digits with N<50. If N is
367 omitted, use a value of 10.
368
369 TH1 regexp Command
-------------------
 
 
370
371 * regexp ?-nocase? ?--? exp string
372
373 Checks the string against the specified regular expression and returns
374 non-zero if it matches. If the regular expression is invalid or cannot
375 be compiled, an error will be generated.
376
377 TH1 reinitialize Command
-------------------------
 
 
378
379 * reinitialize ?FLAGS?
380
381 Reinitializes the TH1 interpreter using the specified flags.
382
383 TH1 render Command
-------------------
 
 
384
385 * render STRING
386
387 Renders the TH1 template and writes the results.
388
389 TH1 repository Command
-----------------------
 
 
390
391 * repository ?BOOLEAN?
392
393 Returns the fully qualified file name of the open repository or an empty
394 string if one is not currently open. Optionally, it will attempt to open
395 the repository if the boolean argument is non-zero.
396
397 TH1 searchable Command
-----------------------
 
 
398
399 * searchable STRING...
400
401 Return true if searching in any of the document classes identified
402 by STRING is enabled for the repository and user has the necessary
@@ -426,104 +426,104 @@
426 if {[searchable cdtw]} {...}
427
428 This command is useful for enabling or disabling a "Search" entry on the
429 menu bar.
430
431 TH1 setParameter Command
-------------------------
 
 
432
433 * setParameter NAME VALUE
434
435 Sets the value of the specified query parameter.
436
437 TH1 setting Command
--------------------
 
 
438
439 * setting name
440
441 Gets and returns the value of the specified setting.
442
443 TH1 styleHeader Command
------------------------
 
 
444
445 * styleHeader TITLE
446
447 Render the configured style header.
448
449 TH1 styleFooter Command
------------------------
 
 
450
451 * styleFooter
452
453 Render the configured style footer.
454
455 TH1 tclEval Command
--------------------
 
 
456
457 **This command requires the Tcl integration feature.**
458
459 * tclEval arg ?arg ...?
460
461 Evaluates the Tcl script and returns its result verbatim. If a Tcl script
462 error is generated, it will be transformed into a TH1 script error. A Tcl
463 interpreter will be created automatically if it has not been already.
464
465 TH1 tclExpr Command
--------------------
 
 
466
467 **This command requires the Tcl integration feature.**
468
469 * tclExpr arg ?arg ...?
470
471 Evaluates the Tcl expression and returns its result verbatim. If a Tcl
472 script error is generated, it will be transformed into a TH1 script error.
473 A Tcl interpreter will be created automatically if it has not been already.
474
475 TH1 tclInvoke Command
----------------------
 
 
476
477 **This command requires the Tcl integration feature.**
478
479 * tclInvoke command ?arg ...?
480
481 Invokes the Tcl command using the supplied arguments. No additional
482 substitutions are performed on the arguments. A Tcl interpreter will
483 be created automatically if it has not been already.
484
485 TH1 tclReady Command
---------------------
 
 
486
487 * tclReady
488
489 Returns true if the binary has the Tcl integration feature enabled and it
490 is currently available for use by TH1 scripts.
491
492 TH1 trace Command
------------------
 
 
493
494 * trace STRING
495
496 Generates a TH1 trace message if TH1 tracing is enabled.
497
498 TH1 stime Command
------------------
 
 
499
500 * stime
501
502 Returns the number of microseconds of CPU time consumed by the current
503 process in system space.
504
505 TH1 utime Command
------------------
 
 
506
507 * utime
508
509 Returns the number of microseconds of CPU time consumed by the current
510 process in user space.
511
512 TH1 wiki Command
-----------------
 
 
513
514 * wiki STRING
515
516 Renders STRING as wiki content.
517
@@ -536,22 +536,22 @@
536 Tcl commands:
537
538 * th1Eval
539 * th1Expr
540
541 Tcl th1Eval Command
--------------------
 
 
542
543 **This command requires the Tcl integration feature.**
544
545 * th1Eval arg
546
547 Evaluates the TH1 script and returns its result verbatim. If a TH1 script
548 error is generated, it will be transformed into a Tcl script error.
549
550 Tcl th1Expr Command
--------------------
 
 
551
552 **This command requires the Tcl integration feature.**
553
554 * th1Expr arg
555
556
--- www/th1.md
+++ www/th1.md
@@ -166,90 +166,90 @@
166 All commands starting with "tcl", with the exception of "tclReady",
167 require the Tcl integration subsystem be included at compile-time.
168 Additionally, the "tcl" repository setting must be enabled at runtime
169 in order to successfully make use of these commands.
170
 
--------------------
171 <a name="anoncap"></a>TH1 anoncap Command
172 -----------------------------------------
173
174 * anoncap STRING...
175
176 Returns true if the anonymous user has all of the capabilities listed
177 in STRING.
178
 
-------------------
179 <a name="anycap"></a>TH1 anycap Command
180 ---------------------------------------
181
182 * anycap STRING
183
184 Returns true if the current user user has any one of the capabilities
185 listed in STRING.
186
 
---------------------
187 <a name="artifact"></a>TH1 artifact Command
188 -------------------------------------------
189
190 * artifact ID ?FILENAME?
191
192 Attempts to locate the specified artifact and return its contents. An
193 error is generated if the repository is not open or the artifact cannot
194 be found.
195
 
---------------------
196 <a name="checkout"></a>TH1 checkout Command
197 -------------------------------------------
198
199 * checkout ?BOOLEAN?
200
201 Return the fully qualified directory name of the current checkout or an
202 empty string if it is not available. Optionally, it will attempt to find
203 the current checkout, opening the configuration ("user") database and the
204 repository as necessary, if the boolean argument is non-zero.
205
 
---------------------
206 <a name="combobox"></a>TH1 combobox Command
207 -------------------------------------------
208
209 * combobox NAME TEXT-LIST NUMLINES
210
211 Generates and emits an HTML combobox. NAME is both the name of the
212 CGI parameter and the name of a variable that contains the currently
213 selected value. TEXT-LIST is a list of possible values for the
214 combobox. NUMLINES is 1 for a true combobox. If NUMLINES is greater
215 than one then the display is a listbox with the number of lines given.
216
 
-----------------
217 <a name="date"></a>TH1 date Command
218 -----------------------------------
219
220 * date ?-local?
221
222 Return a strings which is the current time and date. If the -local
223 option is used, the date appears using localtime instead of UTC.
224
 
---------------------
225 <a name="decorate"></a>TH1 decorate Command
226 -------------------------------------------
227
228 * decorate STRING
229
230 Renders STRING as wiki content; however, only links are handled. No
231 other markup is processed.
232
 
--------------------------
233 <a name="enable_output"></a>TH1 enable_output Command
234 -----------------------------------------------------
235
236 * enable_output BOOLEAN
237
238 Enable or disable sending output when the combobox, puts, or wiki
239 commands are used.
240
 
-------------------------
241 <a name="getParameter"></a>TH1 getParameter Command
242 ---------------------------------------------------
243
244 * getParameter NAME ?DEFAULT?
245
246 Returns the value of the specified query parameter or the specified
247 default value when there is no matching query parameter.
248
 
------------------------
249 <a name="globalState"></a>TH1 globalState Command
250 -------------------------------------------------
251
252 * globalState NAME ?DEFAULT?
253
254 Returns a string containing the value of the specified global state
255 variable -OR- the specified default value. The supported items are:
@@ -266,20 +266,20 @@
266
267 Attempts to query for unsupported global state variables will result
268 in a script error. Additional global state variables may be exposed
269 in the future.
270
 
-------------------
271 <a name="hascap"></a>TH1 hascap Command
272 ---------------------------------------
273
274 * hascap STRING...
275
276 Returns true if the current user has all of the capabilities listed
277 in STRING.
278
 
-----------------------
279 <a name="hasfeature"></a>TH1 hasfeature Command
280 -----------------------------------------------
281
282 * hasfeature STRING
283
284 Returns true if the binary has the given compile-time feature enabled.
285 The possible features are:
@@ -294,27 +294,27 @@
294 1. **tclPrivateStubs** -- _Uses Tcl private stubs (i.e. header-only)._
295 1. **json** -- _Support for the JSON APIs._
296 1. **markdown** -- _Support for Markdown documentation format._
297 1. **unicodeCmdLine** -- _The command line arguments are Unicode._
298
 
-----------------
299 <a name="html"></a>TH1 html Command
300 -----------------------------------
301
302 * html STRING
303
304 Outputs the STRING escaped for HTML.
305
 
--------------------
306 <a name="htmlize"></a>TH1 htmlize Command
307 -----------------------------------------
308
309 * htmlize STRING
310
311 Escape all characters of STRING which have special meaning in HTML.
312 Returns the escaped string.
313
 
-----------------
314 <a name="http"></a>TH1 http Command
315 -----------------------------------
316
317 * http ?-asynchronous? ?--? url ?payload?
318
319 Performs an HTTP or HTTPS request for the specified URL. If a
320 payload is present, it will be interpreted as text/plain and
@@ -322,35 +322,35 @@
322 be used. Upon success, if the -asynchronous option is used, an
323 empty string is returned as the result; otherwise, the response
324 from the server is returned as the result. Synchronous requests
325 are not currently implemented.
326
 
--------------------
327 <a name="httpize"></a>TH1 httpize Command
328 -----------------------------------------
329
330 * httpize STRING
331
332 Escape all characters of STRING which have special meaning in URI
333 components. Returns the escaped string.
334
 
----------------------
335 <a name="linecount"></a>TH1 linecount Command
336 ---------------------------------------------
337
338 * linecount STRING MAX MIN
339
340 Returns one more than the number of \n characters in STRING. But
341 never returns less than MIN or more than MAX.
342
 
-----------------
343 <a name="puts"></a>TH1 puts Command
344 -----------------------------------
345
346 * puts STRING
347
348 Outputs the STRING unchanged.
349
 
------------------
350 <a name="query"></a>TH1 query Command
351 -------------------------------------
352
353 * query SQL CODE
354
355 Runs the SQL query given by the SQL argument. For each row in the result
356 set, run CODE.
@@ -357,52 +357,52 @@
357
358 In SQL, parameters such as $var are filled in using the value of variable
359 "var". Result values are stored in variables with the column name prior
360 to each invocation of CODE.
361
 
--------------------
362 <a name="randhex"></a>TH1 randhex Command
363 -----------------------------------------
364
365 * randhex N
366
367 Returns a string of N*2 random hexadecimal digits with N<50. If N is
368 omitted, use a value of 10.
369
 
-------------------
370 <a name="regexp"></a>TH1 regexp Command
371 ---------------------------------------
372
373 * regexp ?-nocase? ?--? exp string
374
375 Checks the string against the specified regular expression and returns
376 non-zero if it matches. If the regular expression is invalid or cannot
377 be compiled, an error will be generated.
378
 
-------------------------
379 <a name="reinitialize"></a>TH1 reinitialize Command
380 ---------------------------------------------------
381
382 * reinitialize ?FLAGS?
383
384 Reinitializes the TH1 interpreter using the specified flags.
385
 
-------------------
386 <a name="render"></a>TH1 render Command
387 ---------------------------------------
388
389 * render STRING
390
391 Renders the TH1 template and writes the results.
392
 
-----------------------
393 <a name="repository"></a>TH1 repository Command
394 -----------------------------------------------
395
396 * repository ?BOOLEAN?
397
398 Returns the fully qualified file name of the open repository or an empty
399 string if one is not currently open. Optionally, it will attempt to open
400 the repository if the boolean argument is non-zero.
401
 
-----------------------
402 <a name="searchable"></a>TH1 searchable Command
403 -----------------------------------------------
404
405 * searchable STRING...
406
407 Return true if searching in any of the document classes identified
408 by STRING is enabled for the repository and user has the necessary
@@ -426,104 +426,104 @@
426 if {[searchable cdtw]} {...}
427
428 This command is useful for enabling or disabling a "Search" entry on the
429 menu bar.
430
 
-------------------------
431 <a name="setParameter"></a>TH1 setParameter Command
432 ---------------------------------------------------
433
434 * setParameter NAME VALUE
435
436 Sets the value of the specified query parameter.
437
 
--------------------
438 <a name="setting"></a>TH1 setting Command
439 -----------------------------------------
440
441 * setting name
442
443 Gets and returns the value of the specified setting.
444
 
------------------------
445 <a name="styleHeader"></a>TH1 styleHeader Command
446 -------------------------------------------------
447
448 * styleHeader TITLE
449
450 Render the configured style header.
451
 
------------------------
452 <a name="styleFooter"></a>TH1 styleFooter Command
453 -------------------------------------------------
454
455 * styleFooter
456
457 Render the configured style footer.
458
 
--------------------
459 <a name="tclEval"></a>TH1 tclEval Command
460 -----------------------------------------
461
462 **This command requires the Tcl integration feature.**
463
464 * tclEval arg ?arg ...?
465
466 Evaluates the Tcl script and returns its result verbatim. If a Tcl script
467 error is generated, it will be transformed into a TH1 script error. A Tcl
468 interpreter will be created automatically if it has not been already.
469
 
--------------------
470 <a name="tclExpr"></a>TH1 tclExpr Command
471 -----------------------------------------
472
473 **This command requires the Tcl integration feature.**
474
475 * tclExpr arg ?arg ...?
476
477 Evaluates the Tcl expression and returns its result verbatim. If a Tcl
478 script error is generated, it will be transformed into a TH1 script error.
479 A Tcl interpreter will be created automatically if it has not been already.
480
 
----------------------
481 <a name="tclInvoke"></a>TH1 tclInvoke Command
482 ---------------------------------------------
483
484 **This command requires the Tcl integration feature.**
485
486 * tclInvoke command ?arg ...?
487
488 Invokes the Tcl command using the supplied arguments. No additional
489 substitutions are performed on the arguments. A Tcl interpreter will
490 be created automatically if it has not been already.
491
 
---------------------
492 <a name="tclReady"></a>TH1 tclReady Command
493 -------------------------------------------
494
495 * tclReady
496
497 Returns true if the binary has the Tcl integration feature enabled and it
498 is currently available for use by TH1 scripts.
499
 
------------------
500 <a name="trace"></a>TH1 trace Command
501 -------------------------------------
502
503 * trace STRING
504
505 Generates a TH1 trace message if TH1 tracing is enabled.
506
 
------------------
507 <a name="stime"></a>TH1 stime Command
508 -------------------------------------
509
510 * stime
511
512 Returns the number of microseconds of CPU time consumed by the current
513 process in system space.
514
 
------------------
515 <a name="utime"></a>TH1 utime Command
516 -------------------------------------
517
518 * utime
519
520 Returns the number of microseconds of CPU time consumed by the current
521 process in user space.
522
 
-----------------
523 <a name="wiki"></a>TH1 wiki Command
524 -----------------------------------
525
526 * wiki STRING
527
528 Renders STRING as wiki content.
529
@@ -536,22 +536,22 @@
536 Tcl commands:
537
538 * th1Eval
539 * th1Expr
540
 
--------------------
541 <a name="th1Eval"></a>Tcl th1Eval Command
542 -----------------------------------------
543
544 **This command requires the Tcl integration feature.**
545
546 * th1Eval arg
547
548 Evaluates the TH1 script and returns its result verbatim. If a TH1 script
549 error is generated, it will be transformed into a Tcl script error.
550
 
--------------------
551 <a name="th1Expr"></a>Tcl th1Expr Command
552 -----------------------------------------
553
554 **This command requires the Tcl integration feature.**
555
556 * th1Expr arg
557
558

Keyboard Shortcuts

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