Fossil

Check-in [315351f4ac]
Login

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

Overview
Comment:Merge in trunk (release 2.17)
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | wcontent-subsets
Files: files | file ages | folders
SHA3-256: 315351f4acab9df8fc3d5f0292f87f33ed109b053f57be3f65258d91f8648542
User & Date: george 2021-10-09 19:50:28.542
Context
2022-01-21
20:13
Merge from trunk check-in: 5c0515e20c user: george tags: wcontent-subsets
2021-10-09
19:50
Merge in trunk (release 2.17) check-in: 315351f4ac user: george tags: wcontent-subsets
14:43
Version 2.17 check-in: f48180f2ff user: drh tags: trunk, release, version-2.17
2021-08-15
23:27
Merge from trunk check-in: 282c6f956f user: george tags: wcontent-subsets
Changes
Unified Diff Ignore Whitespace Patch
Deleted art/CollRev1.dia.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
<?xml version="1.0" encoding="UTF-8"?>
<dia:diagram xmlns:dia="http://www.lysator.liu.se/~alla/dia/">
  <dia:diagramdata>
    <dia:attribute name="background">
      <dia:color val="#ffffff"/>
    </dia:attribute>
    <dia:attribute name="pagebreak">
      <dia:color val="#000099"/>
    </dia:attribute>
    <dia:attribute name="paper">
      <dia:composite type="paper">
        <dia:attribute name="name">
          <dia:string>#Letter#</dia:string>
        </dia:attribute>
        <dia:attribute name="tmargin">
          <dia:real val="2.5399999618530273"/>
        </dia:attribute>
        <dia:attribute name="bmargin">
          <dia:real val="2.5399999618530273"/>
        </dia:attribute>
        <dia:attribute name="lmargin">
          <dia:real val="2.5399999618530273"/>
        </dia:attribute>
        <dia:attribute name="rmargin">
          <dia:real val="2.5399999618530273"/>
        </dia:attribute>
        <dia:attribute name="is_portrait">
          <dia:boolean val="true"/>
        </dia:attribute>
        <dia:attribute name="scaling">
          <dia:real val="1"/>
        </dia:attribute>
        <dia:attribute name="fitto">
          <dia:boolean val="false"/>
        </dia:attribute>
      </dia:composite>
    </dia:attribute>
    <dia:attribute name="grid">
      <dia:composite type="grid">
        <dia:attribute name="width_x">
          <dia:real val="1"/>
        </dia:attribute>
        <dia:attribute name="width_y">
          <dia:real val="1"/>
        </dia:attribute>
        <dia:attribute name="visible_x">
          <dia:int val="1"/>
        </dia:attribute>
        <dia:attribute name="visible_y">
          <dia:int val="1"/>
        </dia:attribute>
        <dia:composite type="color"/>
      </dia:composite>
    </dia:attribute>
    <dia:attribute name="color">
      <dia:color val="#d8e5e5"/>
    </dia:attribute>
    <dia:attribute name="guides">
      <dia:composite type="guides">
        <dia:attribute name="hguides"/>
        <dia:attribute name="vguides"/>
      </dia:composite>
    </dia:attribute>
  </dia:diagramdata>
  <dia:layer name="Background" visible="true">
    <dia:group>
      <dia:group>
        <dia:object type="Standard - Box" version="0" id="O0">
          <dia:attribute name="obj_pos">
            <dia:point val="15,13"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="14.95,12.95;20.05,15.05"/>
          </dia:attribute>
          <dia:attribute name="elem_corner">
            <dia:point val="15,13"/>
          </dia:attribute>
          <dia:attribute name="elem_width">
            <dia:real val="5"/>
          </dia:attribute>
          <dia:attribute name="elem_height">
            <dia:real val="2"/>
          </dia:attribute>
          <dia:attribute name="show_background">
            <dia:boolean val="true"/>
          </dia:attribute>
        </dia:object>
        <dia:object type="Standard - Text" version="1" id="O1">
          <dia:attribute name="obj_pos">
            <dia:point val="16.2733,14.064"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="16.2733,13.5215;18.7096,14.4615"/>
          </dia:attribute>
          <dia:attribute name="text">
            <dia:composite type="text">
              <dia:attribute name="string">
                <dia:string>#Revision#</dia:string>
              </dia:attribute>
              <dia:attribute name="font">
                <dia:font family="sans" style="0" name="Helvetica"/>
              </dia:attribute>
              <dia:attribute name="height">
                <dia:real val="0.80000000000000004"/>
              </dia:attribute>
              <dia:attribute name="pos">
                <dia:point val="16.2733,14.064"/>
              </dia:attribute>
              <dia:attribute name="color">
                <dia:color val="#000000"/>
              </dia:attribute>
              <dia:attribute name="alignment">
                <dia:enum val="0"/>
              </dia:attribute>
            </dia:composite>
          </dia:attribute>
          <dia:attribute name="valign">
            <dia:enum val="3"/>
          </dia:attribute>
        </dia:object>
      </dia:group>
      <dia:group>
        <dia:object type="Standard - Box" version="0" id="O2">
          <dia:attribute name="obj_pos">
            <dia:point val="15,7"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="14.95,6.95;20.05,9.05"/>
          </dia:attribute>
          <dia:attribute name="elem_corner">
            <dia:point val="15,7"/>
          </dia:attribute>
          <dia:attribute name="elem_width">
            <dia:real val="5"/>
          </dia:attribute>
          <dia:attribute name="elem_height">
            <dia:real val="2"/>
          </dia:attribute>
          <dia:attribute name="show_background">
            <dia:boolean val="true"/>
          </dia:attribute>
        </dia:object>
        <dia:object type="Standard - Text" version="1" id="O3">
          <dia:attribute name="obj_pos">
            <dia:point val="17.0039,8.06397"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="17.0039,7.52147;17.979,8.46147"/>
          </dia:attribute>
          <dia:attribute name="text">
            <dia:composite type="text">
              <dia:attribute name="string">
                <dia:string>#File#</dia:string>
              </dia:attribute>
              <dia:attribute name="font">
                <dia:font family="sans" style="0" name="Helvetica"/>
              </dia:attribute>
              <dia:attribute name="height">
                <dia:real val="0.80000000000000004"/>
              </dia:attribute>
              <dia:attribute name="pos">
                <dia:point val="17.0039,8.06397"/>
              </dia:attribute>
              <dia:attribute name="color">
                <dia:color val="#000000"/>
              </dia:attribute>
              <dia:attribute name="alignment">
                <dia:enum val="0"/>
              </dia:attribute>
            </dia:composite>
          </dia:attribute>
          <dia:attribute name="valign">
            <dia:enum val="3"/>
          </dia:attribute>
        </dia:object>
      </dia:group>
      <dia:group>
        <dia:object type="Standard - Box" version="0" id="O4">
          <dia:attribute name="obj_pos">
            <dia:point val="15,1"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="14.95,0.95;20.05,3.05"/>
          </dia:attribute>
          <dia:attribute name="elem_corner">
            <dia:point val="15,1"/>
          </dia:attribute>
          <dia:attribute name="elem_width">
            <dia:real val="5"/>
          </dia:attribute>
          <dia:attribute name="elem_height">
            <dia:real val="2"/>
          </dia:attribute>
          <dia:attribute name="show_background">
            <dia:boolean val="true"/>
          </dia:attribute>
        </dia:object>
        <dia:object type="Standard - Text" version="1" id="O5">
          <dia:attribute name="obj_pos">
            <dia:point val="16.4942,2.06397"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="16.4942,1.52147;18.4887,2.46147"/>
          </dia:attribute>
          <dia:attribute name="text">
            <dia:composite type="text">
              <dia:attribute name="string">
                <dia:string>#Project#</dia:string>
              </dia:attribute>
              <dia:attribute name="font">
                <dia:font family="sans" style="0" name="Helvetica"/>
              </dia:attribute>
              <dia:attribute name="height">
                <dia:real val="0.80000000000000004"/>
              </dia:attribute>
              <dia:attribute name="pos">
                <dia:point val="16.4942,2.06397"/>
              </dia:attribute>
              <dia:attribute name="color">
                <dia:color val="#000000"/>
              </dia:attribute>
              <dia:attribute name="alignment">
                <dia:enum val="0"/>
              </dia:attribute>
            </dia:composite>
          </dia:attribute>
          <dia:attribute name="valign">
            <dia:enum val="3"/>
          </dia:attribute>
        </dia:object>
      </dia:group>
      <dia:object type="Standard - ZigZagLine" version="1" id="O6">
        <dia:attribute name="obj_pos">
          <dia:point val="17.5,13"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="17.45,8.92929;17.55,13"/>
        </dia:attribute>
        <dia:attribute name="orth_points">
          <dia:point val="17.5,13"/>
          <dia:point val="17.5,13"/>
          <dia:point val="17.5,9"/>
          <dia:point val="17.5,9"/>
        </dia:attribute>
        <dia:attribute name="orth_orient">
          <dia:enum val="0"/>
          <dia:enum val="1"/>
          <dia:enum val="0"/>
        </dia:attribute>
        <dia:attribute name="autorouting">
          <dia:boolean val="true"/>
        </dia:attribute>
        <dia:attribute name="end_arrow">
          <dia:enum val="22"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_length">
          <dia:real val="0.5"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_width">
          <dia:real val="0.5"/>
        </dia:attribute>
      </dia:object>
      <dia:object type="Standard - ZigZagLine" version="1" id="O7">
        <dia:attribute name="obj_pos">
          <dia:point val="17.5,7"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="17.45,2.92929;17.55,7"/>
        </dia:attribute>
        <dia:attribute name="orth_points">
          <dia:point val="17.5,7"/>
          <dia:point val="17.5,7"/>
          <dia:point val="17.5,3"/>
          <dia:point val="17.5,3"/>
        </dia:attribute>
        <dia:attribute name="orth_orient">
          <dia:enum val="0"/>
          <dia:enum val="1"/>
          <dia:enum val="0"/>
        </dia:attribute>
        <dia:attribute name="autorouting">
          <dia:boolean val="true"/>
        </dia:attribute>
        <dia:attribute name="end_arrow">
          <dia:enum val="22"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_length">
          <dia:real val="0.5"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_width">
          <dia:real val="0.5"/>
        </dia:attribute>
      </dia:object>
      <dia:group>
        <dia:object type="Standard - Box" version="0" id="O8">
          <dia:attribute name="obj_pos">
            <dia:point val="15,19"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="14.95,18.95;20.05,21.05"/>
          </dia:attribute>
          <dia:attribute name="elem_corner">
            <dia:point val="15,19"/>
          </dia:attribute>
          <dia:attribute name="elem_width">
            <dia:real val="5"/>
          </dia:attribute>
          <dia:attribute name="elem_height">
            <dia:real val="2"/>
          </dia:attribute>
          <dia:attribute name="show_background">
            <dia:boolean val="true"/>
          </dia:attribute>
        </dia:object>
        <dia:object type="Standard - Text" version="1" id="O9">
          <dia:attribute name="obj_pos">
            <dia:point val="16.7775,20.064"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="16.7775,19.5215;18.2225,20.4615"/>
          </dia:attribute>
          <dia:attribute name="text">
            <dia:composite type="text">
              <dia:attribute name="string">
                <dia:string>#Meta#</dia:string>
              </dia:attribute>
              <dia:attribute name="font">
                <dia:font family="sans" style="0" name="Helvetica"/>
              </dia:attribute>
              <dia:attribute name="height">
                <dia:real val="0.80000000000000004"/>
              </dia:attribute>
              <dia:attribute name="pos">
                <dia:point val="16.7775,20.064"/>
              </dia:attribute>
              <dia:attribute name="color">
                <dia:color val="#000000"/>
              </dia:attribute>
              <dia:attribute name="alignment">
                <dia:enum val="0"/>
              </dia:attribute>
            </dia:composite>
          </dia:attribute>
          <dia:attribute name="valign">
            <dia:enum val="3"/>
          </dia:attribute>
        </dia:object>
      </dia:group>
      <dia:object type="Standard - PolyLine" version="0" id="O10">
        <dia:attribute name="obj_pos">
          <dia:point val="15,20"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="7.5,14.95;15.05,20.05"/>
        </dia:attribute>
        <dia:attribute name="poly_points">
          <dia:point val="15,20"/>
          <dia:point val="8,20"/>
          <dia:point val="8,15"/>
        </dia:attribute>
        <dia:attribute name="end_arrow">
          <dia:enum val="22"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_length">
          <dia:real val="0.5"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_width">
          <dia:real val="0.5"/>
        </dia:attribute>
      </dia:object>
      <dia:object type="Standard - Line" version="0" id="O11">
        <dia:attribute name="obj_pos">
          <dia:point val="15,14"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="10.95,13.5;15.05,14.5"/>
        </dia:attribute>
        <dia:attribute name="conn_endpoints">
          <dia:point val="15,14"/>
          <dia:point val="11,14"/>
        </dia:attribute>
        <dia:attribute name="numcp">
          <dia:int val="1"/>
        </dia:attribute>
        <dia:attribute name="end_arrow">
          <dia:enum val="22"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_length">
          <dia:real val="0.5"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_width">
          <dia:real val="0.5"/>
        </dia:attribute>
      </dia:object>
      <dia:object type="Standard - ZigZagLine" version="1" id="O12">
        <dia:attribute name="obj_pos">
          <dia:point val="20,20"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="19.95,1.5;27.05,20.05"/>
        </dia:attribute>
        <dia:attribute name="orth_points">
          <dia:point val="20,20"/>
          <dia:point val="27,20"/>
          <dia:point val="27,2"/>
          <dia:point val="20,2"/>
        </dia:attribute>
        <dia:attribute name="orth_orient">
          <dia:enum val="0"/>
          <dia:enum val="1"/>
          <dia:enum val="0"/>
        </dia:attribute>
        <dia:attribute name="autorouting">
          <dia:boolean val="false"/>
        </dia:attribute>
        <dia:attribute name="end_arrow">
          <dia:enum val="22"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_length">
          <dia:real val="0.5"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_width">
          <dia:real val="0.5"/>
        </dia:attribute>
      </dia:object>
      <dia:object type="Standard - Line" version="0" id="O13">
        <dia:attribute name="obj_pos">
          <dia:point val="17.5,15"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="17,14.95;18,19.05"/>
        </dia:attribute>
        <dia:attribute name="conn_endpoints">
          <dia:point val="17.5,15"/>
          <dia:point val="17.5,19"/>
        </dia:attribute>
        <dia:attribute name="numcp">
          <dia:int val="1"/>
        </dia:attribute>
        <dia:attribute name="end_arrow">
          <dia:enum val="22"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_length">
          <dia:real val="0.5"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_width">
          <dia:real val="0.5"/>
        </dia:attribute>
      </dia:object>
      <dia:object type="Standard - PolyLine" version="0" id="O14">
        <dia:attribute name="obj_pos">
          <dia:point val="8,13"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="7.95,1.5;15.05,13.05"/>
        </dia:attribute>
        <dia:attribute name="poly_points">
          <dia:point val="8,13"/>
          <dia:point val="8,2"/>
          <dia:point val="15,2"/>
        </dia:attribute>
        <dia:attribute name="end_arrow">
          <dia:enum val="22"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_length">
          <dia:real val="0.5"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_width">
          <dia:real val="0.5"/>
        </dia:attribute>
      </dia:object>
      <dia:group>
        <dia:object type="Standard - Box" version="0" id="O15">
          <dia:attribute name="obj_pos">
            <dia:point val="5,13"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="4.95,12.95;11.05,15.05"/>
          </dia:attribute>
          <dia:attribute name="elem_corner">
            <dia:point val="5,13"/>
          </dia:attribute>
          <dia:attribute name="elem_width">
            <dia:real val="6"/>
          </dia:attribute>
          <dia:attribute name="elem_height">
            <dia:real val="2"/>
          </dia:attribute>
          <dia:attribute name="show_background">
            <dia:boolean val="true"/>
          </dia:attribute>
        </dia:object>
        <dia:object type="Standard - Text" version="1" id="O16">
          <dia:attribute name="obj_pos">
            <dia:point val="6.91375,14.0725"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="6.91375,13.53;9.08625,14.47"/>
          </dia:attribute>
          <dia:attribute name="text">
            <dia:composite type="text">
              <dia:attribute name="string">
                <dia:string>#Symbol#</dia:string>
              </dia:attribute>
              <dia:attribute name="font">
                <dia:font family="sans" style="0" name="Helvetica"/>
              </dia:attribute>
              <dia:attribute name="height">
                <dia:real val="0.80000000000000004"/>
              </dia:attribute>
              <dia:attribute name="pos">
                <dia:point val="6.91375,14.0725"/>
              </dia:attribute>
              <dia:attribute name="color">
                <dia:color val="#000000"/>
              </dia:attribute>
              <dia:attribute name="alignment">
                <dia:enum val="0"/>
              </dia:attribute>
            </dia:composite>
          </dia:attribute>
          <dia:attribute name="valign">
            <dia:enum val="3"/>
          </dia:attribute>
        </dia:object>
      </dia:group>
      <dia:object type="Standard - Text" version="1" id="O17">
        <dia:attribute name="obj_pos">
          <dia:point val="18,12"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="18,11.4575;21.06,12.3975"/>
        </dia:attribute>
        <dia:attribute name="text">
          <dia:composite type="text">
            <dia:attribute name="string">
              <dia:string>#belongs to#</dia:string>
            </dia:attribute>
            <dia:attribute name="font">
              <dia:font family="sans" style="0" name="Helvetica"/>
            </dia:attribute>
            <dia:attribute name="height">
              <dia:real val="0.80000000000000004"/>
            </dia:attribute>
            <dia:attribute name="pos">
              <dia:point val="18,12"/>
            </dia:attribute>
            <dia:attribute name="color">
              <dia:color val="#000000"/>
            </dia:attribute>
            <dia:attribute name="alignment">
              <dia:enum val="0"/>
            </dia:attribute>
          </dia:composite>
        </dia:attribute>
        <dia:attribute name="valign">
          <dia:enum val="3"/>
        </dia:attribute>
      </dia:object>
      <dia:object type="Standard - Text" version="1" id="O18">
        <dia:attribute name="obj_pos">
          <dia:point val="18,6"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="18,5.4575;21.06,6.3975"/>
        </dia:attribute>
        <dia:attribute name="text">
          <dia:composite type="text">
            <dia:attribute name="string">
              <dia:string>#belongs to#</dia:string>
            </dia:attribute>
            <dia:attribute name="font">
              <dia:font family="sans" style="0" name="Helvetica"/>
            </dia:attribute>
            <dia:attribute name="height">
              <dia:real val="0.80000000000000004"/>
            </dia:attribute>
            <dia:attribute name="pos">
              <dia:point val="18,6"/>
            </dia:attribute>
            <dia:attribute name="color">
              <dia:color val="#000000"/>
            </dia:attribute>
            <dia:attribute name="alignment">
              <dia:enum val="0"/>
            </dia:attribute>
          </dia:composite>
        </dia:attribute>
        <dia:attribute name="valign">
          <dia:enum val="3"/>
        </dia:attribute>
      </dia:object>
      <dia:object type="Standard - Text" version="1" id="O19">
        <dia:attribute name="obj_pos">
          <dia:point val="18,16"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="18,15.4575;19.03,16.3975"/>
        </dia:attribute>
        <dia:attribute name="text">
          <dia:composite type="text">
            <dia:attribute name="string">
              <dia:string>#has#</dia:string>
            </dia:attribute>
            <dia:attribute name="font">
              <dia:font family="sans" style="0" name="Helvetica"/>
            </dia:attribute>
            <dia:attribute name="height">
              <dia:real val="0.80000000000000004"/>
            </dia:attribute>
            <dia:attribute name="pos">
              <dia:point val="18,16"/>
            </dia:attribute>
            <dia:attribute name="color">
              <dia:color val="#000000"/>
            </dia:attribute>
            <dia:attribute name="alignment">
              <dia:enum val="0"/>
            </dia:attribute>
          </dia:composite>
        </dia:attribute>
        <dia:attribute name="valign">
          <dia:enum val="3"/>
        </dia:attribute>
      </dia:object>
      <dia:object type="Standard - Text" version="1" id="O20">
        <dia:attribute name="obj_pos">
          <dia:point val="21,20"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="21,19.4575;24.06,20.3975"/>
        </dia:attribute>
        <dia:attribute name="text">
          <dia:composite type="text">
            <dia:attribute name="string">
              <dia:string>#belongs to#</dia:string>
            </dia:attribute>
            <dia:attribute name="font">
              <dia:font family="sans" style="0" name="Helvetica"/>
            </dia:attribute>
            <dia:attribute name="height">
              <dia:real val="0.80000000000000004"/>
            </dia:attribute>
            <dia:attribute name="pos">
              <dia:point val="21,20"/>
            </dia:attribute>
            <dia:attribute name="color">
              <dia:color val="#000000"/>
            </dia:attribute>
            <dia:attribute name="alignment">
              <dia:enum val="0"/>
            </dia:attribute>
          </dia:composite>
        </dia:attribute>
        <dia:attribute name="valign">
          <dia:enum val="3"/>
        </dia:attribute>
      </dia:object>
      <dia:object type="Standard - Text" version="1" id="O21">
        <dia:attribute name="obj_pos">
          <dia:point val="11,20"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="11,19.4575;14.06,20.3975"/>
        </dia:attribute>
        <dia:attribute name="text">
          <dia:composite type="text">
            <dia:attribute name="string">
              <dia:string>#belongs to#</dia:string>
            </dia:attribute>
            <dia:attribute name="font">
              <dia:font family="sans" style="0" name="Helvetica"/>
            </dia:attribute>
            <dia:attribute name="height">
              <dia:real val="0.80000000000000004"/>
            </dia:attribute>
            <dia:attribute name="pos">
              <dia:point val="11,20"/>
            </dia:attribute>
            <dia:attribute name="color">
              <dia:color val="#000000"/>
            </dia:attribute>
            <dia:attribute name="alignment">
              <dia:enum val="0"/>
            </dia:attribute>
          </dia:composite>
        </dia:attribute>
        <dia:attribute name="valign">
          <dia:enum val="3"/>
        </dia:attribute>
      </dia:object>
      <dia:object type="Standard - Text" version="1" id="O22">
        <dia:attribute name="obj_pos">
          <dia:point val="12,15"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="12,14.4575;15.06,15.3975"/>
        </dia:attribute>
        <dia:attribute name="text">
          <dia:composite type="text">
            <dia:attribute name="string">
              <dia:string>#belongs to#</dia:string>
            </dia:attribute>
            <dia:attribute name="font">
              <dia:font family="sans" style="0" name="Helvetica"/>
            </dia:attribute>
            <dia:attribute name="height">
              <dia:real val="0.80000000000000004"/>
            </dia:attribute>
            <dia:attribute name="pos">
              <dia:point val="12,15"/>
            </dia:attribute>
            <dia:attribute name="color">
              <dia:color val="#000000"/>
            </dia:attribute>
            <dia:attribute name="alignment">
              <dia:enum val="0"/>
            </dia:attribute>
          </dia:composite>
        </dia:attribute>
        <dia:attribute name="valign">
          <dia:enum val="3"/>
        </dia:attribute>
      </dia:object>
      <dia:object type="Standard - Text" version="1" id="O23">
        <dia:attribute name="obj_pos">
          <dia:point val="9,12"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="9,11.4575;12.06,12.3975"/>
        </dia:attribute>
        <dia:attribute name="text">
          <dia:composite type="text">
            <dia:attribute name="string">
              <dia:string>#belongs to#</dia:string>
            </dia:attribute>
            <dia:attribute name="font">
              <dia:font family="sans" style="0" name="Helvetica"/>
            </dia:attribute>
            <dia:attribute name="height">
              <dia:real val="0.80000000000000004"/>
            </dia:attribute>
            <dia:attribute name="pos">
              <dia:point val="9,12"/>
            </dia:attribute>
            <dia:attribute name="color">
              <dia:color val="#000000"/>
            </dia:attribute>
            <dia:attribute name="alignment">
              <dia:enum val="0"/>
            </dia:attribute>
          </dia:composite>
        </dia:attribute>
        <dia:attribute name="valign">
          <dia:enum val="3"/>
        </dia:attribute>
      </dia:object>
      <dia:object type="Standard - Text" version="1" id="O24">
        <dia:attribute name="obj_pos">
          <dia:point val="1,13"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="1,12.4575;10.5175,13.3975"/>
        </dia:attribute>
        <dia:attribute name="text">
          <dia:composite type="text">
            <dia:attribute name="string">
              <dia:string>#(Line of Development  /  Branch)#</dia:string>
            </dia:attribute>
            <dia:attribute name="font">
              <dia:font family="sans" style="0" name="Helvetica"/>
            </dia:attribute>
            <dia:attribute name="height">
              <dia:real val="0.80000000000000004"/>
            </dia:attribute>
            <dia:attribute name="pos">
              <dia:point val="1,13"/>
            </dia:attribute>
            <dia:attribute name="color">
              <dia:color val="#000000"/>
            </dia:attribute>
            <dia:attribute name="alignment">
              <dia:enum val="0"/>
            </dia:attribute>
          </dia:composite>
        </dia:attribute>
        <dia:attribute name="valign">
          <dia:enum val="3"/>
        </dia:attribute>
      </dia:object>
    </dia:group>
  </dia:layer>
</dia:diagram>
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


















































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted art/CollRev2.dia.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
<?xml version="1.0" encoding="UTF-8"?>
<dia:diagram xmlns:dia="http://www.lysator.liu.se/~alla/dia/">
  <dia:diagramdata>
    <dia:attribute name="background">
      <dia:color val="#ffffff"/>
    </dia:attribute>
    <dia:attribute name="pagebreak">
      <dia:color val="#000099"/>
    </dia:attribute>
    <dia:attribute name="paper">
      <dia:composite type="paper">
        <dia:attribute name="name">
          <dia:string>#Letter#</dia:string>
        </dia:attribute>
        <dia:attribute name="tmargin">
          <dia:real val="2.5399999618530273"/>
        </dia:attribute>
        <dia:attribute name="bmargin">
          <dia:real val="2.5399999618530273"/>
        </dia:attribute>
        <dia:attribute name="lmargin">
          <dia:real val="2.5399999618530273"/>
        </dia:attribute>
        <dia:attribute name="rmargin">
          <dia:real val="2.5399999618530273"/>
        </dia:attribute>
        <dia:attribute name="is_portrait">
          <dia:boolean val="true"/>
        </dia:attribute>
        <dia:attribute name="scaling">
          <dia:real val="1"/>
        </dia:attribute>
        <dia:attribute name="fitto">
          <dia:boolean val="false"/>
        </dia:attribute>
      </dia:composite>
    </dia:attribute>
    <dia:attribute name="grid">
      <dia:composite type="grid">
        <dia:attribute name="width_x">
          <dia:real val="1"/>
        </dia:attribute>
        <dia:attribute name="width_y">
          <dia:real val="1"/>
        </dia:attribute>
        <dia:attribute name="visible_x">
          <dia:int val="1"/>
        </dia:attribute>
        <dia:attribute name="visible_y">
          <dia:int val="1"/>
        </dia:attribute>
        <dia:composite type="color"/>
      </dia:composite>
    </dia:attribute>
    <dia:attribute name="color">
      <dia:color val="#d8e5e5"/>
    </dia:attribute>
    <dia:attribute name="guides">
      <dia:composite type="guides">
        <dia:attribute name="hguides"/>
        <dia:attribute name="vguides"/>
      </dia:composite>
    </dia:attribute>
  </dia:diagramdata>
  <dia:layer name="Background" visible="true">
    <dia:group>
      <dia:group>
        <dia:object type="Standard - Box" version="0" id="O0">
          <dia:attribute name="obj_pos">
            <dia:point val="13,1"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="12.95,0.95;20.05,3.05"/>
          </dia:attribute>
          <dia:attribute name="elem_corner">
            <dia:point val="13,1"/>
          </dia:attribute>
          <dia:attribute name="elem_width">
            <dia:real val="7"/>
          </dia:attribute>
          <dia:attribute name="elem_height">
            <dia:real val="2"/>
          </dia:attribute>
          <dia:attribute name="show_background">
            <dia:boolean val="true"/>
          </dia:attribute>
        </dia:object>
        <dia:object type="Standard - Text" version="1" id="O1">
          <dia:attribute name="obj_pos">
            <dia:point val="15.2818,2.06397"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="15.2818,1.52147;17.7182,2.46147"/>
          </dia:attribute>
          <dia:attribute name="text">
            <dia:composite type="text">
              <dia:attribute name="string">
                <dia:string>#Revision#</dia:string>
              </dia:attribute>
              <dia:attribute name="font">
                <dia:font family="sans" style="0" name="Helvetica"/>
              </dia:attribute>
              <dia:attribute name="height">
                <dia:real val="0.80000000000000004"/>
              </dia:attribute>
              <dia:attribute name="pos">
                <dia:point val="15.2818,2.06397"/>
              </dia:attribute>
              <dia:attribute name="color">
                <dia:color val="#000000"/>
              </dia:attribute>
              <dia:attribute name="alignment">
                <dia:enum val="0"/>
              </dia:attribute>
            </dia:composite>
          </dia:attribute>
          <dia:attribute name="valign">
            <dia:enum val="3"/>
          </dia:attribute>
        </dia:object>
      </dia:group>
      <dia:group>
        <dia:object type="Standard - Box" version="0" id="O2">
          <dia:attribute name="obj_pos">
            <dia:point val="13,7"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="12.95,6.95;20.05,9.05"/>
          </dia:attribute>
          <dia:attribute name="elem_corner">
            <dia:point val="13,7"/>
          </dia:attribute>
          <dia:attribute name="elem_width">
            <dia:real val="7"/>
          </dia:attribute>
          <dia:attribute name="elem_height">
            <dia:real val="2"/>
          </dia:attribute>
          <dia:attribute name="show_background">
            <dia:boolean val="true"/>
          </dia:attribute>
        </dia:object>
        <dia:object type="Standard - Text" version="1" id="O3">
          <dia:attribute name="obj_pos">
            <dia:point val="14.1456,8.06397"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="14.1456,7.52147;18.8544,8.46147"/>
          </dia:attribute>
          <dia:attribute name="text">
            <dia:composite type="text">
              <dia:attribute name="string">
                <dia:string>#Revision' (Child)#</dia:string>
              </dia:attribute>
              <dia:attribute name="font">
                <dia:font family="sans" style="0" name="Helvetica"/>
              </dia:attribute>
              <dia:attribute name="height">
                <dia:real val="0.80000000000000004"/>
              </dia:attribute>
              <dia:attribute name="pos">
                <dia:point val="14.1456,8.06397"/>
              </dia:attribute>
              <dia:attribute name="color">
                <dia:color val="#000000"/>
              </dia:attribute>
              <dia:attribute name="alignment">
                <dia:enum val="0"/>
              </dia:attribute>
            </dia:composite>
          </dia:attribute>
          <dia:attribute name="valign">
            <dia:enum val="3"/>
          </dia:attribute>
        </dia:object>
      </dia:group>
      <dia:group>
        <dia:object type="Standard - Box" version="0" id="O4">
          <dia:attribute name="obj_pos">
            <dia:point val="2,2"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="1.95,1.95;9.05,4.05"/>
          </dia:attribute>
          <dia:attribute name="elem_corner">
            <dia:point val="2,2"/>
          </dia:attribute>
          <dia:attribute name="elem_width">
            <dia:real val="7"/>
          </dia:attribute>
          <dia:attribute name="elem_height">
            <dia:real val="2"/>
          </dia:attribute>
          <dia:attribute name="show_background">
            <dia:boolean val="true"/>
          </dia:attribute>
        </dia:object>
        <dia:object type="Standard - Text" version="1" id="O5">
          <dia:attribute name="obj_pos">
            <dia:point val="5.00393,3.06397"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="5.00393,2.52147;5.97901,3.46147"/>
          </dia:attribute>
          <dia:attribute name="text">
            <dia:composite type="text">
              <dia:attribute name="string">
                <dia:string>#File#</dia:string>
              </dia:attribute>
              <dia:attribute name="font">
                <dia:font family="sans" style="0" name="Helvetica"/>
              </dia:attribute>
              <dia:attribute name="height">
                <dia:real val="0.80000000000000004"/>
              </dia:attribute>
              <dia:attribute name="pos">
                <dia:point val="5.00393,3.06397"/>
              </dia:attribute>
              <dia:attribute name="color">
                <dia:color val="#000000"/>
              </dia:attribute>
              <dia:attribute name="alignment">
                <dia:enum val="0"/>
              </dia:attribute>
            </dia:composite>
          </dia:attribute>
          <dia:attribute name="valign">
            <dia:enum val="3"/>
          </dia:attribute>
        </dia:object>
      </dia:group>
      <dia:object type="Standard - Line" version="0" id="O6">
        <dia:attribute name="obj_pos">
          <dia:point val="13,8"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="8.83023,6.5028;13.0606,8.06063"/>
        </dia:attribute>
        <dia:attribute name="conn_endpoints">
          <dia:point val="13,8"/>
          <dia:point val="9,7"/>
        </dia:attribute>
        <dia:attribute name="numcp">
          <dia:int val="1"/>
        </dia:attribute>
        <dia:attribute name="end_arrow">
          <dia:enum val="22"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_length">
          <dia:real val="0.5"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_width">
          <dia:real val="0.5"/>
        </dia:attribute>
      </dia:object>
      <dia:object type="Standard - Line" version="0" id="O7">
        <dia:attribute name="obj_pos">
          <dia:point val="13,2"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="8.83023,1.93937;13.0606,3.4972"/>
        </dia:attribute>
        <dia:attribute name="conn_endpoints">
          <dia:point val="13,2"/>
          <dia:point val="9,3"/>
        </dia:attribute>
        <dia:attribute name="numcp">
          <dia:int val="1"/>
        </dia:attribute>
        <dia:attribute name="end_arrow">
          <dia:enum val="22"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_length">
          <dia:real val="0.5"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_width">
          <dia:real val="0.5"/>
        </dia:attribute>
      </dia:object>
      <dia:object type="Standard - Line" version="0" id="O8">
        <dia:attribute name="obj_pos">
          <dia:point val="13,2"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="8.57833,1.92972;13.0703,7.35139"/>
        </dia:attribute>
        <dia:attribute name="conn_endpoints">
          <dia:point val="13,2"/>
          <dia:point val="9,7"/>
        </dia:attribute>
        <dia:attribute name="numcp">
          <dia:int val="1"/>
        </dia:attribute>
        <dia:attribute name="end_arrow">
          <dia:enum val="22"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_length">
          <dia:real val="0.5"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_width">
          <dia:real val="0.5"/>
        </dia:attribute>
      </dia:object>
      <dia:object type="Standard - Line" version="0" id="O9">
        <dia:attribute name="obj_pos">
          <dia:point val="13,8"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="8.57833,2.64861;13.0703,8.07028"/>
        </dia:attribute>
        <dia:attribute name="conn_endpoints">
          <dia:point val="13,8"/>
          <dia:point val="9,3"/>
        </dia:attribute>
        <dia:attribute name="numcp">
          <dia:int val="1"/>
        </dia:attribute>
        <dia:attribute name="end_arrow">
          <dia:enum val="22"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_length">
          <dia:real val="0.5"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_width">
          <dia:real val="0.5"/>
        </dia:attribute>
      </dia:object>
      <dia:group>
        <dia:object type="Standard - Box" version="0" id="O10">
          <dia:attribute name="obj_pos">
            <dia:point val="2,6"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="1.95,5.95;9.05,8.05"/>
          </dia:attribute>
          <dia:attribute name="elem_corner">
            <dia:point val="2,6"/>
          </dia:attribute>
          <dia:attribute name="elem_width">
            <dia:real val="7"/>
          </dia:attribute>
          <dia:attribute name="elem_height">
            <dia:real val="2"/>
          </dia:attribute>
          <dia:attribute name="show_background">
            <dia:boolean val="true"/>
          </dia:attribute>
        </dia:object>
        <dia:object type="Standard - Text" version="1" id="O11">
          <dia:attribute name="obj_pos">
            <dia:point val="3.53147,6.6725"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="3.53147,6.13;7.45147,7.87"/>
          </dia:attribute>
          <dia:attribute name="text">
            <dia:composite type="text">
              <dia:attribute name="string">
                <dia:string>#Line of
Development#</dia:string>
              </dia:attribute>
              <dia:attribute name="font">
                <dia:font family="sans" style="0" name="Helvetica"/>
              </dia:attribute>
              <dia:attribute name="height">
                <dia:real val="0.80000000000000004"/>
              </dia:attribute>
              <dia:attribute name="pos">
                <dia:point val="3.53147,6.6725"/>
              </dia:attribute>
              <dia:attribute name="color">
                <dia:color val="#000000"/>
              </dia:attribute>
              <dia:attribute name="alignment">
                <dia:enum val="0"/>
              </dia:attribute>
            </dia:composite>
          </dia:attribute>
          <dia:attribute name="valign">
            <dia:enum val="3"/>
          </dia:attribute>
        </dia:object>
      </dia:group>
      <dia:object type="Standard - Text" version="1" id="O12">
        <dia:attribute name="obj_pos">
          <dia:point val="18,6"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="18,5.4575;20.0947,6.3975"/>
        </dia:attribute>
        <dia:attribute name="text">
          <dia:composite type="text">
            <dia:attribute name="string">
              <dia:string># parent#</dia:string>
            </dia:attribute>
            <dia:attribute name="font">
              <dia:font family="sans" style="0" name="Helvetica"/>
            </dia:attribute>
            <dia:attribute name="height">
              <dia:real val="0.80000000000000004"/>
            </dia:attribute>
            <dia:attribute name="pos">
              <dia:point val="18,6"/>
            </dia:attribute>
            <dia:attribute name="color">
              <dia:color val="#000000"/>
            </dia:attribute>
            <dia:attribute name="alignment">
              <dia:enum val="0"/>
            </dia:attribute>
          </dia:composite>
        </dia:attribute>
        <dia:attribute name="valign">
          <dia:enum val="3"/>
        </dia:attribute>
      </dia:object>
      <dia:object type="Standard - Line" version="0" id="O13">
        <dia:attribute name="obj_pos">
          <dia:point val="18,7"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="17.5,2.95;18.5,7.05"/>
        </dia:attribute>
        <dia:attribute name="conn_endpoints">
          <dia:point val="18,7"/>
          <dia:point val="18,3"/>
        </dia:attribute>
        <dia:attribute name="numcp">
          <dia:int val="1"/>
        </dia:attribute>
        <dia:attribute name="end_arrow">
          <dia:enum val="22"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_length">
          <dia:real val="0.5"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_width">
          <dia:real val="0.5"/>
        </dia:attribute>
      </dia:object>
      <dia:group>
        <dia:object type="Standard - Text" version="1" id="O14">
          <dia:attribute name="obj_pos">
            <dia:point val="22,7"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="22,6.4575;28.4122,8.1975"/>
          </dia:attribute>
          <dia:attribute name="text">
            <dia:composite type="text">
              <dia:attribute name="string">
                <dia:string>#branch parent symbol
       (NULL)#</dia:string>
              </dia:attribute>
              <dia:attribute name="font">
                <dia:font family="sans" style="0" name="Helvetica"/>
              </dia:attribute>
              <dia:attribute name="height">
                <dia:real val="0.80000000000000004"/>
              </dia:attribute>
              <dia:attribute name="pos">
                <dia:point val="22,7"/>
              </dia:attribute>
              <dia:attribute name="color">
                <dia:color val="#000000"/>
              </dia:attribute>
              <dia:attribute name="alignment">
                <dia:enum val="0"/>
              </dia:attribute>
            </dia:composite>
          </dia:attribute>
          <dia:attribute name="valign">
            <dia:enum val="3"/>
          </dia:attribute>
        </dia:object>
        <dia:object type="Standard - Line" version="0" id="O15">
          <dia:attribute name="obj_pos">
            <dia:point val="20,8"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="19.95,7.5;22.05,8.5"/>
          </dia:attribute>
          <dia:attribute name="conn_endpoints">
            <dia:point val="20,8"/>
            <dia:point val="22,8"/>
          </dia:attribute>
          <dia:attribute name="numcp">
            <dia:int val="1"/>
          </dia:attribute>
          <dia:attribute name="end_arrow">
            <dia:enum val="22"/>
          </dia:attribute>
          <dia:attribute name="end_arrow_length">
            <dia:real val="0.5"/>
          </dia:attribute>
          <dia:attribute name="end_arrow_width">
            <dia:real val="0.5"/>
          </dia:attribute>
        </dia:object>
        <dia:object type="Standard - Polygon" version="0" id="O16">
          <dia:attribute name="obj_pos">
            <dia:point val="23,7"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="21.9293,6.87929;23.05,9.12071"/>
          </dia:attribute>
          <dia:attribute name="poly_points">
            <dia:point val="23,7"/>
            <dia:point val="22,8"/>
            <dia:point val="23,9"/>
          </dia:attribute>
          <dia:attribute name="show_background">
            <dia:boolean val="true"/>
          </dia:attribute>
        </dia:object>
      </dia:group>
      <dia:object type="Standard - Text" version="1" id="O17">
        <dia:attribute name="obj_pos">
          <dia:point val="15,4"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="15,3.4575;16.57,4.3975"/>
        </dia:attribute>
        <dia:attribute name="text">
          <dia:composite type="text">
            <dia:attribute name="string">
              <dia:string># child#</dia:string>
            </dia:attribute>
            <dia:attribute name="font">
              <dia:font family="sans" style="0" name="Helvetica"/>
            </dia:attribute>
            <dia:attribute name="height">
              <dia:real val="0.80000000000000004"/>
            </dia:attribute>
            <dia:attribute name="pos">
              <dia:point val="15,4"/>
            </dia:attribute>
            <dia:attribute name="color">
              <dia:color val="#000000"/>
            </dia:attribute>
            <dia:attribute name="alignment">
              <dia:enum val="0"/>
            </dia:attribute>
          </dia:composite>
        </dia:attribute>
        <dia:attribute name="valign">
          <dia:enum val="3"/>
        </dia:attribute>
      </dia:object>
      <dia:object type="Standard - Line" version="0" id="O18">
        <dia:attribute name="obj_pos">
          <dia:point val="15,3"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="14.5,2.95;15.5,7.05"/>
        </dia:attribute>
        <dia:attribute name="conn_endpoints">
          <dia:point val="15,3"/>
          <dia:point val="15,7"/>
        </dia:attribute>
        <dia:attribute name="numcp">
          <dia:int val="1"/>
        </dia:attribute>
        <dia:attribute name="end_arrow">
          <dia:enum val="22"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_length">
          <dia:real val="0.5"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_width">
          <dia:real val="0.5"/>
        </dia:attribute>
      </dia:object>
    </dia:group>
  </dia:layer>
</dia:diagram>
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted art/CollRev3.dia.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
<?xml version="1.0" encoding="UTF-8"?>
<dia:diagram xmlns:dia="http://www.lysator.liu.se/~alla/dia/">
  <dia:diagramdata>
    <dia:attribute name="background">
      <dia:color val="#ffffff"/>
    </dia:attribute>
    <dia:attribute name="pagebreak">
      <dia:color val="#000099"/>
    </dia:attribute>
    <dia:attribute name="paper">
      <dia:composite type="paper">
        <dia:attribute name="name">
          <dia:string>#Letter#</dia:string>
        </dia:attribute>
        <dia:attribute name="tmargin">
          <dia:real val="2.5399999618530273"/>
        </dia:attribute>
        <dia:attribute name="bmargin">
          <dia:real val="2.5399999618530273"/>
        </dia:attribute>
        <dia:attribute name="lmargin">
          <dia:real val="2.5399999618530273"/>
        </dia:attribute>
        <dia:attribute name="rmargin">
          <dia:real val="2.5399999618530273"/>
        </dia:attribute>
        <dia:attribute name="is_portrait">
          <dia:boolean val="true"/>
        </dia:attribute>
        <dia:attribute name="scaling">
          <dia:real val="1"/>
        </dia:attribute>
        <dia:attribute name="fitto">
          <dia:boolean val="false"/>
        </dia:attribute>
      </dia:composite>
    </dia:attribute>
    <dia:attribute name="grid">
      <dia:composite type="grid">
        <dia:attribute name="width_x">
          <dia:real val="1"/>
        </dia:attribute>
        <dia:attribute name="width_y">
          <dia:real val="1"/>
        </dia:attribute>
        <dia:attribute name="visible_x">
          <dia:int val="1"/>
        </dia:attribute>
        <dia:attribute name="visible_y">
          <dia:int val="1"/>
        </dia:attribute>
        <dia:composite type="color"/>
      </dia:composite>
    </dia:attribute>
    <dia:attribute name="color">
      <dia:color val="#d8e5e5"/>
    </dia:attribute>
    <dia:attribute name="guides">
      <dia:composite type="guides">
        <dia:attribute name="hguides"/>
        <dia:attribute name="vguides"/>
      </dia:composite>
    </dia:attribute>
  </dia:diagramdata>
  <dia:layer name="Background" visible="true">
    <dia:group>
      <dia:object type="Standard - Text" version="1" id="O0">
        <dia:attribute name="obj_pos">
          <dia:point val="7,15"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="7,14.6;7,15.8"/>
        </dia:attribute>
        <dia:attribute name="text">
          <dia:composite type="text">
            <dia:attribute name="string">
              <dia:string>##</dia:string>
            </dia:attribute>
            <dia:attribute name="font">
              <dia:font family="sans" style="0" name="Helvetica"/>
            </dia:attribute>
            <dia:attribute name="height">
              <dia:real val="0.80000000000000004"/>
            </dia:attribute>
            <dia:attribute name="pos">
              <dia:point val="7,15"/>
            </dia:attribute>
            <dia:attribute name="color">
              <dia:color val="#000000"/>
            </dia:attribute>
            <dia:attribute name="alignment">
              <dia:enum val="0"/>
            </dia:attribute>
          </dia:composite>
        </dia:attribute>
        <dia:attribute name="valign">
          <dia:enum val="3"/>
        </dia:attribute>
      </dia:object>
      <dia:group>
        <dia:object type="Standard - Box" version="0" id="O1">
          <dia:attribute name="obj_pos">
            <dia:point val="13,1"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="12.95,0.95;19.05,3.05"/>
          </dia:attribute>
          <dia:attribute name="elem_corner">
            <dia:point val="13,1"/>
          </dia:attribute>
          <dia:attribute name="elem_width">
            <dia:real val="6"/>
          </dia:attribute>
          <dia:attribute name="elem_height">
            <dia:real val="2"/>
          </dia:attribute>
          <dia:attribute name="show_background">
            <dia:boolean val="true"/>
          </dia:attribute>
        </dia:object>
        <dia:object type="Standard - Text" version="1" id="O2">
          <dia:attribute name="obj_pos">
            <dia:point val="14.04,1.66397"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="14.04,1.12147;17.96,2.86147"/>
          </dia:attribute>
          <dia:attribute name="text">
            <dia:composite type="text">
              <dia:attribute name="string">
                <dia:string>#Line of
Development#</dia:string>
              </dia:attribute>
              <dia:attribute name="font">
                <dia:font family="sans" style="0" name="Helvetica"/>
              </dia:attribute>
              <dia:attribute name="height">
                <dia:real val="0.80000000000000004"/>
              </dia:attribute>
              <dia:attribute name="pos">
                <dia:point val="14.04,1.66397"/>
              </dia:attribute>
              <dia:attribute name="color">
                <dia:color val="#000000"/>
              </dia:attribute>
              <dia:attribute name="alignment">
                <dia:enum val="0"/>
              </dia:attribute>
            </dia:composite>
          </dia:attribute>
          <dia:attribute name="valign">
            <dia:enum val="3"/>
          </dia:attribute>
        </dia:object>
      </dia:group>
      <dia:group>
        <dia:object type="Standard - Box" version="0" id="O3">
          <dia:attribute name="obj_pos">
            <dia:point val="3,1"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="2.95,0.95;9.05,3.05"/>
          </dia:attribute>
          <dia:attribute name="elem_corner">
            <dia:point val="3,1"/>
          </dia:attribute>
          <dia:attribute name="elem_width">
            <dia:real val="6"/>
          </dia:attribute>
          <dia:attribute name="elem_height">
            <dia:real val="2"/>
          </dia:attribute>
          <dia:attribute name="show_background">
            <dia:boolean val="true"/>
          </dia:attribute>
        </dia:object>
        <dia:object type="Standard - Text" version="1" id="O4">
          <dia:attribute name="obj_pos">
            <dia:point val="4.04,1.66397"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="4.04,1.12147;7.96,2.86147"/>
          </dia:attribute>
          <dia:attribute name="text">
            <dia:composite type="text">
              <dia:attribute name="string">
                <dia:string>#Line' of
Development#</dia:string>
              </dia:attribute>
              <dia:attribute name="font">
                <dia:font family="sans" style="0" name="Helvetica"/>
              </dia:attribute>
              <dia:attribute name="height">
                <dia:real val="0.80000000000000004"/>
              </dia:attribute>
              <dia:attribute name="pos">
                <dia:point val="4.04,1.66397"/>
              </dia:attribute>
              <dia:attribute name="color">
                <dia:color val="#000000"/>
              </dia:attribute>
              <dia:attribute name="alignment">
                <dia:enum val="0"/>
              </dia:attribute>
            </dia:composite>
          </dia:attribute>
          <dia:attribute name="valign">
            <dia:enum val="3"/>
          </dia:attribute>
        </dia:object>
      </dia:group>
      <dia:group>
        <dia:object type="Standard - Box" version="0" id="O5">
          <dia:attribute name="obj_pos">
            <dia:point val="3,13"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="2.95,12.95;9.05,15.05"/>
          </dia:attribute>
          <dia:attribute name="elem_corner">
            <dia:point val="3,13"/>
          </dia:attribute>
          <dia:attribute name="elem_width">
            <dia:real val="6"/>
          </dia:attribute>
          <dia:attribute name="elem_height">
            <dia:real val="2"/>
          </dia:attribute>
          <dia:attribute name="show_background">
            <dia:boolean val="true"/>
          </dia:attribute>
        </dia:object>
        <dia:object type="Standard - Text" version="1" id="O6">
          <dia:attribute name="obj_pos">
            <dia:point val="3.94,13.664"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="3.94,13.1215;8.06,14.8615"/>
          </dia:attribute>
          <dia:attribute name="text">
            <dia:composite type="text">
              <dia:attribute name="string">
                <dia:string>#Revision''
(Branch Start)#</dia:string>
              </dia:attribute>
              <dia:attribute name="font">
                <dia:font family="sans" style="0" name="Helvetica"/>
              </dia:attribute>
              <dia:attribute name="height">
                <dia:real val="0.80000000000000004"/>
              </dia:attribute>
              <dia:attribute name="pos">
                <dia:point val="3.94,13.664"/>
              </dia:attribute>
              <dia:attribute name="color">
                <dia:color val="#000000"/>
              </dia:attribute>
              <dia:attribute name="alignment">
                <dia:enum val="0"/>
              </dia:attribute>
            </dia:composite>
          </dia:attribute>
          <dia:attribute name="valign">
            <dia:enum val="3"/>
          </dia:attribute>
        </dia:object>
      </dia:group>
      <dia:group>
        <dia:object type="Standard - Box" version="0" id="O7">
          <dia:attribute name="obj_pos">
            <dia:point val="13,7"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="12.95,6.95;19.05,9.05"/>
          </dia:attribute>
          <dia:attribute name="elem_corner">
            <dia:point val="13,7"/>
          </dia:attribute>
          <dia:attribute name="elem_width">
            <dia:real val="6"/>
          </dia:attribute>
          <dia:attribute name="elem_height">
            <dia:real val="2"/>
          </dia:attribute>
          <dia:attribute name="show_background">
            <dia:boolean val="true"/>
          </dia:attribute>
        </dia:object>
        <dia:object type="Standard - Text" version="1" id="O8">
          <dia:attribute name="obj_pos">
            <dia:point val="14.7733,8.0725"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="14.7733,7.53;17.2096,8.47"/>
          </dia:attribute>
          <dia:attribute name="text">
            <dia:composite type="text">
              <dia:attribute name="string">
                <dia:string>#Revision#</dia:string>
              </dia:attribute>
              <dia:attribute name="font">
                <dia:font family="sans" style="0" name="Helvetica"/>
              </dia:attribute>
              <dia:attribute name="height">
                <dia:real val="0.80000000000000004"/>
              </dia:attribute>
              <dia:attribute name="pos">
                <dia:point val="14.7733,8.0725"/>
              </dia:attribute>
              <dia:attribute name="color">
                <dia:color val="#000000"/>
              </dia:attribute>
              <dia:attribute name="alignment">
                <dia:enum val="0"/>
              </dia:attribute>
            </dia:composite>
          </dia:attribute>
          <dia:attribute name="valign">
            <dia:enum val="3"/>
          </dia:attribute>
        </dia:object>
      </dia:group>
      <dia:group>
        <dia:object type="Standard - Box" version="0" id="O9">
          <dia:attribute name="obj_pos">
            <dia:point val="23,13"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="22.95,12.95;29.05,15.05"/>
          </dia:attribute>
          <dia:attribute name="elem_corner">
            <dia:point val="23,13"/>
          </dia:attribute>
          <dia:attribute name="elem_width">
            <dia:real val="6"/>
          </dia:attribute>
          <dia:attribute name="elem_height">
            <dia:real val="2"/>
          </dia:attribute>
          <dia:attribute name="show_background">
            <dia:boolean val="true"/>
          </dia:attribute>
        </dia:object>
        <dia:object type="Standard - Text" version="1" id="O10">
          <dia:attribute name="obj_pos">
            <dia:point val="25.5039,14.0725"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="25.5039,13.53;26.479,14.47"/>
          </dia:attribute>
          <dia:attribute name="text">
            <dia:composite type="text">
              <dia:attribute name="string">
                <dia:string>#File#</dia:string>
              </dia:attribute>
              <dia:attribute name="font">
                <dia:font family="sans" style="0" name="Helvetica"/>
              </dia:attribute>
              <dia:attribute name="height">
                <dia:real val="0.80000000000000004"/>
              </dia:attribute>
              <dia:attribute name="pos">
                <dia:point val="25.5039,14.0725"/>
              </dia:attribute>
              <dia:attribute name="color">
                <dia:color val="#000000"/>
              </dia:attribute>
              <dia:attribute name="alignment">
                <dia:enum val="0"/>
              </dia:attribute>
            </dia:composite>
          </dia:attribute>
          <dia:attribute name="valign">
            <dia:enum val="3"/>
          </dia:attribute>
        </dia:object>
      </dia:group>
      <dia:group>
        <dia:object type="Standard - Box" version="0" id="O11">
          <dia:attribute name="obj_pos">
            <dia:point val="13,13"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="12.95,12.95;19.05,15.05"/>
          </dia:attribute>
          <dia:attribute name="elem_corner">
            <dia:point val="13,13"/>
          </dia:attribute>
          <dia:attribute name="elem_width">
            <dia:real val="6"/>
          </dia:attribute>
          <dia:attribute name="elem_height">
            <dia:real val="2"/>
          </dia:attribute>
          <dia:attribute name="show_background">
            <dia:boolean val="true"/>
          </dia:attribute>
        </dia:object>
        <dia:object type="Standard - Text" version="1" id="O12">
          <dia:attribute name="obj_pos">
            <dia:point val="14.6933,13.6725"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="14.6933,13.13;17.2896,14.87"/>
          </dia:attribute>
          <dia:attribute name="text">
            <dia:composite type="text">
              <dia:attribute name="string">
                <dia:string>#Revision'
(Child)#</dia:string>
              </dia:attribute>
              <dia:attribute name="font">
                <dia:font family="sans" style="0" name="Helvetica"/>
              </dia:attribute>
              <dia:attribute name="height">
                <dia:real val="0.80000000000000004"/>
              </dia:attribute>
              <dia:attribute name="pos">
                <dia:point val="14.6933,13.6725"/>
              </dia:attribute>
              <dia:attribute name="color">
                <dia:color val="#000000"/>
              </dia:attribute>
              <dia:attribute name="alignment">
                <dia:enum val="0"/>
              </dia:attribute>
            </dia:composite>
          </dia:attribute>
          <dia:attribute name="valign">
            <dia:enum val="3"/>
          </dia:attribute>
        </dia:object>
      </dia:group>
      <dia:object type="Standard - Line" version="0" id="O13">
        <dia:attribute name="obj_pos">
          <dia:point val="19,14"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="18.95,13.5;23.05,14.5"/>
        </dia:attribute>
        <dia:attribute name="conn_endpoints">
          <dia:point val="19,14"/>
          <dia:point val="23,14"/>
        </dia:attribute>
        <dia:attribute name="numcp">
          <dia:int val="1"/>
        </dia:attribute>
        <dia:attribute name="end_arrow">
          <dia:enum val="22"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_length">
          <dia:real val="0.5"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_width">
          <dia:real val="0.5"/>
        </dia:attribute>
      </dia:object>
      <dia:object type="Standard - Line" version="0" id="O14">
        <dia:attribute name="obj_pos">
          <dia:point val="6,13"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="5.5,2.95;6.5,13.05"/>
        </dia:attribute>
        <dia:attribute name="conn_endpoints">
          <dia:point val="6,13"/>
          <dia:point val="6,3"/>
        </dia:attribute>
        <dia:attribute name="numcp">
          <dia:int val="1"/>
        </dia:attribute>
        <dia:attribute name="end_arrow">
          <dia:enum val="22"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_length">
          <dia:real val="0.5"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_width">
          <dia:real val="0.5"/>
        </dia:attribute>
      </dia:object>
      <dia:object type="Standard - Line" version="0" id="O15">
        <dia:attribute name="obj_pos">
          <dia:point val="18,9"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="17.5,8.95;18.5,13.05"/>
        </dia:attribute>
        <dia:attribute name="conn_endpoints">
          <dia:point val="18,9"/>
          <dia:point val="18,13"/>
        </dia:attribute>
        <dia:attribute name="numcp">
          <dia:int val="1"/>
        </dia:attribute>
        <dia:attribute name="end_arrow">
          <dia:enum val="22"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_length">
          <dia:real val="0.5"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_width">
          <dia:real val="0.5"/>
        </dia:attribute>
      </dia:object>
      <dia:object type="Standard - Line" version="0" id="O16">
        <dia:attribute name="obj_pos">
          <dia:point val="16,7"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="15.5,2.95;16.5,7.05"/>
        </dia:attribute>
        <dia:attribute name="conn_endpoints">
          <dia:point val="16,7"/>
          <dia:point val="16,3"/>
        </dia:attribute>
        <dia:attribute name="numcp">
          <dia:int val="1"/>
        </dia:attribute>
        <dia:attribute name="end_arrow">
          <dia:enum val="22"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_length">
          <dia:real val="0.5"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_width">
          <dia:real val="0.5"/>
        </dia:attribute>
      </dia:object>
      <dia:object type="Standard - Line" version="0" id="O17">
        <dia:attribute name="obj_pos">
          <dia:point val="14,13"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="13.5,8.95;14.5,13.05"/>
        </dia:attribute>
        <dia:attribute name="conn_endpoints">
          <dia:point val="14,13"/>
          <dia:point val="14,9"/>
        </dia:attribute>
        <dia:attribute name="numcp">
          <dia:int val="1"/>
        </dia:attribute>
        <dia:attribute name="end_arrow">
          <dia:enum val="22"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_length">
          <dia:real val="0.5"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_width">
          <dia:real val="0.5"/>
        </dia:attribute>
      </dia:object>
      <dia:object type="Standard - ZigZagLine" version="1" id="O18">
        <dia:attribute name="obj_pos">
          <dia:point val="9,14"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="8.95,7.5;13.05,14.05"/>
        </dia:attribute>
        <dia:attribute name="orth_points">
          <dia:point val="9,14"/>
          <dia:point val="11,14"/>
          <dia:point val="11,8"/>
          <dia:point val="13,8"/>
        </dia:attribute>
        <dia:attribute name="orth_orient">
          <dia:enum val="0"/>
          <dia:enum val="1"/>
          <dia:enum val="0"/>
        </dia:attribute>
        <dia:attribute name="autorouting">
          <dia:boolean val="true"/>
        </dia:attribute>
        <dia:attribute name="end_arrow">
          <dia:enum val="22"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_length">
          <dia:real val="0.5"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_width">
          <dia:real val="0.5"/>
        </dia:attribute>
      </dia:object>
      <dia:object type="Standard - ZigZagLine" version="1" id="O19">
        <dia:attribute name="obj_pos">
          <dia:point val="6,15"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="5.95,14.95;26.5,17.05"/>
        </dia:attribute>
        <dia:attribute name="orth_points">
          <dia:point val="6,15"/>
          <dia:point val="6,17"/>
          <dia:point val="26,17"/>
          <dia:point val="26,15"/>
        </dia:attribute>
        <dia:attribute name="orth_orient">
          <dia:enum val="1"/>
          <dia:enum val="0"/>
          <dia:enum val="1"/>
        </dia:attribute>
        <dia:attribute name="autorouting">
          <dia:boolean val="false"/>
        </dia:attribute>
        <dia:attribute name="end_arrow">
          <dia:enum val="22"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_length">
          <dia:real val="0.5"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_width">
          <dia:real val="0.5"/>
        </dia:attribute>
      </dia:object>
      <dia:object type="Standard - ZigZagLine" version="1" id="O20">
        <dia:attribute name="obj_pos">
          <dia:point val="19,8"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="18.95,7.95;26.5,13.05"/>
        </dia:attribute>
        <dia:attribute name="orth_points">
          <dia:point val="19,8"/>
          <dia:point val="26,8"/>
          <dia:point val="26,13"/>
        </dia:attribute>
        <dia:attribute name="orth_orient">
          <dia:enum val="0"/>
          <dia:enum val="1"/>
        </dia:attribute>
        <dia:attribute name="autorouting">
          <dia:boolean val="true"/>
        </dia:attribute>
        <dia:attribute name="end_arrow">
          <dia:enum val="22"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_length">
          <dia:real val="0.5"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_width">
          <dia:real val="0.5"/>
        </dia:attribute>
      </dia:object>
      <dia:object type="Standard - Text" version="1" id="O21">
        <dia:attribute name="obj_pos">
          <dia:point val="6,12"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="6,11.4575;8.2125,13.1975"/>
        </dia:attribute>
        <dia:attribute name="text">
          <dia:composite type="text">
            <dia:attribute name="string">
              <dia:string># branch
 parent#</dia:string>
            </dia:attribute>
            <dia:attribute name="font">
              <dia:font family="sans" style="0" name="Helvetica"/>
            </dia:attribute>
            <dia:attribute name="height">
              <dia:real val="0.80000000000000004"/>
            </dia:attribute>
            <dia:attribute name="pos">
              <dia:point val="6,12"/>
            </dia:attribute>
            <dia:attribute name="color">
              <dia:color val="#000000"/>
            </dia:attribute>
            <dia:attribute name="alignment">
              <dia:enum val="0"/>
            </dia:attribute>
          </dia:composite>
        </dia:attribute>
        <dia:attribute name="valign">
          <dia:enum val="3"/>
        </dia:attribute>
      </dia:object>
      <dia:object type="Standard - Text" version="1" id="O22">
        <dia:attribute name="obj_pos">
          <dia:point val="14,12"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="14,11.4575;16.0947,12.3975"/>
        </dia:attribute>
        <dia:attribute name="text">
          <dia:composite type="text">
            <dia:attribute name="string">
              <dia:string># parent#</dia:string>
            </dia:attribute>
            <dia:attribute name="font">
              <dia:font family="sans" style="0" name="Helvetica"/>
            </dia:attribute>
            <dia:attribute name="height">
              <dia:real val="0.80000000000000004"/>
            </dia:attribute>
            <dia:attribute name="pos">
              <dia:point val="14,12"/>
            </dia:attribute>
            <dia:attribute name="color">
              <dia:color val="#000000"/>
            </dia:attribute>
            <dia:attribute name="alignment">
              <dia:enum val="0"/>
            </dia:attribute>
          </dia:composite>
        </dia:attribute>
        <dia:attribute name="valign">
          <dia:enum val="3"/>
        </dia:attribute>
      </dia:object>
      <dia:object type="Standard - Text" version="1" id="O23">
        <dia:attribute name="obj_pos">
          <dia:point val="18,10"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="18,9.4575;19.57,10.3975"/>
        </dia:attribute>
        <dia:attribute name="text">
          <dia:composite type="text">
            <dia:attribute name="string">
              <dia:string># child#</dia:string>
            </dia:attribute>
            <dia:attribute name="font">
              <dia:font family="sans" style="0" name="Helvetica"/>
            </dia:attribute>
            <dia:attribute name="height">
              <dia:real val="0.80000000000000004"/>
            </dia:attribute>
            <dia:attribute name="pos">
              <dia:point val="18,10"/>
            </dia:attribute>
            <dia:attribute name="color">
              <dia:color val="#000000"/>
            </dia:attribute>
            <dia:attribute name="alignment">
              <dia:enum val="0"/>
            </dia:attribute>
          </dia:composite>
        </dia:attribute>
        <dia:attribute name="valign">
          <dia:enum val="3"/>
        </dia:attribute>
      </dia:object>
      <dia:object type="Standard - Text" version="1" id="O24">
        <dia:attribute name="obj_pos">
          <dia:point val="19,7"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="19,6.52875;22.245,8.39875"/>
        </dia:attribute>
        <dia:attribute name="text">
          <dia:composite type="text">
            <dia:attribute name="string">
              <dia:string>#
 belongs to#</dia:string>
            </dia:attribute>
            <dia:attribute name="font">
              <dia:font family="sans" style="0" name="Helvetica"/>
            </dia:attribute>
            <dia:attribute name="height">
              <dia:real val="0.80000000000000004"/>
            </dia:attribute>
            <dia:attribute name="pos">
              <dia:point val="19,7"/>
            </dia:attribute>
            <dia:attribute name="color">
              <dia:color val="#000000"/>
            </dia:attribute>
            <dia:attribute name="alignment">
              <dia:enum val="0"/>
            </dia:attribute>
          </dia:composite>
        </dia:attribute>
        <dia:attribute name="valign">
          <dia:enum val="3"/>
        </dia:attribute>
      </dia:object>
      <dia:object type="Standard - Text" version="1" id="O25">
        <dia:attribute name="obj_pos">
          <dia:point val="6,15"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="6,14.4575;9.245,16.1975"/>
        </dia:attribute>
        <dia:attribute name="text">
          <dia:composite type="text">
            <dia:attribute name="string">
              <dia:string>#
 belongs to#</dia:string>
            </dia:attribute>
            <dia:attribute name="font">
              <dia:font family="sans" style="0" name="Helvetica"/>
            </dia:attribute>
            <dia:attribute name="height">
              <dia:real val="0.80000000000000004"/>
            </dia:attribute>
            <dia:attribute name="pos">
              <dia:point val="6,15"/>
            </dia:attribute>
            <dia:attribute name="color">
              <dia:color val="#000000"/>
            </dia:attribute>
            <dia:attribute name="alignment">
              <dia:enum val="0"/>
            </dia:attribute>
          </dia:composite>
        </dia:attribute>
        <dia:attribute name="valign">
          <dia:enum val="3"/>
        </dia:attribute>
      </dia:object>
      <dia:object type="Standard - Text" version="1" id="O26">
        <dia:attribute name="obj_pos">
          <dia:point val="19,13"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="19,12.5288;22.245,14.3987"/>
        </dia:attribute>
        <dia:attribute name="text">
          <dia:composite type="text">
            <dia:attribute name="string">
              <dia:string>#
 belongs to#</dia:string>
            </dia:attribute>
            <dia:attribute name="font">
              <dia:font family="sans" style="0" name="Helvetica"/>
            </dia:attribute>
            <dia:attribute name="height">
              <dia:real val="0.80000000000000004"/>
            </dia:attribute>
            <dia:attribute name="pos">
              <dia:point val="19,13"/>
            </dia:attribute>
            <dia:attribute name="color">
              <dia:color val="#000000"/>
            </dia:attribute>
            <dia:attribute name="alignment">
              <dia:enum val="0"/>
            </dia:attribute>
          </dia:composite>
        </dia:attribute>
        <dia:attribute name="valign">
          <dia:enum val="3"/>
        </dia:attribute>
      </dia:object>
      <dia:object type="Standard - Text" version="1" id="O27">
        <dia:attribute name="obj_pos">
          <dia:point val="9,14"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="9,13.5288;11.0947,15.3987"/>
        </dia:attribute>
        <dia:attribute name="text">
          <dia:composite type="text">
            <dia:attribute name="string">
              <dia:string>#
 parent#</dia:string>
            </dia:attribute>
            <dia:attribute name="font">
              <dia:font family="sans" style="0" name="Helvetica"/>
            </dia:attribute>
            <dia:attribute name="height">
              <dia:real val="0.80000000000000004"/>
            </dia:attribute>
            <dia:attribute name="pos">
              <dia:point val="9,14"/>
            </dia:attribute>
            <dia:attribute name="color">
              <dia:color val="#000000"/>
            </dia:attribute>
            <dia:attribute name="alignment">
              <dia:enum val="0"/>
            </dia:attribute>
          </dia:composite>
        </dia:attribute>
        <dia:attribute name="valign">
          <dia:enum val="3"/>
        </dia:attribute>
      </dia:object>
      <dia:object type="Standard - ZigZagLine" version="1" id="O28">
        <dia:attribute name="obj_pos">
          <dia:point val="3,14"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="0.95,1.5;3.05,14.05"/>
        </dia:attribute>
        <dia:attribute name="orth_points">
          <dia:point val="3,14"/>
          <dia:point val="1,14"/>
          <dia:point val="1,2"/>
          <dia:point val="3,2"/>
        </dia:attribute>
        <dia:attribute name="orth_orient">
          <dia:enum val="0"/>
          <dia:enum val="1"/>
          <dia:enum val="0"/>
        </dia:attribute>
        <dia:attribute name="autorouting">
          <dia:boolean val="false"/>
        </dia:attribute>
        <dia:attribute name="end_arrow">
          <dia:enum val="22"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_length">
          <dia:real val="0.5"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_width">
          <dia:real val="0.5"/>
        </dia:attribute>
      </dia:object>
      <dia:object type="Standard - Text" version="1" id="O29">
        <dia:attribute name="obj_pos">
          <dia:point val="1,12"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="1,11.4575;4.245,12.3975"/>
        </dia:attribute>
        <dia:attribute name="text">
          <dia:composite type="text">
            <dia:attribute name="string">
              <dia:string># belongs to#</dia:string>
            </dia:attribute>
            <dia:attribute name="font">
              <dia:font family="sans" style="0" name="Helvetica"/>
            </dia:attribute>
            <dia:attribute name="height">
              <dia:real val="0.80000000000000004"/>
            </dia:attribute>
            <dia:attribute name="pos">
              <dia:point val="1,12"/>
            </dia:attribute>
            <dia:attribute name="color">
              <dia:color val="#000000"/>
            </dia:attribute>
            <dia:attribute name="alignment">
              <dia:enum val="0"/>
            </dia:attribute>
          </dia:composite>
        </dia:attribute>
        <dia:attribute name="valign">
          <dia:enum val="3"/>
        </dia:attribute>
      </dia:object>
      <dia:object type="Standard - Text" version="1" id="O30">
        <dia:attribute name="obj_pos">
          <dia:point val="10,2.12153"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="10,1.10403;12.205,2.86403"/>
        </dia:attribute>
        <dia:attribute name="text">
          <dia:composite type="text">
            <dia:attribute name="string">
              <dia:string>#=/=#</dia:string>
            </dia:attribute>
            <dia:attribute name="font">
              <dia:font family="sans" style="0" name="Helvetica"/>
            </dia:attribute>
            <dia:attribute name="height">
              <dia:real val="1.5"/>
            </dia:attribute>
            <dia:attribute name="pos">
              <dia:point val="10,2.12153"/>
            </dia:attribute>
            <dia:attribute name="color">
              <dia:color val="#000000"/>
            </dia:attribute>
            <dia:attribute name="alignment">
              <dia:enum val="0"/>
            </dia:attribute>
          </dia:composite>
        </dia:attribute>
        <dia:attribute name="valign">
          <dia:enum val="3"/>
        </dia:attribute>
      </dia:object>
    </dia:group>
  </dia:layer>
</dia:diagram>
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<








































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted art/CollRev4.dia.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
<?xml version="1.0" encoding="UTF-8"?>
<dia:diagram xmlns:dia="http://www.lysator.liu.se/~alla/dia/">
  <dia:diagramdata>
    <dia:attribute name="background">
      <dia:color val="#ffffff"/>
    </dia:attribute>
    <dia:attribute name="pagebreak">
      <dia:color val="#000099"/>
    </dia:attribute>
    <dia:attribute name="paper">
      <dia:composite type="paper">
        <dia:attribute name="name">
          <dia:string>#Letter#</dia:string>
        </dia:attribute>
        <dia:attribute name="tmargin">
          <dia:real val="2.5399999618530273"/>
        </dia:attribute>
        <dia:attribute name="bmargin">
          <dia:real val="2.5399999618530273"/>
        </dia:attribute>
        <dia:attribute name="lmargin">
          <dia:real val="2.5399999618530273"/>
        </dia:attribute>
        <dia:attribute name="rmargin">
          <dia:real val="2.5399999618530273"/>
        </dia:attribute>
        <dia:attribute name="is_portrait">
          <dia:boolean val="true"/>
        </dia:attribute>
        <dia:attribute name="scaling">
          <dia:real val="1"/>
        </dia:attribute>
        <dia:attribute name="fitto">
          <dia:boolean val="false"/>
        </dia:attribute>
      </dia:composite>
    </dia:attribute>
    <dia:attribute name="grid">
      <dia:composite type="grid">
        <dia:attribute name="width_x">
          <dia:real val="1"/>
        </dia:attribute>
        <dia:attribute name="width_y">
          <dia:real val="1"/>
        </dia:attribute>
        <dia:attribute name="visible_x">
          <dia:int val="1"/>
        </dia:attribute>
        <dia:attribute name="visible_y">
          <dia:int val="1"/>
        </dia:attribute>
        <dia:composite type="color"/>
      </dia:composite>
    </dia:attribute>
    <dia:attribute name="color">
      <dia:color val="#d8e5e5"/>
    </dia:attribute>
    <dia:attribute name="guides">
      <dia:composite type="guides">
        <dia:attribute name="hguides"/>
        <dia:attribute name="vguides"/>
      </dia:composite>
    </dia:attribute>
  </dia:diagramdata>
  <dia:layer name="Background" visible="true">
    <dia:group>
      <dia:group>
        <dia:object type="Standard - Box" version="0" id="O0">
          <dia:attribute name="obj_pos">
            <dia:point val="3,8"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="2.95,7.95;9.05,10.05"/>
          </dia:attribute>
          <dia:attribute name="elem_corner">
            <dia:point val="3,8"/>
          </dia:attribute>
          <dia:attribute name="elem_width">
            <dia:real val="6"/>
          </dia:attribute>
          <dia:attribute name="elem_height">
            <dia:real val="2"/>
          </dia:attribute>
          <dia:attribute name="show_background">
            <dia:boolean val="true"/>
          </dia:attribute>
        </dia:object>
        <dia:object type="Standard - Text" version="1" id="O1">
          <dia:attribute name="obj_pos">
            <dia:point val="4.11647,8.66397"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="4.11647,8.12147;7.86647,9.86147"/>
          </dia:attribute>
          <dia:attribute name="text">
            <dia:composite type="text">
              <dia:attribute name="string">
                <dia:string>#Revision'
(Child NTDB)#</dia:string>
              </dia:attribute>
              <dia:attribute name="font">
                <dia:font family="sans" style="0" name="Helvetica"/>
              </dia:attribute>
              <dia:attribute name="height">
                <dia:real val="0.80000000000000004"/>
              </dia:attribute>
              <dia:attribute name="pos">
                <dia:point val="4.11647,8.66397"/>
              </dia:attribute>
              <dia:attribute name="color">
                <dia:color val="#000000"/>
              </dia:attribute>
              <dia:attribute name="alignment">
                <dia:enum val="0"/>
              </dia:attribute>
            </dia:composite>
          </dia:attribute>
          <dia:attribute name="valign">
            <dia:enum val="3"/>
          </dia:attribute>
        </dia:object>
      </dia:group>
      <dia:group>
        <dia:object type="Standard - Box" version="0" id="O2">
          <dia:attribute name="obj_pos">
            <dia:point val="5,1"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="4.95,0.95;11.05,3.05"/>
          </dia:attribute>
          <dia:attribute name="elem_corner">
            <dia:point val="5,1"/>
          </dia:attribute>
          <dia:attribute name="elem_width">
            <dia:real val="6"/>
          </dia:attribute>
          <dia:attribute name="elem_height">
            <dia:real val="2"/>
          </dia:attribute>
          <dia:attribute name="show_background">
            <dia:boolean val="true"/>
          </dia:attribute>
        </dia:object>
        <dia:object type="Standard - Text" version="1" id="O3">
          <dia:attribute name="obj_pos">
            <dia:point val="6.78184,1.6725"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="6.78184,1.13;9.21816,2.87"/>
          </dia:attribute>
          <dia:attribute name="text">
            <dia:composite type="text">
              <dia:attribute name="string">
                <dia:string>#Revision
(NTDB)#</dia:string>
              </dia:attribute>
              <dia:attribute name="font">
                <dia:font family="sans" style="0" name="Helvetica"/>
              </dia:attribute>
              <dia:attribute name="height">
                <dia:real val="0.80000000000000004"/>
              </dia:attribute>
              <dia:attribute name="pos">
                <dia:point val="6.78184,1.6725"/>
              </dia:attribute>
              <dia:attribute name="color">
                <dia:color val="#000000"/>
              </dia:attribute>
              <dia:attribute name="alignment">
                <dia:enum val="0"/>
              </dia:attribute>
            </dia:composite>
          </dia:attribute>
          <dia:attribute name="valign">
            <dia:enum val="3"/>
          </dia:attribute>
        </dia:object>
      </dia:group>
      <dia:group>
        <dia:object type="Standard - Box" version="0" id="O4">
          <dia:attribute name="obj_pos">
            <dia:point val="1,15"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="0.95,14.95;7.05,17.05"/>
          </dia:attribute>
          <dia:attribute name="elem_corner">
            <dia:point val="1,15"/>
          </dia:attribute>
          <dia:attribute name="elem_width">
            <dia:real val="6"/>
          </dia:attribute>
          <dia:attribute name="elem_height">
            <dia:real val="2"/>
          </dia:attribute>
          <dia:attribute name="show_background">
            <dia:boolean val="true"/>
          </dia:attribute>
        </dia:object>
        <dia:object type="Standard - Text" version="1" id="O5">
          <dia:attribute name="obj_pos">
            <dia:point val="2.11647,15.664"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="2.11647,15.1215;5.86647,16.8615"/>
          </dia:attribute>
          <dia:attribute name="text">
            <dia:composite type="text">
              <dia:attribute name="string">
                <dia:string>#Revision''
(Child NTDB)#</dia:string>
              </dia:attribute>
              <dia:attribute name="font">
                <dia:font family="sans" style="0" name="Helvetica"/>
              </dia:attribute>
              <dia:attribute name="height">
                <dia:real val="0.80000000000000004"/>
              </dia:attribute>
              <dia:attribute name="pos">
                <dia:point val="2.11647,15.664"/>
              </dia:attribute>
              <dia:attribute name="color">
                <dia:color val="#000000"/>
              </dia:attribute>
              <dia:attribute name="alignment">
                <dia:enum val="0"/>
              </dia:attribute>
            </dia:composite>
          </dia:attribute>
          <dia:attribute name="valign">
            <dia:enum val="3"/>
          </dia:attribute>
        </dia:object>
      </dia:group>
      <dia:group>
        <dia:object type="Standard - Box" version="0" id="O6">
          <dia:attribute name="obj_pos">
            <dia:point val="13,13"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="12.95,12.95;19.05,15.05"/>
          </dia:attribute>
          <dia:attribute name="elem_corner">
            <dia:point val="13,13"/>
          </dia:attribute>
          <dia:attribute name="elem_width">
            <dia:real val="6"/>
          </dia:attribute>
          <dia:attribute name="elem_height">
            <dia:real val="2"/>
          </dia:attribute>
          <dia:attribute name="show_background">
            <dia:boolean val="true"/>
          </dia:attribute>
        </dia:object>
        <dia:object type="Standard - Text" version="1" id="O7">
          <dia:attribute name="obj_pos">
            <dia:point val="14.2915,13.664"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="14.2915,13.1215;17.6915,14.8615"/>
          </dia:attribute>
          <dia:attribute name="text">
            <dia:composite type="text">
              <dia:attribute name="string">
                <dia:string>#Revision""
(non-NTDB)#</dia:string>
              </dia:attribute>
              <dia:attribute name="font">
                <dia:font family="sans" style="0" name="Helvetica"/>
              </dia:attribute>
              <dia:attribute name="height">
                <dia:real val="0.80000000000000004"/>
              </dia:attribute>
              <dia:attribute name="pos">
                <dia:point val="14.2915,13.664"/>
              </dia:attribute>
              <dia:attribute name="color">
                <dia:color val="#000000"/>
              </dia:attribute>
              <dia:attribute name="alignment">
                <dia:enum val="0"/>
              </dia:attribute>
            </dia:composite>
          </dia:attribute>
          <dia:attribute name="valign">
            <dia:enum val="3"/>
          </dia:attribute>
        </dia:object>
      </dia:group>
      <dia:object type="Standard - Line" version="0" id="O8">
        <dia:attribute name="obj_pos">
          <dia:point val="8,8"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="7.93501,2.76788;10.4828,8.06499"/>
        </dia:attribute>
        <dia:attribute name="conn_endpoints">
          <dia:point val="8,8"/>
          <dia:point val="10,3"/>
        </dia:attribute>
        <dia:attribute name="numcp">
          <dia:int val="1"/>
        </dia:attribute>
        <dia:attribute name="end_arrow">
          <dia:enum val="22"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_length">
          <dia:real val="0.5"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_width">
          <dia:real val="0.5"/>
        </dia:attribute>
      </dia:object>
      <dia:object type="Standard - Line" version="0" id="O9">
        <dia:attribute name="obj_pos">
          <dia:point val="6,3"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="3.51719,2.93501;6.06499,8.23212"/>
        </dia:attribute>
        <dia:attribute name="conn_endpoints">
          <dia:point val="6,3"/>
          <dia:point val="4,8"/>
        </dia:attribute>
        <dia:attribute name="numcp">
          <dia:int val="1"/>
        </dia:attribute>
        <dia:attribute name="end_arrow">
          <dia:enum val="22"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_length">
          <dia:real val="0.5"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_width">
          <dia:real val="0.5"/>
        </dia:attribute>
      </dia:object>
      <dia:object type="Standard - Line" version="0" id="O10">
        <dia:attribute name="obj_pos">
          <dia:point val="4,10"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="1.51719,9.93501;4.06499,15.2321"/>
        </dia:attribute>
        <dia:attribute name="conn_endpoints">
          <dia:point val="4,10"/>
          <dia:point val="2,15"/>
        </dia:attribute>
        <dia:attribute name="numcp">
          <dia:int val="1"/>
        </dia:attribute>
        <dia:attribute name="end_arrow">
          <dia:enum val="22"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_length">
          <dia:real val="0.5"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_width">
          <dia:real val="0.5"/>
        </dia:attribute>
      </dia:object>
      <dia:object type="Standard - Line" version="0" id="O11">
        <dia:attribute name="obj_pos">
          <dia:point val="6,15"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="5.93501,9.76788;8.48281,15.065"/>
        </dia:attribute>
        <dia:attribute name="conn_endpoints">
          <dia:point val="6,15"/>
          <dia:point val="8,10"/>
        </dia:attribute>
        <dia:attribute name="numcp">
          <dia:int val="1"/>
        </dia:attribute>
        <dia:attribute name="end_arrow">
          <dia:enum val="22"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_length">
          <dia:real val="0.5"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_width">
          <dia:real val="0.5"/>
        </dia:attribute>
      </dia:object>
      <dia:object type="Standard - Line" version="0" id="O12">
        <dia:attribute name="obj_pos">
          <dia:point val="16,13"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="8.70852,8.54107;16.0682,13.0682"/>
        </dia:attribute>
        <dia:attribute name="conn_endpoints">
          <dia:point val="16,13"/>
          <dia:point val="9,9"/>
        </dia:attribute>
        <dia:attribute name="numcp">
          <dia:int val="1"/>
        </dia:attribute>
        <dia:attribute name="end_arrow">
          <dia:enum val="22"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_length">
          <dia:real val="0.5"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_width">
          <dia:real val="0.5"/>
        </dia:attribute>
      </dia:object>
      <dia:object type="Standard - Line" version="0" id="O13">
        <dia:attribute name="obj_pos">
          <dia:point val="6,10"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="5.93178,9.93178;13.2915,14.4589"/>
        </dia:attribute>
        <dia:attribute name="conn_endpoints">
          <dia:point val="6,10"/>
          <dia:point val="13,14"/>
        </dia:attribute>
        <dia:attribute name="numcp">
          <dia:int val="1"/>
        </dia:attribute>
        <dia:attribute name="end_arrow">
          <dia:enum val="22"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_length">
          <dia:real val="0.5"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_width">
          <dia:real val="0.5"/>
        </dia:attribute>
      </dia:object>
      <dia:object type="Standard - Text" version="1" id="O14">
        <dia:attribute name="obj_pos">
          <dia:point val="6,14"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="6,13.5288;8.27969,15.3987"/>
        </dia:attribute>
        <dia:attribute name="text">
          <dia:composite type="text">
            <dia:attribute name="string">
              <dia:string>#
  parent#</dia:string>
            </dia:attribute>
            <dia:attribute name="font">
              <dia:font family="sans" style="0" name="Helvetica"/>
            </dia:attribute>
            <dia:attribute name="height">
              <dia:real val="0.80000000000000004"/>
            </dia:attribute>
            <dia:attribute name="pos">
              <dia:point val="6,14"/>
            </dia:attribute>
            <dia:attribute name="color">
              <dia:color val="#000000"/>
            </dia:attribute>
            <dia:attribute name="alignment">
              <dia:enum val="0"/>
            </dia:attribute>
          </dia:composite>
        </dia:attribute>
        <dia:attribute name="valign">
          <dia:enum val="3"/>
        </dia:attribute>
      </dia:object>
      <dia:object type="Standard - Text" version="1" id="O15">
        <dia:attribute name="obj_pos">
          <dia:point val="6,3"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="6,2.4575;7.385,4.1975"/>
        </dia:attribute>
        <dia:attribute name="text">
          <dia:composite type="text">
            <dia:attribute name="string">
              <dia:string>#
child#</dia:string>
            </dia:attribute>
            <dia:attribute name="font">
              <dia:font family="sans" style="0" name="Helvetica"/>
            </dia:attribute>
            <dia:attribute name="height">
              <dia:real val="0.80000000000000004"/>
            </dia:attribute>
            <dia:attribute name="pos">
              <dia:point val="6,3"/>
            </dia:attribute>
            <dia:attribute name="color">
              <dia:color val="#000000"/>
            </dia:attribute>
            <dia:attribute name="alignment">
              <dia:enum val="0"/>
            </dia:attribute>
          </dia:composite>
        </dia:attribute>
        <dia:attribute name="valign">
          <dia:enum val="3"/>
        </dia:attribute>
      </dia:object>
      <dia:object type="Standard - Text" version="1" id="O16">
        <dia:attribute name="obj_pos">
          <dia:point val="4,10"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="4,9.4575;5.385,11.1975"/>
        </dia:attribute>
        <dia:attribute name="text">
          <dia:composite type="text">
            <dia:attribute name="string">
              <dia:string>#
child#</dia:string>
            </dia:attribute>
            <dia:attribute name="font">
              <dia:font family="sans" style="0" name="Helvetica"/>
            </dia:attribute>
            <dia:attribute name="height">
              <dia:real val="0.80000000000000004"/>
            </dia:attribute>
            <dia:attribute name="pos">
              <dia:point val="4,10"/>
            </dia:attribute>
            <dia:attribute name="color">
              <dia:color val="#000000"/>
            </dia:attribute>
            <dia:attribute name="alignment">
              <dia:enum val="0"/>
            </dia:attribute>
          </dia:composite>
        </dia:attribute>
        <dia:attribute name="valign">
          <dia:enum val="3"/>
        </dia:attribute>
      </dia:object>
      <dia:object type="Standard - Text" version="1" id="O17">
        <dia:attribute name="obj_pos">
          <dia:point val="15,12"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="15,11.5288;18.3897,13.3987"/>
        </dia:attribute>
        <dia:attribute name="text">
          <dia:composite type="text">
            <dia:attribute name="string">
              <dia:string>#
    dbparent#</dia:string>
            </dia:attribute>
            <dia:attribute name="font">
              <dia:font family="sans" style="0" name="Helvetica"/>
            </dia:attribute>
            <dia:attribute name="height">
              <dia:real val="0.80000000000000004"/>
            </dia:attribute>
            <dia:attribute name="pos">
              <dia:point val="15,12"/>
            </dia:attribute>
            <dia:attribute name="color">
              <dia:color val="#000000"/>
            </dia:attribute>
            <dia:attribute name="alignment">
              <dia:enum val="0"/>
            </dia:attribute>
          </dia:composite>
        </dia:attribute>
        <dia:attribute name="valign">
          <dia:enum val="3"/>
        </dia:attribute>
      </dia:object>
      <dia:object type="Standard - Text" version="1" id="O18">
        <dia:attribute name="obj_pos">
          <dia:point val="9,12"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="9,11.4575;11.865,12.3975"/>
        </dia:attribute>
        <dia:attribute name="text">
          <dia:composite type="text">
            <dia:attribute name="string">
              <dia:string>#    dbchild#</dia:string>
            </dia:attribute>
            <dia:attribute name="font">
              <dia:font family="sans" style="0" name="Helvetica"/>
            </dia:attribute>
            <dia:attribute name="height">
              <dia:real val="0.80000000000000004"/>
            </dia:attribute>
            <dia:attribute name="pos">
              <dia:point val="9,12"/>
            </dia:attribute>
            <dia:attribute name="color">
              <dia:color val="#000000"/>
            </dia:attribute>
            <dia:attribute name="alignment">
              <dia:enum val="0"/>
            </dia:attribute>
          </dia:composite>
        </dia:attribute>
        <dia:attribute name="valign">
          <dia:enum val="3"/>
        </dia:attribute>
      </dia:object>
      <dia:object type="Standard - Text" version="1" id="O19">
        <dia:attribute name="obj_pos">
          <dia:point val="8,7"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="8,6.4575;10.2797,8.1975"/>
        </dia:attribute>
        <dia:attribute name="text">
          <dia:composite type="text">
            <dia:attribute name="string">
              <dia:string>#
  parent#</dia:string>
            </dia:attribute>
            <dia:attribute name="font">
              <dia:font family="sans" style="0" name="Helvetica"/>
            </dia:attribute>
            <dia:attribute name="height">
              <dia:real val="0.80000000000000004"/>
            </dia:attribute>
            <dia:attribute name="pos">
              <dia:point val="8,7"/>
            </dia:attribute>
            <dia:attribute name="color">
              <dia:color val="#000000"/>
            </dia:attribute>
            <dia:attribute name="alignment">
              <dia:enum val="0"/>
            </dia:attribute>
          </dia:composite>
        </dia:attribute>
        <dia:attribute name="valign">
          <dia:enum val="3"/>
        </dia:attribute>
      </dia:object>
    </dia:group>
  </dia:layer>
</dia:diagram>
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted art/branching.odp.

cannot compute difference between binary files

Deleted art/concept1.dia.

cannot compute difference between binary files

Deleted art/concept2.dia.

cannot compute difference between binary files

Deleted art/delta1.dia.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
<?xml version="1.0" encoding="UTF-8"?>
<dia:diagram xmlns:dia="http://www.lysator.liu.se/~alla/dia/">
  <dia:diagramdata>
    <dia:attribute name="background">
      <dia:color val="#ffffff"/>
    </dia:attribute>
    <dia:attribute name="pagebreak">
      <dia:color val="#000099"/>
    </dia:attribute>
    <dia:attribute name="paper">
      <dia:composite type="paper">
        <dia:attribute name="name">
          <dia:string>#Letter#</dia:string>
        </dia:attribute>
        <dia:attribute name="tmargin">
          <dia:real val="2.5399999618530273"/>
        </dia:attribute>
        <dia:attribute name="bmargin">
          <dia:real val="2.5399999618530273"/>
        </dia:attribute>
        <dia:attribute name="lmargin">
          <dia:real val="2.5399999618530273"/>
        </dia:attribute>
        <dia:attribute name="rmargin">
          <dia:real val="2.5399999618530273"/>
        </dia:attribute>
        <dia:attribute name="is_portrait">
          <dia:boolean val="true"/>
        </dia:attribute>
        <dia:attribute name="scaling">
          <dia:real val="1"/>
        </dia:attribute>
        <dia:attribute name="fitto">
          <dia:boolean val="false"/>
        </dia:attribute>
      </dia:composite>
    </dia:attribute>
    <dia:attribute name="grid">
      <dia:composite type="grid">
        <dia:attribute name="width_x">
          <dia:real val="1"/>
        </dia:attribute>
        <dia:attribute name="width_y">
          <dia:real val="1"/>
        </dia:attribute>
        <dia:attribute name="visible_x">
          <dia:int val="1"/>
        </dia:attribute>
        <dia:attribute name="visible_y">
          <dia:int val="1"/>
        </dia:attribute>
        <dia:composite type="color"/>
      </dia:composite>
    </dia:attribute>
    <dia:attribute name="color">
      <dia:color val="#d8e5e5"/>
    </dia:attribute>
    <dia:attribute name="guides">
      <dia:composite type="guides">
        <dia:attribute name="hguides"/>
        <dia:attribute name="vguides"/>
      </dia:composite>
    </dia:attribute>
  </dia:diagramdata>
  <dia:layer name="Background" visible="true">
    <dia:group>
      <dia:group>
        <dia:object type="Standard - Box" version="0" id="O0">
          <dia:attribute name="obj_pos">
            <dia:point val="1,1"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="0.95,0.95;5.05,3.05"/>
          </dia:attribute>
          <dia:attribute name="elem_corner">
            <dia:point val="1,1"/>
          </dia:attribute>
          <dia:attribute name="elem_width">
            <dia:real val="4"/>
          </dia:attribute>
          <dia:attribute name="elem_height">
            <dia:real val="2"/>
          </dia:attribute>
          <dia:attribute name="show_background">
            <dia:boolean val="true"/>
          </dia:attribute>
        </dia:object>
        <dia:object type="Standard - Text" version="1" id="O1">
          <dia:attribute name="obj_pos">
            <dia:point val="2,2"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="2,1.4575;4.12,2.3975"/>
          </dia:attribute>
          <dia:attribute name="text">
            <dia:composite type="text">
              <dia:attribute name="string">
                <dia:string>#Header#</dia:string>
              </dia:attribute>
              <dia:attribute name="font">
                <dia:font family="sans" style="0" name="Helvetica"/>
              </dia:attribute>
              <dia:attribute name="height">
                <dia:real val="0.80000000000000004"/>
              </dia:attribute>
              <dia:attribute name="pos">
                <dia:point val="2,2"/>
              </dia:attribute>
              <dia:attribute name="color">
                <dia:color val="#000000"/>
              </dia:attribute>
              <dia:attribute name="alignment">
                <dia:enum val="0"/>
              </dia:attribute>
            </dia:composite>
          </dia:attribute>
          <dia:attribute name="valign">
            <dia:enum val="3"/>
          </dia:attribute>
        </dia:object>
      </dia:group>
      <dia:group>
        <dia:object type="Standard - Box" version="0" id="O2">
          <dia:attribute name="obj_pos">
            <dia:point val="5,1"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="4.95,0.95;9.05,3.05"/>
          </dia:attribute>
          <dia:attribute name="elem_corner">
            <dia:point val="5,1"/>
          </dia:attribute>
          <dia:attribute name="elem_width">
            <dia:real val="4"/>
          </dia:attribute>
          <dia:attribute name="elem_height">
            <dia:real val="2"/>
          </dia:attribute>
          <dia:attribute name="show_background">
            <dia:boolean val="true"/>
          </dia:attribute>
        </dia:object>
        <dia:object type="Standard - Text" version="1" id="O3">
          <dia:attribute name="obj_pos">
            <dia:point val="5.53022,2"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="5.53022,1.4575;8.45272,2.3975"/>
          </dia:attribute>
          <dia:attribute name="text">
            <dia:composite type="text">
              <dia:attribute name="string">
                <dia:string>#Segments#</dia:string>
              </dia:attribute>
              <dia:attribute name="font">
                <dia:font family="sans" style="0" name="Helvetica"/>
              </dia:attribute>
              <dia:attribute name="height">
                <dia:real val="0.80000000000000004"/>
              </dia:attribute>
              <dia:attribute name="pos">
                <dia:point val="5.53022,2"/>
              </dia:attribute>
              <dia:attribute name="color">
                <dia:color val="#000000"/>
              </dia:attribute>
              <dia:attribute name="alignment">
                <dia:enum val="0"/>
              </dia:attribute>
            </dia:composite>
          </dia:attribute>
          <dia:attribute name="valign">
            <dia:enum val="3"/>
          </dia:attribute>
        </dia:object>
      </dia:group>
      <dia:group>
        <dia:object type="Standard - Box" version="0" id="O4">
          <dia:attribute name="obj_pos">
            <dia:point val="9,1"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="8.95,0.95;13.05,3.05"/>
          </dia:attribute>
          <dia:attribute name="elem_corner">
            <dia:point val="9,1"/>
          </dia:attribute>
          <dia:attribute name="elem_width">
            <dia:real val="4"/>
          </dia:attribute>
          <dia:attribute name="elem_height">
            <dia:real val="2"/>
          </dia:attribute>
          <dia:attribute name="show_background">
            <dia:boolean val="true"/>
          </dia:attribute>
        </dia:object>
        <dia:object type="Standard - Text" version="1" id="O5">
          <dia:attribute name="obj_pos">
            <dia:point val="10,2"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="10,1.4575;11.7893,2.3975"/>
          </dia:attribute>
          <dia:attribute name="text">
            <dia:composite type="text">
              <dia:attribute name="string">
                <dia:string>#Trailer#</dia:string>
              </dia:attribute>
              <dia:attribute name="font">
                <dia:font family="sans" style="0" name="Helvetica"/>
              </dia:attribute>
              <dia:attribute name="height">
                <dia:real val="0.80000000000000004"/>
              </dia:attribute>
              <dia:attribute name="pos">
                <dia:point val="10,2"/>
              </dia:attribute>
              <dia:attribute name="color">
                <dia:color val="#000000"/>
              </dia:attribute>
              <dia:attribute name="alignment">
                <dia:enum val="0"/>
              </dia:attribute>
            </dia:composite>
          </dia:attribute>
          <dia:attribute name="valign">
            <dia:enum val="3"/>
          </dia:attribute>
        </dia:object>
      </dia:group>
    </dia:group>
  </dia:layer>
</dia:diagram>
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




















































































































































































































































































































































































































































































Deleted art/delta2.dia.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
<?xml version="1.0" encoding="UTF-8"?>
<dia:diagram xmlns:dia="http://www.lysator.liu.se/~alla/dia/">
  <dia:diagramdata>
    <dia:attribute name="background">
      <dia:color val="#ffffff"/>
    </dia:attribute>
    <dia:attribute name="pagebreak">
      <dia:color val="#000099"/>
    </dia:attribute>
    <dia:attribute name="paper">
      <dia:composite type="paper">
        <dia:attribute name="name">
          <dia:string>#Letter#</dia:string>
        </dia:attribute>
        <dia:attribute name="tmargin">
          <dia:real val="2.5399999618530273"/>
        </dia:attribute>
        <dia:attribute name="bmargin">
          <dia:real val="2.5399999618530273"/>
        </dia:attribute>
        <dia:attribute name="lmargin">
          <dia:real val="2.5399999618530273"/>
        </dia:attribute>
        <dia:attribute name="rmargin">
          <dia:real val="2.5399999618530273"/>
        </dia:attribute>
        <dia:attribute name="is_portrait">
          <dia:boolean val="true"/>
        </dia:attribute>
        <dia:attribute name="scaling">
          <dia:real val="1"/>
        </dia:attribute>
        <dia:attribute name="fitto">
          <dia:boolean val="false"/>
        </dia:attribute>
      </dia:composite>
    </dia:attribute>
    <dia:attribute name="grid">
      <dia:composite type="grid">
        <dia:attribute name="width_x">
          <dia:real val="1"/>
        </dia:attribute>
        <dia:attribute name="width_y">
          <dia:real val="1"/>
        </dia:attribute>
        <dia:attribute name="visible_x">
          <dia:int val="1"/>
        </dia:attribute>
        <dia:attribute name="visible_y">
          <dia:int val="1"/>
        </dia:attribute>
        <dia:composite type="color"/>
      </dia:composite>
    </dia:attribute>
    <dia:attribute name="color">
      <dia:color val="#d8e5e5"/>
    </dia:attribute>
    <dia:attribute name="guides">
      <dia:composite type="guides">
        <dia:attribute name="hguides"/>
        <dia:attribute name="vguides"/>
      </dia:composite>
    </dia:attribute>
  </dia:diagramdata>
  <dia:layer name="Background" visible="true">
    <dia:group>
      <dia:group>
        <dia:object type="Standard - Box" version="0" id="O0">
          <dia:attribute name="obj_pos">
            <dia:point val="4,7"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="3.95,6.95;9.05,9.05"/>
          </dia:attribute>
          <dia:attribute name="elem_corner">
            <dia:point val="4,7"/>
          </dia:attribute>
          <dia:attribute name="elem_width">
            <dia:real val="5"/>
          </dia:attribute>
          <dia:attribute name="elem_height">
            <dia:real val="2"/>
          </dia:attribute>
          <dia:attribute name="show_background">
            <dia:boolean val="true"/>
          </dia:attribute>
        </dia:object>
        <dia:object type="Standard - Text" version="1" id="O1">
          <dia:attribute name="obj_pos">
            <dia:point val="4.73538,8.06397"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="4.73538,7.52147;8.24757,8.46147"/>
          </dia:attribute>
          <dia:attribute name="text">
            <dia:composite type="text">
              <dia:attribute name="string">
                <dia:string>#Copy Range#</dia:string>
              </dia:attribute>
              <dia:attribute name="font">
                <dia:font family="sans" style="0" name="Helvetica"/>
              </dia:attribute>
              <dia:attribute name="height">
                <dia:real val="0.80000000000000004"/>
              </dia:attribute>
              <dia:attribute name="pos">
                <dia:point val="4.73538,8.06397"/>
              </dia:attribute>
              <dia:attribute name="color">
                <dia:color val="#000000"/>
              </dia:attribute>
              <dia:attribute name="alignment">
                <dia:enum val="0"/>
              </dia:attribute>
            </dia:composite>
          </dia:attribute>
          <dia:attribute name="valign">
            <dia:enum val="3"/>
          </dia:attribute>
        </dia:object>
      </dia:group>
      <dia:group>
        <dia:object type="Standard - Box" version="0" id="O2">
          <dia:attribute name="obj_pos">
            <dia:point val="4,4"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="3.95,3.95;9.05,6.05"/>
          </dia:attribute>
          <dia:attribute name="elem_corner">
            <dia:point val="4,4"/>
          </dia:attribute>
          <dia:attribute name="elem_width">
            <dia:real val="5"/>
          </dia:attribute>
          <dia:attribute name="elem_height">
            <dia:real val="2"/>
          </dia:attribute>
          <dia:attribute name="show_background">
            <dia:boolean val="true"/>
          </dia:attribute>
        </dia:object>
        <dia:object type="Standard - Text" version="1" id="O3">
          <dia:attribute name="obj_pos">
            <dia:point val="4.64772,5.06397"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="4.64772,4.52147;8.33522,5.46147"/>
          </dia:attribute>
          <dia:attribute name="text">
            <dia:composite type="text">
              <dia:attribute name="string">
                <dia:string>#Insert Literal#</dia:string>
              </dia:attribute>
              <dia:attribute name="font">
                <dia:font family="sans" style="0" name="Helvetica"/>
              </dia:attribute>
              <dia:attribute name="height">
                <dia:real val="0.80000000000000004"/>
              </dia:attribute>
              <dia:attribute name="pos">
                <dia:point val="4.64772,5.06397"/>
              </dia:attribute>
              <dia:attribute name="color">
                <dia:color val="#000000"/>
              </dia:attribute>
              <dia:attribute name="alignment">
                <dia:enum val="0"/>
              </dia:attribute>
            </dia:composite>
          </dia:attribute>
          <dia:attribute name="valign">
            <dia:enum val="3"/>
          </dia:attribute>
        </dia:object>
      </dia:group>
      <dia:object type="Standard - ZigZagLine" version="1" id="O4">
        <dia:attribute name="obj_pos">
          <dia:point val="2.5,3"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="2.45,2.95;4.05,5.5"/>
        </dia:attribute>
        <dia:attribute name="orth_points">
          <dia:point val="2.5,3"/>
          <dia:point val="2.5,5"/>
          <dia:point val="4,5"/>
        </dia:attribute>
        <dia:attribute name="orth_orient">
          <dia:enum val="1"/>
          <dia:enum val="0"/>
        </dia:attribute>
        <dia:attribute name="autorouting">
          <dia:boolean val="true"/>
        </dia:attribute>
        <dia:attribute name="end_arrow">
          <dia:enum val="22"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_length">
          <dia:real val="0.5"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_width">
          <dia:real val="0.5"/>
        </dia:attribute>
      </dia:object>
      <dia:object type="Standard - ZigZagLine" version="1" id="O5">
        <dia:attribute name="obj_pos">
          <dia:point val="2.5,3"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="2.45,2.95;4.05,8.5"/>
        </dia:attribute>
        <dia:attribute name="orth_points">
          <dia:point val="2.5,3"/>
          <dia:point val="2.5,8"/>
          <dia:point val="4,8"/>
        </dia:attribute>
        <dia:attribute name="orth_orient">
          <dia:enum val="1"/>
          <dia:enum val="0"/>
        </dia:attribute>
        <dia:attribute name="autorouting">
          <dia:boolean val="true"/>
        </dia:attribute>
        <dia:attribute name="end_arrow">
          <dia:enum val="22"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_length">
          <dia:real val="0.5"/>
        </dia:attribute>
        <dia:attribute name="end_arrow_width">
          <dia:real val="0.5"/>
        </dia:attribute>
      </dia:object>
      <dia:group>
        <dia:object type="Standard - Box" version="0" id="O6">
          <dia:attribute name="obj_pos">
            <dia:point val="1,1"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="0.95,0.95;2.05,3.05"/>
          </dia:attribute>
          <dia:attribute name="elem_corner">
            <dia:point val="1,1"/>
          </dia:attribute>
          <dia:attribute name="elem_width">
            <dia:real val="1"/>
          </dia:attribute>
          <dia:attribute name="elem_height">
            <dia:real val="2"/>
          </dia:attribute>
          <dia:attribute name="show_background">
            <dia:boolean val="true"/>
          </dia:attribute>
        </dia:object>
        <dia:object type="Standard - Box" version="0" id="O7">
          <dia:attribute name="obj_pos">
            <dia:point val="2,1"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="1.95,0.95;3.05,3.05"/>
          </dia:attribute>
          <dia:attribute name="elem_corner">
            <dia:point val="2,1"/>
          </dia:attribute>
          <dia:attribute name="elem_width">
            <dia:real val="1"/>
          </dia:attribute>
          <dia:attribute name="elem_height">
            <dia:real val="2"/>
          </dia:attribute>
          <dia:attribute name="show_background">
            <dia:boolean val="true"/>
          </dia:attribute>
        </dia:object>
        <dia:object type="Standard - Box" version="0" id="O8">
          <dia:attribute name="obj_pos">
            <dia:point val="3,1"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="2.95,0.95;4.05,3.05"/>
          </dia:attribute>
          <dia:attribute name="elem_corner">
            <dia:point val="3,1"/>
          </dia:attribute>
          <dia:attribute name="elem_width">
            <dia:real val="1"/>
          </dia:attribute>
          <dia:attribute name="elem_height">
            <dia:real val="2"/>
          </dia:attribute>
          <dia:attribute name="show_background">
            <dia:boolean val="true"/>
          </dia:attribute>
        </dia:object>
        <dia:object type="Standard - Box" version="0" id="O9">
          <dia:attribute name="obj_pos">
            <dia:point val="7,1"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="6.95,0.95;8.05,3.05"/>
          </dia:attribute>
          <dia:attribute name="elem_corner">
            <dia:point val="7,1"/>
          </dia:attribute>
          <dia:attribute name="elem_width">
            <dia:real val="1"/>
          </dia:attribute>
          <dia:attribute name="elem_height">
            <dia:real val="2"/>
          </dia:attribute>
          <dia:attribute name="show_background">
            <dia:boolean val="true"/>
          </dia:attribute>
        </dia:object>
        <dia:object type="Standard - Text" version="1" id="O10">
          <dia:attribute name="obj_pos">
            <dia:point val="5,2.06397"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="5,1.52147;5.8775,2.46147"/>
          </dia:attribute>
          <dia:attribute name="text">
            <dia:composite type="text">
              <dia:attribute name="string">
                <dia:string>#***#</dia:string>
              </dia:attribute>
              <dia:attribute name="font">
                <dia:font family="sans" style="0" name="Helvetica"/>
              </dia:attribute>
              <dia:attribute name="height">
                <dia:real val="0.80000000000000004"/>
              </dia:attribute>
              <dia:attribute name="pos">
                <dia:point val="5,2.06397"/>
              </dia:attribute>
              <dia:attribute name="color">
                <dia:color val="#000000"/>
              </dia:attribute>
              <dia:attribute name="alignment">
                <dia:enum val="0"/>
              </dia:attribute>
            </dia:composite>
          </dia:attribute>
          <dia:attribute name="valign">
            <dia:enum val="3"/>
          </dia:attribute>
        </dia:object>
      </dia:group>
    </dia:group>
  </dia:layer>
</dia:diagram>
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
































































































































































































































































































































































































































































































































































































































































































































Deleted art/delta3.dia.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
<?xml version="1.0" encoding="UTF-8"?>
<dia:diagram xmlns:dia="http://www.lysator.liu.se/~alla/dia/">
  <dia:diagramdata>
    <dia:attribute name="background">
      <dia:color val="#ffffff"/>
    </dia:attribute>
    <dia:attribute name="pagebreak">
      <dia:color val="#000099"/>
    </dia:attribute>
    <dia:attribute name="paper">
      <dia:composite type="paper">
        <dia:attribute name="name">
          <dia:string>#Letter#</dia:string>
        </dia:attribute>
        <dia:attribute name="tmargin">
          <dia:real val="2.5399999618530273"/>
        </dia:attribute>
        <dia:attribute name="bmargin">
          <dia:real val="2.5399999618530273"/>
        </dia:attribute>
        <dia:attribute name="lmargin">
          <dia:real val="2.5399999618530273"/>
        </dia:attribute>
        <dia:attribute name="rmargin">
          <dia:real val="2.5399999618530273"/>
        </dia:attribute>
        <dia:attribute name="is_portrait">
          <dia:boolean val="true"/>
        </dia:attribute>
        <dia:attribute name="scaling">
          <dia:real val="1"/>
        </dia:attribute>
        <dia:attribute name="fitto">
          <dia:boolean val="false"/>
        </dia:attribute>
      </dia:composite>
    </dia:attribute>
    <dia:attribute name="grid">
      <dia:composite type="grid">
        <dia:attribute name="width_x">
          <dia:real val="1"/>
        </dia:attribute>
        <dia:attribute name="width_y">
          <dia:real val="1"/>
        </dia:attribute>
        <dia:attribute name="visible_x">
          <dia:int val="1"/>
        </dia:attribute>
        <dia:attribute name="visible_y">
          <dia:int val="1"/>
        </dia:attribute>
        <dia:composite type="color"/>
      </dia:composite>
    </dia:attribute>
    <dia:attribute name="color">
      <dia:color val="#d8e5e5"/>
    </dia:attribute>
    <dia:attribute name="guides">
      <dia:composite type="guides">
        <dia:attribute name="hguides"/>
        <dia:attribute name="vguides"/>
      </dia:composite>
    </dia:attribute>
  </dia:diagramdata>
  <dia:layer name="Background" visible="true">
    <dia:group>
      <dia:group>
        <dia:object type="Standard - Box" version="0" id="O0">
          <dia:attribute name="obj_pos">
            <dia:point val="1,1"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="0.95,0.95;5.05,3.05"/>
          </dia:attribute>
          <dia:attribute name="elem_corner">
            <dia:point val="1,1"/>
          </dia:attribute>
          <dia:attribute name="elem_width">
            <dia:real val="4"/>
          </dia:attribute>
          <dia:attribute name="elem_height">
            <dia:real val="2"/>
          </dia:attribute>
          <dia:attribute name="show_background">
            <dia:boolean val="true"/>
          </dia:attribute>
        </dia:object>
        <dia:object type="Standard - Text" version="1" id="O1">
          <dia:attribute name="obj_pos">
            <dia:point val="1.98659,2.0725"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="1.98659,1.53;3.99635,2.47"/>
          </dia:attribute>
          <dia:attribute name="text">
            <dia:composite type="text">
              <dia:attribute name="string">
                <dia:string>#Length#</dia:string>
              </dia:attribute>
              <dia:attribute name="font">
                <dia:font family="sans" style="0" name="Helvetica"/>
              </dia:attribute>
              <dia:attribute name="height">
                <dia:real val="0.80000000000000004"/>
              </dia:attribute>
              <dia:attribute name="pos">
                <dia:point val="1.98659,2.0725"/>
              </dia:attribute>
              <dia:attribute name="color">
                <dia:color val="#000000"/>
              </dia:attribute>
              <dia:attribute name="alignment">
                <dia:enum val="0"/>
              </dia:attribute>
            </dia:composite>
          </dia:attribute>
          <dia:attribute name="valign">
            <dia:enum val="3"/>
          </dia:attribute>
        </dia:object>
      </dia:group>
      <dia:group>
        <dia:object type="Standard - Box" version="0" id="O2">
          <dia:attribute name="obj_pos">
            <dia:point val="5,1"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="4.95,0.95;7.05,3.05"/>
          </dia:attribute>
          <dia:attribute name="elem_corner">
            <dia:point val="5,1"/>
          </dia:attribute>
          <dia:attribute name="elem_width">
            <dia:real val="2"/>
          </dia:attribute>
          <dia:attribute name="elem_height">
            <dia:real val="2"/>
          </dia:attribute>
          <dia:attribute name="show_background">
            <dia:boolean val="true"/>
          </dia:attribute>
        </dia:object>
        <dia:object type="Standard - Text" version="1" id="O3">
          <dia:attribute name="obj_pos">
            <dia:point val="5.43272,2.06397"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="5.43272,1.52147;6.55022,2.46147"/>
          </dia:attribute>
          <dia:attribute name="text">
            <dia:composite type="text">
              <dia:attribute name="string">
                <dia:string>#"@"#</dia:string>
              </dia:attribute>
              <dia:attribute name="font">
                <dia:font family="sans" style="0" name="Helvetica"/>
              </dia:attribute>
              <dia:attribute name="height">
                <dia:real val="0.80000000000000004"/>
              </dia:attribute>
              <dia:attribute name="pos">
                <dia:point val="5.43272,2.06397"/>
              </dia:attribute>
              <dia:attribute name="color">
                <dia:color val="#000000"/>
              </dia:attribute>
              <dia:attribute name="alignment">
                <dia:enum val="0"/>
              </dia:attribute>
            </dia:composite>
          </dia:attribute>
          <dia:attribute name="valign">
            <dia:enum val="3"/>
          </dia:attribute>
        </dia:object>
      </dia:group>
      <dia:group>
        <dia:object type="Standard - Box" version="0" id="O4">
          <dia:attribute name="obj_pos">
            <dia:point val="7,1"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="6.95,0.95;11.05,3.05"/>
          </dia:attribute>
          <dia:attribute name="elem_corner">
            <dia:point val="7,1"/>
          </dia:attribute>
          <dia:attribute name="elem_width">
            <dia:real val="4"/>
          </dia:attribute>
          <dia:attribute name="elem_height">
            <dia:real val="2"/>
          </dia:attribute>
          <dia:attribute name="show_background">
            <dia:boolean val="true"/>
          </dia:attribute>
        </dia:object>
        <dia:object type="Standard - Text" version="1" id="O5">
          <dia:attribute name="obj_pos">
            <dia:point val="8.12625,2.06397"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="8.12625,1.52147;9.87375,2.46147"/>
          </dia:attribute>
          <dia:attribute name="text">
            <dia:composite type="text">
              <dia:attribute name="string">
                <dia:string>#Offset#</dia:string>
              </dia:attribute>
              <dia:attribute name="font">
                <dia:font family="sans" style="0" name="Helvetica"/>
              </dia:attribute>
              <dia:attribute name="height">
                <dia:real val="0.80000000000000004"/>
              </dia:attribute>
              <dia:attribute name="pos">
                <dia:point val="8.12625,2.06397"/>
              </dia:attribute>
              <dia:attribute name="color">
                <dia:color val="#000000"/>
              </dia:attribute>
              <dia:attribute name="alignment">
                <dia:enum val="0"/>
              </dia:attribute>
            </dia:composite>
          </dia:attribute>
          <dia:attribute name="valign">
            <dia:enum val="3"/>
          </dia:attribute>
        </dia:object>
      </dia:group>
      <dia:group>
        <dia:object type="Standard - Box" version="0" id="O6">
          <dia:attribute name="obj_pos">
            <dia:point val="11,1"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="10.95,0.95;13.05,3.05"/>
          </dia:attribute>
          <dia:attribute name="elem_corner">
            <dia:point val="11,1"/>
          </dia:attribute>
          <dia:attribute name="elem_width">
            <dia:real val="2"/>
          </dia:attribute>
          <dia:attribute name="elem_height">
            <dia:real val="2"/>
          </dia:attribute>
          <dia:attribute name="show_background">
            <dia:boolean val="true"/>
          </dia:attribute>
        </dia:object>
        <dia:object type="Standard - Text" version="1" id="O7">
          <dia:attribute name="obj_pos">
            <dia:point val="11.64,2.06397"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="11.64,1.52147;12.36,2.46147"/>
          </dia:attribute>
          <dia:attribute name="text">
            <dia:composite type="text">
              <dia:attribute name="string">
                <dia:string>#","#</dia:string>
              </dia:attribute>
              <dia:attribute name="font">
                <dia:font family="sans" style="0" name="Helvetica"/>
              </dia:attribute>
              <dia:attribute name="height">
                <dia:real val="0.80000000000000004"/>
              </dia:attribute>
              <dia:attribute name="pos">
                <dia:point val="11.64,2.06397"/>
              </dia:attribute>
              <dia:attribute name="color">
                <dia:color val="#000000"/>
              </dia:attribute>
              <dia:attribute name="alignment">
                <dia:enum val="0"/>
              </dia:attribute>
            </dia:composite>
          </dia:attribute>
          <dia:attribute name="valign">
            <dia:enum val="3"/>
          </dia:attribute>
        </dia:object>
      </dia:group>
    </dia:group>
  </dia:layer>
</dia:diagram>
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


































































































































































































































































































































































































































































































































































































Deleted art/delta4.dia.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
<?xml version="1.0" encoding="UTF-8"?>
<dia:diagram xmlns:dia="http://www.lysator.liu.se/~alla/dia/">
  <dia:diagramdata>
    <dia:attribute name="background">
      <dia:color val="#ffffff"/>
    </dia:attribute>
    <dia:attribute name="pagebreak">
      <dia:color val="#000099"/>
    </dia:attribute>
    <dia:attribute name="paper">
      <dia:composite type="paper">
        <dia:attribute name="name">
          <dia:string>#Letter#</dia:string>
        </dia:attribute>
        <dia:attribute name="tmargin">
          <dia:real val="2.5399999618530273"/>
        </dia:attribute>
        <dia:attribute name="bmargin">
          <dia:real val="2.5399999618530273"/>
        </dia:attribute>
        <dia:attribute name="lmargin">
          <dia:real val="2.5399999618530273"/>
        </dia:attribute>
        <dia:attribute name="rmargin">
          <dia:real val="2.5399999618530273"/>
        </dia:attribute>
        <dia:attribute name="is_portrait">
          <dia:boolean val="true"/>
        </dia:attribute>
        <dia:attribute name="scaling">
          <dia:real val="1"/>
        </dia:attribute>
        <dia:attribute name="fitto">
          <dia:boolean val="false"/>
        </dia:attribute>
      </dia:composite>
    </dia:attribute>
    <dia:attribute name="grid">
      <dia:composite type="grid">
        <dia:attribute name="width_x">
          <dia:real val="1"/>
        </dia:attribute>
        <dia:attribute name="width_y">
          <dia:real val="1"/>
        </dia:attribute>
        <dia:attribute name="visible_x">
          <dia:int val="1"/>
        </dia:attribute>
        <dia:attribute name="visible_y">
          <dia:int val="1"/>
        </dia:attribute>
        <dia:composite type="color"/>
      </dia:composite>
    </dia:attribute>
    <dia:attribute name="color">
      <dia:color val="#d8e5e5"/>
    </dia:attribute>
    <dia:attribute name="guides">
      <dia:composite type="guides">
        <dia:attribute name="hguides"/>
        <dia:attribute name="vguides"/>
      </dia:composite>
    </dia:attribute>
  </dia:diagramdata>
  <dia:layer name="Background" visible="true">
    <dia:group>
      <dia:group>
        <dia:object type="Standard - Box" version="0" id="O0">
          <dia:attribute name="obj_pos">
            <dia:point val="1,1"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="0.95,0.95;5.05,3.05"/>
          </dia:attribute>
          <dia:attribute name="elem_corner">
            <dia:point val="1,1"/>
          </dia:attribute>
          <dia:attribute name="elem_width">
            <dia:real val="4"/>
          </dia:attribute>
          <dia:attribute name="elem_height">
            <dia:real val="2"/>
          </dia:attribute>
          <dia:attribute name="show_background">
            <dia:boolean val="true"/>
          </dia:attribute>
        </dia:object>
        <dia:object type="Standard - Text" version="1" id="O1">
          <dia:attribute name="obj_pos">
            <dia:point val="1.98659,2.0725"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="1.98659,1.53;3.99636,2.47"/>
          </dia:attribute>
          <dia:attribute name="text">
            <dia:composite type="text">
              <dia:attribute name="string">
                <dia:string>#Length#</dia:string>
              </dia:attribute>
              <dia:attribute name="font">
                <dia:font family="sans" style="0" name="Helvetica"/>
              </dia:attribute>
              <dia:attribute name="height">
                <dia:real val="0.80000000000000004"/>
              </dia:attribute>
              <dia:attribute name="pos">
                <dia:point val="1.98659,2.0725"/>
              </dia:attribute>
              <dia:attribute name="color">
                <dia:color val="#000000"/>
              </dia:attribute>
              <dia:attribute name="alignment">
                <dia:enum val="0"/>
              </dia:attribute>
            </dia:composite>
          </dia:attribute>
          <dia:attribute name="valign">
            <dia:enum val="3"/>
          </dia:attribute>
        </dia:object>
      </dia:group>
      <dia:group>
        <dia:object type="Standard - Box" version="0" id="O2">
          <dia:attribute name="obj_pos">
            <dia:point val="7,1"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="6.95,0.95;11.05,3.05"/>
          </dia:attribute>
          <dia:attribute name="elem_corner">
            <dia:point val="7,1"/>
          </dia:attribute>
          <dia:attribute name="elem_width">
            <dia:real val="4"/>
          </dia:attribute>
          <dia:attribute name="elem_height">
            <dia:real val="2"/>
          </dia:attribute>
          <dia:attribute name="show_background">
            <dia:boolean val="true"/>
          </dia:attribute>
        </dia:object>
        <dia:object type="Standard - Text" version="1" id="O3">
          <dia:attribute name="obj_pos">
            <dia:point val="8.18375,2.06397"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="8.18375,1.52147;9.81625,2.46147"/>
          </dia:attribute>
          <dia:attribute name="text">
            <dia:composite type="text">
              <dia:attribute name="string">
                <dia:string>#Bytes#</dia:string>
              </dia:attribute>
              <dia:attribute name="font">
                <dia:font family="sans" style="0" name="Helvetica"/>
              </dia:attribute>
              <dia:attribute name="height">
                <dia:real val="0.80000000000000004"/>
              </dia:attribute>
              <dia:attribute name="pos">
                <dia:point val="8.18375,2.06397"/>
              </dia:attribute>
              <dia:attribute name="color">
                <dia:color val="#000000"/>
              </dia:attribute>
              <dia:attribute name="alignment">
                <dia:enum val="0"/>
              </dia:attribute>
            </dia:composite>
          </dia:attribute>
          <dia:attribute name="valign">
            <dia:enum val="3"/>
          </dia:attribute>
        </dia:object>
      </dia:group>
      <dia:group>
        <dia:object type="Standard - Box" version="0" id="O4">
          <dia:attribute name="obj_pos">
            <dia:point val="5,1"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="4.95,0.95;7.05,3.05"/>
          </dia:attribute>
          <dia:attribute name="elem_corner">
            <dia:point val="5,1"/>
          </dia:attribute>
          <dia:attribute name="elem_width">
            <dia:real val="2"/>
          </dia:attribute>
          <dia:attribute name="elem_height">
            <dia:real val="2"/>
          </dia:attribute>
          <dia:attribute name="show_background">
            <dia:boolean val="true"/>
          </dia:attribute>
        </dia:object>
        <dia:object type="Standard - Text" version="1" id="O5">
          <dia:attribute name="obj_pos">
            <dia:point val="5.63375,2.06397"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="5.63375,1.52147;6.36625,2.46147"/>
          </dia:attribute>
          <dia:attribute name="text">
            <dia:composite type="text">
              <dia:attribute name="string">
                <dia:string>#":"#</dia:string>
              </dia:attribute>
              <dia:attribute name="font">
                <dia:font family="sans" style="0" name="Helvetica"/>
              </dia:attribute>
              <dia:attribute name="height">
                <dia:real val="0.80000000000000004"/>
              </dia:attribute>
              <dia:attribute name="pos">
                <dia:point val="5.63375,2.06397"/>
              </dia:attribute>
              <dia:attribute name="color">
                <dia:color val="#000000"/>
              </dia:attribute>
              <dia:attribute name="alignment">
                <dia:enum val="0"/>
              </dia:attribute>
            </dia:composite>
          </dia:attribute>
          <dia:attribute name="valign">
            <dia:enum val="3"/>
          </dia:attribute>
        </dia:object>
      </dia:group>
    </dia:group>
  </dia:layer>
</dia:diagram>
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




















































































































































































































































































































































































































































































Deleted art/delta5.dia.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
<?xml version="1.0" encoding="UTF-8"?>
<dia:diagram xmlns:dia="http://www.lysator.liu.se/~alla/dia/">
  <dia:diagramdata>
    <dia:attribute name="background">
      <dia:color val="#ffffff"/>
    </dia:attribute>
    <dia:attribute name="pagebreak">
      <dia:color val="#000099"/>
    </dia:attribute>
    <dia:attribute name="paper">
      <dia:composite type="paper">
        <dia:attribute name="name">
          <dia:string>#Letter#</dia:string>
        </dia:attribute>
        <dia:attribute name="tmargin">
          <dia:real val="2.5399999618530273"/>
        </dia:attribute>
        <dia:attribute name="bmargin">
          <dia:real val="2.5399999618530273"/>
        </dia:attribute>
        <dia:attribute name="lmargin">
          <dia:real val="2.5399999618530273"/>
        </dia:attribute>
        <dia:attribute name="rmargin">
          <dia:real val="2.5399999618530273"/>
        </dia:attribute>
        <dia:attribute name="is_portrait">
          <dia:boolean val="true"/>
        </dia:attribute>
        <dia:attribute name="scaling">
          <dia:real val="1"/>
        </dia:attribute>
        <dia:attribute name="fitto">
          <dia:boolean val="false"/>
        </dia:attribute>
      </dia:composite>
    </dia:attribute>
    <dia:attribute name="grid">
      <dia:composite type="grid">
        <dia:attribute name="width_x">
          <dia:real val="1"/>
        </dia:attribute>
        <dia:attribute name="width_y">
          <dia:real val="1"/>
        </dia:attribute>
        <dia:attribute name="visible_x">
          <dia:int val="1"/>
        </dia:attribute>
        <dia:attribute name="visible_y">
          <dia:int val="1"/>
        </dia:attribute>
        <dia:composite type="color"/>
      </dia:composite>
    </dia:attribute>
    <dia:attribute name="color">
      <dia:color val="#d8e5e5"/>
    </dia:attribute>
    <dia:attribute name="guides">
      <dia:composite type="guides">
        <dia:attribute name="hguides"/>
        <dia:attribute name="vguides"/>
      </dia:composite>
    </dia:attribute>
  </dia:diagramdata>
  <dia:layer name="Background" visible="true">
    <dia:group>
      <dia:group>
        <dia:object type="Standard - Box" version="0" id="O0">
          <dia:attribute name="obj_pos">
            <dia:point val="5,1"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="4.95,0.95;7.05,3.05"/>
          </dia:attribute>
          <dia:attribute name="elem_corner">
            <dia:point val="5,1"/>
          </dia:attribute>
          <dia:attribute name="elem_width">
            <dia:real val="2"/>
          </dia:attribute>
          <dia:attribute name="elem_height">
            <dia:real val="2"/>
          </dia:attribute>
          <dia:attribute name="show_background">
            <dia:boolean val="true"/>
          </dia:attribute>
        </dia:object>
        <dia:object type="Standard - Text" version="1" id="O1">
          <dia:attribute name="obj_pos">
            <dia:point val="5.62522,2.06397"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="5.62522,1.52147;6.35772,2.46147"/>
          </dia:attribute>
          <dia:attribute name="text">
            <dia:composite type="text">
              <dia:attribute name="string">
                <dia:string>#";"#</dia:string>
              </dia:attribute>
              <dia:attribute name="font">
                <dia:font family="sans" style="0" name="Helvetica"/>
              </dia:attribute>
              <dia:attribute name="height">
                <dia:real val="0.80000000000000004"/>
              </dia:attribute>
              <dia:attribute name="pos">
                <dia:point val="5.62522,2.06397"/>
              </dia:attribute>
              <dia:attribute name="color">
                <dia:color val="#000000"/>
              </dia:attribute>
              <dia:attribute name="alignment">
                <dia:enum val="0"/>
              </dia:attribute>
            </dia:composite>
          </dia:attribute>
          <dia:attribute name="valign">
            <dia:enum val="3"/>
          </dia:attribute>
        </dia:object>
      </dia:group>
      <dia:group>
        <dia:object type="Standard - Box" version="0" id="O2">
          <dia:attribute name="obj_pos">
            <dia:point val="1,1"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="0.95,0.95;5.05,3.05"/>
          </dia:attribute>
          <dia:attribute name="elem_corner">
            <dia:point val="1,1"/>
          </dia:attribute>
          <dia:attribute name="elem_width">
            <dia:real val="4"/>
          </dia:attribute>
          <dia:attribute name="elem_height">
            <dia:real val="2"/>
          </dia:attribute>
          <dia:attribute name="show_background">
            <dia:boolean val="true"/>
          </dia:attribute>
        </dia:object>
        <dia:object type="Standard - Text" version="1" id="O3">
          <dia:attribute name="obj_pos">
            <dia:point val="1.47522,2.06397"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="1.47522,1.52147;4.50772,2.46147"/>
          </dia:attribute>
          <dia:attribute name="text">
            <dia:composite type="text">
              <dia:attribute name="string">
                <dia:string>#Checksum#</dia:string>
              </dia:attribute>
              <dia:attribute name="font">
                <dia:font family="sans" style="0" name="Helvetica"/>
              </dia:attribute>
              <dia:attribute name="height">
                <dia:real val="0.80000000000000004"/>
              </dia:attribute>
              <dia:attribute name="pos">
                <dia:point val="1.47522,2.06397"/>
              </dia:attribute>
              <dia:attribute name="color">
                <dia:color val="#000000"/>
              </dia:attribute>
              <dia:attribute name="alignment">
                <dia:enum val="0"/>
              </dia:attribute>
            </dia:composite>
          </dia:attribute>
          <dia:attribute name="valign">
            <dia:enum val="3"/>
          </dia:attribute>
        </dia:object>
      </dia:group>
    </dia:group>
  </dia:layer>
</dia:diagram>
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






































































































































































































































































































































































Deleted art/delta6.dia.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
<?xml version="1.0" encoding="UTF-8"?>
<dia:diagram xmlns:dia="http://www.lysator.liu.se/~alla/dia/">
  <dia:diagramdata>
    <dia:attribute name="background">
      <dia:color val="#ffffff"/>
    </dia:attribute>
    <dia:attribute name="pagebreak">
      <dia:color val="#000099"/>
    </dia:attribute>
    <dia:attribute name="paper">
      <dia:composite type="paper">
        <dia:attribute name="name">
          <dia:string>#Letter#</dia:string>
        </dia:attribute>
        <dia:attribute name="tmargin">
          <dia:real val="2.5399999618530273"/>
        </dia:attribute>
        <dia:attribute name="bmargin">
          <dia:real val="2.5399999618530273"/>
        </dia:attribute>
        <dia:attribute name="lmargin">
          <dia:real val="2.5399999618530273"/>
        </dia:attribute>
        <dia:attribute name="rmargin">
          <dia:real val="2.5399999618530273"/>
        </dia:attribute>
        <dia:attribute name="is_portrait">
          <dia:boolean val="true"/>
        </dia:attribute>
        <dia:attribute name="scaling">
          <dia:real val="1"/>
        </dia:attribute>
        <dia:attribute name="fitto">
          <dia:boolean val="false"/>
        </dia:attribute>
      </dia:composite>
    </dia:attribute>
    <dia:attribute name="grid">
      <dia:composite type="grid">
        <dia:attribute name="width_x">
          <dia:real val="1"/>
        </dia:attribute>
        <dia:attribute name="width_y">
          <dia:real val="1"/>
        </dia:attribute>
        <dia:attribute name="visible_x">
          <dia:int val="1"/>
        </dia:attribute>
        <dia:attribute name="visible_y">
          <dia:int val="1"/>
        </dia:attribute>
        <dia:composite type="color"/>
      </dia:composite>
    </dia:attribute>
    <dia:attribute name="color">
      <dia:color val="#d8e5e5"/>
    </dia:attribute>
    <dia:attribute name="guides">
      <dia:composite type="guides">
        <dia:attribute name="hguides"/>
        <dia:attribute name="vguides"/>
      </dia:composite>
    </dia:attribute>
  </dia:diagramdata>
  <dia:layer name="Background" visible="true">
    <dia:group>
      <dia:group>
        <dia:object type="Standard - Box" version="0" id="O0">
          <dia:attribute name="obj_pos">
            <dia:point val="1,1"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="0.95,0.95;5.05,3.05"/>
          </dia:attribute>
          <dia:attribute name="elem_corner">
            <dia:point val="1,1"/>
          </dia:attribute>
          <dia:attribute name="elem_width">
            <dia:real val="4"/>
          </dia:attribute>
          <dia:attribute name="elem_height">
            <dia:real val="2"/>
          </dia:attribute>
          <dia:attribute name="show_background">
            <dia:boolean val="true"/>
          </dia:attribute>
        </dia:object>
        <dia:object type="Standard - Text" version="1" id="O1">
          <dia:attribute name="obj_pos">
            <dia:point val="2.39397,2.06397"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="2.39397,1.50441;3.60603,2.49559"/>
          </dia:attribute>
          <dia:attribute name="text">
            <dia:composite type="text">
              <dia:attribute name="string">
                <dia:string>#Size#</dia:string>
              </dia:attribute>
              <dia:attribute name="font">
                <dia:font family="sans" style="0" name="Helvetica"/>
              </dia:attribute>
              <dia:attribute name="height">
                <dia:real val="0.80000000000000004"/>
              </dia:attribute>
              <dia:attribute name="pos">
                <dia:point val="2.39397,2.06397"/>
              </dia:attribute>
              <dia:attribute name="color">
                <dia:color val="#000000"/>
              </dia:attribute>
              <dia:attribute name="alignment">
                <dia:enum val="0"/>
              </dia:attribute>
            </dia:composite>
          </dia:attribute>
          <dia:attribute name="valign">
            <dia:enum val="3"/>
          </dia:attribute>
        </dia:object>
      </dia:group>
      <dia:group>
        <dia:object type="Standard - Box" version="0" id="O2">
          <dia:attribute name="obj_pos">
            <dia:point val="5,1"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="4.95,0.95;7.05,3.05"/>
          </dia:attribute>
          <dia:attribute name="elem_corner">
            <dia:point val="5,1"/>
          </dia:attribute>
          <dia:attribute name="elem_width">
            <dia:real val="2"/>
          </dia:attribute>
          <dia:attribute name="elem_height">
            <dia:real val="2"/>
          </dia:attribute>
          <dia:attribute name="show_background">
            <dia:boolean val="true"/>
          </dia:attribute>
        </dia:object>
        <dia:object type="Standard - Text" version="1" id="O3">
          <dia:attribute name="obj_pos">
            <dia:point val="5.44022,2.06397"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="5.44022,1.50441;6.55978,2.49559"/>
          </dia:attribute>
          <dia:attribute name="text">
            <dia:composite type="text">
              <dia:attribute name="string">
                <dia:string>#"\n"#</dia:string>
              </dia:attribute>
              <dia:attribute name="font">
                <dia:font family="sans" style="0" name="Helvetica"/>
              </dia:attribute>
              <dia:attribute name="height">
                <dia:real val="0.80000000000000004"/>
              </dia:attribute>
              <dia:attribute name="pos">
                <dia:point val="5.44022,2.06397"/>
              </dia:attribute>
              <dia:attribute name="color">
                <dia:color val="#000000"/>
              </dia:attribute>
              <dia:attribute name="alignment">
                <dia:enum val="0"/>
              </dia:attribute>
            </dia:composite>
          </dia:attribute>
          <dia:attribute name="valign">
            <dia:enum val="3"/>
          </dia:attribute>
        </dia:object>
      </dia:group>
    </dia:group>
  </dia:layer>
</dia:diagram>
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






































































































































































































































































































































































Deleted art/encode10.dia.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
<?xml version="1.0" encoding="UTF-8"?>
<dia:diagram xmlns:dia="http://www.lysator.liu.se/~alla/dia/">
  <dia:diagramdata>
    <dia:attribute name="background">
      <dia:color val="#ffffff"/>
    </dia:attribute>
    <dia:attribute name="pagebreak">
      <dia:color val="#000099"/>
    </dia:attribute>
    <dia:attribute name="paper">
      <dia:composite type="paper">
        <dia:attribute name="name">
          <dia:string>#Letter#</dia:string>
        </dia:attribute>
        <dia:attribute name="tmargin">
          <dia:real val="2.5399999618530273"/>
        </dia:attribute>
        <dia:attribute name="bmargin">
          <dia:real val="2.5399999618530273"/>
        </dia:attribute>
        <dia:attribute name="lmargin">
          <dia:real val="2.5399999618530273"/>
        </dia:attribute>
        <dia:attribute name="rmargin">
          <dia:real val="2.5399999618530273"/>
        </dia:attribute>
        <dia:attribute name="is_portrait">
          <dia:boolean val="true"/>
        </dia:attribute>
        <dia:attribute name="scaling">
          <dia:real val="1"/>
        </dia:attribute>
        <dia:attribute name="fitto">
          <dia:boolean val="false"/>
        </dia:attribute>
      </dia:composite>
    </dia:attribute>
    <dia:attribute name="grid">
      <dia:composite type="grid">
        <dia:attribute name="width_x">
          <dia:real val="1"/>
        </dia:attribute>
        <dia:attribute name="width_y">
          <dia:real val="1"/>
        </dia:attribute>
        <dia:attribute name="visible_x">
          <dia:int val="1"/>
        </dia:attribute>
        <dia:attribute name="visible_y">
          <dia:int val="1"/>
        </dia:attribute>
        <dia:composite type="color"/>
      </dia:composite>
    </dia:attribute>
    <dia:attribute name="color">
      <dia:color val="#d8e5e5"/>
    </dia:attribute>
    <dia:attribute name="guides">
      <dia:composite type="guides">
        <dia:attribute name="hguides"/>
        <dia:attribute name="vguides"/>
      </dia:composite>
    </dia:attribute>
  </dia:diagramdata>
  <dia:layer name="Background" visible="true">
    <dia:group>
      <dia:group>
        <dia:object type="Standard - Box" version="0" id="O0">
          <dia:attribute name="obj_pos">
            <dia:point val="6,2"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="5.975,1.975;12.025,22.025"/>
          </dia:attribute>
          <dia:attribute name="elem_corner">
            <dia:point val="6,2"/>
          </dia:attribute>
          <dia:attribute name="elem_width">
            <dia:real val="6"/>
          </dia:attribute>
          <dia:attribute name="elem_height">
            <dia:real val="20"/>
          </dia:attribute>
          <dia:attribute name="border_width">
            <dia:real val="0.050000000000000003"/>
          </dia:attribute>
          <dia:attribute name="show_background">
            <dia:boolean val="true"/>
          </dia:attribute>
          <dia:attribute name="corner_radius">
            <dia:real val="1.1754943508222875e-38"/>
          </dia:attribute>
        </dia:object>
        <dia:group>
          <dia:object type="Standard - Box" version="0" id="O1">
            <dia:attribute name="obj_pos">
              <dia:point val="6,8"/>
            </dia:attribute>
            <dia:attribute name="obj_bb">
              <dia:rectangle val="5.975,7.975;12.025,9.025"/>
            </dia:attribute>
            <dia:attribute name="elem_corner">
              <dia:point val="6,8"/>
            </dia:attribute>
            <dia:attribute name="elem_width">
              <dia:real val="6"/>
            </dia:attribute>
            <dia:attribute name="elem_height">
              <dia:real val="1"/>
            </dia:attribute>
            <dia:attribute name="border_width">
              <dia:real val="0.050000000000000003"/>
            </dia:attribute>
            <dia:attribute name="inner_color">
              <dia:color val="#ffff00"/>
            </dia:attribute>
            <dia:attribute name="show_background">
              <dia:boolean val="true"/>
            </dia:attribute>
            <dia:attribute name="corner_radius">
              <dia:real val="1.1754943508222875e-38"/>
            </dia:attribute>
          </dia:object>
          <dia:object type="Standard - Text" version="1" id="O2">
            <dia:attribute name="obj_pos">
              <dia:point val="5.95,8.4925"/>
            </dia:attribute>
            <dia:attribute name="obj_bb">
              <dia:rectangle val="5.95,7.95;10.145,8.89"/>
            </dia:attribute>
            <dia:attribute name="text">
              <dia:composite type="text">
                <dia:attribute name="string">
                  <dia:string>#Gap =&gt; Insert#</dia:string>
                </dia:attribute>
                <dia:attribute name="font">
                  <dia:font family="sans" style="0" name="Helvetica"/>
                </dia:attribute>
                <dia:attribute name="height">
                  <dia:real val="0.80000000000000004"/>
                </dia:attribute>
                <dia:attribute name="pos">
                  <dia:point val="5.95,8.4925"/>
                </dia:attribute>
                <dia:attribute name="color">
                  <dia:color val="#000000"/>
                </dia:attribute>
                <dia:attribute name="alignment">
                  <dia:enum val="0"/>
                </dia:attribute>
              </dia:composite>
            </dia:attribute>
            <dia:attribute name="valign">
              <dia:enum val="3"/>
            </dia:attribute>
          </dia:object>
        </dia:group>
        <dia:group>
          <dia:object type="Standard - Box" version="0" id="O3">
            <dia:attribute name="obj_pos">
              <dia:point val="6,2"/>
            </dia:attribute>
            <dia:attribute name="obj_bb">
              <dia:rectangle val="5.975,1.975;12.025,8.025"/>
            </dia:attribute>
            <dia:attribute name="elem_corner">
              <dia:point val="6,2"/>
            </dia:attribute>
            <dia:attribute name="elem_width">
              <dia:real val="6"/>
            </dia:attribute>
            <dia:attribute name="elem_height">
              <dia:real val="6"/>
            </dia:attribute>
            <dia:attribute name="border_width">
              <dia:real val="0.050000000000000003"/>
            </dia:attribute>
            <dia:attribute name="inner_color">
              <dia:color val="#90ee90"/>
            </dia:attribute>
            <dia:attribute name="show_background">
              <dia:boolean val="true"/>
            </dia:attribute>
            <dia:attribute name="corner_radius">
              <dia:real val="1.1754943508222875e-38"/>
            </dia:attribute>
          </dia:object>
          <dia:object type="Standard - Text" version="1" id="O4">
            <dia:attribute name="obj_pos">
              <dia:point val="5.975,2.53456"/>
            </dia:attribute>
            <dia:attribute name="obj_bb">
              <dia:rectangle val="5.975,1.99206;8.91195,2.93206"/>
            </dia:attribute>
            <dia:attribute name="text">
              <dia:composite type="text">
                <dia:attribute name="string">
                  <dia:string>#Processed#</dia:string>
                </dia:attribute>
                <dia:attribute name="font">
                  <dia:font family="sans" style="0" name="Helvetica"/>
                </dia:attribute>
                <dia:attribute name="height">
                  <dia:real val="0.80000000000000004"/>
                </dia:attribute>
                <dia:attribute name="pos">
                  <dia:point val="5.975,2.53456"/>
                </dia:attribute>
                <dia:attribute name="color">
                  <dia:color val="#000000"/>
                </dia:attribute>
                <dia:attribute name="alignment">
                  <dia:enum val="0"/>
                </dia:attribute>
              </dia:composite>
            </dia:attribute>
            <dia:attribute name="valign">
              <dia:enum val="3"/>
            </dia:attribute>
          </dia:object>
        </dia:group>
        <dia:group>
          <dia:object type="Standard - Box" version="0" id="O5">
            <dia:attribute name="obj_pos">
              <dia:point val="6,9"/>
            </dia:attribute>
            <dia:attribute name="obj_bb">
              <dia:rectangle val="5.975,8.975;12.025,18.025"/>
            </dia:attribute>
            <dia:attribute name="elem_corner">
              <dia:point val="6,9"/>
            </dia:attribute>
            <dia:attribute name="elem_width">
              <dia:real val="6"/>
            </dia:attribute>
            <dia:attribute name="elem_height">
              <dia:real val="9"/>
            </dia:attribute>
            <dia:attribute name="border_width">
              <dia:real val="0.050000000000000003"/>
            </dia:attribute>
            <dia:attribute name="inner_color">
              <dia:color val="#ffa500"/>
            </dia:attribute>
            <dia:attribute name="show_background">
              <dia:boolean val="true"/>
            </dia:attribute>
            <dia:attribute name="corner_radius">
              <dia:real val="1.1754943508222875e-38"/>
            </dia:attribute>
          </dia:object>
          <dia:object type="Standard - Text" version="1" id="O6">
            <dia:attribute name="obj_pos">
              <dia:point val="5.975,9.53456"/>
            </dia:attribute>
            <dia:attribute name="obj_bb">
              <dia:rectangle val="5.975,8.99206;11.4275,9.93206"/>
            </dia:attribute>
            <dia:attribute name="text">
              <dia:composite type="text">
                <dia:attribute name="string">
                  <dia:string>#Common =&gt; Copy#</dia:string>
                </dia:attribute>
                <dia:attribute name="font">
                  <dia:font family="sans" style="0" name="Helvetica"/>
                </dia:attribute>
                <dia:attribute name="height">
                  <dia:real val="0.80000000000000004"/>
                </dia:attribute>
                <dia:attribute name="pos">
                  <dia:point val="5.975,9.53456"/>
                </dia:attribute>
                <dia:attribute name="color">
                  <dia:color val="#000000"/>
                </dia:attribute>
                <dia:attribute name="alignment">
                  <dia:enum val="0"/>
                </dia:attribute>
              </dia:composite>
            </dia:attribute>
            <dia:attribute name="valign">
              <dia:enum val="3"/>
            </dia:attribute>
          </dia:object>
        </dia:group>
        <dia:group>
          <dia:object type="Standard - Box" version="0" id="O7">
            <dia:attribute name="obj_pos">
              <dia:point val="5,11"/>
            </dia:attribute>
            <dia:attribute name="obj_bb">
              <dia:rectangle val="4.95,10.95;13.05,15.05"/>
            </dia:attribute>
            <dia:attribute name="elem_corner">
              <dia:point val="5,11"/>
            </dia:attribute>
            <dia:attribute name="elem_width">
              <dia:real val="8"/>
            </dia:attribute>
            <dia:attribute name="elem_height">
              <dia:real val="4"/>
            </dia:attribute>
            <dia:attribute name="inner_color">
              <dia:color val="#bfbfbf"/>
            </dia:attribute>
            <dia:attribute name="show_background">
              <dia:boolean val="true"/>
            </dia:attribute>
            <dia:attribute name="corner_radius">
              <dia:real val="1.1754943508222875e-38"/>
            </dia:attribute>
          </dia:object>
          <dia:object type="Standard - Text" version="1" id="O8">
            <dia:attribute name="obj_pos">
              <dia:point val="4.95,11.9675"/>
            </dia:attribute>
            <dia:attribute name="obj_bb">
              <dia:rectangle val="4.95,10.95;9.26848,12.71"/>
            </dia:attribute>
            <dia:attribute name="text">
              <dia:composite type="text">
                <dia:attribute name="string">
                  <dia:string>#Window#</dia:string>
                </dia:attribute>
                <dia:attribute name="font">
                  <dia:font family="sans" style="0" name="Helvetica"/>
                </dia:attribute>
                <dia:attribute name="height">
                  <dia:real val="1.5"/>
                </dia:attribute>
                <dia:attribute name="pos">
                  <dia:point val="4.95,11.9675"/>
                </dia:attribute>
                <dia:attribute name="color">
                  <dia:color val="#000000"/>
                </dia:attribute>
                <dia:attribute name="alignment">
                  <dia:enum val="0"/>
                </dia:attribute>
              </dia:composite>
            </dia:attribute>
            <dia:attribute name="valign">
              <dia:enum val="3"/>
            </dia:attribute>
          </dia:object>
        </dia:group>
      </dia:group>
      <dia:group>
        <dia:object type="Standard - Box" version="0" id="O9">
          <dia:attribute name="obj_pos">
            <dia:point val="18,2"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="17.975,1.975;24.025,24.025"/>
          </dia:attribute>
          <dia:attribute name="elem_corner">
            <dia:point val="18,2"/>
          </dia:attribute>
          <dia:attribute name="elem_width">
            <dia:real val="6"/>
          </dia:attribute>
          <dia:attribute name="elem_height">
            <dia:real val="22"/>
          </dia:attribute>
          <dia:attribute name="border_width">
            <dia:real val="0.050000000000000003"/>
          </dia:attribute>
          <dia:attribute name="show_background">
            <dia:boolean val="true"/>
          </dia:attribute>
          <dia:attribute name="corner_radius">
            <dia:real val="1.1754943508222875e-38"/>
          </dia:attribute>
        </dia:object>
        <dia:object type="Standard - Box" version="0" id="O10">
          <dia:attribute name="obj_pos">
            <dia:point val="18,5"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="17.975,4.975;24.025,14.025"/>
          </dia:attribute>
          <dia:attribute name="elem_corner">
            <dia:point val="18,5"/>
          </dia:attribute>
          <dia:attribute name="elem_width">
            <dia:real val="6"/>
          </dia:attribute>
          <dia:attribute name="elem_height">
            <dia:real val="9"/>
          </dia:attribute>
          <dia:attribute name="border_width">
            <dia:real val="0.050000000000000003"/>
          </dia:attribute>
          <dia:attribute name="inner_color">
            <dia:color val="#ffa500"/>
          </dia:attribute>
          <dia:attribute name="show_background">
            <dia:boolean val="true"/>
          </dia:attribute>
          <dia:attribute name="corner_radius">
            <dia:real val="1.1754943508222875e-38"/>
          </dia:attribute>
        </dia:object>
      </dia:group>
      <dia:group>
        <dia:object type="Standard - Text" version="1" id="O11">
          <dia:attribute name="obj_pos">
            <dia:point val="14,9"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="14,8.4575;16.8122,9.3975"/>
          </dia:attribute>
          <dia:attribute name="text">
            <dia:composite type="text">
              <dia:attribute name="string">
                <dia:string>#Signature#</dia:string>
              </dia:attribute>
              <dia:attribute name="font">
                <dia:font family="sans" style="0" name="Helvetica"/>
              </dia:attribute>
              <dia:attribute name="height">
                <dia:real val="0.80000000000000004"/>
              </dia:attribute>
              <dia:attribute name="pos">
                <dia:point val="14,9"/>
              </dia:attribute>
              <dia:attribute name="color">
                <dia:color val="#000000"/>
              </dia:attribute>
              <dia:attribute name="alignment">
                <dia:enum val="0"/>
              </dia:attribute>
            </dia:composite>
          </dia:attribute>
          <dia:attribute name="valign">
            <dia:enum val="3"/>
          </dia:attribute>
        </dia:object>
        <dia:object type="Standard - ZigZagLine" version="1" id="O12">
          <dia:attribute name="obj_pos">
            <dia:point val="12,13"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="11.95,9;18.05,13.05"/>
          </dia:attribute>
          <dia:attribute name="orth_points">
            <dia:point val="12,13"/>
            <dia:point val="15,13"/>
            <dia:point val="15,9.5"/>
            <dia:point val="18,9.5"/>
          </dia:attribute>
          <dia:attribute name="orth_orient">
            <dia:enum val="0"/>
            <dia:enum val="1"/>
            <dia:enum val="0"/>
          </dia:attribute>
          <dia:attribute name="autorouting">
            <dia:boolean val="true"/>
          </dia:attribute>
          <dia:attribute name="end_arrow">
            <dia:enum val="22"/>
          </dia:attribute>
          <dia:attribute name="end_arrow_length">
            <dia:real val="0.5"/>
          </dia:attribute>
          <dia:attribute name="end_arrow_width">
            <dia:real val="0.5"/>
          </dia:attribute>
        </dia:object>
      </dia:group>
      <dia:group>
        <dia:object type="Standard - Text" version="1" id="O13">
          <dia:attribute name="obj_pos">
            <dia:point val="2,8"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="2,6.9825;4.6625,8.7425"/>
          </dia:attribute>
          <dia:attribute name="text">
            <dia:composite type="text">
              <dia:attribute name="string">
                <dia:string>#Base#</dia:string>
              </dia:attribute>
              <dia:attribute name="font">
                <dia:font family="sans" style="0" name="Helvetica"/>
              </dia:attribute>
              <dia:attribute name="height">
                <dia:real val="1.5"/>
              </dia:attribute>
              <dia:attribute name="pos">
                <dia:point val="2,8"/>
              </dia:attribute>
              <dia:attribute name="color">
                <dia:color val="#000000"/>
              </dia:attribute>
              <dia:attribute name="alignment">
                <dia:enum val="0"/>
              </dia:attribute>
            </dia:composite>
          </dia:attribute>
          <dia:attribute name="valign">
            <dia:enum val="3"/>
          </dia:attribute>
        </dia:object>
        <dia:object type="Standard - Line" version="0" id="O14">
          <dia:attribute name="obj_pos">
            <dia:point val="5,8"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="4.95,7.5;6.05,8.5"/>
          </dia:attribute>
          <dia:attribute name="conn_endpoints">
            <dia:point val="5,8"/>
            <dia:point val="6,8"/>
          </dia:attribute>
          <dia:attribute name="numcp">
            <dia:int val="1"/>
          </dia:attribute>
          <dia:attribute name="end_arrow">
            <dia:enum val="22"/>
          </dia:attribute>
          <dia:attribute name="end_arrow_length">
            <dia:real val="0.5"/>
          </dia:attribute>
          <dia:attribute name="end_arrow_width">
            <dia:real val="0.5"/>
          </dia:attribute>
        </dia:object>
      </dia:group>
      <dia:group>
        <dia:object type="Standard - Text" version="1" id="O15">
          <dia:attribute name="obj_pos">
            <dia:point val="1,11"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="1,9.9825;3.6725,11.7425"/>
          </dia:attribute>
          <dia:attribute name="text">
            <dia:composite type="text">
              <dia:attribute name="string">
                <dia:string>#Slide#</dia:string>
              </dia:attribute>
              <dia:attribute name="font">
                <dia:font family="sans" style="0" name="Helvetica"/>
              </dia:attribute>
              <dia:attribute name="height">
                <dia:real val="1.5"/>
              </dia:attribute>
              <dia:attribute name="pos">
                <dia:point val="1,11"/>
              </dia:attribute>
              <dia:attribute name="color">
                <dia:color val="#000000"/>
              </dia:attribute>
              <dia:attribute name="alignment">
                <dia:enum val="0"/>
              </dia:attribute>
            </dia:composite>
          </dia:attribute>
          <dia:attribute name="valign">
            <dia:enum val="3"/>
          </dia:attribute>
        </dia:object>
        <dia:object type="Standard - Line" version="0" id="O16">
          <dia:attribute name="obj_pos">
            <dia:point val="4,11"/>
          </dia:attribute>
          <dia:attribute name="obj_bb">
            <dia:rectangle val="3.95,10.5;5.05,11.5"/>
          </dia:attribute>
          <dia:attribute name="conn_endpoints">
            <dia:point val="4,11"/>
            <dia:point val="5,11"/>
          </dia:attribute>
          <dia:attribute name="numcp">
            <dia:int val="1"/>
          </dia:attribute>
          <dia:attribute name="end_arrow">
            <dia:enum val="22"/>
          </dia:attribute>
          <dia:attribute name="end_arrow_length">
            <dia:real val="0.5"/>
          </dia:attribute>
          <dia:attribute name="end_arrow_width">
            <dia:real val="0.5"/>
          </dia:attribute>
        </dia:object>
      </dia:group>
      <dia:object type="Standard - Text" version="1" id="O17">
        <dia:attribute name="obj_pos">
          <dia:point val="6,2"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="6,0.9825;9.38727,2.7425"/>
        </dia:attribute>
        <dia:attribute name="text">
          <dia:composite type="text">
            <dia:attribute name="string">
              <dia:string>#Target#</dia:string>
            </dia:attribute>
            <dia:attribute name="font">
              <dia:font family="sans" style="0" name="Helvetica"/>
            </dia:attribute>
            <dia:attribute name="height">
              <dia:real val="1.5"/>
            </dia:attribute>
            <dia:attribute name="pos">
              <dia:point val="6,2"/>
            </dia:attribute>
            <dia:attribute name="color">
              <dia:color val="#000000"/>
            </dia:attribute>
            <dia:attribute name="alignment">
              <dia:enum val="0"/>
            </dia:attribute>
          </dia:composite>
        </dia:attribute>
        <dia:attribute name="valign">
          <dia:enum val="3"/>
        </dia:attribute>
      </dia:object>
      <dia:object type="Standard - Text" version="1" id="O18">
        <dia:attribute name="obj_pos">
          <dia:point val="18,2"/>
        </dia:attribute>
        <dia:attribute name="obj_bb">
          <dia:rectangle val="18,0.9825;21.3125,2.7425"/>
        </dia:attribute>
        <dia:attribute name="text">
          <dia:composite type="text">
            <dia:attribute name="string">
              <dia:string>#Origin#</dia:string>
            </dia:attribute>
            <dia:attribute name="font">
              <dia:font family="sans" style="0" name="Helvetica"/>
            </dia:attribute>
            <dia:attribute name="height">
              <dia:real val="1.5"/>
            </dia:attribute>
            <dia:attribute name="pos">
              <dia:point val="18,2"/>
            </dia:attribute>
            <dia:attribute name="color">
              <dia:color val="#000000"/>
            </dia:attribute>
            <dia:attribute name="alignment">
              <dia:enum val="0"/>
            </dia:attribute>
          </dia:composite>
        </dia:attribute>
        <dia:attribute name="valign">
          <dia:enum val="3"/>
        </dia:attribute>
      </dia:object>
    </dia:group>
  </dia:layer>
</dia:diagram>
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Changes to skins/ardoise/css.txt.
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
a {
  background-color: transparent;
  color: #ff8000;
  text-decoration: unset
}
a:active,
a:hover,
pre.udiff:focus,
table.sbsdiffcols:focus {
  outline: 0
}
abbr[title] {
  border-bottom: 1px dotted
}
b,
optgroup,
strong,
td.usetupEditLabel {







<
<
<
<







81
82
83
84
85
86
87




88
89
90
91
92
93
94
a {
  background-color: transparent;
  color: #ff8000;
  text-decoration: unset
}
a:active,
a:hover,




abbr[title] {
  border-bottom: 1px dotted
}
b,
optgroup,
strong,
td.usetupEditLabel {
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136

1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147

1148
1149
1150
1151

1152
1153




1154
1155

1156
1157
1158
1159

1160
1161
1162
1163
1164

1165
1166

1167
1168




1169
1170
1171
1172
1173
1174
1175
.tl-line.warp {
  background: #600000
}
table.login_out .login_out_label {
  font-weight: 700;
  text-align: right
}
pre.udiff,
table.sbsdiffcols {
  width: 100%;
  overflow: auto;
  padding: 0 5px;
  font-size: 1rem;
  background: #000;
  border-radius: 5px
}
pre.udiff,
pre.udiff pre,
table.sbsdiffcols pre {
  font-size: 1.15rem

}
pre.udiff {
  padding: 10px 0
}
div.difftxtcol {
  width: 52rem;
  overflow-x: auto
}
span.diffchng {
  background-color: #8080e8;
  color: #000

}
span.diffadd {
  background-color: #559855;
  color: #000

}
span.diffrm {




  background-color: #c55;
  color: #000

}
div.diffmkrcol {
  padding: 0 1em;
  background: #111

}
span.diffhr {
  display: inline-block;
  margin: .5em 0 1em;
  color: #555

}
span.diffln {

  color: #666
}




table.report {
  width: 100%;
  cursor: auto;
  margin: 0 0 1em;
  color: #000
}
table.report thead {







<
|


<


|

<
|
<
|
>

|


|

<

|
|
|
>

|
|
|
>

|
>
>
>
>

|
>

|
<
|
>

|
<
|
|
>

|
>
|

>
>
>
>







1113
1114
1115
1116
1117
1118
1119

1120
1121
1122

1123
1124
1125
1126

1127

1128
1129
1130
1131
1132
1133
1134
1135

1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156

1157
1158
1159
1160

1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
.tl-line.warp {
  background: #600000
}
table.login_out .login_out_label {
  font-weight: 700;
  text-align: right
}

table.diff {
  width: 100%;
  overflow: auto;

  font-size: 1rem;
  background: #000;
  border-radius: 5px;
}

table.diff pre {

  font-size: 1.15rem;
  scrollbar-color: black #999;
}
table.udiff pre {
  padding: 10px 0
}
td.difftxt {
  width: 52rem;

}
td.diffln ins {
  background-color: #559855;
  color: #000;
  text-decoration: none;
}
td.diffln del {
  background-color: #c55;
  color: #000;
  text-decoration: none;
}
td.difftxt del {
  background-color: inherit;
  text-decoration: none;
}
td.difftxt del > del {
  background-color: #c55;
  color: #000;
  text-decoration: none;
}
td.difftxt ins {

  background-color: inherit;
  text-decoration: none;
}
td.difftxt ins > ins {

  background-color: #559855;
  color: #000;
  text-decoration: none;
}

tr.diffskip.jchunk {
  background-color: #404040;
}
tr.diffskip > td.chunkctrl .jcbutton {
  background-color: black;
}

table.report {
  width: 100%;
  cursor: auto;
  margin: 0 0 1em;
  color: #000
}
table.report thead {
Changes to skins/black_and_white/css.txt.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/* General settings for the entire page */
body {
    margin:0px 0px 0px 0px;
    padding:0px;
    font-family:verdana, arial, helvetica, "sans serif";
    color:#333;
    background-color:white;
    -moz-text-size-adjust: none;
    -webkit-text-size-adjust: none;
    -mx-text-size-adjust: none;
}

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







|
<
<







1
2
3
4
5
6
7
8


9
10
11
12
13
14
15
/* General settings for the entire page */
body {
    margin:0px 0px 0px 0px;
    padding:0px;
    font-family:verdana, arial, helvetica, "sans serif";
    color:#333;
    background-color:white;
    text-size-adjust: none;


}

/* consistent colours */
h2 {
  color: #333;
}
h3 {
Changes to skins/blitz/css.txt.
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
table.login_out td {
  border: 0;
}


/* Diff displays
––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */
pre.udiff, table.sbsdiffcols {
  width: 100%;
  overflow: auto;
  border: 1px solid #ccc;
  padding: 5px;
  font-size: 1rem;
}

pre.udiff:focus, table.sbsdiffcols:focus {
  outline: none;
}


/* Ticket Reports
––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */
table.report {







|







|







1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
table.login_out td {
  border: 0;
}


/* Diff displays
––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */
table.diff {
  width: 100%;
  overflow: auto;
  border: 1px solid #ccc;
  padding: 5px;
  font-size: 1rem;
}

table.diff:focus {
  outline: none;
}


/* Ticket Reports
––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */
table.report {
Changes to skins/bootstrap/css.txt.
4398
4399
4400
4401
4402
4403
4404
























  height: 4px;
  background: #000;
}

body.branch .submenu > a.timeline-link {
  color: black;
}































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
4398
4399
4400
4401
4402
4403
4404
4405
4406
4407
4408
4409
4410
4411
4412
4413
4414
4415
4416
4417
4418
4419
4420
4421
4422
4423
4424
4425
4426
4427
4428
  height: 4px;
  background: #000;
}

body.branch .submenu > a.timeline-link {
  color: black;
}

tr.diffskip > td.chunkctrl .jcbutton {
  min-width: 3.5ex;
  max-width: revert;
}

/* Bootstrap installs a 'table' class on tables which causes its
   styles to be more specific matches than our diff tables, so we have
   to fight that fire with more fire... */
table.diff.table>thead>tr>th, table.diff.table>tbody>tr>th,
table.diff.table>tfoot>tr>th, table.diff.table>thead>tr>td,
table.diff.table>tbody>tr>td, table.diff.table>tfoot>tr>td {
  padding: 0;
  line-height: revert;
  vertical-align: top;
  border-top: none;
}
table.diff tr.diffskip.jchunk > td {
  padding: 0.25em 0.5em;
}
table.diff pre {
  border: none;
  word-wrap: initial;
}
Changes to skins/darkmode/css.txt.
449
450
451
452
453
454
455
456
457
458

459
460
461
462

463
464




465
466

467
468
469

470
471

472

473
474



475
476
477
478
479
480
481
482
  border-left: 1px dashed #bbb;
  background: rgba(255,255,255,0);
}

/************************************************************************
diffs...
************************************************************************/
span.diffchng {
  background-color: #8080e8;
  color: #000

}
span.diffadd {
  background-color: #559855;
  color: #000

}
span.diffrm {




  background-color: #c55;
  color: #000

}
div.diffmkrcol {
  background: #111

}
span.diffhr {

  color: #555

}
span.diffln {



  color: #666
}

/************************************************************************
************************************************************************/
body.wikiedit #fossil-status-bar,
body.fileedit #fossil-status-bar{
  border-radius: 0.25em 0.25em 0 0;







|
|
|
>

|
|
|
>

|
>
>
>
>

|
>

|
|
>

|
>
|
>

|
>
>
>
|







449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
  border-left: 1px dashed #bbb;
  background: rgba(255,255,255,0);
}

/************************************************************************
diffs...
************************************************************************/
td.diffln ins {
  background-color: #559855;
  color: #000;
  text-decoration: none;
}
td.diffln del {
  background-color: #c55;
  color: #000;
  text-decoration: none;
}
td.difftxt del {
  background-color: inherit;
  text-decoration: none;
}
td.difftxt del > del {
  background-color: #c55;
  color: #000;
  text-decoration: none;
}
td.difftxt ins {
  background-color: inherit;
  text-decoration: none;
}
td.difftxt ins > ins {
  background-color: #559855;
  color: #000;
  text-decoration: none;
}
tr.diffskip.jchunk {
  background-color: black;
}
tr.diffskip > td.chunkctrl .jcbutton {
  background-color: #303536;
}

/************************************************************************
************************************************************************/
body.wikiedit #fossil-status-bar,
body.fileedit #fossil-status-bar{
  border-radius: 0.25em 0.25em 0 0;
505
506
507
508
509
510
511
512
513
514
515
516



517
518
519
520




521
522
523
524
525
526
527
  font-weight: bold;
}
button,
input,
optgroup,
select,
textarea {
  background-color: inherit;
  color: inherit;
  font: inherit;
  margin: 0
}



input, textarea, select {
  border: 1px solid rgba(127, 201, 255, 0.9);
  padding: 1px;
}




.capsumOff {
  background-color: #222;
}
.capsumRead {
  background-color: #262;
}
.capsumWrite {







|




>
>
>




>
>
>
>







518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
  font-weight: bold;
}
button,
input,
optgroup,
select,
textarea {
  background: inherit;
  color: inherit;
  font: inherit;
  margin: 0
}
button {
  background-color: rgba(45,45,45,0.75);
}
input, textarea, select {
  border: 1px solid rgba(127, 201, 255, 0.9);
  padding: 1px;
}
select {
  color: #1f1f1f;
  background: #ffffffe0;
}
.capsumOff {
  background-color: #222;
}
.capsumRead {
  background-color: #262;
}
.capsumWrite {
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
}

body.forum .forumPostBody > div blockquote {
    border: 1px inset;
    padding: 0 0.5em;
}

pre.udiff {
  overflow-x: auto;
}

body.report table.report tr td { color: black }
body.report table.report a { color: blue }
body.tkt td.tktDspValue { color: black }
body.tkt td.tktDspValue a { color: blue }

body.branch .brlist > table > tbody > tr:hover:not(.selected),
body.branch .brlist > table > tbody > tr.selected {
  background-color: #442800;
}







<
<
<
<









565
566
567
568
569
570
571




572
573
574
575
576
577
578
579
580
}

body.forum .forumPostBody > div blockquote {
    border: 1px inset;
    padding: 0 0.5em;
}





body.report table.report tr td { color: black }
body.report table.report a { color: blue }
body.tkt td.tktDspValue { color: black }
body.tkt td.tktDspValue a { color: blue }

body.branch .brlist > table > tbody > tr:hover:not(.selected),
body.branch .brlist > table > tbody > tr.selected {
  background-color: #442800;
}
Changes to skins/default/css.txt.
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
.footer {
  border-top: 1px solid #ccc;
  padding: 10px;
  font-size: 0.7em;
  margin-top: 10px;
  color: #ccc;
}


/* Exceptions for /info diff views */

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


/* Forum */

.forum a:visited {
  color: #6A7F94;
}








<
<
<
<
<
<
<
<
<
<
<







156
157
158
159
160
161
162











163
164
165
166
167
168
169
.footer {
  border-top: 1px solid #ccc;
  padding: 10px;
  font-size: 0.7em;
  margin-top: 10px;
  color: #ccc;
}












/* Forum */

.forum a:visited {
  color: #6A7F94;
}

Changes to skins/eagle/css.txt.
11
12
13
14
15
16
17
18
19







20
21
22
23
24
25
26
div.logo {
  display: table-cell;
  text-align: center;
  vertical-align: bottom;
  font-weight: bold;
  color: white;
  min-width: 50px;
  padding: 5 0 5 0em;
  white-space: nowrap;







}

/* The page title centered at the top of each page */
div.title {
  display: table-cell;
  font-size: 2em;
  font-weight: bold;







<

>
>
>
>
>
>
>







11
12
13
14
15
16
17

18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
div.logo {
  display: table-cell;
  text-align: center;
  vertical-align: bottom;
  font-weight: bold;
  color: white;
  min-width: 50px;

  white-space: nowrap;
  position: relative;
  filter: drop-shadow(2px 4px 6px rgba(0,0,0,0.75));
  top: 0.5em;
  right: -0.5em;
}
div.logo img{
  border-radius: 2mm;
}

/* The page title centered at the top of each page */
div.title {
  display: table-cell;
  font-size: 2em;
  font-weight: bold;
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
  border-top: 0px dashed #fff;
  border-left: 1px dashed #fff;
  background: rgba(255,255,255,0);
}


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

/* format for the layout table, used for the captcha display */
table.captcha {







|





<







261
262
263
264
265
266
267
268
269
270
271
272
273

274
275
276
277
278
279
280
  border-top: 0px dashed #fff;
  border-left: 1px dashed #fff;
  background: rgba(255,255,255,0);
}


/* Side-by-side diff */
table.splitdiff {
  background-color: #485D7B;
  font-family: fixed, Dejavu Sans Mono, Monaco, Lucida Console, monospace;
  font-size: 8pt;
  border-collapse:collapse;
  white-space: pre;

  border: 1px #000 dashed;
  margin-left: auto;
  margin-right: auto;
}

/* format for the layout table, used for the captcha display */
table.captcha {
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350


351
352
353
354
355
356
357
358
359
360
361

362
363
364
365
366
367
368
369
370
371
372
/* List of files in a timeline */
ul.filelist {
  margin-top: 3px;
  line-height: 100%;
}

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

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

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

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

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



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

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

}

.fileage tr:hover {
  background-color: #7EA2D9;
}

span.modpending {
  color: #c0c0c0;
  font-style: italic;
}
span.forum_author {







|






|




|
|
|

|
<
<
|



|


>
>
|
<
|
<
<
|

|
<
<

>



|







323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346


347
348
349
350
351
352
353
354
355
356

357


358
359
360


361
362
363
364
365
366
367
368
369
370
371
372
373
/* List of files in a timeline */
ul.filelist {
  margin-top: 3px;
  line-height: 100%;
}

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

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

/* added code in a diff */
td.difftxt ins > ins, td.diffln ins {
  background-color: rgb(100, 200, 100);
}
td.difftxt ins {


  background-color: inherit;
}

/* deleted in a diff */
td.difftxt del > del, td.diffln del {
  background-color: rgb(230, 110, 110);
}
td.difftxt del {
  background-color: inherit;
}

tr.diffskip.jchunk {


  background-color: #7EA2D9;
}
tr.diffskip > td.chunkctrl .jcbutton{


  color: white;
  background-color: #485D7B;
}

.fileage tr:hover {
  background-color:  #7EA2D9;
}

span.modpending {
  color: #c0c0c0;
  font-style: italic;
}
span.forum_author {
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
  background-color: #7EA2D9;
}

.timelineModernCell[id], .timelineColumnarCell[id], .timelineDetailCell[id] {
  background-color: #455978;
}

div.difflncol {
  padding-right: 1em;
  text-align: right;
  color: white;
}
.capsumOff {
  background-color: #bbbbbb;
}
.capsumRead {
  background-color: #006d00;
}
.capsumWrite {







<
<
<
<
<







418
419
420
421
422
423
424





425
426
427
428
429
430
431
  background-color: #7EA2D9;
}

.timelineModernCell[id], .timelineColumnarCell[id], .timelineDetailCell[id] {
  background-color: #455978;
}






.capsumOff {
  background-color: #bbbbbb;
}
.capsumRead {
  background-color: #006d00;
}
.capsumWrite {
Changes to skins/eagle/header.txt.
54
55
56
57
58
59
60


61




62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82

83

84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
          set logourl $baseurl
        }
      } else {
        set logourl $baseurl
      }
      return $logourl
    }


    set logourl [getLogoUrl $baseurl]




    </th1>
    <a href="$logourl">
      <img src="$logo_image_url" border="0" alt="$project_name">
    </a>
  </div>
  <div class="title">$<title></div>
  <div class="status"><nobr><th1>
     if {[info exists login]} {
       puts "Logged in as $login"
     } else {
       puts "Not logged in"
     }
  </th1></nobr><small><div id="clock"></div></small></div>
</div>
<th1>html "<script nonce='$nonce'>"</th1>
function updateClock(){
  var e = document.getElementById("clock");
  if(e){
    var d = new Date();
    function f(n) {
      return n < 10 ? '0' + n : n;

    }

    e.innerHTML = d.getUTCFullYear()+ '-' +
      f(d.getUTCMonth() + 1) + '-' +
      f(d.getUTCDate())      + ' ' +
      f(d.getUTCHours())     + ':' +
      f(d.getUTCMinutes());
    setTimeout(updateClock,(60-d.getUTCSeconds())*1000);
  }
}
updateClock();
</script>
<div class="mainmenu"><th1>
html "<a id='hbbtn' href='$home/sitemap' aria-label='Site Map'>&#9776;</a>\n"
builtin_request_js hbmenu.js
foreach {name url expr class} $mainmenu {
  if {![capexpr $expr]} continue
  if {[string match /* $url]} {set url $home$url}







>
>
|
>
>
>
>















|

|
|
|

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







54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98


99
100
101
102
103
104
105
          set logourl $baseurl
        }
      } else {
        set logourl $baseurl
      }
      return $logourl
    }
    if {1} {
      # Link logo to the top of the current domain
      set logourl [getLogoUrl $baseurl]
    } else {
      # Link logo to the top of the current repo
      set logourl $baseurl
    }
    </th1>
    <a href="$logourl">
      <img src="$logo_image_url" border="0" alt="$project_name">
    </a>
  </div>
  <div class="title">$<title></div>
  <div class="status"><nobr><th1>
     if {[info exists login]} {
       puts "Logged in as $login"
     } else {
       puts "Not logged in"
     }
  </th1></nobr><small><div id="clock"></div></small></div>
</div>
<th1>html "<script nonce='$nonce'>"</th1>
(function updateClock(){
  var e = document.getElementById("clock");
  if(!e) return;
  if(!updateClock.fmt){
    updateClock.fmt = function(n){
      return n < 10 ? '0' + n : n;
    };
  }
  var d = new Date();
  e.innerHTML = d.getUTCFullYear()+ '-' +
    updateClock.fmt(d.getUTCMonth() + 1) + '-' +
    updateClock.fmt(d.getUTCDate())      + ' ' +
    updateClock.fmt(d.getUTCHours())     + ':' +
    updateClock.fmt(d.getUTCMinutes());
  setTimeout(updateClock,(60-d.getUTCSeconds())*1000);
})();


</script>
<div class="mainmenu"><th1>
html "<a id='hbbtn' href='$home/sitemap' aria-label='Site Map'>&#9776;</a>\n"
builtin_request_js hbmenu.js
foreach {name url expr class} $mainmenu {
  if {![capexpr $expr]} continue
  if {[string match /* $url]} {set url $home$url}
Changes to skins/khaki/css.txt.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/* General settings for the entire page */
body {
  margin: 0ex 0ex;
  padding: 0px;
  background-color: #fef3bc;
  font-family: sans-serif;
  -moz-text-size-adjust: none;
  -webkit-text-size-adjust: none;
  -mx-text-size-adjust: none;
}

/* The project logo in the upper left-hand corner of each page */
div.logo {
  display: inline;
  text-align: center;
  vertical-align: bottom;






|
<
<







1
2
3
4
5
6
7


8
9
10
11
12
13
14
/* General settings for the entire page */
body {
  margin: 0ex 0ex;
  padding: 0px;
  background-color: #fef3bc;
  font-family: sans-serif;
  text-size-adjust: none;


}

/* The project logo in the upper left-hand corner of each page */
div.logo {
  display: inline;
  text-align: center;
  vertical-align: bottom;
168
169
170
171
172
173
174










div.forumPostBody blockquote {
  border-width: 1pt;
  border-radius: 0.25em;
  border-style: solid;
  padding: 0 0.5em;
}
















>
>
>
>
>
>
>
>
>
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181

div.forumPostBody blockquote {
  border-width: 1pt;
  border-radius: 0.25em;
  border-style: solid;
  padding: 0 0.5em;
}

tr.diffskip > td.chunkctrl .jcbutton {
  color: white;
  background-color: #a09048;
}

tr.diffskip.jchunk {
  background-color: #c0af58;
}
Changes to skins/plain_gray/css.txt.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/* General settings for the entire page */
body {
  margin: 0ex 1ex;
  padding: 0px;
  background-color: white;
  font-family: sans-serif;
  -moz-text-size-adjust: none;
  -webkit-text-size-adjust: none;
  -mx-text-size-adjust: none;
}

/* The page title centered at the top of each page */
div.title {
  display: table-cell;
  font-size: 1.5em;
  font-weight: bold;






|
<
<







1
2
3
4
5
6
7


8
9
10
11
12
13
14
/* General settings for the entire page */
body {
  margin: 0ex 1ex;
  padding: 0px;
  background-color: white;
  font-family: sans-serif;
  text-size-adjust: none;


}

/* The page title centered at the top of each page */
div.title {
  display: table-cell;
  font-size: 1.5em;
  font-weight: bold;
Changes to skins/xekri/css.txt.
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
  font-size: 1em;
  min-height: 100%;
}

body {
  margin: 0;
  padding: 0;
  -moz-text-size-adjust: none;
  -ms-text-size-adjust: none;
  -webkit-text-size-adjust: none;
}

a {
  color: #40a0ff;
}

a:hover {







|
<
<







20
21
22
23
24
25
26
27


28
29
30
31
32
33
34
  font-size: 1em;
  min-height: 100%;
}

body {
  margin: 0;
  padding: 0;
  text-size-adjust: none;


}

a {
  color: #40a0ff;
}

a:hover {
89
90
91
92
93
94
95










96
97
98
99
100
101
102
103
104
105
106
107
108
109

/**************************************
 * Main Area: Header
 */

div.header {
  margin: 0.5rem auto 0 auto;










}

div.logo img {
  float: left;
  padding: 0;
  box-shadow: 3px 3px 1px #000;
  margin: 0 6px 6px 0;
}

div.logo br {
  display: none;
}

div.logo nobr {







>
>
>
>
>
>
>
>
>
>



<

|
|







87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106

107
108
109
110
111
112
113
114
115
116

/**************************************
 * Main Area: Header
 */

div.header {
  margin: 0.5rem auto 0 auto;
  display: flex;
  flex-direction: row;
  align-items: center;
  flex-wrap: wrap;
}
div.logo {
  display: inline;
  max-height: 4em;
  max-width: 4em;
  flex: 0 1 auto;
}

div.logo img {

  padding: 0;
  box-shadow: 2px 4px 6px rgba(180,180,180,0.70);
  border-radius: 2mm;
}

div.logo br {
  display: none;
}

div.logo nobr {
120
121
122
123
124
125
126

127
128
129
130
131
132
133
134

135
136
137
138
139
140
141
  color: #3297f9;
  font-family: Verdana, sans-serif;
  font-weight: bold;
  font-size: 2.5rem;
  padding: 0.5rem;
  text-align: center;
  text-shadow: 3px 3px 1px #000;

}

div.status {
  color: #ee0;
  font-size: 1rem;
  padding: 0.25rem;
  text-align: right;
  text-shadow: 2px 2px 1px #000;

}


/**************************************
 * Main Area: Global Menu
 */








>








>







127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
  color: #3297f9;
  font-family: Verdana, sans-serif;
  font-weight: bold;
  font-size: 2.5rem;
  padding: 0.5rem;
  text-align: center;
  text-shadow: 3px 3px 1px #000;
  flex: 10 0 auto;
}

div.status {
  color: #ee0;
  font-size: 1rem;
  padding: 0.25rem;
  text-align: right;
  text-shadow: 2px 2px 1px #000;
  flex: 0 1 auto;
}


/**************************************
 * Main Area: Global Menu
 */

226
227
228
229
230
231
232
233
234
235
236
237
238
239
240


div.footer div {
  background-color: #222;
  box-shadow: 3px 3px 1px #000;
  border-radius: 0 0 1rem 1rem;
  margin: 0 0 10px 0;
  padding: 0.5rem 0.75rem;
}

div.footer div.page-time {
  float: left;
}

div.footer div.fossil-info {







|







235
236
237
238
239
240
241
242
243
244
245
246
247
248
249


div.footer div {
  background-color: #222;
  box-shadow: 3px 3px 1px #000;
  border-radius: 0 0 1rem 1rem;
  margin: 0 0 10px 0;
  padding: 0.25rem 0.75rem;
}

div.footer div.page-time {
  float: left;
}

div.footer div.fossil-info {
261
262
263
264
265
266
267
268







269
270

271
272
273
274
275
276
277
278
279
280
281
282

283
284
285



286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
  padding: 0.1rem 1rem;
}


/**************************************
 * Diffs
 */








/* Code Added */
span.diffadd {

  background-color: #7f7;
  color: #000;
}

/* Code Changed */
span.diffchng {
  background-color: #77f;
  color: #000;
}

/* Code Deleted */
span.diffrm {

  background-color: #f77;
  color: #000;
}





/**************************************
 * Diffs : Side-By-Side
 */

/* display (column-based) */
table.sbsdiffcols {
  border-spacing: 0;
  font-size: 0.85rem;
  width: 90%;
}

table.sbsdiffcols pre {
  border: 0;
  margin: 0;
  padding: 0;
}

table.sbsdiffcols td {
  padding: 0;
  vertical-align: top;
}

/* line number column */
div.difflncol {
  color: #ee0;
  padding-right: 0.75em;
  text-align: right;
}

/* diff text column */
div.difftxtcol {
  background-color: #111;
  overflow-x: auto;
  width: 45em;
}

/* suppressed lines */
span.diffhr {
  display: inline-block;
  margin-bottom: 0.75em;
  color: #ff0;
}

/* diff marker column */
div.diffmkrcol {
  padding: 0 0.5em;
}


/**************************************
 * Diffs : Unified
 */

pre.udiff {
  background-color: #111;
}

/* line numbers */
span.diffln {
  background-color: #222;
  color: #ee0;
}


/**************************************
 * File List : Flat
 */

table.browser {
  width: 100%;








>
>
>
>
>
>
>

|
>



|
<
<
|
<



|
>



>
>
>







|


<


|

|



|





|






|





<
<
<
<
<
|
<

|








|



<
<
<
<
<
<







270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291


292

293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313

314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340





341

342
343
344
345
346
347
348
349
350
351
352
353
354
355






356
357
358
359
360
361
362
  padding: 0.1rem 1rem;
}


/**************************************
 * Diffs
 */

tr.diffskip.jchunk {
  background-color: black;
}
tr.diffskip > td.chunkctrl .jcbutton {
  background-color: #303536;
}

/* Code Added */
td.diffln ins,
td.difftxt ins > ins {
  background-color: #7f7;
  color: #000;
}
td.difftxt ins {


  background-color: inherit;

}

/* Code Deleted */
td.diffln del,
td.difftxt del > del {
  background-color: #f77;
  color: #000;
}
td.difftxt del {
  background-color: inherit;
}


/**************************************
 * Diffs : Side-By-Side
 */

/* display (column-based) */
table.splitdiff {
  border-spacing: 0;
  font-size: 0.85rem;

}

table.splitdiff pre {
  border: 0;
  margin: 0 0.5em;
  padding: 0;
}

table.splitdiff td {
  padding: 0;
  vertical-align: top;
}

/* line number column */
td.diffln {
  color: #ee0;
  padding-right: 0.75em;
  text-align: right;
}

/* diff text column */
td.difftxt {
  background-color: #111;
  overflow-x: auto;
  width: 45em;
}








/* diff marker column */
td.diffsep {
  padding: 0 0.5em;
}


/**************************************
 * Diffs : Unified
 */

table.udiff pre {
  background-color: #111;
}








/**************************************
 * File List : Flat
 */

table.browser {
  width: 100%;
1144
1145
1146
1147
1148
1149
1150














  color: black;
}

body.branch .brlist > table > tbody > tr:hover:not(.selected),
body.branch .brlist > table > tbody > tr.selected {
  background-color: #444;
}





















>
>
>
>
>
>
>
>
>
>
>
>
>
>
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
  color: black;
}

body.branch .brlist > table > tbody > tr:hover:not(.selected),
body.branch .brlist > table > tbody > tr.selected {
  background-color: #444;
}

body.chat div.header, body.chat div.footer,
body.chat div.mainmenu, body.chat div.submenu,
body.chat div.content {
  margin-left: 0.5em;
  margin-right: 0.5em;
  margin-top: auto/*eliminates unnecessary scrollbars*/;
}
body.chat.chat-only-mode div.content {
  max-width: revert;
}
body.chat #chat-user-list .chat-user{
  color: white;
}
Changes to skins/xekri/header.txt.
54
55
56
57
58
59
60


61




62
63
64
65
66
67
68
          set logourl $baseurl
        }
      } else {
        set logourl $baseurl
      }
      return $logourl
    }


    set logourl [getLogoUrl $baseurl]




    </th1>
    <a href="$logourl">
      <img src="$logo_image_url" border="0" alt="$project_name">
    </a>
  </div>
  <div class="title">$<title></div>
  <div class="status"><nobr><th1>







>
>
|
>
>
>
>







54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
          set logourl $baseurl
        }
      } else {
        set logourl $baseurl
      }
      return $logourl
    }
    if {1} {
      # Link logo to the top of the current domain
      set logourl [getLogoUrl $baseurl]
    } else {
      # Link logo to the top of the current repo
      set logourl $baseurl
    }
    </th1>
    <a href="$logourl">
      <img src="$logo_image_url" border="0" alt="$project_name">
    </a>
  </div>
  <div class="title">$<title></div>
  <div class="status"><nobr><th1>
Changes to src/ajax.c.
147
148
149
150
151
152
153





154
155

156

157


158
159
160
161
162
163
164
165
166
167
168
169
170
171
  }
}

/*
** Renders diffs for ajax routes. pOrig is the "original" (v1) content
** and pContent is the locally-edited (v2) content. diffFlags is any
** set of flags suitable for passing to text_diff().





*/
void ajax_render_diff(Blob * pOrig, Blob *pContent, u64 diffFlags){

  Blob out = empty_blob;




  text_diff(pOrig, pContent, &out, 0, diffFlags);
  if(blob_size(&out)==0){
    /* nothing to do */
  }else if(DIFF_SIDEBYSIDE & diffFlags){
    CX("%b",&out);
  }else{
    CX("<pre class='udiff'>%b</pre>",&out);
  }
  blob_reset(&out);
}

/*
** Uses P(zKey) to fetch a CGI environment variable. If that var is
** NULL or starts with '0' or 'f' then this function returns false,







>
>
>
>
>

|
>

>

>
>
|


<
<

|







147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169


170
171
172
173
174
175
176
177
178
  }
}

/*
** Renders diffs for ajax routes. pOrig is the "original" (v1) content
** and pContent is the locally-edited (v2) content. diffFlags is any
** set of flags suitable for passing to text_diff().
**
** zOrigHash, if not NULL, must be the SCM-side hash of pOrig's
** contents. If set, additional information may be built into
** the diff output to enable dynamic loading of additional
** diff context.
*/
void ajax_render_diff(Blob * pOrig, const char * zOrigHash,
                      Blob *pContent, u64 diffFlags){
  Blob out = empty_blob;
  DiffConfig DCfg;

  diff_config_init(&DCfg, diffFlags);
  DCfg.zLeftHash = zOrigHash;
  text_diff(pOrig, pContent, &out, &DCfg);
  if(blob_size(&out)==0){
    /* nothing to do */


  }else{
    CX("%b",&out);
  }
  blob_reset(&out);
}

/*
** Uses P(zKey) to fetch a CGI environment variable. If that var is
** NULL or starts with '0' or 'f' then this function returns false,
255
256
257
258
259
260
261
262
263
264
265
266
267


268
269
270
271
272
273
274
    *zFn = PD("filename",P("fn"));
    if (*zFn) ++rc;
  }
  return rc;
}

/*
** AJAX route /ajax/preview-wiki
**
** Required query parameters:
**
** filename=name of content, for use in determining the
** mimetype/render mode.  content=text


**
** Optional query parameters:
**
** render_mode=integer (AJAX_RENDER_xxx) (default=AJAX_RENDER_GUESS)
**
** ln=0 or 1 to disable/enable line number mode in
** AJAX_RENDER_PLAIN_TEXT mode.







|




|
>
>







262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
    *zFn = PD("filename",P("fn"));
    if (*zFn) ++rc;
  }
  return rc;
}

/*
** AJAX route /ajax/preview-text
**
** Required query parameters:
**
** filename=name of content, for use in determining the
** mimetype/render mode.
**
** content=text
**
** Optional query parameters:
**
** render_mode=integer (AJAX_RENDER_xxx) (default=AJAX_RENDER_GUESS)
**
** ln=0 or 1 to disable/enable line number mode in
** AJAX_RENDER_PLAIN_TEXT mode.
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
int cmp_ajax_route_name(const void *a, const void *b){
  const AjaxRoute * rA = (const AjaxRoute*)a;
  const AjaxRoute * rB = (const AjaxRoute*)b;
  return fossil_strcmp(rA->zName, rB->zName);
}

/*
** WEBPAGE: ajax
**
** The main dispatcher for shared ajax-served routes. Requires the
** 'name' parameter be the main route's name (as defined in a list in
** this function), noting that fossil automatically assigns all path
** parts after "ajax" to "name", e.g. /ajax/foo/bar assigns
** name=foo/bar.
**







|







365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
int cmp_ajax_route_name(const void *a, const void *b){
  const AjaxRoute * rA = (const AjaxRoute*)a;
  const AjaxRoute * rB = (const AjaxRoute*)b;
  return fossil_strcmp(rA->zName, rB->zName);
}

/*
** WEBPAGE: ajax hidden
**
** The main dispatcher for shared ajax-served routes. Requires the
** 'name' parameter be the main route's name (as defined in a list in
** this function), noting that fossil automatically assigns all path
** parts after "ajax" to "name", e.g. /ajax/foo/bar assigns
** name=foo/bar.
**
Changes to src/alerts.c.
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
    db_exec_sql(zAlertInit);
    return;
  }
  if( db_table_has_column("repository","subscriber","lastContact") ){
    return;
  }
  db_multi_exec(
    "DROP TABLE IF EXISTS repository.alert_bounde;\n"
    "ALTER TABLE repository.subscriber ADD COLUMN lastContact INT;\n"
    "UPDATE subscriber SET lastContact=mtime/86400;"
  );
  if( db_table_has_column("repository","pending_alert","sentMod") ){
    return;
  }
  db_multi_exec(







|







126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
    db_exec_sql(zAlertInit);
    return;
  }
  if( db_table_has_column("repository","subscriber","lastContact") ){
    return;
  }
  db_multi_exec(
    "DROP TABLE IF EXISTS repository.alert_bounce;\n"
    "ALTER TABLE repository.subscriber ADD COLUMN lastContact INT;\n"
    "UPDATE subscriber SET lastContact=mtime/86400;"
  );
  if( db_table_has_column("repository","pending_alert","sentMod") ){
    return;
  }
  db_multi_exec(
Changes to src/allrepo.c.
89
90
91
92
93
94
95

96
97
98
99
100
101
102
103
**
**    extras      Shows "extra" files from all local checkouts.  The command
**                line options supported by the extra command itself, if any
**                are present, are passed along verbatim.
**
**    fts-config  Run the "fts-config" command on all repositories.
**

**    git export  Do the "git export" command on all repositories for which
**                a Git mirror has been previously established.
**
**    info        Run the "info" command on all repositories.
**
**    pull        Run a "pull" operation on all repositories.  Only the
**                --verbose option is supported.
**







>
|







89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
**
**    extras      Shows "extra" files from all local checkouts.  The command
**                line options supported by the extra command itself, if any
**                are present, are passed along verbatim.
**
**    fts-config  Run the "fts-config" command on all repositories.
**
**    git CMD     Do the "git export" or "git status" command (which every
**                is specified by CMD) on all repositories for which
**                a Git mirror has been previously established.
**
**    info        Run the "info" command on all repositories.
**
**    pull        Run a "pull" operation on all repositories.  Only the
**                --verbose option is supported.
**
Changes to src/attach.c.
657
658
659
660
661
662
663

664
665
666
667
668
669
670
    const char *zDispUser = zUser && zUser[0] ? zUser : "anonymous";
    if( cnt==0 ){
      @ %s(zHeader)
    }
    cnt++;
    @ <li>
    @ %z(href("%R/artifact/%!S",zSrc))%h(zFile)</a>

    @ added by %h(zDispUser) on
    hyperlink_to_date(zDate, ".");
    @ [%z(href("%R/ainfo/%!S",zUuid))details</a>]
    @ </li>
  }
  if( cnt ){
    @ </ul>







>







657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
    const char *zDispUser = zUser && zUser[0] ? zUser : "anonymous";
    if( cnt==0 ){
      @ %s(zHeader)
    }
    cnt++;
    @ <li>
    @ %z(href("%R/artifact/%!S",zSrc))%h(zFile)</a>
    @ [<a href="%R/attachdownload/%t(zFile)?page=%t(zTarget)&file=%t(zFile)">download</a>]
    @ added by %h(zDispUser) on
    hyperlink_to_date(zDate, ".");
    @ [%z(href("%R/ainfo/%!S",zUuid))details</a>]
    @ </li>
  }
  if( cnt ){
    @ </ul>
Changes to src/blob.c.
273
274
275
276
277
278
279
280


281
282


283
284
285
286
287

288
289
290
291
292
293
294








295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334

335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351




















































































352
353
354
355
356
357
358
  pBlob->aData = (char*)zEmpty;
  pBlob->iCursor = 0;
  pBlob->blobFlags = 0;
  pBlob->xRealloc = blobReallocStatic;
}

/*
** Append text or data to the end of a blob.


**
** The blob_append_full() routine is a complete implementation.


** The blob_append() routine only works for cases where nData>0 and
** no resizing is required, and falls back to blob_append_full() if
** either condition is not met, but runs faster in the common case
** where all conditions are met.  The use of blob_append() is
** recommended, unless it is known in advance that nData<0.

*/
void blob_append_full(Blob *pBlob, const char *aData, int nData){
  sqlite3_int64 nNew;
  assert( aData!=0 || nData==0 );
  blob_is_init(pBlob);
  if( nData<0 ) nData = strlen(aData);
  if( nData==0 ) return;








  nNew = pBlob->nUsed;
  nNew += nData;
  if( nNew >= pBlob->nAlloc ){
    nNew += pBlob->nAlloc;
    nNew += 100;
    if( nNew>=0x7fff0000 ){
      blob_panic();
    }
    pBlob->xRealloc(pBlob, (int)nNew);
    if( pBlob->nUsed + nData >= pBlob->nAlloc ){
      blob_panic();
    }
  }
  memcpy(&pBlob->aData[pBlob->nUsed], aData, nData);
  pBlob->nUsed += nData;
  pBlob->aData[pBlob->nUsed] = 0;   /* Blobs are always nul-terminated */
}
void blob_append(Blob *pBlob, const char *aData, int nData){
  sqlite3_int64 nUsed;
  assert( aData!=0 || nData==0 );
  /* blob_is_init(pBlob); // omitted for speed */
  if( nData<=0 || pBlob->nUsed + nData >= pBlob->nAlloc ){
    blob_append_full(pBlob, aData, nData);
    return;
  }
  nUsed = pBlob->nUsed;
  pBlob->nUsed += nData;
  pBlob->aData[pBlob->nUsed] = 0;
  memcpy(&pBlob->aData[nUsed], aData, nData);
}

/*
** Append a string literal to a blob.
*/
#if INTERFACE
#define blob_append_string(BLOB,STR) blob_append(BLOB,STR,sizeof(STR)-1)
#endif

/*
** Append a single character to the blob

*/
void blob_append_char(Blob *pBlob, char c){
  if( pBlob->nUsed+1 >= pBlob->nAlloc ){
    blob_append_full(pBlob, &c, 1);
  }else{
    pBlob->aData[pBlob->nUsed++] = c;
  }
}

/*
** Copy a blob
*/
void blob_copy(Blob *pTo, Blob *pFrom){
  blob_is_init(pFrom);
  blob_zero(pTo);
  blob_append(pTo, blob_buffer(pFrom), blob_size(pFrom));
}





















































































/*
** Return a pointer to a null-terminated string for a blob.
*/
char *blob_str(Blob *p){
  blob_is_init(p);
  if( p->nUsed==0 ){







|
>
>

<
>
>
|
|
<
|
<
>

|

|
|


>
>
>
>
>
>
>
>



















|
<
|

















|
>


|







|






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







273
274
275
276
277
278
279
280
281
282
283

284
285
286
287

288

289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324

325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
  pBlob->aData = (char*)zEmpty;
  pBlob->iCursor = 0;
  pBlob->blobFlags = 0;
  pBlob->xRealloc = blobReallocStatic;
}

/*
** Append text or data to the end of a blob.  Or, if pBlob==NULL, send
** the text to standard output in terminal mode, or to standard CGI output
** in CGI mode.
**

** If nData<0 then output all of aData up to the first 0x00 byte.
**
** Use the blob_append() routine in all application code.  The blob_append()
** routine is faster, but blob_append_full() handles all the corner cases.

** The blob_append() routine automatically calls blob_append_full() if

** necessary.
*/
static void blob_append_full(Blob *pBlob, const char *aData, int nData){
  sqlite3_int64 nNew;
  /* assert( aData!=0 || nData==0 ); // omitted for speed */
  /* blob_is_init(pBlob); // omitted for speed */
  if( nData<0 ) nData = strlen(aData);
  if( nData==0 ) return;
  if( pBlob==0 ){
    if( g.cgiOutput ){
      pBlob = cgi_output_blob();
    }else{
      fossil_puts(aData, 0, nData);
      return;
    }
  }
  nNew = pBlob->nUsed;
  nNew += nData;
  if( nNew >= pBlob->nAlloc ){
    nNew += pBlob->nAlloc;
    nNew += 100;
    if( nNew>=0x7fff0000 ){
      blob_panic();
    }
    pBlob->xRealloc(pBlob, (int)nNew);
    if( pBlob->nUsed + nData >= pBlob->nAlloc ){
      blob_panic();
    }
  }
  memcpy(&pBlob->aData[pBlob->nUsed], aData, nData);
  pBlob->nUsed += nData;
  pBlob->aData[pBlob->nUsed] = 0;   /* Blobs are always nul-terminated */
}
void blob_append(Blob *pBlob, const char *aData, int nData){
  sqlite3_int64 nUsed;
  /* assert( aData!=0 || nData==0 ); // omitted for speed */

  if( nData<=0 || pBlob==0 || pBlob->nUsed + nData >= pBlob->nAlloc ){
    blob_append_full(pBlob, aData, nData);
    return;
  }
  nUsed = pBlob->nUsed;
  pBlob->nUsed += nData;
  pBlob->aData[pBlob->nUsed] = 0;
  memcpy(&pBlob->aData[nUsed], aData, nData);
}

/*
** Append a string literal to a blob.
*/
#if INTERFACE
#define blob_append_string(BLOB,STR) blob_append(BLOB,STR,sizeof(STR)-1)
#endif

/*
** Append a single character to the blob.  If pBlob is zero then the
** character is written directly to stdout.
*/
void blob_append_char(Blob *pBlob, char c){
  if( pBlob==0 || pBlob->nUsed+1 >= pBlob->nAlloc ){
    blob_append_full(pBlob, &c, 1);
  }else{
    pBlob->aData[pBlob->nUsed++] = c;
  }
}

/*
** Copy a blob.  pTo is reinitialized to be a copy of pFrom.
*/
void blob_copy(Blob *pTo, Blob *pFrom){
  blob_is_init(pFrom);
  blob_zero(pTo);
  blob_append(pTo, blob_buffer(pFrom), blob_size(pFrom));
}

/*
** Append the second blob onto the end of the first blob and reset the
** second blob.  If the first blob (pTo) is NULL, then the content
** of the second blob is written to stdout or to CGI depending on if the
** Fossil is running in terminal or CGI mode.
*/
void blob_append_xfer(Blob *pTo, Blob *pFrom){
  blob_append(pTo, blob_buffer(pFrom), blob_size(pFrom));
  blob_reset(pFrom);
}

/*
** Write into pOut, a string literal representation for the first n bytes
** of z[].  The string literal representation is compatible with C, TCL,
** and JSON.  Double-quotes are added to both ends.  Double-quote and
** backslash characters are escaped.
*/
void blob_append_tcl_literal(Blob *pOut, const char *z, int n){
  int i;
  blob_append_char(pOut, '"');
  for(i=0; i<n; i++){
    char c = z[i];
    switch( c ){
      case '\r':  c = 'r';
      case '[':
      case ']':
      case '$':
      case '"':
      case '\\':
        blob_append_char(pOut, '\\');
      default:
        blob_append_char(pOut, c);
    }
  }
  blob_append_char(pOut, '"');
}
void blob_append_json_literal(Blob *pOut, const char *z, int n){
  int i;
  blob_append_char(pOut, '"');
  for(i=0; i<n; i++){
    char c = z[i];
    switch( c ){
      case 0x00:
      case 0x01:
      case 0x02:
      case 0x03:
      case 0x04:
      case 0x05:
      case 0x06:
      case 0x07: c += '0' - 0x00; blob_append(pOut, "\\u000",5); break;
      case 0x0b:
      case 0x0e:
      case 0x0f: c += 'a' - 0x0a; blob_append(pOut, "\\u000",5); break;
      case 0x10:
      case 0x11:
      case 0x12:
      case 0x13:
      case 0x14:
      case 0x15:
      case 0x16:
      case 0x17:
      case 0x18:
      case 0x19: c += '0' - 0x10; blob_append(pOut, "\\u001",5); break;
      case 0x1a:
      case 0x1b:
      case 0x1c:
      case 0x1d:
      case 0x1e:
      case 0x1f: c += 'a' - 0x1a; blob_append(pOut, "\\u001",5); break;
      case '\b': c = 'b';         blob_append_char(pOut, '\\');  break;
      case '\t': c = 't';         blob_append_char(pOut, '\\');  break;
      case '\r': c = 'r';         blob_append_char(pOut, '\\');  break;
      case '\n': c = 'n';         blob_append_char(pOut, '\\');  break;
      case '\f': c = 'f';         blob_append_char(pOut, '\\');  break;
      case '"':                   blob_append_char(pOut, '\\');  break;
      case '\\':                  blob_append_char(pOut, '\\');  break;
      default:                                                   break;
    }
    blob_append_char(pOut, c);
  }
  blob_append_char(pOut, '"');
}


/*
** Return a pointer to a null-terminated string for a blob.
*/
char *blob_str(Blob *p){
  blob_is_init(p);
  if( p->nUsed==0 ){
833
834
835
836
837
838
839
840

841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
int blob_tokenize(Blob *pIn, Blob *aToken, int nToken){
  int i;
  for(i=0; i<nToken && blob_token(pIn, &aToken[i]); i++){}
  return i;
}

/*
** Do printf-style string rendering and append the results to a blob.

**
** The blob_appendf() version sets the BLOBFLAG_NotSQL bit in Blob.blobFlags
** whereas blob_append_sql() does not.
*/
void blob_appendf(Blob *pBlob, const char *zFormat, ...){
  if( pBlob ){
    va_list ap;
    va_start(ap, zFormat);
    vxprintf(pBlob, zFormat, ap);
    va_end(ap);
    pBlob->blobFlags |= BLOBFLAG_NotSQL;
  }
}
void blob_append_sql(Blob *pBlob, const char *zFormat, ...){
  if( pBlob ){
    va_list ap;
    va_start(ap, zFormat);
    vxprintf(pBlob, zFormat, ap);
    va_end(ap);
  }
}
void blob_vappendf(Blob *pBlob, const char *zFormat, va_list ap){
  if( pBlob ) vxprintf(pBlob, zFormat, ap);
}

/*
** Initialize a blob to the data on an input channel.  Return
** the number of bytes read into the blob.  Any prior content
** of the blob is discarded, not freed.
*/







|
>





<
|
|
|
|
|
|
<

<
|
|
|
|
|
<

|







927
928
929
930
931
932
933
934
935
936
937
938
939
940

941
942
943
944
945
946

947

948
949
950
951
952

953
954
955
956
957
958
959
960
961
int blob_tokenize(Blob *pIn, Blob *aToken, int nToken){
  int i;
  for(i=0; i<nToken && blob_token(pIn, &aToken[i]); i++){}
  return i;
}

/*
** Do printf-style string rendering and append the results to a blob.  Or
** if pBlob==0, do printf-style string rendering directly to stdout.
**
** The blob_appendf() version sets the BLOBFLAG_NotSQL bit in Blob.blobFlags
** whereas blob_append_sql() does not.
*/
void blob_appendf(Blob *pBlob, const char *zFormat, ...){

  va_list ap;
  va_start(ap, zFormat);
  vxprintf(pBlob, zFormat, ap);
  va_end(ap);
  if( pBlob ) pBlob->blobFlags |= BLOBFLAG_NotSQL;
}

void blob_append_sql(Blob *pBlob, const char *zFormat, ...){

  va_list ap;
  va_start(ap, zFormat);
  vxprintf(pBlob, zFormat, ap);
  va_end(ap);
}

void blob_vappendf(Blob *pBlob, const char *zFormat, va_list ap){
  vxprintf(pBlob, zFormat, ap);
}

/*
** Initialize a blob to the data on an input channel.  Return
** the number of bytes read into the blob.  Any prior content
** of the blob is discarded, not freed.
*/
Changes to src/branch.c.
231
232
233
234
235
236
237

238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257

258
259
260
261
262
263
264
**
**      name           Name of the branch
**      mtime          Time of last checkin on this branch
**      isclosed       True if the branch is closed
**      mergeto        Another branch this branch was merged into
**      nckin          Number of checkins on this branch
**      ckin           Hash of the last checkin on this branch

**      bgclr          Background color for this branch
*/
static const char createBrlistQuery[] =
@ CREATE TEMP TABLE IF NOT EXISTS tmp_brlist AS
@ SELECT
@   tagxref.value AS name,
@   max(event.mtime) AS mtime,
@   EXISTS(SELECT 1 FROM tagxref AS tx
@           WHERE tx.rid=tagxref.rid
@             AND tx.tagid=(SELECT tagid FROM tag WHERE tagname='closed')
@             AND tx.tagtype>0) AS isclosed,
@   (SELECT tagxref.value
@      FROM plink CROSS JOIN tagxref
@    WHERE plink.pid=event.objid
@       AND tagxref.rid=plink.cid
@      AND tagxref.tagid=(SELECT tagid FROM tag WHERE tagname='branch')
@      AND tagtype>0) AS mergeto,
@   count(*) AS nckin,
@   (SELECT uuid FROM blob WHERE rid=tagxref.rid) AS ckin,
@   event.bgcolor AS bgclr

@  FROM tagxref, tag, event
@ WHERE tagxref.tagid=tag.tagid
@   AND tagxref.tagtype>0
@   AND tag.tagname='branch'
@   AND event.objid=tagxref.rid
@ GROUP BY 1;
;







>



















|
>







231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
**
**      name           Name of the branch
**      mtime          Time of last checkin on this branch
**      isclosed       True if the branch is closed
**      mergeto        Another branch this branch was merged into
**      nckin          Number of checkins on this branch
**      ckin           Hash of the last checkin on this branch
**      isprivate      True if the branch is private
**      bgclr          Background color for this branch
*/
static const char createBrlistQuery[] =
@ CREATE TEMP TABLE IF NOT EXISTS tmp_brlist AS
@ SELECT
@   tagxref.value AS name,
@   max(event.mtime) AS mtime,
@   EXISTS(SELECT 1 FROM tagxref AS tx
@           WHERE tx.rid=tagxref.rid
@             AND tx.tagid=(SELECT tagid FROM tag WHERE tagname='closed')
@             AND tx.tagtype>0) AS isclosed,
@   (SELECT tagxref.value
@      FROM plink CROSS JOIN tagxref
@    WHERE plink.pid=event.objid
@       AND tagxref.rid=plink.cid
@      AND tagxref.tagid=(SELECT tagid FROM tag WHERE tagname='branch')
@      AND tagtype>0) AS mergeto,
@   count(*) AS nckin,
@   (SELECT uuid FROM blob WHERE rid=tagxref.rid) AS ckin,
@   event.bgcolor AS bgclr,
@   EXISTS(SELECT 1 FROM private WHERE rid=tagxref.rid) AS isprivate
@  FROM tagxref, tag, event
@ WHERE tagxref.tagid=tag.tagid
@   AND tagxref.tagtype>0
@   AND tag.tagname='branch'
@   AND event.objid=tagxref.rid
@ GROUP BY 1;
;
275
276
277
278
279
280
281

282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315

316
317
318
319
320
321
322
*/
#define BRL_CLOSED_ONLY      0x001 /* Show only closed branches */
#define BRL_OPEN_ONLY        0x002 /* Show only open branches */
#define BRL_BOTH             0x003 /* Show both open and closed branches */
#define BRL_OPEN_CLOSED_MASK 0x003
#define BRL_ORDERBY_MTIME    0x004 /* Sort by MTIME. (otherwise sort by name)*/
#define BRL_REVERSE          0x008 /* Reverse the sort order */


#endif /* INTERFACE */

/*
** Prepare a query that will list branches.
**
** If (which<0) then the query pulls only closed branches. If
** (which>0) then the query pulls all (closed and opened)
** branches. Else the query pulls currently-opened branches.
*/
void branch_prepare_list_query(Stmt *pQuery, int brFlags, const char *zBrNameGlob){
  Blob sql;
  blob_init(&sql, 0, 0);
  brlist_create_temp_table();
  switch( brFlags & BRL_OPEN_CLOSED_MASK ){
    case BRL_CLOSED_ONLY: {
      blob_append_sql(&sql,
        "SELECT name FROM tmp_brlist WHERE isclosed"
      );
      break;
    }
    case BRL_BOTH: {
      blob_append_sql(&sql,
        "SELECT name FROM tmp_brlist WHERE 1"
      );
      break;
    }
    case BRL_OPEN_ONLY: {
      blob_append_sql(&sql,
        "SELECT name FROM tmp_brlist WHERE NOT isclosed"
      );
      break;
    }
  }

  if(zBrNameGlob) blob_append_sql(&sql, " AND (name GLOB %Q)", zBrNameGlob);
  if( brFlags & BRL_ORDERBY_MTIME ){
    blob_append_sql(&sql, " ORDER BY -mtime");
  }else{
    blob_append_sql(&sql, " ORDER BY name COLLATE nocase");
  }
  if( brFlags & BRL_REVERSE ){







>

















|





|





|




>







277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
*/
#define BRL_CLOSED_ONLY      0x001 /* Show only closed branches */
#define BRL_OPEN_ONLY        0x002 /* Show only open branches */
#define BRL_BOTH             0x003 /* Show both open and closed branches */
#define BRL_OPEN_CLOSED_MASK 0x003
#define BRL_ORDERBY_MTIME    0x004 /* Sort by MTIME. (otherwise sort by name)*/
#define BRL_REVERSE          0x008 /* Reverse the sort order */
#define BRL_PRIVATE          0x010 /* Show only private branches */

#endif /* INTERFACE */

/*
** Prepare a query that will list branches.
**
** If (which<0) then the query pulls only closed branches. If
** (which>0) then the query pulls all (closed and opened)
** branches. Else the query pulls currently-opened branches.
*/
void branch_prepare_list_query(Stmt *pQuery, int brFlags, const char *zBrNameGlob){
  Blob sql;
  blob_init(&sql, 0, 0);
  brlist_create_temp_table();
  switch( brFlags & BRL_OPEN_CLOSED_MASK ){
    case BRL_CLOSED_ONLY: {
      blob_append_sql(&sql,
        "SELECT name, isprivate FROM tmp_brlist WHERE isclosed"
      );
      break;
    }
    case BRL_BOTH: {
      blob_append_sql(&sql,
        "SELECT name, isprivate FROM tmp_brlist WHERE 1"
      );
      break;
    }
    case BRL_OPEN_ONLY: {
      blob_append_sql(&sql,
        "SELECT name, isprivate FROM tmp_brlist WHERE NOT isclosed"
      );
      break;
    }
  }
  if( brFlags & BRL_PRIVATE ) blob_append_sql(&sql, " AND isprivate");
  if(zBrNameGlob) blob_append_sql(&sql, " AND (name GLOB %Q)", zBrNameGlob);
  if( brFlags & BRL_ORDERBY_MTIME ){
    blob_append_sql(&sql, " ORDER BY -mtime");
  }else{
    blob_append_sql(&sql, " ORDER BY name COLLATE nocase");
  }
  if( brFlags & BRL_REVERSE ){
583
584
585
586
587
588
589

590
591
592
593

594
595
596
597
598
599
600
**        Print information about a branch
**
** >  fossil branch list|ls ?OPTIONS? ?GLOB?
**
**        List all branches. Options:
**          -a|--all      List all branches.  Default show only open branches
**          -c|--closed   List closed branches.

**          -r            Reverse the sort order
**          -t            Show recently changed branches first
**
**        The current branch is marked with an asterisk.

**
**        If GLOB is given, show only branches matching the pattern.
**
** >  fossil branch new BRANCH-NAME BASIS ?OPTIONS?
**
**        Create a new branch BRANCH-NAME off of check-in BASIS.
**        Supported options for this subcommand include:







>



|
>







587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
**        Print information about a branch
**
** >  fossil branch list|ls ?OPTIONS? ?GLOB?
**
**        List all branches. Options:
**          -a|--all      List all branches.  Default show only open branches
**          -c|--closed   List closed branches.
**          -p            List only private branches.
**          -r            Reverse the sort order
**          -t            Show recently changed branches first
**
**        The current branch is marked with an asterisk.  Private branches are
**        marked with a hash sign.
**
**        If GLOB is given, show only branches matching the pattern.
**
** >  fossil branch new BRANCH-NAME BASIS ?OPTIONS?
**
**        Create a new branch BRANCH-NAME off of check-in BASIS.
**        Supported options for this subcommand include:
653
654
655
656
657
658
659

660
661
662
663
664
665
666
667
668
669

670
671


672
673
674
675
676
677
678
    char *zCurrent = 0;
    const char *zBrNameGlob = 0;
    int brFlags = BRL_OPEN_ONLY;
    if( find_option("all","a",0)!=0 ) brFlags = BRL_BOTH;
    if( find_option("closed","c",0)!=0 ) brFlags = BRL_CLOSED_ONLY;
    if( find_option("t",0,0)!=0 ) brFlags |= BRL_ORDERBY_MTIME;
    if( find_option("r",0,0)!=0 ) brFlags |= BRL_REVERSE;

    if( g.argc >= 4 ) zBrNameGlob = g.argv[3];

    if( g.localOpen ){
      vid = db_lget_int("checkout", 0);
      zCurrent = db_text(0, "SELECT value FROM tagxref"
                            " WHERE rid=%d AND tagid=%d", vid, TAG_BRANCH);
    }
    branch_prepare_list_query(&q, brFlags, zBrNameGlob);
    while( db_step(&q)==SQLITE_ROW ){
      const char *zBr = db_column_text(&q, 0);

      int isCur = zCurrent!=0 && fossil_strcmp(zCurrent,zBr)==0;
      fossil_print("%s%s\n", (isCur ? "* " : "  "), zBr);


    }
    db_finalize(&q);
  }else if( strncmp(zCmd,"new",n)==0 ){
    branch_new();
  }else if( strncmp(zCmd,"close",5)==0 ){
    if(g.argc<4){
      usage("branch close branch-name(s)...");







>










>

|
>
>







659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
    char *zCurrent = 0;
    const char *zBrNameGlob = 0;
    int brFlags = BRL_OPEN_ONLY;
    if( find_option("all","a",0)!=0 ) brFlags = BRL_BOTH;
    if( find_option("closed","c",0)!=0 ) brFlags = BRL_CLOSED_ONLY;
    if( find_option("t",0,0)!=0 ) brFlags |= BRL_ORDERBY_MTIME;
    if( find_option("r",0,0)!=0 ) brFlags |= BRL_REVERSE;
    if( find_option("p",0,0)!=0 ) brFlags |= BRL_PRIVATE;
    if( g.argc >= 4 ) zBrNameGlob = g.argv[3];

    if( g.localOpen ){
      vid = db_lget_int("checkout", 0);
      zCurrent = db_text(0, "SELECT value FROM tagxref"
                            " WHERE rid=%d AND tagid=%d", vid, TAG_BRANCH);
    }
    branch_prepare_list_query(&q, brFlags, zBrNameGlob);
    while( db_step(&q)==SQLITE_ROW ){
      const char *zBr = db_column_text(&q, 0);
      int isPriv = zCurrent!=0 && db_column_int(&q, 1)==1;
      int isCur = zCurrent!=0 && fossil_strcmp(zCurrent,zBr)==0;
      fossil_print("%s%s%s\n", 
        ( (brFlags & BRL_PRIVATE) ? " " : ( isPriv ? "#" : " ") ), 
        (isCur ? "* " : "  "), zBr);
    }
    db_finalize(&q);
  }else if( strncmp(zCmd,"new",n)==0 ){
    branch_new();
  }else if( strncmp(zCmd,"close",5)==0 ){
    if(g.argc<4){
      usage("branch close branch-name(s)...");
Changes to src/builtin.c.
621
622
623
624
625
626
627


628
629
630
631
632
633
634
    fossil_free(zName);
    zName = db_get("project-code", "");
    CX("projectCode: %!j,\n", zName);
    fossil_free(zName);
    CX("/* Length of UUID hashes for display purposes. */");
    CX("hashDigits: %d, hashDigitsUrl: %d,\n",
       hash_digits(0), hash_digits(1));


    CX("editStateMarkers: {"
       "/*Symbolic markers to denote certain edit states.*/"
       "isNew:'[+]', isModified:'[*]', isDeleted:'[-]'},\n");
    CX("confirmerButtonTicks: 3 "
       "/*default fossil.confirmer tick count.*/,\n");
    /* Inject certain info about the current skin... */
    CX("skin:{");







>
>







621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
    fossil_free(zName);
    zName = db_get("project-code", "");
    CX("projectCode: %!j,\n", zName);
    fossil_free(zName);
    CX("/* Length of UUID hashes for display purposes. */");
    CX("hashDigits: %d, hashDigitsUrl: %d,\n",
       hash_digits(0), hash_digits(1));
    CX("diffContextLines: %d,\n",
       diff_context_lines(0));
    CX("editStateMarkers: {"
       "/*Symbolic markers to denote certain edit states.*/"
       "isNew:'[+]', isModified:'[*]', isDeleted:'[-]'},\n");
    CX("confirmerButtonTicks: 3 "
       "/*default fossil.confirmer tick count.*/,\n");
    /* Inject certain info about the current skin... */
    CX("skin:{");
700
701
702
703
704
705
706

707
708
709
710
711
712
713
714
715
716
                        ** entries: all known deps of this one. Each
                        ** REQUIRES an EXPLICIT trailing \0, including
                        ** the final one! */
  } fjs[] = {
  /* This list ordering isn't strictly important. */
  {"confirmer",      0, 0},
  {"copybutton",     0, "dom\0"},

  {"dom",            0, 0},
  {"fetch",          0, 0},
  {"info-diff",      0, "dom\0"},
  {"numbered-lines", 0, "popupwidget\0copybutton\0"},
  {"pikchr",         0, "dom\0"},
  {"popupwidget",    0, "dom\0"},
  {"storage",        0, 0},
  {"tabs",           0, "dom\0"}
  };
  const int nFjs = sizeof(fjs) / sizeof(fjs[0]);







>


<







702
703
704
705
706
707
708
709
710
711

712
713
714
715
716
717
718
                        ** entries: all known deps of this one. Each
                        ** REQUIRES an EXPLICIT trailing \0, including
                        ** the final one! */
  } fjs[] = {
  /* This list ordering isn't strictly important. */
  {"confirmer",      0, 0},
  {"copybutton",     0, "dom\0"},
  {"diff",           0, "dom\0fetch\0"},
  {"dom",            0, 0},
  {"fetch",          0, 0},

  {"numbered-lines", 0, "popupwidget\0copybutton\0"},
  {"pikchr",         0, "dom\0"},
  {"popupwidget",    0, "dom\0"},
  {"storage",        0, 0},
  {"tabs",           0, "dom\0"}
  };
  const int nFjs = sizeof(fjs) / sizeof(fjs[0]);
Changes to src/chat.c.
45
46
47
48
49
50
51
52
53
54
55
56


57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78

79
80
81
82
83
84
85
/*
** Outputs JS code to initialize a list of chat alert audio files for
** use by the chat front-end client. A handful of builtin files
** (from alerts/\*.wav) and all unversioned files matching
** alert-sounds/\*.{mp3,ogg,wav} are included.
*/
static void chat_emit_alert_list(void){
  /*Stmt q = empty_Stmt;*/
  unsigned int i;
  const char * azBuiltins[] = {
  "builtin/alerts/plunk.wav",
  "builtin/alerts/b-flat.wav"


  };
  CX("window.fossil.config.chat.alerts = [\n");
  for(i=0; i < sizeof(azBuiltins)/sizeof(azBuiltins[0]); ++i){
    CX("%s%!j", i ? ", " : "", azBuiltins[i]);
  }
#if 0
  /*
  ** 2021-01-05 temporarily disabled until we decide whether we're
  ** going to keep configurable audio files or not. If we do, this
  ** code needs to check whether the [unversioned] table exists before
  ** querying it.
  */
  db_prepare(&q, "SELECT 'uv/'||name FROM unversioned "
             "WHERE content IS NOT NULL "
             "AND (name LIKE 'alert-sounds/%%.wav' "
             "OR name LIKE 'alert-sounds/%%.mp3' "
             "OR name LIKE 'alert-sounds/%%.ogg')");
  while(SQLITE_ROW==db_step(&q)){
    CX(", %!j", db_column_text(&q, 0));
  }
  db_finalize(&q);
#endif

  CX("\n];\n");
}

/* Settings that can be used to control chat */
/*
** SETTING: chat-initial-history    width=10 default=50
**







<



|
>
>





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







45
46
47
48
49
50
51

52
53
54
55
56
57
58
59
60
61
62




63
64

65
66
67
68
69
70
71
72
73

74
75
76
77
78
79
80
81
/*
** Outputs JS code to initialize a list of chat alert audio files for
** use by the chat front-end client. A handful of builtin files
** (from alerts/\*.wav) and all unversioned files matching
** alert-sounds/\*.{mp3,ogg,wav} are included.
*/
static void chat_emit_alert_list(void){

  unsigned int i;
  const char * azBuiltins[] = {
  "builtin/alerts/plunk.wav",
  "builtin/alerts/bflat2.wav",
  "builtin/alerts/bflat3.wav",
  "builtin/alerts/bloop.wav"
  };
  CX("window.fossil.config.chat.alerts = [\n");
  for(i=0; i < sizeof(azBuiltins)/sizeof(azBuiltins[0]); ++i){
    CX("%s%!j", i ? ", " : "", azBuiltins[i]);
  }




  if( db_table_exists("repository","unversioned") ){
    Stmt q = empty_Stmt;

    db_prepare(&q, "SELECT 'uv/'||name FROM unversioned "
               "WHERE content IS NOT NULL "
               "AND (name LIKE 'alert-sounds/%%.wav' "
               "OR name LIKE 'alert-sounds/%%.mp3' "
               "OR name LIKE 'alert-sounds/%%.ogg')");
    while(SQLITE_ROW==db_step(&q)){
      CX(", %!j", db_column_text(&q, 0));
    }
    db_finalize(&q);

  }
  CX("\n];\n");
}

/* Settings that can be used to control chat */
/*
** SETTING: chat-initial-history    width=10 default=50
**
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150



















151
152
153
154
155
156
157
158


159
160
161
162
163
164
165
166
167
168

169

170





171
172
173
174
175
176
177
178
179
180
181
182
183
184












185










186
187
188
189
190

191

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

205
206
207
208
209
210
211
212
213
214
215
216
** For maximum efficiency, it is best to choose the longest delay that
** does not cause timeouts in intermediate proxies or web server.
*/
/*
** SETTING: chat-alert-sound     width=10
**
** This is the name of the builtin sound file to use for the alert tone.
** The value must be the name of one of a builtin WAV file.
*/
/*
** WEBPAGE: chat
**
** Start up a browser-based chat session.
**
** This is the main page that humans use to access the chatroom.  Simply
** point a web-browser at /chat and the screen fills with the latest
** chat messages, and waits for new one.
**
** Other /chat-OP pages are used by XHR requests from this page to
** send new chat message, delete older messages, or poll for changes.
*/
void chat_webpage(void){
  char *zAlert;
  char *zProjectName;



















  login_check_credentials();
  if( !g.perm.Chat ){
    login_needed(g.anon.Chat);
    return;
  }
  zAlert = mprintf("%s/builtin/%s", g.zBaseURL,
                db_get("chat-alert-sound","alerts/plunk.wav"));
  zProjectName = db_get("project-name","Unnamed project");


  style_set_current_feature("chat");
  style_header("Chat");
  @ <form accept-encoding="utf-8" id="chat-form" autocomplete="off">
  @ <div id='chat-input-area'>
  @   <div id='chat-input-line'>
  @     <input type="text" name="msg" id="chat-input-single" \
  @      placeholder="Type message for %h(zProjectName)." autocomplete="off">
  @     <textarea rows="8" id="chat-input-multi" \
  @      placeholder="Type message for %h(zProjectName). Ctrl-Enter sends it." \
  @      class="hidden"></textarea>

  @     <input type="submit" value="Send" id="chat-message-submit">

  @     <span id="chat-settings-button" class="settings-icon" \





  @       aria-label="Settings..." aria-haspopup="true" ></span>
  @   </div>
  @   <div id='chat-input-file-area'>
  @     <div class='file-selection-wrapper'>
  @       <div class='help-buttonlet'>
  @        Select a file to upload, drag/drop a file into this spot,
  @        or paste an image from the clipboard if supported by
  @        your environment.
  @       </div>
  @       <input type="file" name="file" id="chat-input-file">
  @     </div>
  @     <div id="chat-drop-details"></div>
  @   </div>
  @ </div>












  @ </form>










  @ <div id='chat-messages-wrapper'>
  /* New chat messages get inserted immediately after this element */
  @ <span id='message-inject-point'></span>
  @ </div>
  fossil_free(zProjectName);

  builtin_fossil_js_bundle_or("popupwidget", "storage", "fetch", NULL);

  /* Always in-line the javascript for the chat page */
  @ <script nonce="%h(style_nonce())">/* chat.c:%d(__LINE__) */
  /* We need an onload handler to ensure that window.fossil is
     initialized before the chat init code runs. */
  @ window.addEventListener('load', function(){
  @ document.body.classList.add('chat')
  @ /*^^^for skins which add their own BODY tag */;
  @ window.fossil.config.chat = {
  @   fromcli: %h(PB("cli")?"true":"false"),
  @   alertSound: "%h(zAlert)",
  @   initSize: %d(db_get_int("chat-initial-history",50)),
  @   imagesInline: !!%d(db_get_boolean("chat-inline-images",1))
  @ };

  chat_emit_alert_list();
  cgi_append_content(builtin_text("chat.js"),-1);
  @ }, false);
  @ </script>

  style_finish_page();
}

/* Definition of repository tables used by chat
*/
static const char zChatSchema1[] =
@ CREATE TABLE repository.chat(







|
















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








>
>


<

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


|
<
<
<
<
<





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




>
|
>





|







>

<


|







123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177

178
179
180
181

182
183
184
185
186
187
188
189
190
191
192
193
194
195
196





197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247

248
249
250
251
252
253
254
255
256
257
** For maximum efficiency, it is best to choose the longest delay that
** does not cause timeouts in intermediate proxies or web server.
*/
/*
** SETTING: chat-alert-sound     width=10
**
** This is the name of the builtin sound file to use for the alert tone.
** The value must be the name of a builtin WAV file.
*/
/*
** WEBPAGE: chat
**
** Start up a browser-based chat session.
**
** This is the main page that humans use to access the chatroom.  Simply
** point a web-browser at /chat and the screen fills with the latest
** chat messages, and waits for new one.
**
** Other /chat-OP pages are used by XHR requests from this page to
** send new chat message, delete older messages, or poll for changes.
*/
void chat_webpage(void){
  char *zAlert;
  char *zProjectName;
  char * zInputPlaceholder0;  /* Common text input placeholder value */
  const char *zPaperclip =
    "<svg height=\"8.0\" width=\"16.0\"><path "
    "stroke=\"rgb(100,100,100)\" "
    "d=\"M 15.93452,3.2530441 "
    "A 4.1499493,4.1265346 0 0 0 11.804809,6.5256284e-4 H 2.8582923 A "
    "2.8239899,2.8080565 0 0 0 0.68965668,0.96142476 2.874599,2.8583801 "
    "0 0 0 0.03119302,3.2388108 2.7632589,2.7476682 0 0 0 "
    "0.81132923,4.7689293 3.168132,3.1502569 0 0 0 3.0300653,5.66565 l "
    "7.7297897,-4e-7 a 1.6802234,1.6707433 0 0 0 0.0072,-3.3377933 H "
    "5.6138192 v 1.0105899 l 5.1460358,-0.00712 a 0.66804062,0.66427143 "
    "0 0 1 0,1.3237305 l -7.7226325,0.00712 A 2.0243655,2.0129437 0 0 1 "
    "1.0332029,3.0964741 1.8522944,1.8418435 0 0 1 2.8511351,1.0041257 h "
    "8.9465169 a 3.1478884,3.1301275 0 0 1 3.134859,2.4339559 3.0365483,"
    "3.0194156 0 0 1 -0.629835,2.4908908 3.0365483,3.0194156 0 0 1 "
    "-2.31178,1.0746415 l -7.5437026,-0.014233 -0.00716,1.0034736 "
    "7.5365456,0.00715 a 4.048731,4.0258875 0 0 0 3.957938,-4.7469259 z\""
    "/></svg>";

  login_check_credentials();
  if( !g.perm.Chat ){
    login_needed(g.anon.Chat);
    return;
  }
  zAlert = mprintf("%s/builtin/%s", g.zBaseURL,
                db_get("chat-alert-sound","alerts/plunk.wav"));
  zProjectName = db_get("project-name","Unnamed project");
  zInputPlaceholder0 =
    mprintf("Type markdown-formatted message for %h.", zProjectName);
  style_set_current_feature("chat");
  style_header("Chat");

  @ <div id='chat-input-area'>
  @   <div id='chat-input-line' class='single-line'>
  @     <div contenteditable id="chat-input-field" \
  @      data-placeholder0="%h(zInputPlaceholder0)" \

  @      data-placeholder="%h(zInputPlaceholder0)" \
  @      class=""></div>
  @     <div id='chat-buttons-wrapper'>
  @       <span class='cbutton' id="chat-button-preview" \
  @         title="Preview message (Shift-Enter)">&#128065;</span>
  @       <span class='cbutton' id="chat-button-attach" \
  @         title="Attach file to message">%s(zPaperclip)</span>
  @       <span class='cbutton' id="chat-button-settings" \
  @         title="Configure chat">&#9881;</span>
  @       <span class='cbutton' id="chat-button-submit" \
  @         title="Send message (Ctrl-Enter)">&#128228;</span>
  @     </div>
  @   </div>
  @   <div id='chat-input-file-area'>
  @     <div class='file-selection-wrapper hidden'>





  @       <input type="file" name="file" id="chat-input-file">
  @     </div>
  @     <div id="chat-drop-details"></div>
  @   </div>
  @ </div>
  @ <div id='chat-user-list-wrapper' class='hidden'>
  @   <div class='legend'>
  @     <span class='help-buttonlet'>
  @      Users who have messages in the currently-loaded list.<br><br>
  @      <strong>Tap a user name</strong> to filter messages
  @      on that user and tap again to clear the filter.<br><br>
  @      <strong>Tap the title</strong> of this widget to toggle
  @      the list on and off.
  @     </span>
  @     <span>Active users (sorted by last message time)</span>
  @   </div>
  @   <div id='chat-user-list'></div>
  @ </div>
  @ <div id='chat-preview' class='hidden chat-view'>
  @  <header>Preview: (<a href='%R/md_rules' target='_blank'>markdown reference</a>)</header>
  @  <div id='chat-preview-content' class='message-widget-content'></div>
  @  <div id='chat-preview-buttons'><button id='chat-preview-close'>Close Preview</button></div>
  @ </div>
  @ <div id='chat-config' class='hidden chat-view'>
  @ <div id='chat-config-options'></div>
    /* ^^^populated client-side */
  @ <button>Close Settings</button>
  @ </div>
  @ <div id='chat-messages-wrapper' class='chat-view'>
  /* New chat messages get inserted immediately after this element */
  @ <span id='message-inject-point'></span>
  @ </div>
  fossil_free(zProjectName);
  fossil_free(zInputPlaceholder0);
  builtin_fossil_js_bundle_or("popupwidget", "storage", "fetch",
                              "pikchr", "confirmer", NULL);
  /* Always in-line the javascript for the chat page */
  @ <script nonce="%h(style_nonce())">/* chat.c:%d(__LINE__) */
  /* We need an onload handler to ensure that window.fossil is
     initialized before the chat init code runs. */
  @ window.addEventListener('load', function(){
  @ document.body.classList.add('chat');
  @ /*^^^for skins which add their own BODY tag */;
  @ window.fossil.config.chat = {
  @   fromcli: %h(PB("cli")?"true":"false"),
  @   alertSound: "%h(zAlert)",
  @   initSize: %d(db_get_int("chat-initial-history",50)),
  @   imagesInline: !!%d(db_get_boolean("chat-inline-images",1))
  @ };
  ajax_emit_js_preview_modes(0);
  chat_emit_alert_list();

  @ }, false);
  @ </script>
  builtin_request_js("fossil.page.chat.js");
  style_finish_page();
}

/* Definition of repository tables used by chat
*/
static const char zChatSchema1[] =
@ CREATE TABLE repository.chat(
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
    CX("{\"msgs\":[{");
  }else{
    CX("{");
  }
  CX("\"isError\": true, \"xfrom\": null,");
  CX("\"mtime\": %!j, \"lmtime\": %!j,", zTime, zTime);
  CX("\"xmsg\": \"Missing permissions or not logged in. "
     "Try <a href='%R/login?g=%R/chat'>logging in</a>.\"");
  if(fAsMessageList){
    CX("}]}");
  }else{
    CX("}");
  }
  fossil_free(zTime);
}

/*
** WEBPAGE: chat-send
**
** This page receives (via XHR) a new chat-message and/or a new file
** to be entered into the chat history.
**
** On success it responds with an empty response: the new message
** should be fetched via /chat-poll. On error, e.g. login expiry,
** it emits a JSON response in the same form as described for







|









|







322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
    CX("{\"msgs\":[{");
  }else{
    CX("{");
  }
  CX("\"isError\": true, \"xfrom\": null,");
  CX("\"mtime\": %!j, \"lmtime\": %!j,", zTime, zTime);
  CX("\"xmsg\": \"Missing permissions or not logged in. "
     "Try <a href='%R/login?g=chat'>logging in</a>.\"");
  if(fAsMessageList){
    CX("}]}");
  }else{
    CX("}");
  }
  fossil_free(zTime);
}

/*
** WEBPAGE: chat-send hidden
**
** This page receives (via XHR) a new chat-message and/or a new file
** to be entered into the chat history.
**
** On success it responds with an empty response: the new message
** should be fetched via /chat-poll. On error, e.g. login expiry,
** it emits a JSON response in the same form as described for
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389

390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
    blob_reset(&b);
  }
  db_commit_transaction();
}

/*
** This routine receives raw (user-entered) message text and transforms
** it into HTML that is safe to insert using innerHTML.
**
**    *   HTML in the original text is escaped.
**
**    *   Hyperlinks are identified and tagged.  Hyperlinks are:
**
**          -  Undelimited text of the form https:... or http:...
**          -  Any text enclosed within [...]
**
** Space to hold the returned string is obtained from fossil_malloc()
** and must be freed by the caller.
*/
static char *chat_format_to_html(const char *zMsg){
  char *zSafe = mprintf("%h", zMsg);
  int i, j, k;
  Blob out;
  char zClose[20];
  blob_init(&out, 0, 0);
  for(i=j=0; zSafe[i]; i++){
    if( zSafe[i]=='[' ){
      for(k=i+1; zSafe[k] && zSafe[k]!=']'; k++){}
      if( zSafe[k]==']' ){
        zSafe[k] = 0;
        if( j<i ){
          blob_append(&out, zSafe + j, i-j);
          j = i;
        }
        blob_append_char(&out, '[');
        wiki_resolve_hyperlink(&out,
                               WIKI_NOBADLINKS|WIKI_TARGET_BLANK|WIKI_NOBRACKET,
                               zSafe+i+1, zClose, sizeof(zClose), zSafe, 0);
        zSafe[k] = ']';
        j++;
        blob_append(&out, zSafe + j, k - j);
        blob_append(&out, zClose, -1);
        blob_append_char(&out, ']');
        i = k;
        j = k+1;
        continue;

      }
    }else if( zSafe[i]=='h' 
           && (strncmp(zSafe+i,"http:",5)==0
               || strncmp(zSafe+i,"https:",6)==0) ){
      for(k=i+1; zSafe[k] && !fossil_isspace(zSafe[k]); k++){}
      if( k>i+7 ){
        char c = zSafe[k];
        if( !fossil_isalnum(zSafe[k-1]) && zSafe[k-1]!='/' ){
          k--;
          c = zSafe[k];
        }
        if( j<i ){
          blob_append(&out, zSafe + j, i-j);
          j = i;
        }
        zSafe[k] = 0;        
        wiki_resolve_hyperlink(&out, WIKI_NOBADLINKS|WIKI_TARGET_BLANK,
                               zSafe+i, zClose, sizeof(zClose), zSafe, 0);
        zSafe[k] = c;
        blob_append(&out, zSafe + j, k - j);
        blob_append(&out, zClose, -1);
        i = j = k;
        continue;
      }
    }
  }
  if( j<i ){
    blob_append(&out, zSafe+j, j-i);
  }
  fossil_free(zSafe);
  return blob_str(&out);
}

/*
** COMMAND: test-chat-formatter
**
** Usage: %fossil test-chat-formatter STRING ...







|
|
<
|
<
<
<
<





<
<

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







385
386
387
388
389
390
391
392
393

394




395
396
397
398
399


400

401





402



403






404




405
406





























407
408
409
410
411
412
413
    blob_reset(&b);
  }
  db_commit_transaction();
}

/*
** This routine receives raw (user-entered) message text and transforms
** it into HTML that is safe to insert using innerHTML. As of 2021-09-19,
** it does so by using markdown_to_html() to convert markdown-formatted

** zMsg to HTML.




**
** Space to hold the returned string is obtained from fossil_malloc()
** and must be freed by the caller.
*/
static char *chat_format_to_html(const char *zMsg){


  Blob out;

  blob_init(&out, "", 0);





  if(*zMsg){



    Blob bIn;






    blob_init(&bIn, zMsg, (int)strlen(zMsg));




    markdown_to_html(&bIn, NULL, &out);
  }





























  return blob_str(&out);
}

/*
** COMMAND: test-chat-formatter
**
** Usage: %fossil test-chat-formatter STRING ...
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
    zOut = chat_format_to_html(g.argv[i]);
    fossil_print("[%d]: %s\n", i, zOut);
    fossil_free(zOut);
  }
}

/*
** WEBPAGE: chat-poll
**
** The chat page generated by /chat using an XHR to this page to
** request new chat content.  A typical invocation is:
**
**     /chat-poll/N
**     /chat-poll?name=N
**







|







426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
    zOut = chat_format_to_html(g.argv[i]);
    fossil_print("[%d]: %s\n", i, zOut);
    fossil_free(zOut);
  }
}

/*
** WEBPAGE: chat-poll hidden
**
** The chat page generated by /chat using an XHR to this page to
** request new chat content.  A typical invocation is:
**
**     /chat-poll/N
**     /chat-poll?name=N
**
648
649
650
651
652
653
654













































































655
656
657
658
659
660
661
662
  db_finalize(&q1);
  blob_append(&json, "\n]}", 3);
  cgi_set_content(&json);
  return;      
}

/*













































































** WEBPAGE: chat-download
**
** Download the CHAT.FILE attachment associated with a single chat
** entry.  The "name" query parameter begins with an integer that
** identifies the particular chat message. The integer may be followed
** by a / and a filename, which will indicate to the browser to use
** the indicated name when saving the file.
*/







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







635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
  db_finalize(&q1);
  blob_append(&json, "\n]}", 3);
  cgi_set_content(&json);
  return;      
}

/*
** WEBPAGE: chat-fetch-one hidden
**
** /chat-fetch-one/N
**
** Fetches a single message with the given ID, if available.
**
** Options:
**
**   raw = the xmsg field will be returned unparsed.
**
** Response is either a single object in the format returned by
** /chat-poll (without the wrapper array) or a JSON-format error
** response, as documented for ajax_route_error().
*/
void chat_fetch_one(void){
  Blob json = empty_blob;   /* The json to be constructed and returned */
  const int fRaw = PD("raw",0)!=0;
  const int msgid = atoi(PD("name","0"));
  Stmt q;
  login_check_credentials();
  if( !g.perm.Chat ) {
    chat_emit_permissions_error(0);
    return;
  }
  chat_create_tables();
  cgi_set_content_type("application/json");
  db_prepare(&q, 
    "SELECT datetime(mtime), xfrom, xmsg, length(file),"
    "       fname, fmime, lmtime"
    "  FROM chat WHERE msgid=%d AND mdel IS NULL",
    msgid);
  if(SQLITE_ROW==db_step(&q)){
    const char *zDate = db_column_text(&q, 0);
    const char *zFrom = db_column_text(&q, 1);
    const char *zRawMsg = db_column_text(&q, 2);
    const int nByte = db_column_int(&q, 3);
    const char *zFName = db_column_text(&q, 4);
    const char *zFMime = db_column_text(&q, 5);
    const char *zLMtime = db_column_text(&q, 7);
    blob_appendf(&json,"{\"msgid\": %d,", msgid);

    blob_appendf(&json, "\"mtime\":\"%.10sT%sZ\",", zDate, zDate+11);
    if( zLMtime && zLMtime[0] ){
      blob_appendf(&json, "\"lmtime\":%!j,", zLMtime);
    }
    blob_append(&json, "\"xfrom\":", -1);
    if(zFrom){
      blob_appendf(&json, "%!j,", zFrom);
    }else{
      /* see https://fossil-scm.org/forum/forumpost/e0be0eeb4c */
      blob_appendf(&json, "null,");
    }
    blob_appendf(&json, "\"uclr\":%!j,",
                 user_color(zFrom ? zFrom : "nobody"));
    blob_append(&json,"\"xmsg\":", 7);
    if(fRaw){
      blob_appendf(&json, "%!j,", zRawMsg);
    }else{
      char * zMsg = chat_format_to_html(zRawMsg ? zRawMsg : "");
      blob_appendf(&json, "%!j,", zMsg);
      fossil_free(zMsg);
    }
    if( nByte==0 ){
      blob_appendf(&json, "\"fsize\":0");
    }else{
      blob_appendf(&json, "\"fsize\":%d,\"fname\":%!j,\"fmime\":%!j",
                   nByte, zFName, zFMime);
    }    
    blob_append(&json,"}",1);
    cgi_set_content(&json);
  }else{
    ajax_route_error(404,"Chat message #%d not found.", msgid);
  }
  db_finalize(&q);
}

/*
** WEBPAGE: chat-download hidden
**
** Download the CHAT.FILE attachment associated with a single chat
** entry.  The "name" query parameter begins with an integer that
** identifies the particular chat message. The integer may be followed
** by a / and a filename, which will indicate to the browser to use
** the indicated name when saving the file.
*/
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
  db_blob(&r, "SELECT file FROM chat WHERE msgid=%d", msgid);
  cgi_set_content_type(zMime);
  cgi_set_content(&r);
}


/*
** WEBPAGE: chat-delete
**
** Delete the chat entry identified by the name query parameter.
** Invoking fetch("chat-delete/"+msgid) from javascript in the client
** will delete a chat entry from the CHAT table.
**
** This routine both deletes the identified chat entry and also inserts
** a new entry with the current timestamp and with:







|







745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
  db_blob(&r, "SELECT file FROM chat WHERE msgid=%d", msgid);
  cgi_set_content_type(zMime);
  cgi_set_content(&r);
}


/*
** WEBPAGE: chat-delete hidden
**
** Delete the chat entry identified by the name query parameter.
** Invoking fetch("chat-delete/"+msgid) from javascript in the client
** will delete a chat entry from the CHAT table.
**
** This routine both deletes the identified chat entry and also inserts
** a new entry with the current timestamp and with:
Changes to src/checkin.c.
1336
1337
1338
1339
1340
1341
1342

1343
1344
1345
1346
1347


1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
    blob_append(&prompt,
      "#\n"
      "# All merged-in branches will be closed due to the --integrate flag\n"
      "#\n", -1
    );
  }
  if( p->verboseFlag ){

    blob_appendf(&prompt,
        "#\n%.78c\n"
        "# The following diff is excluded from the commit message:\n#\n",
        '#'
    );


    if( g.aCommitFile ){
      FileDirList *diffFiles;
      int i;
      diffFiles = fossil_malloc_zero((g.argc-1) * sizeof(*diffFiles));
      for( i=0; g.aCommitFile[i]!=0; ++i ){
        diffFiles[i].zName  = db_text(0,
         "SELECT pathname FROM vfile WHERE id=%d", g.aCommitFile[i]);
        if( fossil_strcmp(diffFiles[i].zName, "." )==0 ){
          diffFiles[0].zName[0] = '.';
          diffFiles[0].zName[1] = 0;
          break;
        }
        diffFiles[i].nName = strlen(diffFiles[i].zName);
        diffFiles[i].nUsed = 0;
      }
      diff_against_disk(0, 0, diff_get_binary_glob(),
                        db_get_boolean("diff-binary", 1),
                        DIFF_VERBOSE, diffFiles, &prompt);
      for( i=0; diffFiles[i].zName; ++i ){
        fossil_free(diffFiles[i].zName);
      }
      fossil_free(diffFiles);
    }else{
      diff_against_disk(0, 0, diff_get_binary_glob(),
                        db_get_boolean("diff-binary", 1),
                        DIFF_VERBOSE, 0, &prompt);
    }
  }
  prompt_for_user_comment(pComment, &prompt);
  blob_reset(&prompt);
}

/*







>





>
>















<
<
|





|
<
<







1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365


1366
1367
1368
1369
1370
1371
1372


1373
1374
1375
1376
1377
1378
1379
    blob_append(&prompt,
      "#\n"
      "# All merged-in branches will be closed due to the --integrate flag\n"
      "#\n", -1
    );
  }
  if( p->verboseFlag ){
    DiffConfig DCfg;
    blob_appendf(&prompt,
        "#\n%.78c\n"
        "# The following diff is excluded from the commit message:\n#\n",
        '#'
    );
    diff_options(&DCfg, 0, 1);
    DCfg.diffFlags |= DIFF_VERBOSE;
    if( g.aCommitFile ){
      FileDirList *diffFiles;
      int i;
      diffFiles = fossil_malloc_zero((g.argc-1) * sizeof(*diffFiles));
      for( i=0; g.aCommitFile[i]!=0; ++i ){
        diffFiles[i].zName  = db_text(0,
         "SELECT pathname FROM vfile WHERE id=%d", g.aCommitFile[i]);
        if( fossil_strcmp(diffFiles[i].zName, "." )==0 ){
          diffFiles[0].zName[0] = '.';
          diffFiles[0].zName[1] = 0;
          break;
        }
        diffFiles[i].nName = strlen(diffFiles[i].zName);
        diffFiles[i].nUsed = 0;
      }


       diff_against_disk(0, &DCfg, diffFiles, &prompt);
      for( i=0; diffFiles[i].zName; ++i ){
        fossil_free(diffFiles[i].zName);
      }
      fossil_free(diffFiles);
    }else{
      diff_against_disk(0, &DCfg, 0, &prompt);


    }
  }
  prompt_for_user_comment(pComment, &prompt);
  blob_reset(&prompt);
}

/*
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585

  /* Step 2: Insert records for all modified files into the blob
  ** table. If there were arguments passed to this command, only
  ** the identified files are inserted (if they have been modified).
  */
  db_prepare(&q,
    "SELECT id, %Q || pathname, mrid, %s, %s, %s FROM vfile "
    "WHERE chnged IN (1, 7, 9) AND NOT deleted AND is_selected(id)",
    g.zLocalRoot,
    glob_expr("pathname", db_get("crlf-glob",db_get("crnl-glob",""))),
    glob_expr("pathname", db_get("binary-glob","")),
    glob_expr("pathname", db_get("encoding-glob",""))
  );
  while( db_step(&q)==SQLITE_ROW ){
    int id, rid;







|







2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584

  /* Step 2: Insert records for all modified files into the blob
  ** table. If there were arguments passed to this command, only
  ** the identified files are inserted (if they have been modified).
  */
  db_prepare(&q,
    "SELECT id, %Q || pathname, mrid, %s, %s, %s FROM vfile "
    "WHERE chnged<>0 AND NOT deleted AND is_selected(id)",
    g.zLocalRoot,
    glob_expr("pathname", db_get("crlf-glob",db_get("crnl-glob",""))),
    glob_expr("pathname", db_get("binary-glob","")),
    glob_expr("pathname", db_get("encoding-glob",""))
  );
  while( db_step(&q)==SQLITE_ROW ){
    int id, rid;
2609
2610
2611
2612
2613
2614
2615

2616
2617
2618
2619
2620
2621

2622
2623
2624
2625
2626
2627
2628
      file_relative_name(zFullname, &fname, 0);
      fossil_print("possible unresolved merge conflict in %s\n",
                   blob_str(&fname));
      blob_reset(&fname);
    }
    nrid = content_put(&content);
    blob_reset(&content);

    if( rid>0 ){
      content_deltify(rid, &nrid, 1, 0);
    }
    db_multi_exec("UPDATE vfile SET mrid=%d, rid=%d, mhash=NULL WHERE id=%d",
                  nrid,nrid,id);
    db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nrid);

  }
  db_finalize(&q);
  if( nConflict && !allowConflict ){
    fossil_fatal("abort due to unresolved merge conflicts; "
                 "use --allow-conflict to override");
  }else if( abortCommit ){
    fossil_fatal("one or more files were converted on your request; "







>
|
|
|
|
|
|
>







2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
      file_relative_name(zFullname, &fname, 0);
      fossil_print("possible unresolved merge conflict in %s\n",
                   blob_str(&fname));
      blob_reset(&fname);
    }
    nrid = content_put(&content);
    blob_reset(&content);
    if( nrid!=rid ){
      if( rid>0 ){
        content_deltify(rid, &nrid, 1, 0);
      }
      db_multi_exec("UPDATE vfile SET mrid=%d, rid=%d, mhash=NULL WHERE id=%d",
                    nrid,nrid,id);
      db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nrid);
    }
  }
  db_finalize(&q);
  if( nConflict && !allowConflict ){
    fossil_fatal("abort due to unresolved merge conflicts; "
                 "use --allow-conflict to override");
  }else if( abortCommit ){
    fossil_fatal("one or more files were converted on your request; "
Changes to src/clone.c.
263
264
265
266
267
268
269




270
271
272
273
274
275
276
    if( nErr ){
      file_delete(zRepo);
      fossil_fatal("server returned an error - clone aborted");
    }
    db_open_repository(zRepo);
  }
  db_begin_transaction();




  fossil_print("Rebuilding repository meta-data...\n");
  rebuild_db(0, 1, 0);
  if( !noCompress ){
    fossil_print("Extra delta compression... "); fflush(stdout);
    extra_deltification();
    fossil_print("\n");
  }







>
>
>
>







263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
    if( nErr ){
      file_delete(zRepo);
      fossil_fatal("server returned an error - clone aborted");
    }
    db_open_repository(zRepo);
  }
  db_begin_transaction();
  if( db_exists("SELECT 1 FROM delta WHERE srcId IN phantom") ){
    fossil_fatal("there are unresolved deltas -"
                 " the clone is probably incomplete and unusable.");
  }
  fossil_print("Rebuilding repository meta-data...\n");
  rebuild_db(0, 1, 0);
  if( !noCompress ){
    fossil_print("Extra delta compression... "); fflush(stdout);
    extra_deltification();
    fossil_print("\n");
  }
363
364
365
366
367
368
369

370

371
372
373
374
375
376
377

/*
** Set SSH options discovered in global variables (set from command line
** options).
*/
void clone_ssh_db_set_options(void){
  if( g.zSshCmd && g.zSshCmd[0] ){

    db_set("ssh-command", g.zSshCmd, 0);

  }
}

/*
** WEBPAGE: download
**
** Provide a simple page that enables newbies to download the latest tarball or







>

>







367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383

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

/*
** WEBPAGE: download
**
** Provide a simple page that enables newbies to download the latest tarball or
Changes to src/color.c.
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
** The setting is a list of space-separated words pairs.  The first word
** of each pair is a login name.  The second word is an alternative name
** used by the color chooser algorithm.
**
** This list is intended to be relatively short.  The idea is to only use
** this map to resolve color collisions between common users.
**
** Visit /test-hash-color?rand for a list of suggested names for the
** second word of each pair in the list.
*/
char *user_color(const char *zLogin){
  static int once = 0;
  static int nMap = 0;
  static char **azMap = 0;
  static int *anMap = 0;







|







77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
** The setting is a list of space-separated words pairs.  The first word
** of each pair is a login name.  The second word is an alternative name
** used by the color chooser algorithm.
**
** This list is intended to be relatively short.  The idea is to only use
** this map to resolve color collisions between common users.
**
** Visit /hash-color-test?rand for a list of suggested names for the
** second word of each pair in the list.
*/
char *user_color(const char *zLogin){
  static int once = 0;
  static int nMap = 0;
  static char **azMap = 0;
  static int *anMap = 0;
Changes to src/configure.c.
811
812
813
814
815
816
817

818

819
820
821
822
823
824
825
    blob_read_from_file(&in, g.argv[3], ExtFILE);
    db_begin_transaction();
    if( zMethod[0]=='i' ){
      groupMask = CONFIGSET_ALL | CONFIGSET_OVERWRITE;
    }else{
      groupMask = CONFIGSET_ALL;
    }

    configure_receive_all(&in, groupMask);

    db_end_transaction(0);
  }else
  if( strncmp(zMethod, "pull", n)==0
   || strncmp(zMethod, "push", n)==0
   || strncmp(zMethod, "sync", n)==0
  ){
    int mask;







>

>







811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
    blob_read_from_file(&in, g.argv[3], ExtFILE);
    db_begin_transaction();
    if( zMethod[0]=='i' ){
      groupMask = CONFIGSET_ALL | CONFIGSET_OVERWRITE;
    }else{
      groupMask = CONFIGSET_ALL;
    }
    db_unprotect(PROTECT_USER);
    configure_receive_all(&in, groupMask);
    db_protect_pop();
    db_end_transaction(0);
  }else
  if( strncmp(zMethod, "pull", n)==0
   || strncmp(zMethod, "push", n)==0
   || strncmp(zMethod, "sync", n)==0
  ){
    int mask;
Changes to src/db.c.
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924

1925
1926
1927
1928
1929
1930
1931
  if( file_size(zDbName, ExtFILE)<1024*3 ){
    char *zHome = file_dirname(zDbName);
    int rc;
    if( file_isdir(zHome, ExtFILE)==0 ){
      file_mkdir(zHome, ExtFILE, 0);
    }
    rc = file_access(zHome, W_OK);
    fossil_free(zHome);
    if( rc ){
      if( isOptional ) return 0;
      fossil_fatal("home directory \"%s\" must be writeable", zHome);
    }
    db_init_database(zDbName, zConfigSchema, (char*)0);

  }
  if( file_access(zDbName, W_OK) ){
    if( isOptional ) return 0;
    fossil_fatal("configuration file %s must be writeable", zDbName);
  }
  if( useAttach ){
    db_open_or_attach(zDbName, "configdb");







<





>







1912
1913
1914
1915
1916
1917
1918

1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
  if( file_size(zDbName, ExtFILE)<1024*3 ){
    char *zHome = file_dirname(zDbName);
    int rc;
    if( file_isdir(zHome, ExtFILE)==0 ){
      file_mkdir(zHome, ExtFILE, 0);
    }
    rc = file_access(zHome, W_OK);

    if( rc ){
      if( isOptional ) return 0;
      fossil_fatal("home directory \"%s\" must be writeable", zHome);
    }
    db_init_database(zDbName, zConfigSchema, (char*)0);
    fossil_free(zHome);
  }
  if( file_access(zDbName, W_OK) ){
    if( isOptional ) return 0;
    fossil_fatal("configuration file %s must be writeable", zDbName);
  }
  if( useAttach ){
    db_open_or_attach(zDbName, "configdb");
Changes to src/default.css.
527
528
529
530
531
532
533


534
535
536


537
538
539
540






541


542
543
544
545








546





547


















548
549
550































































551
552
553
554
555
556



557



558
559
560

561
562
563
564

565
566
567

568
569
570


571
572


573

574
575

576
577
578


579







580
581
582
583
584
585
586
ul.filelist {
  margin-top: 3px;
  line-height: 100%;
}
ul.filelist li {
  padding-top: 1px;
}


table.sbsdiffcols {
  width: 90%;
  border-spacing: 0;


  font-size: xx-small;
}
table.sbsdiffcols td {
  padding: 0;






  vertical-align: top;


}
table.sbsdiffcols pre {
  margin: 0;
  padding: 0;








  border: 0;





  font-size: inherit;


















  background: inherit;
  color: inherit;
}































































div.difflncol {
  padding-right: 1em;
  text-align: right;
  color: #a0a0a0;
}
div.difftxtcol {



  width: 45em;



  overflow-x: auto;
}
div.diffmkrcol {

  padding: 0 1em;
}
span.diffchng {
  background-color: #c0c0ff;

}
span.diffadd {
  background-color: #c0ffc0;

}
span.diffrm {
  background-color: #ffc8c8;


}
span.diffhr {


  display: inline-block;

  margin: .5em 0 1em;
  color: #0000ff;

}
span.diffln {
  color: #a0a0a0;


}







span.modpending {
  color: #b03800;
  font-style: italic;
}
pre.th1result {
  white-space: pre-wrap;
  word-wrap: break-word;







>
>
|
|

>
>
|

|

>
>
>
>
>
>

>
>

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

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

|

|
>
>
>
|
>
>
>


|
>
|

|
|
>

|
|
>

|
|
>
>

|
>
>
|
>
|
|
>

|
|
>
>

>
>
>
>
>
>
>







527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
ul.filelist {
  margin-top: 3px;
  line-height: 100%;
}
ul.filelist li {
  padding-top: 1px;
}

/* Rules governing diff layout and colors */
table.diff {
  width: 100%;
  border-spacing: 0;
  border-radius: 5px;
  border: 1px solid black;
  font-size: 80%;
}
table.diff td.diffln{
  padding: 0;
}
table.diff td.diffln > pre{
  padding: 0 0.25em 0 0.5em;
  margin: 0;
}
table.diff td {
  vertical-align: top;
  padding: 0;
  overflow: hidden /*work around inner PRE slight overflow/overlap*/;
}
table.diff pre {
  margin: 0 0 0 0;
  padding: 0 0.5em;
  line-height: 1.275/*for mobile: forum post e6f4ee7de98b55c0*/;
  text-size-adjust: none
  /* ^^^ attempt to keep mobile from inflating some text */;
}
table.diff pre > ins,
table.diff pre > del {
  /* Fill platform-dependent color gaps caused by
     inflated line-height */;
  padding: 0.062em 0 0.062em 0;
}
table.diff pre > ins > *,
table.diff pre > del > *{
  /* Avoid odd-looking color swatches in conjunction with
     (table.diff pre > ins/del) padding */
  padding: inherit;
}
table.diff td.diffln > pre {
  padding: 0 0.35em 0 0.5em;
}
table.diff td.difftxt > pre {
  min-width: 100%;
  max-width: 100%;
}
table.diff td > pre {
  /* Workaround for "slight wiggle" when using mouse-wheel in some FF
     versions, apparently caused by the increased line-height forcing
     these elements to be a *tick* larger than they should be but not
     large enough to force a scroll bar to show up. */
  overflow-y: hidden;
}
tr.diffskip.jchunk {
  /* jchunk gets added from JS to diffskip rows when they are
     plugged into the /jchunk route. */
  background-color: aliceblue;
  padding: 0;
}
tr.diffskip.jchunk > td {
  padding: 0.25em 0.5em;
  margin: 0;
}
tr.diffskip.jchunk:hover {
  /*background-color: rgba(127,127,127,0.5);
  cursor: pointer;*/
}
tr.diffskip > td.chunkctrl {
  text-align: left;
  font-family: monospace;
}
tr.diffskip > td.chunkctrl > div {
  display: flex;
  align-items: center;
}
tr.diffskip > td.chunkctrl > div > span.error {
  padding: 0.25em 0.5em;
  border-radius: 0.5em;
}
tr.diffskip > td.chunkctrl .jcbutton
/* class name .button breaks w/ some skins! */ {
  min-width: 3.5ex;
  max-width: 3.5ex;
  text-align: center;
  display: inline-block;
  padding: 0.1em 1em;
  margin: 0 1em 0 0;
  background-color: rgba(127,127,127,0.2);
  border-style: outset;
  border-width: 0;
  border-radius: 0.5em;
  opacity: 0.7;
}
tr.diffskip > td.chunkctrl .jcbutton.up:not(.down){
  /* Simulate an arrow pointing up */
  border-radius: 3em 3em 0.25em 0.25em;
}
tr.diffskip > td.chunkctrl .jcbutton.down:not(.up){
  /* Simulate an arrow pointing down */
  border-radius: 0.25em 0.25em 3em 3em;
}
tr.diffskip > td.chunkctrl .jcbutton > span {
  /* In order to increase the glyph size w/o increasing the em-based
     button size or border-radius, we need an extra layer of DOM
     element for the glyph. */
  font-size: 150%;
}
tr.diffskip > td.chunkctrl .jcbutton.up > span::before {
  content: '⇡';
}
tr.diffskip > td.chunkctrl .jcbutton.down > span::before {
  content: '⇣';
}
tr.diffskip > td.chunkctrl .jcbutton.up.down > span::before {
  content: '⇡⇣';
}

tr.diffskip > td.chunkctrl .jcbutton:hover {
  cursor: pointer;
  opacity: 1;
  filter: contrast(1);
}
td.diffln {
  width: 1px;
  text-align: right;
  padding: 0 1em 0 0;
}
td.difflne {
  padding-bottom: 0.4em;
}
td.diffsep {
  width: 1px;
  padding: 0 0.3em 0 0.5em;
}
td.difftxt pre {
  overflow-x: auto;
}
td.diffln ins {
  background-color: #a0e4b2;
  text-decoration: none;
}
td.diffln del {
  background-color: #ffc0c0;
  text-decoration: none;
}
td.difftxt del {
  background-color: #ffe8e8;
  text-decoration: none;
}
td.difftxt del > del {
  background-color: #ffc0c0;
  text-decoration: none;
  font-weight: bold;
}
td.difftxt del > del.edit {
  background-color: #c0c0ff;
  text-decoration: none;
  font-weight: bold;
}
td.difftxt ins {
  background-color: #dafbe1;
  text-decoration: none;
}
td.difftxt ins > ins {
  background-color: #a0e4b2;
  text-decoration: none;
  font-weight: bold;
}
td.difftxt ins > ins.edit {
  background-color: #c0c0ff;
  text-decoration: none;
  font-weight: bold;
}


span.modpending {
  color: #b03800;
  font-style: italic;
}
pre.th1result {
  white-space: pre-wrap;
  word-wrap: break-word;
1080
1081
1082
1083
1084
1085
1086



1087
1088
1089
1090
1091
1092
1093
  border-color: inherit;
  min-height: 1.5em;
  font-size: 1.2em;
  padding: 0.2em;
  margin: 0.25em 0;
  flex: 0 0 auto;
}



.font-size-100 {
  font-size: 100%;
}
.font-size-125 {
  font-size: 125%;
}
.font-size-150 {







>
>
>







1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
  border-color: inherit;
  min-height: 1.5em;
  font-size: 1.2em;
  padding: 0.2em;
  margin: 0.25em 0;
  flex: 0 0 auto;
}
.font-size-80 {
  font-size: 80%;
}
.font-size-100 {
  font-size: 100%;
}
.font-size-125 {
  font-size: 125%;
}
.font-size-150 {
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183

1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
  margin: 0;
  vertical-align: top;
  padding: 0.25em 0 0 0 /*prevents slight overlap at top */;
}
table.numbered-lines td.line-numbers {
  width: 4.5em;
}
table.numbered-lines td.line-numbers > span:first-of-type {
  margin-top: 0.25em/*must match top PADDING of
                      td.file-content > pre > code*/;

}
table.numbered-lines td.line-numbers > span {
  display: block;
  margin: 0;
  padding: 0;
  line-height: inherit;
  font-size: inherit;
  font-family: inherit;
  cursor: pointer;
  white-space: pre;
  margin-right: 2px/*keep selection from nudging the right column */;
  text-align: right;
}
table.numbered-lines td.line-numbers > span:hover {
  background-color: rgba(112, 112, 112, 0.25);
}
table.numbered-lines td.file-content {
  padding-left: 0.25em;
}
table.numbered-lines td.file-content > pre,
table.numbered-lines td.file-content > pre > code {







|
|
|
>

|
|










|







1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
  margin: 0;
  vertical-align: top;
  padding: 0.25em 0 0 0 /*prevents slight overlap at top */;
}
table.numbered-lines td.line-numbers {
  width: 4.5em;
}
table.numbered-lines td.line-numbers > pre {
  margin: 0.25em/*must match top PADDING of td.file-content
                  > pre > code*/ 0 0 0;
  padding: 0;
}
table.numbered-lines td.line-numbers span {
  display: inline-block;
  margin: 0;
  padding: 0;
  line-height: inherit;
  font-size: inherit;
  font-family: inherit;
  cursor: pointer;
  white-space: pre;
  margin-right: 2px/*keep selection from nudging the right column */;
  text-align: right;
}
table.numbered-lines td.line-numbers span:hover {
  background-color: rgba(112, 112, 112, 0.25);
}
table.numbered-lines td.file-content {
  padding-left: 0.25em;
}
table.numbered-lines td.file-content > pre,
table.numbered-lines td.file-content > pre > code {
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
  margin-top: -2px/*restore alignment*/;
}

.fossil-tooltip {
  text-align: center;
  padding: 0.2em 1em;
  border: 1px solid black;
  border-radius: 0.25em;
  position: absolute;
  display: inline-block;
  z-index: 19/*below default skin's hamburger popup*/;
  box-shadow: -0.15em 0.15em 0.2em rgba(0, 0, 0, 0.75);
  background-color: inherit;
  color: inherit;
}







|







1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
  margin-top: -2px/*restore alignment*/;
}

.fossil-tooltip {
  text-align: center;
  padding: 0.2em 1em;
  border: 1px solid black;
  border-radius: 0.5em;
  position: absolute;
  display: inline-block;
  z-index: 19/*below default skin's hamburger popup*/;
  box-shadow: -0.15em 0.15em 0.2em rgba(0, 0, 0, 0.75);
  background-color: inherit;
  color: inherit;
}
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
  /* Hide image when sources are being shown. */
  position: absolute !important;
  opacity: 0 !important;
  pointer-events: none !important;
  display: none !important;
}

/* Chat-related */
body.chat span.at-name { /* for @USERNAME references */
  text-decoration: underline;
  font-weight: bold;
}
/* A wrapper for a single single chat message (one row of the UI) */
body.chat .message-widget {
  margin-bottom: 0.75em;
  border: none;
  display: flex;
  flex-direction: column;
  border: none;
  align-items: flex-start;
}
body.chat.my-messages-right .message-widget.mine {
  /* Right-aligns a user's own chat messages, similar to how
     most mobile messaging apps do it. */
  align-items: flex-end;
}
body.chat.my-messages-right .message-widget.notification {
  /* Center-aligns a system-level notification message. */
  align-items: center;
}
/* The content area of a message. */
body.chat .message-widget-content {
  display: inline-block;
  border-radius: 0.25em;
  border: 1px solid rgba(0,0,0,0.2);
  box-shadow: 0.2em 0.2em 0.2em rgba(0, 0, 0, 0.29);
  padding: 0.25em 0.5em;
  margin-top: 0;
  min-width: 9em /*avoid unsightly "underlap" with the neighboring
                   .message-widget-tab element*/;
  white-space: pre-wrap/*needed for multi-line edits*/;
}
body.chat.monospace-messages .message-widget-content,
body.chat.monospace-messages textarea,
body.chat.monospace-messages input[type=text]{
  font-family: monospace;  
}
/* User name and timestamp (a LEGEND-like element) */
body.chat .message-widget .message-widget-tab {
  border-radius: 0.25em 0.25em 0 0;
  margin: 0 0.25em 0em 0.15em;
  padding: 0 0.5em 0.15em 0.5em;
  cursor: pointer;
  white-space: nowrap;
}
body.chat .fossil-tooltip.help-buttonlet-content {
  font-size: 80%;
}
body.chat .message-widget .message-widget-tab .xfrom {
  /* Element which holds the "this message is from user X" part
     of the message banner. */
  font-style: italic;
  font-weight: bold;
}
/* The popup element for displaying message timestamps
   and deletion controls. */
body.chat .chat-message-popup {
  font-family: monospace;
  font-size: 0.8em;
  text-align: left;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  padding: 0.25em;
  z-index: 200;
}
/* Full message timestamps. */
body.chat .chat-message-popup > span { white-space: nowrap; }
/* Container for the message deletion buttons. */
body.chat .chat-message-popup > .toolbar {
  padding: 0.2em;
  margin: 0;
  border: 2px inset rgba(0,0,0,0.3);
  border-radius: 0.25em;
  display: flex;
  flex-direction: row;
  justify-content: stretch;
  flex-wrap: wrap;
}
body.chat .chat-message-popup > .toolbar > button {
  flex: 1 1 auto;
}
/* The widget for loading more/older chat messages. */
body.chat #load-msg-toolbar  {
  border-radius: 0.25em;
  padding: 0.1em 0.2em;
  margin-bottom: 1em;
}
/* .all-done is set when chat has loaded all of the available
   historical messages */
body.chat #load-msg-toolbar.all-done {
  opacity: 0.5;
}
body.chat #load-msg-toolbar > div {
  display: flex;
  flex-direction: row;
  justify-content: stretch;
  flex-wrap: wrap;
}
body.chat #load-msg-toolbar > div > button {
  flex: 1 1 auto;
}

/* An icon element intended for use as a button/menu for
   accessing app-specific settings. */
.settings-icon {
  /* Icon source: https://de.wikipedia.org/wiki/Datei:OOjs_UI_icon_settings.svg
     MIT License. */
  background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg \







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







1603
1604
1605
1606
1607
1608
1609









































































































1610
1611
1612
1613
1614
1615
1616
  /* Hide image when sources are being shown. */
  position: absolute !important;
  opacity: 0 !important;
  pointer-events: none !important;
  display: none !important;
}











































































































/* An icon element intended for use as a button/menu for
   accessing app-specific settings. */
.settings-icon {
  /* Icon source: https://de.wikipedia.org/wiki/Datei:OOjs_UI_icon_settings.svg
     MIT License. */
  background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg \
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
}
.settings-icon:hover {
  border: 1px outset rgba(127,127,127,1);
}
body.fossil-dark-style .settings-icon {
  filter: invert(100%);
}
/* "Chat-only mode" hides the site header/footer, showing only
   the chat app. */
body.chat.chat-only-mode{}
body.chat #chat-settings-button {}
/** Popup widget for the /chat settings. */
body.chat .chat-settings-popup {
  font-size: 0.8em;
  text-align: left;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  padding: 0.25em;
  z-index: 200;
}
body.chat .chat-settings-popup > span {
  vertical-align: middle;
}
body.chat .chat-settings-popup > span.menu-entry{
  white-space: nowrap;
  cursor: pointer;
  border: 1px solid;
  border-radius: 0.25em;
  padding: 0.25em 0.5em;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
}
body.chat .chat-settings-popup > span.menu-entry:hover {
}
body.chat .chat-settings-popup > span.menu-entry > .help-buttonlet {
  vertical-align: middle;
}
body.chat .chat-settings-popup > span.menu-entry > span.button {
  margin: 0.25em 0.2em;
  padding: 0.25em;
  flex: 1 1 auto/*eliminates dead no-click zones on the right*/;
}
body.chat .chat-settings-popup > span.menu-entry > input[type=checkbox] {
  cursor: inherit;
}
body.chat .chat-settings-popup > select.menu-entry {
  flex: 1 1 auto;
  padding: 0;
  cursor: pointer;
  min-height: 2.5em;
  border-radius: 0.25em;
}
body.chat .chat-settings-popup > select.menu-entry > option {
  /*Recall that many browsers don't allow styling of OPTION
    elements, or allow only very limited styling.*/
}

/** Container for the list of /chat messages. */
body.chat #chat-messages-wrapper {
  overflow: auto;
  /*max-height: 800em*//*will be re-calc'd in JS*/;
  flex: 2 1 auto;
}
body.chat #chat-messages-wrapper.loading > * {
  /* An attempt at reducing flicker when loading lots of messages. */
  visibility: hidden;
}
body.chat div.content {
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column-reverse;
  /* ^^^^ In order to get good automatic scrolling of new messages on
     the BOTTOM in bottom-up chat mode, such that they scroll up
     instead of down, we have to use column-reverse layout, which
     changes #chat-messages-wrapper's "gravity" for purposes of
     scrolling! If we instead use flex-direction:column then each new
     message pushes #chat-input-area down further off the screen!
 */
  align-items: stretch;
}
/* Wrapper for /chat user input controls */
body.chat #chat-input-area {
  display: flex;
  flex-direction: column;
  padding: 0.5em 1em;
  border-bottom: none;
  border-top: 1px solid black;
  margin: 0.5em 1em 0 1em;
  position: initial /*sticky currently disabled due to scrolling-related issues*/;
  bottom: 0;
}
body.chat:not(.chat-only-mode) #chat-input-area{
  /* Safari user reports that 2em is necessary to keep the file selection
     widget from overlapping the page footer, whereas a margin of 0 is fine
     for FF/Chrome (and 2em is a *huge* waste of space for those). */
  margin-bottom: 0;
}

/* Widget holding the chat message input field, send button, and
   settings button. */
body.chat #chat-input-line {
  display: flex;
  flex-direction: row;
  margin-bottom: 0.25em;
  align-items: self-start;
}
body.chat #chat-input-line > input[type=submit],
body.chat #chat-input-line > #chat-settings-button,
body.chat #chat-input-line > button {
  flex: 1 5 auto;
  max-width: 6em;
  margin: 0 0.25em;
}
body.chat #chat-input-line > button {
  max-width: 4em;
}
body.chat #chat-input-line > #chat-settings-button{
  margin: 0 0 0 0.25em;
  max-width: 2em;
}
body.chat #chat-input-line > input[type=text],
body.chat #chat-input-line > textarea {
  flex: 5 1 auto;
}
/* Widget holding the file selection control and preview */
body.chat #chat-input-file-area  {
  display: flex;
  flex-direction: row;
  align-items: center;
  flex-wrap: wrap;
}
body.chat #chat-input-file-area > .file-selection-wrapper {
  align-self: flex-start;
  margin-right: 0.5em;
  flex: 0 1 auto;
  padding: 0.25em 0.25em 0.25em 0;
}
body.chat #chat-input-file-area .file-selection-wrapper > * {
  vertical-align: middle;
  margin: 0;
}
body.chat #chat-input-file {
  border:1px solid rgba(0,0,0,0);/*avoid UI shift during drop-targeting*/
  border-radius: 0.25em;
  padding: 0.25em;
}
body.chat #chat-input-file > input {
  flex: 1 0 auto;
}
/* Indicator when a drag/drop is in progress */
body.chat #chat-input-file.dragover {
  border: 1px dashed green;
}
/* Widget holding the details of a selected/dropped file/image. */
body.chat #chat-drop-details {
  flex: 0 1 auto;
  padding: 0.5em 1em;
  margin-left: 0.5em;
  white-space: pre;
  font-family: monospace;
}

body.chat #chat-drop-details img {
  max-width: 45%;
  max-height: 45%;
}

input[type="checkbox"].diff-toggle {
  float: right;
}

body.branch .brlist > table > tbody > tr:hover:not(.selected),
body.branch .brlist > table > tbody > tr.selected {







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







1636
1637
1638
1639
1640
1641
1642



































































































































































1643
1644
1645
1646
1647
1648
1649
}
.settings-icon:hover {
  border: 1px outset rgba(127,127,127,1);
}
body.fossil-dark-style .settings-icon {
  filter: invert(100%);
}




































































































































































input[type="checkbox"].diff-toggle {
  float: right;
}

body.branch .brlist > table > tbody > tr:hover:not(.selected),
body.branch .brlist > table > tbody > tr.selected {
Changes to src/diff.c.
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46







47
48
49
50
51
52
53


#if INTERFACE
/*
** Flag parameters to the text_diff() routine used to control the formatting
** of the diff output.
*/
#define DIFF_CONTEXT_MASK ((u64)0x0000ffff) /* Lines of context. Default if 0 */
#define DIFF_WIDTH_MASK   ((u64)0x00ff0000) /* side-by-side column width */
#define DIFF_IGNORE_EOLWS ((u64)0x01000000) /* Ignore end-of-line whitespace */
#define DIFF_IGNORE_ALLWS ((u64)0x03000000) /* Ignore all whitespace */
#define DIFF_SIDEBYSIDE   ((u64)0x04000000) /* Generate a side-by-side diff */
#define DIFF_VERBOSE      ((u64)0x08000000) /* Missing shown as empty files */
#define DIFF_BRIEF        ((u64)0x10000000) /* Show filenames only */
#define DIFF_HTML         ((u64)0x20000000) /* Render for HTML */
#define DIFF_LINENO       ((u64)0x40000000) /* Show line numbers */
#define DIFF_NUMSTAT      ((u64)0x80000000) /* Show line count of changes */
#define DIFF_NOOPT        (((u64)0x01)<<32) /* Suppress optimizations (debug) */
#define DIFF_INVERT       (((u64)0x02)<<32) /* Invert the diff (debug) */
#define DIFF_CONTEXT_EX   (((u64)0x04)<<32) /* Use context even if zero */
#define DIFF_NOTTOOBIG    (((u64)0x08)<<32) /* Only display if not too big */
#define DIFF_STRIP_EOLCR  (((u64)0x10)<<32) /* Strip trailing CR */
#define DIFF_SLOW_SBS     (((u64)0x20)<<32) /* Better but slower side-by-side */








/*
** These error messages are shared in multiple locations.  They are defined
** here for consistency.
*/
#define DIFF_CANNOT_COMPUTE_BINARY \
    "cannot compute difference between binary files\n"







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







24
25
26
27
28
29
30


31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58


#if INTERFACE
/*
** Flag parameters to the text_diff() routine used to control the formatting
** of the diff output.
*/


#define DIFF_IGNORE_EOLWS      0x00000001 /* Ignore end-of-line whitespace */
#define DIFF_IGNORE_ALLWS      0x00000003 /* Ignore all whitespace */
#define DIFF_SIDEBYSIDE        0x00000004 /* Generate a side-by-side diff */
#define DIFF_VERBOSE           0x00000008 /* Missing shown as empty files */
#define DIFF_BRIEF             0x00000010 /* Show filenames only */
#define DIFF_HTML              0x00000020 /* Render for HTML */
#define DIFF_LINENO            0x00000040 /* Show line numbers */
#define DIFF_NUMSTAT           0x00000080 /* Show line count of changes */
#define DIFF_NOOPT             0x00000100 /* Suppress optimizations (debug) */
#define DIFF_INVERT            0x00000200 /* Invert the diff (debug) */
#define DIFF_CONTEXT_EX        0x00000400 /* Use context even if zero */
#define DIFF_NOTTOOBIG         0x00000800 /* Only display if not too big */
#define DIFF_STRIP_EOLCR       0x00001000 /* Strip trailing CR */
#define DIFF_SLOW_SBS          0x00002000 /* Better but slower side-by-side */
#define DIFF_WEBPAGE           0x00004000 /* Complete webpage */
#define DIFF_BROWSER           0x00008000 /* The --browser option */
#define DIFF_JSON              0x00010000 /* JSON output */
#define DIFF_DEBUG             0x00020000 /* Debugging diff output */
#define DIFF_RAW               0x00040000 /* Raw triples - for debugging */
#define DIFF_TCL               0x00080000 /* For the --tk option */
#define DIFF_INCBINARY         0x00100000 /* The --diff-binary option */

/*
** These error messages are shared in multiple locations.  They are defined
** here for consistency.
*/
#define DIFF_CANNOT_COMPUTE_BINARY \
    "cannot compute difference between binary files\n"
62
63
64
65
66
67
68
69





























70









71
72
73
74
75
76
77
    "whitespace changes only\n"

/*
** Maximum length of a line in a text file, in bytes.  (2**15 = 32768 bytes)
*/
#define LENGTH_MASK_SZ  15
#define LENGTH_MASK     ((1<<LENGTH_MASK_SZ)-1)






























#endif /* INTERFACE */










/*
** Information about each line of a file being diffed.
**
** The lower LENGTH_MASK_SZ bits of the hash (DLine.h) are the length
** of the line.  If any line is longer than LENGTH_MASK characters,
** the file is considered binary.








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

>
>
>
>
>
>
>
>
>







67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
    "whitespace changes only\n"

/*
** Maximum length of a line in a text file, in bytes.  (2**15 = 32768 bytes)
*/
#define LENGTH_MASK_SZ  15
#define LENGTH_MASK     ((1<<LENGTH_MASK_SZ)-1)

/*
** An instance of this object describes the formatting and processing
** details desired of a "diff" operation.
**
** Conceptually, this object is as an encoding of the command-line options
** for the "fossil diff" command.  That is not a precise description, though,
** because not all diff operations are started from the command-line.  But
** the idea is sound.
**
** Information encoded by this object includes but is not limited to:
**
**    *   The desired output format (unified vs. side-by-side, 
**        TCL, JSON, HTML vs. plain-text).
**
**    *   Number of lines of context surrounding each difference block
**
**    *   Width of output columns for text side-by-side diffop          
*/
struct DiffConfig {
  u64 diffFlags;           /* Diff flags */
  int nContext;            /* Number of lines of context */
  int wColumn;             /* Column width in -y mode */
  u32 nFile;               /* Number of files diffed so far */
  const char *zDiffCmd;    /* External diff command to use instead of builtin */
  const char *zBinGlob;    /* GLOB pattern for binary files */
  ReCompiled *pRe;         /* Show only changes matching this pattern */
  const char *zLeftHash;   /* HASH-id of the left file */
};

#endif /* INTERFACE */

/*
** Initialize memory for a DiffConfig based on just a diffFlags integer.
*/
DiffConfig *diff_config_init(DiffConfig *pCfg, u64 diffFlags){
  memset(pCfg, 0, sizeof(*pCfg));
  pCfg->diffFlags = diffFlags;
  return pCfg;
}

/*
** Information about each line of a file being diffed.
**
** The lower LENGTH_MASK_SZ bits of the hash (DLine.h) are the length
** of the line.  If any line is longer than LENGTH_MASK characters,
** the file is considered binary.
91
92
93
94
95
96
97





98
99
100
101
102
103
104
};

/*
** Length of a dline
*/
#define LENGTH(X)   ((X)->n)






/*
** A context for running a raw diff.
**
** The aEdit[] array describes the raw diff.  Each triple of integers in
** aEdit[] means:
**
**   (1) COPY:   Number of lines aFrom and aTo have in common







>
>
>
>
>







134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
};

/*
** Length of a dline
*/
#define LENGTH(X)   ((X)->n)

/*
** Number of diff chunks generated
*/
static int nChunk = 0;

/*
** A context for running a raw diff.
**
** The aEdit[] array describes the raw diff.  Each triple of integers in
** aEdit[] means:
**
**   (1) COPY:   Number of lines aFrom and aTo have in common
122
123
124
125
126
127
128




129
130
131
132
133
134
135

/*
** Count the number of lines in the input string.  Include the last line
** in the count even if it lacks the \n terminator.  If an empty string
** is specified, the number of lines is zero.  For the purposes of this
** function, a string is considered empty if it contains no characters
** -OR- it contains only NUL characters.




*/
int count_lines(
  const char *z,
  int n,
  int *pnLine
){
  int nLine;







>
>
>
>







170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187

/*
** Count the number of lines in the input string.  Include the last line
** in the count even if it lacks the \n terminator.  If an empty string
** is specified, the number of lines is zero.  For the purposes of this
** function, a string is considered empty if it contains no characters
** -OR- it contains only NUL characters.
**
** Returns true if the input seems to be plain text input, else false.
** If it returns false, pnLine is not modified, else it is set to the
** number of lines in z.
*/
int count_lines(
  const char *z,
  int n,
  int *pnLine
){
  int nLine;
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
  *pnLine = nLine;
  return a;
}

/*
** Return zero if two DLine elements are identical.
*/
static int same_dline(const DLine *pA, const DLine *pB){
  if( pA->h!=pB->h ) return 1;
  return memcmp(pA->z,pB->z, pA->h&LENGTH_MASK);
}

/*
** Return zero if two DLine elements are identical, ignoring
** all whitespace. The indent field of pA/pB already points
** to the first non-space character in the string.
*/

static int same_dline_ignore_allws(const DLine *pA, const DLine *pB){
  int a = pA->indent, b = pB->indent;
  if( pA->h==pB->h ){
    while( a<pA->n || b<pB->n ){
      if( a<pA->n && b<pB->n && pA->z[a++] != pB->z[b++] ) return 1;
      while( a<pA->n && fossil_isspace(pA->z[a])) ++a;
      while( b<pB->n && fossil_isspace(pB->z[b])) ++b;
    }
    return pA->n-a != pB->n-b;
  }
  return 1;
}

/*
** Return true if the regular expression *pRe matches any of the
** N dlines
*/
static int re_dline_match(
  ReCompiled *pRe,    /* The regular expression to be matched */
  DLine *aDLine,      /* First of N DLines to compare against */
  int N               /* Number of DLines to check */
){
  while( N-- ){
    if( re_match(pRe, (const unsigned char *)aDLine->z, LENGTH(aDLine)) ){
      return 1;
    }
    aDLine++;
  }
  return 0;
}

/*
** Append a single line of context-diff output to pOut.
*/
static void appendDiffLine(
  Blob *pOut,         /* Where to write the line of output */
  char cPrefix,       /* One of " ", "+",  or "-" */
  DLine *pLine,       /* The line to be output */
  int html,           /* True if generating HTML.  False for plain text */
  ReCompiled *pRe     /* Colorize only if line matches this Regex */
){
  blob_append(pOut, &cPrefix, 1);
  if( html ){
    if( pRe && re_dline_match(pRe, pLine, 1)==0 ){
      cPrefix = ' ';
    }else if( cPrefix=='+' ){
      blob_append(pOut, "<span class=\"diffadd\">", -1);
    }else if( cPrefix=='-' ){
      blob_append(pOut, "<span class=\"diffrm\">", -1);
    }
    htmlize_to_blob(pOut, pLine->z, pLine->n);
    if( cPrefix!=' ' ){
      blob_append(pOut, "</span>", -1);
    }
  }else{
    blob_append(pOut, pLine->z, pLine->n);
  }
  blob_append(pOut, "\n", 1);
}

/*
** Add two line numbers to the beginning of an output line for a context
** diff.  One or the other of the two numbers might be zero, which means
** to leave that number field blank.  The "html" parameter means to format
** the output for HTML.
*/
static void appendDiffLineno(Blob *pOut, int lnA, int lnB, int html){
  if( html ) blob_append(pOut, "<span class=\"diffln\">", -1);
  if( lnA>0 ){
    blob_appendf(pOut, "%6d ", lnA);
  }else{
    blob_append(pOut, "       ", 7);
  }
  if( lnB>0 ){
    blob_appendf(pOut, "%6d  ", lnB);
  }else{
    blob_append(pOut, "        ", 8);
  }
  if( html ) blob_append(pOut, "</span>", -1);
}

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

  nContext = diff_context_lines(diffFlags);
  showLn = (diffFlags & DIFF_LINENO)!=0;
  html = (diffFlags & DIFF_HTML)!=0;
  A = p->aFrom;
  B = p->aTo;
  R = p->aEdit;
  mxr = p->nEdit;
  while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; }
  for(r=0; r<mxr; r += 3*nr){
    /* Figure out how many triples to show in a single block */
    for(nr=1; R[r+nr*3]>0 && R[r+nr*3]<nContext*2; nr++){}
    /* printf("r=%d nr=%d\n", r, nr); */

    /* If there is a regex, skip this block (generate no diff output)
    ** if the regex matches or does not match both insert and delete.
    ** Only display the block if one side matches but the other side does
    ** not.
    */
    if( pRe ){
      int hideBlock = 1;
      int xa = a, xb = b;
      for(i=0; hideBlock && i<nr; i++){
        int c1, c2;
        xa += R[r+i*3];
        xb += R[r+i*3];
        c1 = re_dline_match(pRe, &A[xa], R[r+i*3+1]);
        c2 = re_dline_match(pRe, &B[xb], R[r+i*3+2]);
        hideBlock = c1==c2;
        xa += R[r+i*3+1];
        xb += R[r+i*3+2];
      }
      if( hideBlock ){
        a = xa;
        b = xb;
        continue;
      }
    }

    /* For the current block comprising nr triples, figure out
    ** how many lines of A and B are to be displayed
    */
    if( R[r]>nContext ){
      na = nb = nContext;
      skip = R[r] - nContext;
    }else{







|










|

















|
|
|
















|
<
<

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





|
<

|
<










<



<
|




|
<
















<


|
|
<










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







288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343


344
345













346

347
348
349
350
351
352
353

354
355

356
357
358
359
360
361
362
363
364
365

366
367
368

369
370
371
372
373
374

375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390

391
392
393
394

395
396
397
398
399
400
401
402
403
404

























405
406
407
408
409
410
411
  *pnLine = nLine;
  return a;
}

/*
** Return zero if two DLine elements are identical.
*/
static int compare_dline(const DLine *pA, const DLine *pB){
  if( pA->h!=pB->h ) return 1;
  return memcmp(pA->z,pB->z, pA->h&LENGTH_MASK);
}

/*
** Return zero if two DLine elements are identical, ignoring
** all whitespace. The indent field of pA/pB already points
** to the first non-space character in the string.
*/

static int compare_dline_ignore_allws(const DLine *pA, const DLine *pB){
  int a = pA->indent, b = pB->indent;
  if( pA->h==pB->h ){
    while( a<pA->n || b<pB->n ){
      if( a<pA->n && b<pB->n && pA->z[a++] != pB->z[b++] ) return 1;
      while( a<pA->n && fossil_isspace(pA->z[a])) ++a;
      while( b<pB->n && fossil_isspace(pB->z[b])) ++b;
    }
    return pA->n-a != pB->n-b;
  }
  return 1;
}

/*
** Return true if the regular expression *pRe matches any of the
** N dlines
*/
static int re_dline_match(
  ReCompiled *pRe,      /* The regular expression to be matched */
  const DLine *aDLine,  /* First of N DLines to compare against */
  int N                 /* Number of DLines to check */
){
  while( N-- ){
    if( re_match(pRe, (const unsigned char *)aDLine->z, LENGTH(aDLine)) ){
      return 1;
    }
    aDLine++;
  }
  return 0;
}

/*
** Append a single line of context-diff output to pOut.
*/
static void appendDiffLine(
  Blob *pOut,         /* Where to write the line of output */
  char cPrefix,       /* One of " ", "+",  or "-" */
  DLine *pLine        /* The line to be output */


){
  blob_append_char(pOut, cPrefix);













  blob_append(pOut, pLine->z, pLine->n);

  blob_append_char(pOut, '\n');
}

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

*/
static void appendDiffLineno(Blob *pOut, int lnA, int lnB){

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

}

/*

** Output a patch-style text diff.
*/
static void contextDiff(
  DContext *p,      /* The difference */
  Blob *pOut,       /* Output a context diff to here */
  DiffConfig *pCfg  /* Configuration options */

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

  int showDivider = 0;  /* True to show the divider between diff blocks */

  nContext = diff_context_lines(pCfg);
  showLn = (pCfg->diffFlags & DIFF_LINENO)!=0;

  A = p->aFrom;
  B = p->aTo;
  R = p->aEdit;
  mxr = p->nEdit;
  while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; }
  for(r=0; r<mxr; r += 3*nr){
    /* Figure out how many triples to show in a single block */
    for(nr=1; R[r+nr*3]>0 && R[r+nr*3]<nContext*2; nr++){}
    /* printf("r=%d nr=%d\n", r, nr); */


























    /* For the current block comprising nr triples, figure out
    ** how many lines of A and B are to be displayed
    */
    if( R[r]>nContext ){
      na = nb = nContext;
      skip = R[r] - nContext;
    }else{
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636

637
638

639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664



665
666
667
668
669
670
671
672
673
    ** the previous block.
    */
    nChunk++;
    if( showLn ){
      if( !showDivider ){
        /* Do not show a top divider */
        showDivider = 1;
      }else if( html ){
        blob_appendf(pOut, "<span class=\"diffhr\">%.80c</span>\n", '.');
      }else{
        blob_appendf(pOut, "%.80c\n", '.');
      }
      if( html ) blob_appendf(pOut, "<span id=\"chunk%d\"></span>", nChunk);
    }else{
      if( html ) blob_appendf(pOut, "<span class=\"diffln\">");
      /*
       * If the patch changes an empty file or results in an empty file,
       * the block header must use 0,0 as position indicator and not 1,0.
       * Otherwise, patch would be confused and may reject the diff.
       */
      blob_appendf(pOut,"@@ -%d,%d +%d,%d @@",
        na ? a+skip+1 : a+skip, na,
        nb ? b+skip+1 : b+skip, nb);
      if( html ) blob_appendf(pOut, "</span>");
      blob_append(pOut, "\n", 1);
    }

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

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

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

/*
** Status of a single output line
*/
typedef struct SbsLine SbsLine;
struct SbsLine {
  Blob *apCols[5];         /* Array of pointers to output columns */
  int width;               /* Maximum width of a column in the output */
  unsigned char escHtml;   /* True to escape html characters */
  int iStart;              /* Write zStart prior to character iStart */
  const char *zStart;      /* A <span> tag */
  int iEnd;                /* Write </span> prior to character iEnd */
  int iStart2;             /* Write zStart2 prior to character iStart2 */
  const char *zStart2;     /* A <span> tag */
  int iEnd2;               /* Write </span> prior to character iEnd2 */
  ReCompiled *pRe;         /* Only colorize matching lines, if not NULL */
};

/*
** Column indices for SbsLine.apCols[]
*/
#define SBS_LNA  0     /* Left line number */
#define SBS_TXTA 1     /* Left text */
#define SBS_MKR  2     /* Middle separator column */
#define SBS_LNB  3     /* Right line number */
#define SBS_TXTB 4     /* Right text */

/*
** Append newlines to all columns.
*/
static void sbsWriteNewlines(SbsLine *p){
  int i;
  for( i=p->escHtml ? SBS_LNA : SBS_TXTB; i<=SBS_TXTB; i++ ){
    blob_append(p->apCols[i], "\n", 1);
  }
}

/*
** Append n spaces to the column.
*/
static void sbsWriteSpace(SbsLine *p, int n, int col){
  blob_appendf(p->apCols[col], "%*s", n, "");
}

/*
** Write the text of pLine into column iCol of p.
**
** If outputting HTML, write the full line.  Otherwise, only write the
** width characters.  Translate tabs into spaces.  Add newlines if col
** is SBS_TXTB.  Translate HTML characters if escHtml is true.  Pad the
** rendering to width bytes if col is SBS_TXTA and escHtml is false.
**
** This comment contains multibyte unicode characters (ü, Æ, ð) in order
** to test the ability of the diff code to handle such characters.
*/
static void sbsWriteText(SbsLine *p, DLine *pLine, int col){
  Blob *pCol = p->apCols[col];
  int n = pLine->n;
  int i;   /* Number of input characters consumed */
  int k;   /* Cursor position */
  int needEndSpan = 0;
  const char *zIn = pLine->z;
  int w = p->width;
  int colorize = p->escHtml;
  if( colorize && p->pRe && re_dline_match(p->pRe, pLine, 1)==0 ){
    colorize = 0;
  }
  for(i=k=0; (p->escHtml || k<w) && i<n; i++, k++){
    char c = zIn[i];
    if( colorize ){
      if( i==p->iStart ){
        int x = strlen(p->zStart);
        blob_append(pCol, p->zStart, x);
        needEndSpan = 1;
        if( p->iStart2 ){
          p->iStart = p->iStart2;
          p->zStart = p->zStart2;
          p->iStart2 = 0;
        }
      }else if( i==p->iEnd ){
        blob_append(pCol, "</span>", 7);
        needEndSpan = 0;
        if( p->iEnd2 ){
          p->iEnd = p->iEnd2;
          p->iEnd2 = 0;
        }
      }
    }
    if( c=='\t' && !p->escHtml ){
      blob_append(pCol, " ", 1);
      while( (k&7)!=7 && (p->escHtml || k<w) ){
        blob_append(pCol, " ", 1);
        k++;
      }
    }else if( c=='\r' || c=='\f' ){
      blob_append(pCol, " ", 1);
    }else if( c=='<' && p->escHtml ){
      blob_append(pCol, "&lt;", 4);
    }else if( c=='&' && p->escHtml ){
      blob_append(pCol, "&amp;", 5);
    }else if( c=='>' && p->escHtml ){
      blob_append(pCol, "&gt;", 4);
    }else if( c=='"' && p->escHtml ){
      blob_append(pCol, "&quot;", 6);
    }else{
      blob_append(pCol, &zIn[i], 1);
      if( (c&0xc0)==0x80 ) k--;
    }
  }
  if( needEndSpan ){
    blob_append(pCol, "</span>", 7);
  }
  if( col==SBS_TXTB ){
    sbsWriteNewlines(p);
  }else if( !p->escHtml ){
    sbsWriteSpace(p, w-k, SBS_TXTA);
  }
}

/*
** Append a column to the final output blob.
*/
static void sbsWriteColumn(Blob *pOut, Blob *pCol, int col){
  blob_appendf(pOut,
    "<td><div class=\"diff%scol\">\n"
    "<pre>\n"
    "%s"
    "</pre>\n"
    "</div></td>\n",
    (col % 3) ? (col == SBS_MKR ? "mkr" : "txt") : "ln",
    blob_str(pCol)
  );
}

/*

** Append a separator line to column iCol
*/

static void sbsWriteSep(SbsLine *p, int len, int col){
  char ch = '.';
  if( len<1 ){
    len = 1;
    ch = ' ';
  }
  blob_appendf(p->apCols[col], "<span class=\"diffhr\">%.*c</span>\n", len, ch);
}

/*
** Append the appropriate marker into the center column of the diff.
*/
static void sbsWriteMarker(SbsLine *p, const char *zTxt, const char *zHtml){
  blob_append(p->apCols[SBS_MKR], p->escHtml ? zHtml : zTxt, -1);
}

/*
** Append a line number to the column.
*/
static void sbsWriteLineno(SbsLine *p, int ln, int col){
  if( p->escHtml ){
    blob_appendf(p->apCols[col], "%d", ln+1);
  }else{
    char zLn[7];
    sqlite3_snprintf(7, zLn, "%5d ", ln+1);
    blob_appendf(p->apCols[col], "%s ", zLn);



  }
}

/*
** The two text segments zLeft and zRight are known to be different on
** both ends, but they might have  a common segment in the middle.  If
** they do not have a common segment, return 0.  If they do have a large
** common segment, return 1 and before doing so set:
**







<
<



<

<








<








|
|








|
|




|
|





|
|











|
|




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

>
|

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







433
434
435
436
437
438
439


440
441
442

443

444
445
446
447
448
449
450
451

452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
















502


















































































































503

504
505
506
507
508
509
510

511




512

513




514










515
516
517
518

519
520
521
522
523
524
525
    ** the previous block.
    */
    nChunk++;
    if( showLn ){
      if( !showDivider ){
        /* Do not show a top divider */
        showDivider = 1;


      }else{
        blob_appendf(pOut, "%.80c\n", '.');
      }

    }else{

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

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

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

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

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

















#define MX_CSN  8  /* Maximum number of change spans across a change region */




















































































































/*
** A description of zero or more (up to MX_CSN) areas of difference
** between two lines of text.
*/
typedef struct LineChange LineChange;
struct LineChange {
  int n;            /* Number of change spans */

  struct Span {




    int iStart1;    /* Byte offset to start of a change on the left */

    int iLen1;      /* Length of the left change in bytes */




    int iStart2;    /* Byte offset to start of a change on the right */










    int iLen2;      /* Length of the change on the right in bytes */
    int isMin;      /* True if this change is known to have no useful subdivs */
  } a[MX_CSN];     /* Array of change spans, sorted order */
};


/*
** The two text segments zLeft and zRight are known to be different on
** both ends, but they might have  a common segment in the middle.  If
** they do not have a common segment, return 0.  If they do have a large
** common segment, return 1 and before doing so set:
**
682
683
684
685
686
687
688
689
690
691

692
693
694
695









696



697

698
699
700

701





702
703
704



705
706
707
708

709
710
711
712

713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729






730




731









732
733


734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749

750
751
752
753
754

755
756





757
758

759

760






761




762
763
764


765








766
767

768
769
770
771

772
773
774


775
776
777
778
779
780




781
782
783
784
785
786
787

788
789
790
791
792
793

794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817

818
819
820
821
822
823
824
825

826
827
828
829
830
831
832
833
834
835
836
837
838
839
static int textLCS(
  const char *zLeft,  int nA,       /* String on the left */
  const char *zRight,  int nB,      /* String on the right */
  int *aLCS                         /* Identify bounds of LCS here */
){
  const unsigned char *zA = (const unsigned char*)zLeft;    /* left string */
  const unsigned char *zB = (const unsigned char*)zRight;   /* right string */
  int nt;                    /* Number of target points */
  int ti[3];                 /* Index for start of each 4-byte target */
  unsigned int target[3];    /* 4-byte alignment targets */

  unsigned int probe;        /* probe to compare against target */
  int iAS, iAE, iBS, iBE;    /* Range of common segment */
  int i, j;                  /* Loop counters */
  int rc = 0;                /* Result code.  1 for success */













  if( nA<6 || nB<6 ) return 0;

  memset(aLCS, 0, sizeof(int)*4);
  ti[0] = i = nB/2-2;
  target[0] = (zB[i]<<24) | (zB[i+1]<<16) | (zB[i+2]<<8) | zB[i+3];

  probe = 0;





  if( nB<16 ){
    nt = 1;
  }else{



    ti[1] = i = nB/4-2;
    target[1] = (zB[i]<<24) | (zB[i+1]<<16) | (zB[i+2]<<8) | zB[i+3];
    ti[2] = i = (nB*3)/4-2;
    target[2] = (zB[i]<<24) | (zB[i+1]<<16) | (zB[i+2]<<8) | zB[i+3];

    nt = 3;
  }
  probe = (zA[0]<<16) | (zA[1]<<8) | zA[2];
  for(i=3; i<nA; i++){

    probe = (probe<<8) | zA[i];
    for(j=0; j<nt; j++){
      if( probe==target[j] ){
        iAS = i-3;
        iAE = i+1;
        iBS = ti[j];
        iBE = ti[j]+4;
        while( iAE<nA && iBE<nB && zA[iAE]==zB[iBE] ){ iAE++; iBE++; }
        while( iAS>0 && iBS>0 && zA[iAS-1]==zB[iBS-1] ){ iAS--; iBS--; }
        if( iAE-iAS > aLCS[1] - aLCS[0] ){
          aLCS[0] = iAS;
          aLCS[1] = iAE;
          aLCS[2] = iBS;
          aLCS[3] = iBE;
          rc = 1;
        }
      }






    }




  }









  return rc;
}



/*
** Try to shift iStart as far as possible to the left.
*/
static void sbsShiftLeft(SbsLine *p, const char *z){
  int i, j;
  while( (i=p->iStart)>0 && z[i-1]==z[i] ){
    for(j=i+1; j<p->iEnd && z[j-1]==z[j]; j++){}
    if( j<p->iEnd ) break;
    p->iStart--;
    p->iEnd--;
  }
}

/*
** Simplify iStart and iStart2:

**
**    *  If iStart is a null-change then move iStart2 into iStart
**    *  Make sure any null-changes are in canonoical form.
**    *  Make sure all changes are at character boundaries for
**       multi-byte characters.

*/
static void sbsSimplifyLine(SbsLine *p, const char *z){





  if( p->iStart2==p->iEnd2 ){
    p->iStart2 = p->iEnd2 = 0;

  }else if( p->iStart2 ){

    while( p->iStart2>0 && (z[p->iStart2]&0xc0)==0x80 ) p->iStart2--;






    while( (z[p->iEnd2]&0xc0)==0x80 ) p->iEnd2++;




  }
  if( p->iStart==p->iEnd ){
    p->iStart = p->iStart2;


    p->iEnd = p->iEnd2;








    p->zStart = p->zStart2;
    p->iStart2 = 0;

    p->iEnd2 = 0;
  }
  if( p->iStart==p->iEnd ){
    p->iStart = p->iEnd = -1;

  }else if( p->iStart>0 ){
    while( p->iStart>0 && (z[p->iStart]&0xc0)==0x80 ) p->iStart--;
    while( (z[p->iEnd]&0xc0)==0x80 ) p->iEnd++;


  }
}

/*
** Write out lines that have been edited.  Adjust the highlight to cover
** only those parts of the line that actually changed.




*/
static void sbsWriteLineChange(
  SbsLine *p,          /* The SBS output line */
  DLine *pLeft,        /* Left line of the change */
  int lnLeft,          /* Line number for the left line */
  DLine *pRight,       /* Right line of the change */
  int lnRight          /* Line number of the right line */

){
  int nLeft;           /* Length of left line in bytes */
  int nRight;          /* Length of right line in bytes */
  int nShort;          /* Shortest of left and right */
  int nPrefix;         /* Length of common prefix */
  int nSuffix;         /* Length of common suffix */

  const char *zLeft;   /* Text of the left line */
  const char *zRight;  /* Text of the right line */
  int nLeftDiff;       /* nLeft - nPrefix - nSuffix */
  int nRightDiff;      /* nRight - nPrefix - nSuffix */
  int aLCS[4];         /* Bounds of common middle segment */
  static const char zClassRm[]   = "<span class=\"diffrm\">";
  static const char zClassAdd[]  = "<span class=\"diffadd\">";
  static const char zClassChng[] = "<span class=\"diffchng\">";

  nLeft = pLeft->n;
  zLeft = pLeft->z;
  nRight = pRight->n;
  zRight = pRight->z;
  nShort = nLeft<nRight ? nLeft : nRight;

  nPrefix = 0;
  while( nPrefix<nShort && zLeft[nPrefix]==zRight[nPrefix] ){
    nPrefix++;
  }
  if( nPrefix<nShort ){
    while( nPrefix>0 && (zLeft[nPrefix]&0xc0)==0x80 ) nPrefix--;
  }
  nSuffix = 0;
  if( nPrefix<nShort ){

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


  /* If the prefix and suffix overlap, that means that we are dealing with
  ** a pure insertion or deletion of text that can have multiple alignments.
  ** Try to find an alignment to begins and ends on whitespace, or on
  ** punctuation, rather than in the middle of a name or number.
  */
  if( nPrefix+nSuffix > nShort ){
    int iBest = -1;
    int iBestVal = -1;
    int i;
    int nLong = nLeft<nRight ? nRight : nLeft;
    int nGap = nLong - nShort;
    for(i=nShort-nSuffix; i<=nPrefix; i++){
       int iVal = 0;







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

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

>
>
|
<
<

|
|
|
<
|
<
<
|
|
<

<
>

|
|
<
|
>

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


<
|
>
>
>
>

|
<
|
<
|
<
>






>




<
<
<
<
















>
|







>






|







534
535
536
537
538
539
540
541
542
543
544
545

546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564

565
566
567
568
569
570
571
572
573

574
575
576
577

578

579
580

581
582
583
584
585
586
587
588




589
590



591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619


620
621
622
623

624


625
626

627

628
629
630
631

632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680


681
682
683
684
685
686

687
688
689
690
691
692
693

694

695

696
697
698
699
700
701
702
703
704
705
706
707




708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
static int textLCS(
  const char *zLeft,  int nA,       /* String on the left */
  const char *zRight,  int nB,      /* String on the right */
  int *aLCS                         /* Identify bounds of LCS here */
){
  const unsigned char *zA = (const unsigned char*)zLeft;    /* left string */
  const unsigned char *zB = (const unsigned char*)zRight;   /* right string */
  int i, j, k;               /* Loop counters */
  int lenBest = 0;           /* Match length to beat */

  for(i=0; i<nA-lenBest; i++){
    unsigned char cA = zA[i];

    if( (cA&0xc0)==0x80 ) continue;
    for(j=0; j<nB-lenBest; j++ ){
      if( zB[j]==cA ){
        for(k=1; j+k<nB && i+k<nA && zB[j+k]==zA[i+k]; k++){}
        while( (zB[j+k]&0xc0)==0x80 ){ k--; }
        if( k>lenBest ){
          lenBest = k;
          aLCS[0] = i;
          aLCS[1] = i+k;
          aLCS[2] = j;
          aLCS[3] = j+k;
        }
      }
    }
  }
  return lenBest>0;
}

/*

** Find the smallest spans that are different between two text strings that
** are known to be different on both ends.
*/
static int textLineChanges(
  const char *zLeft,  int nA,       /* String on the left */
  const char *zRight,  int nB,      /* String on the right */
  LineChange *p                     /* Write results here */
){
  p->n = 1;

  p->a[0].iStart1 = 0;
  p->a[0].iLen1 = nA;
  p->a[0].iStart2 = 0;
  p->a[0].iLen2 = nB;

  p->a[0].isMin = 0;

  while( p->n<MX_CSN-1 ){
    int mxi = -1;

    int mxLen = -1;
    int x, i;
    int aLCS[4];
    struct Span *a, *b;
    for(i=0; i<p->n; i++){
      if( p->a[i].isMin ) continue;
      x = p->a[i].iLen1;
      if( p->a[i].iLen2<x ) x = p->a[i].iLen2;




      if( x>mxLen ){
        mxLen = x;



        mxi = i;
      }
    }
    if( mxLen<6 ) break;
    x = textLCS(zLeft + p->a[mxi].iStart1, p->a[mxi].iLen1,
                zRight + p->a[mxi].iStart2, p->a[mxi].iLen2, aLCS);
    if( x==0 ){
      p->a[mxi].isMin = 1;
      continue;
    }
    a = p->a+mxi;
    b = a+1;
    if( mxi<p->n-1 ){
      memmove(b+1, b, sizeof(*b)*(p->n-mxi-1));
    }
    p->n++;
    b->iStart1 = a->iStart1 + aLCS[1];
    b->iLen1 = a->iLen1 - aLCS[1];
    a->iLen1 = aLCS[0];
    b->iStart2 = a->iStart2 + aLCS[3];
    b->iLen2 = a->iLen2 - aLCS[3];
    a->iLen2 = aLCS[2];
    b->isMin = 0;
  }
  return p->n;
}

/*
** Return true if the string starts with n spaces


*/
static int allSpaces(const char *z, int n){
  int i;
  for(i=0; i<n && fossil_isspace(z[i]); i++){}

  return i==n;


}


/*

** Try to improve the human-readability of the LineChange p.
**
** (1)  If the first change span shows a change of indentation, try to
**      move that indentation change to the left margin.

**
** (2)  Try to shift changes so that they begin or end with a space.
*/
static void improveReadability(
  const char *zA,  /* Left line of the change */
  const char *zB,  /* Right line of the change */
  LineChange *p    /* The LineChange to be adjusted */
){
  int j, n, len;
  if( p->n<1 ) return;

  /* (1) Attempt to move indentation changes to the left margin */
  if( p->a[0].iLen1==0
   && (len = p->a[0].iLen2)>0
   && (j = p->a[0].iStart2)>0
   && zB[0]==zB[j]
   && allSpaces(zB, j)
  ){
    for(n=1; n<len && n<j && zB[j]==zB[j+n]; n++){}
    if( n<len ){
      memmove(&p->a[1], &p->a[0], sizeof(p->a[0])*p->n);
      p->n++;
      p->a[0] = p->a[1];
      p->a[1].iStart2 += n;
      p->a[1].iLen2 -= n;
      p->a[0].iLen2 = n;
    }
    p->a[0].iStart1 = 0;
    p->a[0].iStart2 = 0;
  }else
  if( p->a[0].iLen2==0
   && (len = p->a[0].iLen1)>0
   && (j = p->a[0].iStart1)>0
   && zA[0]==zA[j]
   && allSpaces(zA, j)
  ){
    for(n=1; n<len && n<j && zA[j]==zA[j+n]; n++){}
    if( n<len ){
      memmove(&p->a[1], &p->a[0], sizeof(p->a[0])*p->n);
      p->n++;
      p->a[0] = p->a[1];
      p->a[1].iStart1 += n;
      p->a[1].iLen1 -= n;
      p->a[0].iLen1 = n;
    }
    p->a[0].iStart1 = 0;
    p->a[0].iStart2 = 0;
  }



  /* (2) Try to shift changes so that they begin or end with a
  ** space.  (TBD) */
}


/*

** Given two lines of text, pFrom and pTo, compute a set of changes
** between those two lines, for enhanced display purposes.
**
** The result is written into the LineChange object given by the
** third parameter.
*/
static void oneLineChange(

  const DLine *pLeft,  /* Left line of the change */

  const DLine *pRight, /* Right line of the change */

  LineChange *p        /* OUTPUT: Write the results here */
){
  int nLeft;           /* Length of left line in bytes */
  int nRight;          /* Length of right line in bytes */
  int nShort;          /* Shortest of left and right */
  int nPrefix;         /* Length of common prefix */
  int nSuffix;         /* Length of common suffix */
  int nCommon;         /* Total byte length of suffix and prefix */
  const char *zLeft;   /* Text of the left line */
  const char *zRight;  /* Text of the right line */
  int nLeftDiff;       /* nLeft - nPrefix - nSuffix */
  int nRightDiff;      /* nRight - nPrefix - nSuffix */





  nLeft = pLeft->n;
  zLeft = pLeft->z;
  nRight = pRight->n;
  zRight = pRight->z;
  nShort = nLeft<nRight ? nLeft : nRight;

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

  /* If the prefix and suffix overlap, that means that we are dealing with
  ** a pure insertion or deletion of text that can have multiple alignments.
  ** Try to find an alignment to begins and ends on whitespace, or on
  ** punctuation, rather than in the middle of a name or number.
  */
  if( nCommon > nShort ){
    int iBest = -1;
    int iBestVal = -1;
    int i;
    int nLong = nLeft<nRight ? nRight : nLeft;
    int nGap = nLong - nShort;
    for(i=nShort-nSuffix; i<=nPrefix; i++){
       int iVal = 0;
852
853
854
855
856
857
858

859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904

905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944

945

946








947



948
949




































950
951
952
953
954
955
956











































































































































































































































































































































































































































































































































































































































































































































































































































































957
958
959
960
961
962
963
964
965

966

967
968
969
970
971
972
973


974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993









994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021





























1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038

1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050

1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062

1063

1064
1065
1066

1067

1068
1069

























1070
1071
1072










1073
1074

1075




1076
1077





1078
1079
1080



1081
1082
1083
1084
1085
1086


1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
       if( iVal>iBestVal ){
         iBestVal = iVal;
         iBest = i;
       }
    }
    nPrefix = iBest;
    nSuffix = nShort - nPrefix;

  }

  /* A single chunk of text inserted on the right */
  if( nPrefix+nSuffix==nLeft ){
    sbsWriteLineno(p, lnLeft, SBS_LNA);
    p->iStart2 = p->iEnd2 = 0;
    p->iStart = p->iEnd = -1;
    sbsWriteText(p, pLeft, SBS_TXTA);
    if( nLeft==nRight && zLeft[nLeft]==zRight[nRight] ){
      sbsWriteMarker(p, "   ", "");
    }else{
      sbsWriteMarker(p, " | ", "|");
    }
    sbsWriteLineno(p, lnRight, SBS_LNB);
    p->iStart = nPrefix;
    p->iEnd = nRight - nSuffix;
    p->zStart = zClassAdd;
    sbsWriteText(p, pRight, SBS_TXTB);
    return;
  }

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

  /* At this point we know that there is a chunk of text that has
  ** changed between the left and the right.  Check to see if there
  ** is a large unchanged section in the middle of that changed block.
  */
  nLeftDiff = nLeft - nSuffix - nPrefix;
  nRightDiff = nRight - nSuffix - nPrefix;
  if( p->escHtml
   && nLeftDiff >= 6
   && nRightDiff >= 6

   && textLCS(&zLeft[nPrefix], nLeftDiff, &zRight[nPrefix], nRightDiff, aLCS)
  ){
    sbsWriteLineno(p, lnLeft, SBS_LNA);
    p->iStart = nPrefix;
    p->iEnd = nPrefix + aLCS[0];
    if( aLCS[2]==0 ){
      sbsShiftLeft(p, pLeft->z);
      p->zStart = zClassRm;
    }else{
      p->zStart = zClassChng;
    }
    p->iStart2 = nPrefix + aLCS[1];
    p->iEnd2 = nLeft - nSuffix;
    p->zStart2 = aLCS[3]==nRightDiff ? zClassRm : zClassChng;
    sbsSimplifyLine(p, zLeft);
    sbsWriteText(p, pLeft, SBS_TXTA);
    sbsWriteMarker(p, " | ", "|");
    sbsWriteLineno(p, lnRight, SBS_LNB);
    p->iStart = nPrefix;
    p->iEnd = nPrefix + aLCS[2];
    if( aLCS[0]==0 ){
      sbsShiftLeft(p, pRight->z);
      p->zStart = zClassAdd;
    }else{
      p->zStart = zClassChng;
    }
    p->iStart2 = nPrefix + aLCS[3];
    p->iEnd2 = nRight - nSuffix;
    p->zStart2 = aLCS[1]==nLeftDiff ? zClassAdd : zClassChng;
    sbsSimplifyLine(p, zRight);
    sbsWriteText(p, pRight, SBS_TXTB);
    return;
  }

  /* If all else fails, show a single big change between left and right */
  sbsWriteLineno(p, lnLeft, SBS_LNA);
  p->iStart2 = p->iEnd2 = 0;
  p->iStart = nPrefix;
  p->iEnd = nLeft - nSuffix;
  p->zStart = zClassChng;

  sbsWriteText(p, pLeft, SBS_TXTA);

  sbsWriteMarker(p, " | ", "|");








  sbsWriteLineno(p, lnRight, SBS_LNB);



  p->iEnd = nRight - nSuffix;
  sbsWriteText(p, pRight, SBS_TXTB);




































}

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












































































































































































































































































































































































































































































































































































































































































































































































































































































/*
** Return the number between 0 and 100 that is smaller the closer pA and
** pB match.  Return 0 for a perfect match.  Return 100 if pA and pB are
** completely different.
**
** The current algorithm is as follows:
**
** (1) Remove leading and trailing whitespace.
** (2) Truncate both strings to at most 250 characters

** (3) Find the length of the longest common subsequence

** (4) Longer common subsequences yield lower scores.
*/
static int match_dline(DLine *pA, DLine *pB){
  const char *zA;            /* Left string */
  const char *zB;            /* right string */
  int nA;                    /* Bytes in zA[] */
  int nB;                    /* Bytes in zB[] */


  int avg;                   /* Average length of A and B */
  int i, j, k;               /* Loop counters */
  int best = 0;              /* Longest match found so far */
  int score;                 /* Final score.  0..100 */
  unsigned char c;           /* Character being examined */
  unsigned char aFirst[256]; /* aFirst[X] = index in zB[] of first char X */
  unsigned char aNext[252];  /* aNext[i] = index in zB[] of next zB[i] char */

  zA = pA->z;
  zB = pB->z;
  nA = pA->n;
  nB = pB->n;
  while( nA>0 && fossil_isspace(zA[0]) ){ nA--; zA++; }
  while( nA>0 && fossil_isspace(zA[nA-1]) ){ nA--; }
  while( nB>0 && fossil_isspace(zB[0]) ){ nB--; zB++; }
  while( nB>0 && fossil_isspace(zB[nB-1]) ){ nB--; }
  if( nA>250 ) nA = 250;
  if( nB>250 ) nB = 250;
  avg = (nA+nB)/2;
  if( avg==0 ) return 0;









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

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

  /* Return the result */
  return score;
}






























/*
** There is a change block in which nLeft lines of text on the left are
** converted into nRight lines of text on the right.  This routine computes
** how the lines on the left line up with the lines on the right.
**
** The return value is a buffer of unsigned characters, obtained from
** fossil_malloc().  (The caller needs to free the return value using
** fossil_free().)  Entries in the returned array have values as follows:
**
**    1.  Delete the next line of pLeft.
**    2.  Insert the next line of pRight.
**    3.  The next line of pLeft changes into the next line of pRight.
**    4.  Delete one line from pLeft and add one line to pRight.
**
** Values larger than three indicate better matches.
**
** The length of the returned array will be just large enough to cause

** all elements of pLeft and pRight to be consumed.
**
** Algorithm:  Wagner's minimum edit-distance algorithm, modified by
** adding a cost to each match based on how well the two rows match
** each other.  Insertion and deletion costs are 50.  Match costs
** are between 0 and 100 where 0 is a perfect match 100 is a complete
** mismatch.
*/
static unsigned char *sbsAlignment(
   DLine *aLeft, int nLeft,       /* Text on the left */
   DLine *aRight, int nRight,     /* Text on the right */
   u64 diffFlags                  /* Flags passed into the original diff */

){
  int i, j, k;                 /* Loop counters */
  int *a;                      /* One row of the Wagner matrix */
  int *pToFree;                /* Space that needs to be freed */
  unsigned char *aM;           /* Wagner result matrix */
  int nMatch, iMatch;          /* Number of matching lines and match score */
  int mnLen;                   /* MIN(nLeft, nRight) */
  int mxLen;                   /* MAX(nLeft, nRight) */
  int aBuf[100];               /* Stack space for a[] if nRight not to big */

  aM = fossil_malloc( (nLeft+1)*(nRight+1) );
  if( nLeft==0 ){

    memset(aM, 2, nRight);

    return aM;
  }
  if( nRight==0 ){

    memset(aM, 1, nLeft);

    return aM;
  }


























  /* This algorithm is O(N**2).  So if N is too big, bail out with a
  ** simple (but stupid and ugly) result that doesn't take too long. */










  mnLen = nLeft<nRight ? nLeft : nRight;
  if( nLeft*nRight>100000 && (diffFlags & DIFF_SLOW_SBS)==0 ){

    memset(aM, 4, mnLen);




    if( nLeft>mnLen )  memset(aM+mnLen, 1, nLeft-mnLen);
    if( nRight>mnLen ) memset(aM+mnLen, 2, nRight-mnLen);





    return aM;
  }




  if( nRight < count(aBuf)-1 ){
    pToFree = 0;
    a = aBuf;
  }else{
    a = pToFree = fossil_malloc( sizeof(a[0])*(nRight+1) );
  }



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







>


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



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







|
|
<
|
|
>
|

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

<
<
<
|
<




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







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









>
|
>
|

|




>
>












|
|
|
|




>
>
>
>
>
>
>
>
>








<








|










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














<
<
|
>
|







|
|
|
|
>






<
<


<

>

>



>

>


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


>
>
>






>
>




















|







760
761
762
763
764
765
766
767
768
769
770
771

772
773
774






775
776

777
778
779
780
781
782


783
784
785
786



787
788
789
790
791
792
793
794
795
796
797

798
799
800
801
802

803



804










805
806





807



808

809
810
811
812

813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833

834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777

1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839


1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860


1861
1862

1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900


1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
       if( iVal>iBestVal ){
         iBestVal = iVal;
         iBest = i;
       }
    }
    nPrefix = iBest;
    nSuffix = nShort - nPrefix;
    nCommon = nPrefix + nSuffix;
  }

  /* A single chunk of text inserted */
  if( nCommon==nLeft ){

    p->n = 1;
    p->a[0].iStart1 = nPrefix;
    p->a[0].iLen1 = 0;






    p->a[0].iStart2 = nPrefix;
    p->a[0].iLen2 = nRight - nCommon;

    improveReadability(zLeft, zRight, p);
    return;
  }

  /* A single chunk of text deleted */
  if( nCommon==nRight ){


    p->n = 1;
    p->a[0].iStart1 = nPrefix;
    p->a[0].iLen1 = nLeft - nCommon;
    p->a[0].iStart2 = nPrefix;



    p->a[0].iLen2 = 0;
    improveReadability(zLeft, zRight, p);
    return;
  }

  /* At this point we know that there is a chunk of text that has
  ** changed between the left and the right.  Check to see if there
  ** is a large unchanged section in the middle of that changed block.
  */
  nLeftDiff = nLeft - nCommon;
  nRightDiff = nRight - nCommon;

  if( nLeftDiff >= 4
   && nRightDiff >= 4
   && textLineChanges(&zLeft[nPrefix], nLeftDiff,
                      &zRight[nPrefix], nRightDiff, p)>1
  ){

    int i;



    for(i=0; i<p->n; i++){










      p->a[i].iStart1 += nPrefix;
      p->a[i].iStart2 += nPrefix;





    }



    improveReadability(zLeft, zRight, p);

    return;
  }

  /* If all else fails, show a single big change between left and right */

  p->n = 1;
  p->a[0].iStart1 = nPrefix;
  p->a[0].iLen1 = nLeft - nCommon;
  p->a[0].iStart2 = nPrefix;
  p->a[0].iLen2 = nRight - nCommon;
  improveReadability(zLeft, zRight, p);
}

/*
** COMMAND: test-line-diff
** Usage: %fossil% test-line-diff STRING1 STRING2
**
** Show the differences between the two strings.  Used for testing
** the oneLineChange() routine in the diff logic.
*/
void test_line_diff(void){
  DLine a, b;
  LineChange chng;
  int i, j, x;
  if( g.argc!=4 ) usage("STRING1 STRING2");
  a.z = g.argv[2];

  a.n = (int)strlen(a.z);
  b.z = g.argv[3];
  b.n = (int)strlen(b.z);
  oneLineChange(&a, &b, &chng);
  fossil_print("left:  [%s]\n", a.z);
  for(i=x=0; i<chng.n; i++){
    int ofst = chng.a[i].iStart1;
    int len = chng.a[i].iLen1;
    if( len ){
      if( x==0 ){ fossil_print("%*s", 8, ""); }
      while( ofst > x ){
        if( (a.z[x]&0xc0)!=0x80 ) fossil_print(" ");
        x++;
      }
      for(j=0; j<len; j++, x++){
        if( (a.z[x]&0xc0)!=0x80 ) fossil_print("%d",i);
      }
    }
  }
  if( x ) fossil_print("\n");
  fossil_print("right: [%s]\n", b.z);
  for(i=x=0; i<chng.n; i++){
    int ofst = chng.a[i].iStart2;
    int len = chng.a[i].iLen2;
    if( len ){
      if( x==0 ){ fossil_print("%*s", 8, ""); }
      while( ofst > x ){
        if( (b.z[x]&0xc0)!=0x80 ) fossil_print(" ");
        x++;
      }
      for(j=0; j<len; j++, x++){
        if( (b.z[x]&0xc0)!=0x80 ) fossil_print("%d",i);
      }
    }
  }
  if( x ) fossil_print("\n");
}

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



/*
** This is an abstract superclass for an object that accepts difference
** lines and formats them for display.  Subclasses of this object format
** the diff output in different ways.
**
** To subclass, create an instance of the DiffBuilder object and fill
** in appropriate method implementations.
*/ 
typedef struct DiffBuilder DiffBuilder;
struct DiffBuilder {
  void (*xSkip)(DiffBuilder*, unsigned int, int);
  void (*xCommon)(DiffBuilder*,const DLine*);
  void (*xInsert)(DiffBuilder*,const DLine*);
  void (*xDelete)(DiffBuilder*,const DLine*);
  void (*xReplace)(DiffBuilder*,const DLine*, const DLine*);
  void (*xEdit)(DiffBuilder*,const DLine*,const DLine*);
  void (*xEnd)(DiffBuilder*);
  unsigned int lnLeft;              /* Lines seen on the left (delete) side */
  unsigned int lnRight;             /* Lines seen on the right (insert) side */
  unsigned int nPending;            /* Number of pending lines */
  int eState;                       /* State of the output */
  int width;                        /* Display width */
  Blob *pOut;                       /* Output blob */
  Blob aCol[5];                     /* Holding blobs */
  DiffConfig *pCfg;                 /* Configuration information */
};

/************************* DiffBuilderDebug ********************************/
/* This version of DiffBuilder is used for debugging the diff and diff
** diff formatter logic.  It is accessed using the (undocumented) --debug
** option to the diff command.  The output is human-readable text that
** describes the various method calls that are invoked agains the DiffBuilder
** object.
*/
static void dfdebugSkip(DiffBuilder *p, unsigned int n, int isFinal){
  blob_appendf(p->pOut, "SKIP %d (%d..%d left and %d..%d right)%s\n",
                n, p->lnLeft+1, p->lnLeft+n, p->lnRight+1, p->lnRight+n,
                isFinal ? " FINAL" : "");
  p->lnLeft += n;
  p->lnRight += n;
}
static void dfdebugCommon(DiffBuilder *p, const DLine *pLine){
  p->lnLeft++;
  p->lnRight++;
  blob_appendf(p->pOut, "COMMON  %8u %8u %.*s\n",
      p->lnLeft, p->lnRight, (int)pLine->n, pLine->z);
}
static void dfdebugInsert(DiffBuilder *p, const DLine *pLine){
  p->lnRight++;
  blob_appendf(p->pOut, "INSERT           %8d %.*s\n",
      p->lnRight, (int)pLine->n, pLine->z);
}
static void dfdebugDelete(DiffBuilder *p, const DLine *pLine){
  p->lnLeft++;
  blob_appendf(p->pOut, "DELETE  %8u          %.*s\n",
      p->lnLeft, (int)pLine->n, pLine->z);
}
static void dfdebugReplace(DiffBuilder *p, const DLine *pX, const DLine *pY){
  p->lnLeft++;
  p->lnRight++;
  blob_appendf(p->pOut, "REPLACE %8u          %.*s\n",
      p->lnLeft, (int)pX->n, pX->z);
  blob_appendf(p->pOut, "            %8u %.*s\n",
      p->lnRight, (int)pY->n, pY->z);
}
static void dfdebugEdit(DiffBuilder *p, const DLine *pX, const DLine *pY){
  int i, j;
  int x;
  LineChange chng;
  p->lnLeft++;
  p->lnRight++;
  blob_appendf(p->pOut, "EDIT    %8u          %.*s\n",
               p->lnLeft, (int)pX->n, pX->z);
  oneLineChange(pX, pY, &chng);
  for(i=x=0; i<chng.n; i++){
    int ofst = chng.a[i].iStart1;
    int len = chng.a[i].iLen1;
    if( len ){
      char c = '0' + i;
      if( x==0 ){ blob_appendf(p->pOut, "%*s", 26, ""); }
      while( ofst > x ){
        if( (pX->z[x]&0xc0)!=0x80 ) blob_append_char(p->pOut, ' ');
        x++;
      }
      for(j=0; j<len; j++, x++){
        if( (pX->z[x]&0xc0)!=0x80 ) blob_append_char(p->pOut, c);
      }
    }
  }
  if( x ) blob_append_char(p->pOut, '\n');
  blob_appendf(p->pOut, "                 %8u %.*s\n",
               p->lnRight, (int)pY->n, pY->z);
  for(i=x=0; i<chng.n; i++){
    int ofst = chng.a[i].iStart2;
    int len = chng.a[i].iLen2;
    if( len ){
      char c = '0' + i;
      if( x==0 ){ blob_appendf(p->pOut, "%*s", 26, ""); }
      while( ofst > x ){
        if( (pY->z[x]&0xc0)!=0x80 ) blob_append_char(p->pOut, ' ');
        x++;
      }
      for(j=0; j<len; j++, x++){
        if( (pY->z[x]&0xc0)!=0x80 ) blob_append_char(p->pOut, c);
      }
    }
  }
  if( x ) blob_append_char(p->pOut, '\n');
}
static void dfdebugEnd(DiffBuilder *p){
  blob_appendf(p->pOut, "END with %u lines left and %u lines right\n",
     p->lnLeft, p->lnRight);
  fossil_free(p);
}
static DiffBuilder *dfdebugNew(Blob *pOut){
  DiffBuilder *p = fossil_malloc(sizeof(*p));
  p->xSkip = dfdebugSkip;
  p->xCommon = dfdebugCommon;
  p->xInsert = dfdebugInsert;
  p->xDelete = dfdebugDelete;
  p->xReplace = dfdebugReplace;
  p->xEdit = dfdebugEdit;
  p->xEnd = dfdebugEnd;
  p->lnLeft = p->lnRight = 0;
  p->pOut = pOut;
  return p;
}

/************************* DiffBuilderTcl ********************************/
/*
** This formatter outputs a description of the diff formatted as TCL, for
** use by the --tk option to "diff".   See also the "diff.tcl" file.  The
** output can be viewed directly using the --tcl option.
**
** There is one line per method call:
**
**     SKIP n                      -- Skip "n" lines of input
**     COM string                  -- "string" is an unchanged context line
**     INS string                  -- "string" is in the right file only
**     DEL string                  -- "string" is in the left file only
**     EDIT string ....            -- Complex edit between left and right
**
** The EDIT verb will be followed by 3*N or 3*N+1 strings.  The triples
** each show:
**
**     1.  Common text
**     2.  Text from the left side
**     3.  Text on the right that replaces (2) from the left
**
** For inserted text (2) will be an empty string.  For deleted text, (3)
** will be an empty string.  (1) might be empty for the first triple if
** the line begins with an edit.  After all triples, there might be one
** additional string which is a common suffix.
*/
static void dftclSkip(DiffBuilder *p, unsigned int n, int isFinal){
  blob_appendf(p->pOut, "SKIP %u\n", n);
}
static void dftclCommon(DiffBuilder *p, const DLine *pLine){
  blob_appendf(p->pOut, "COM ");
  blob_append_tcl_literal(p->pOut, pLine->z, pLine->n);
  blob_append_char(p->pOut, '\n');
}
static void dftclInsert(DiffBuilder *p, const DLine *pLine){
  blob_append(p->pOut, "INS ", -1);
  blob_append_tcl_literal(p->pOut, pLine->z, pLine->n);
  blob_append_char(p->pOut, '\n');
}
static void dftclDelete(DiffBuilder *p, const DLine *pLine){
  blob_append(p->pOut, "DEL ", -1);
  blob_append_tcl_literal(p->pOut, pLine->z, pLine->n);
  blob_append_char(p->pOut, '\n');
}
static void dftclReplace(DiffBuilder *p, const DLine *pX, const DLine *pY){
  blob_append(p->pOut, "EDIT \"\" ", -1);
  blob_append_tcl_literal(p->pOut, pX->z, pX->n);
  blob_append_char(p->pOut, ' ');
  blob_append_tcl_literal(p->pOut, pY->z, pY->n);
  blob_append_char(p->pOut, '\n');
}
static void dftclEdit(DiffBuilder *p, const DLine *pX, const DLine *pY){
  int i, x;
  LineChange chng;
  blob_append(p->pOut, "EDIT", 4);
  oneLineChange(pX, pY, &chng);
  for(i=x=0; i<chng.n; i++){
    blob_append_char(p->pOut, ' ');
    blob_append_tcl_literal(p->pOut, pX->z + x, chng.a[i].iStart1 - x);
    x = chng.a[i].iStart1;
    blob_append_char(p->pOut, ' ');
    blob_append_tcl_literal(p->pOut, pX->z + x, chng.a[i].iLen1);
    x += chng.a[i].iLen1;
    blob_append_char(p->pOut, ' ');
    blob_append_tcl_literal(p->pOut, 
                         pY->z + chng.a[i].iStart2, chng.a[i].iLen2);
  }
  if( x<pX->n ){
    blob_append_char(p->pOut, ' ');
    blob_append_tcl_literal(p->pOut, pX->z + x, pX->n - x);
  }
  blob_append_char(p->pOut, '\n');
}
static void dftclEnd(DiffBuilder *p){
  fossil_free(p);
}
static DiffBuilder *dftclNew(Blob *pOut){
  DiffBuilder *p = fossil_malloc(sizeof(*p));
  p->xSkip = dftclSkip;
  p->xCommon = dftclCommon;
  p->xInsert = dftclInsert;
  p->xDelete = dftclDelete;
  p->xReplace = dftclReplace;
  p->xEdit = dftclEdit;
  p->xEnd = dftclEnd;
  p->pOut = pOut;
  return p;
}

/************************* DiffBuilderJson ********************************/
/*
** This formatter generates a JSON array that describes the difference.
**
** The Json array consists of integer opcodes with each opcode followed
** by zero or more arguments:
**
**   Syntax        Mnemonic    Description
**   -----------   --------    --------------------------
**   0             END         This is the end of the diff
**   1  INTEGER    SKIP        Skip N lines from both files
**   2  STRING     COMMON      The line show by STRING is in both files
**   3  STRING     INSERT      The line STRING is in only the right file
**   4  STRING     DELETE      The STRING line is in only the left file
**   5  SUBARRAY   EDIT        One line is different on left and right.
**
** The SUBARRAY is an array of 3*N+1 strings with N>=0.  The triples
** represent common-text, left-text, and right-text.  The last string
** in SUBARRAY is the common-suffix.  Any string can be empty if it does
** not apply.
*/
static void dfjsonSkip(DiffBuilder *p, unsigned int n, int isFinal){
  blob_appendf(p->pOut, "1,%u,\n", n);
}
static void dfjsonCommon(DiffBuilder *p, const DLine *pLine){
  blob_append(p->pOut, "2,",2);
  blob_append_json_literal(p->pOut, pLine->z, (int)pLine->n);
  blob_append(p->pOut, ",\n",2);
}
static void dfjsonInsert(DiffBuilder *p, const DLine *pLine){
  blob_append(p->pOut, "3,",2);
  blob_append_json_literal(p->pOut, pLine->z, (int)pLine->n);
  blob_append(p->pOut, ",\n",2);
}
static void dfjsonDelete(DiffBuilder *p, const DLine *pLine){
  blob_append(p->pOut, "4,",2);
  blob_append_json_literal(p->pOut, pLine->z, (int)pLine->n);
  blob_append(p->pOut, ",\n",2);
}
static void dfjsonReplace(DiffBuilder *p, const DLine *pX, const DLine *pY){
  blob_append(p->pOut, "5,[\"\",",-1);
  blob_append_json_literal(p->pOut, pX->z, (int)pX->n);
  blob_append(p->pOut, ",",1);
  blob_append_json_literal(p->pOut, pY->z, (int)pY->n);
  blob_append(p->pOut, ",\"\"],\n",-1);
}
static void dfjsonEdit(DiffBuilder *p, const DLine *pX, const DLine *pY){
  int i, x;
  LineChange chng;
  blob_append(p->pOut, "5,[", 3);
  oneLineChange(pX, pY, &chng);
  for(i=x=0; i<chng.n; i++){
    blob_append_json_literal(p->pOut, pX->z + x, chng.a[i].iStart1 - x);
    x = chng.a[i].iStart1;
    blob_append_char(p->pOut, ',');
    blob_append_json_literal(p->pOut, pX->z + x, chng.a[i].iLen1);
    x += chng.a[i].iLen1;
    blob_append_char(p->pOut, ',');
    blob_append_json_literal(p->pOut, 
                         pY->z + chng.a[i].iStart2, chng.a[i].iLen2);
  }
  blob_append_char(p->pOut, ',');
  blob_append_json_literal(p->pOut, pX->z + x, pX->n - x);
  blob_append(p->pOut, "],\n",3);
}
static void dfjsonEnd(DiffBuilder *p){
  blob_append(p->pOut, "0]}", 3);
  fossil_free(p);
}
static DiffBuilder *dfjsonNew(Blob *pOut){
  DiffBuilder *p = fossil_malloc(sizeof(*p));
  p->xSkip = dfjsonSkip;
  p->xCommon = dfjsonCommon;
  p->xInsert = dfjsonInsert;
  p->xDelete = dfjsonDelete;
  p->xReplace = dfjsonReplace;
  p->xEdit = dfjsonEdit;
  p->xEnd = dfjsonEnd;
  p->lnLeft = p->lnRight = 0;
  p->pOut = pOut;
  blob_append_char(pOut, '[');
  return p;
}

/************************* DiffBuilderUnified********************************/
/* This formatter generates a unified diff for HTML.
**
** The result is a <table> with four columns.  The four columns hold:
**
**     1.   The line numbers for the first file.
**     2.   The line numbers for the second file.
**     3.   The "diff mark":  "+" or "-" or just a space
**     4.   Text of the line
**
** Inserted lines are marked with <ins> and deleted lines are marked
** with <del>.  The whole line is marked this way, not just the part that
** changed.  The part that change has an additional nested <ins> or <del>.
** The CSS needs to be set up such that a single <ins> or <del> gives a
** light background and a nested <ins> or <del> gives a darker background.
** Additional attributes (like bold font) might also be added to nested
** <ins> and <del> since those are the characters that have actually
** changed.
**
** Accumulator strategy:
**
**    *   Delete line numbers are output directly to p->pOut
**    *   Insert line numbers accumulate in p->aCol[0].
**    *   Separator marks accumulate in p->aCol[1].
**    *   Change text accumulates in p->aCol[2].
**    *   Pending insert line numbers go into p->aCol[3].
**    *   Pending insert text goes into p->aCol[4].
**
** eState is 1 if text has an open <del>
*/
static void dfunifiedFinishDelete(DiffBuilder *p){
  if( p->eState==0 ) return;
  blob_append(p->pOut, "</del>", 6);
  blob_append(&p->aCol[2], "</del>", 6);
  p->eState = 0;
}
static void dfunifiedFinishInsert(DiffBuilder *p){
  unsigned int i;
  if( p->nPending==0 ) return;
  dfunifiedFinishDelete(p);

  /* Blank lines for delete line numbers for each inserted line */
  for(i=0; i<p->nPending; i++) blob_append_char(p->pOut, '\n');

  /* Insert line numbers */
  blob_append(&p->aCol[0], "<ins>", 5);
  blob_append_xfer(&p->aCol[0], &p->aCol[3]);
  blob_append(&p->aCol[0], "</ins>", 6);

  /* "+" marks for the separator on inserted lines */
  for(i=0; i<p->nPending; i++) blob_append(&p->aCol[1], "+\n", 2);

  /* Text of the inserted lines */
  blob_append(&p->aCol[2], "<ins>", 5);
  blob_append_xfer(&p->aCol[2], &p->aCol[4]);
  blob_append(&p->aCol[2], "</ins>", 6);
  
  p->nPending = 0;
}
static void dfunifiedFinishRow(DiffBuilder *p){
  dfunifiedFinishDelete(p);
  dfunifiedFinishInsert(p);
  if( blob_size(&p->aCol[0])==0 ) return;
  blob_append(p->pOut, "</pre></td><td class=\"diffln difflnr\"><pre>\n", -1);
  blob_append_xfer(p->pOut, &p->aCol[0]);
  blob_append(p->pOut, "</pre></td><td class=\"diffsep\"><pre>\n", -1);
  blob_append_xfer(p->pOut, &p->aCol[1]);
  blob_append(p->pOut, "</pre></td><td class=\"difftxt difftxtu\"><pre>\n",-1);
  blob_append_xfer(p->pOut, &p->aCol[2]);
  blob_append(p->pOut, "</pre></td></tr>\n", -1);
}
static void dfunifiedStartRow(DiffBuilder *p){
  if( blob_size(&p->aCol[0])>0 ) return;
  blob_appendf(p->pOut,"<tr id=\"chunk%d\">"
                       "<td class=\"diffln difflnl\"><pre>\n", ++nChunk);
}
static void dfunifiedSkip(DiffBuilder *p, unsigned int n, int isFinal){
  dfunifiedFinishRow(p);
  if( p->pCfg && p->pCfg->zLeftHash ){
    blob_appendf(p->pOut,
       "<tr class=\"diffskip\" data-startln=\"%d\" data-endln=\"%d\""
       " id=\"skip%xh%xi%x\">\n",
       p->lnLeft+1, p->lnLeft+n,
       nChunk, p->lnLeft, n);
  }else{
    blob_append(p->pOut, "<tr>", 4);
  }
  blob_append(p->pOut, "<td class=\"diffln difflne\">"
                       "&#xfe19;</td><td></td><td></td></tr>\n", -1);
  p->lnLeft += n;
  p->lnRight += n;
}
static void dfunifiedCommon(DiffBuilder *p, const DLine *pLine){
  dfunifiedStartRow(p);
  dfunifiedFinishDelete(p);
  dfunifiedFinishInsert(p);
  p->lnLeft++;
  p->lnRight++;
  blob_appendf(p->pOut,"%d\n", p->lnLeft);
  blob_appendf(&p->aCol[0],"%d\n",p->lnRight);
  blob_append_char(&p->aCol[1], '\n');
  htmlize_to_blob(&p->aCol[2], pLine->z, (int)pLine->n);
  blob_append_char(&p->aCol[2], '\n');
}
static void dfunifiedInsert(DiffBuilder *p, const DLine *pLine){
  dfunifiedStartRow(p);
  p->lnRight++;
  blob_appendf(&p->aCol[3],"%d\n", p->lnRight);
  blob_append(&p->aCol[4], "<ins>", 5);
  htmlize_to_blob(&p->aCol[4], pLine->z, (int)pLine->n);
  blob_append(&p->aCol[4], "</ins>\n", 7);
  p->nPending++;
}
static void dfunifiedDelete(DiffBuilder *p, const DLine *pLine){
  dfunifiedStartRow(p);
  dfunifiedFinishInsert(p);
  if( p->eState==0 ){
    dfunifiedFinishInsert(p);
    blob_append(p->pOut, "<del>", 5);
    blob_append(&p->aCol[2], "<del>", 5);
    p->eState = 1;
  }
  p->lnLeft++;
  blob_appendf(p->pOut,"%d\n", p->lnLeft);
  blob_append_char(&p->aCol[0],'\n');
  blob_append(&p->aCol[1],"-\n",2);
  blob_append(&p->aCol[2], "<del>", 5);
  htmlize_to_blob(&p->aCol[2], pLine->z, (int)pLine->n);
  blob_append(&p->aCol[2], "</del>\n", 7);
}
static void dfunifiedReplace(DiffBuilder *p, const DLine *pX, const DLine *pY){
  dfunifiedStartRow(p);
  if( p->eState==0 ){
    dfunifiedFinishInsert(p);
    blob_append(p->pOut, "<del>", 5);
    blob_append(&p->aCol[2], "<del>", 5);
    p->eState = 1;
  }
  p->lnLeft++;
  p->lnRight++;
  blob_appendf(p->pOut,"%d\n", p->lnLeft);
  blob_append_char(&p->aCol[0], '\n');
  blob_append(&p->aCol[1], "-\n", 2);

  htmlize_to_blob(&p->aCol[2], pX->z,  pX->n);
  blob_append_char(&p->aCol[2], '\n');

  blob_appendf(&p->aCol[3],"%d\n", p->lnRight);

  htmlize_to_blob(&p->aCol[4], pY->z,  pY->n);
  blob_append_char(&p->aCol[4], '\n');
  p->nPending++;
}
static void dfunifiedEdit(DiffBuilder *p, const DLine *pX, const DLine *pY){
  int i;
  int x;
  LineChange chng;
  oneLineChange(pX, pY, &chng);
  dfunifiedStartRow(p);
  if( p->eState==0 ){
    dfunifiedFinishInsert(p);
    blob_append(p->pOut, "<del>", 5);
    blob_append(&p->aCol[2], "<del>", 5);
    p->eState = 1;
  }
  p->lnLeft++;
  p->lnRight++;
  blob_appendf(p->pOut,"%d\n", p->lnLeft);
  blob_append_char(&p->aCol[0], '\n');
  blob_append(&p->aCol[1], "-\n", 2);

  for(i=x=0; i<chng.n; i++){
    int ofst = chng.a[i].iStart1;
    int len = chng.a[i].iLen1;
    if( len ){
      htmlize_to_blob(&p->aCol[2], pX->z+x, ofst - x);
      x = ofst;
      blob_append(&p->aCol[2], "<del>", 5);
      htmlize_to_blob(&p->aCol[2], pX->z+x, len);
      x += len;
      blob_append(&p->aCol[2], "</del>", 6);
    }
  }
  htmlize_to_blob(&p->aCol[2], pX->z+x,  pX->n - x);
  blob_append_char(&p->aCol[2], '\n');

  blob_appendf(&p->aCol[3],"%d\n", p->lnRight);
  for(i=x=0; i<chng.n; i++){
    int ofst = chng.a[i].iStart2;
    int len = chng.a[i].iLen2;
    if( len ){
      htmlize_to_blob(&p->aCol[4], pY->z+x, ofst - x);
      x = ofst;
      blob_append(&p->aCol[4], "<ins>", 5);
      htmlize_to_blob(&p->aCol[4], pY->z+x, len);
      x += len;
      blob_append(&p->aCol[4], "</ins>", 6);
    }
  }
  htmlize_to_blob(&p->aCol[4], pY->z+x,  pY->n - x);
  blob_append_char(&p->aCol[4], '\n');
  p->nPending++;
}
static void dfunifiedEnd(DiffBuilder *p){
  dfunifiedFinishRow(p);
  blob_append(p->pOut, "</table>\n",-1);
  fossil_free(p);
}
static DiffBuilder *dfunifiedNew(Blob *pOut, DiffConfig *pCfg){
  DiffBuilder *p = fossil_malloc(sizeof(*p));
  p->xSkip = dfunifiedSkip;
  p->xCommon = dfunifiedCommon;
  p->xInsert = dfunifiedInsert;
  p->xDelete = dfunifiedDelete;
  p->xReplace = dfunifiedReplace;
  p->xEdit = dfunifiedEdit;
  p->xEnd = dfunifiedEnd;
  p->lnLeft = p->lnRight = 0;
  p->eState = 0;
  p->nPending = 0;
  p->pOut = pOut;
  if( pCfg->zLeftHash ){
    blob_appendf(pOut, "<table class=\"diff udiff\" data-lefthash=\"%s\">\n",
                pCfg->zLeftHash);
  }else{
    blob_append(pOut, "<table class=\"diff udiff\">\n", -1);
  }
  blob_init(&p->aCol[0], 0, 0);
  blob_init(&p->aCol[1], 0, 0);
  blob_init(&p->aCol[2], 0, 0);
  blob_init(&p->aCol[3], 0, 0);
  blob_init(&p->aCol[4], 0, 0);
  p->pCfg = pCfg;
  return p;
}

/************************* DiffBuilderSplit  ******************************/
/* This formatter creates a side-by-side diff in HTML.  The output is a
** <table> with 5 columns:
**
**    1.  Line numbers for the first file.
**    2.  Text for the first file.
**    3.  The difference mark.  "<", ">", "|" or blank
**    4.  Line numbers for the second file.
**    5.  Text for the second file.
**
** The <ins> and <del> strategy is the same as for unified diff above.
** In fact, the same CSS can be used for both.
**
** Accumulator strategy:
**
**    *   Left line numbers are output directly to p->pOut
**    *   Left text accumulates in p->aCol[0].
**    *   Edit marks accumulates in p->aCol[1].
**    *   Right line numbers accumulate in p->aCol[2].
**    *   Right text accumulates in p->aCol[3].
**
** eState:
**    0   In common block
**    1   Have <del> on the left
**    2   Have <ins> on the right
**    3   Have <del> on left and <ins> on the right
*/
static void dfsplitChangeState(DiffBuilder *p, int newState){
  if( p->eState == newState ) return;
  if( (p->eState&1)==0 && (newState & 1)!=0 ){
    blob_append(p->pOut, "<del>", 5);
    blob_append(&p->aCol[0], "<del>", 5);
    p->eState |= 1;
  }else if( (p->eState&1)!=0 && (newState & 1)==0 ){
    blob_append(p->pOut, "</del>", 6);
    blob_append(&p->aCol[0], "</del>", 6);
    p->eState &= ~1;
  }
  if( (p->eState&2)==0 && (newState & 2)!=0 ){
    blob_append(&p->aCol[2], "<ins>", 5);
    blob_append(&p->aCol[3], "<ins>", 5);
    p->eState |= 2;
  }else if( (p->eState&2)!=0 && (newState & 2)==0 ){
    blob_append(&p->aCol[2], "</ins>", 6);
    blob_append(&p->aCol[3], "</ins>", 6);
    p->eState &= ~2;
  }
}
static void dfsplitFinishRow(DiffBuilder *p){
  if( blob_size(&p->aCol[0])==0 ) return;
  dfsplitChangeState(p, 0);
  blob_append(p->pOut, "</pre></td><td class=\"difftxt difftxtl\"><pre>\n",-1);
  blob_append_xfer(p->pOut, &p->aCol[0]);
  blob_append(p->pOut, "</pre></td><td class=\"diffsep\"><pre>\n", -1);
  blob_append_xfer(p->pOut, &p->aCol[1]);
  blob_append(p->pOut, "</pre></td><td class=\"diffln difflnr\"><pre>\n",-1);
  blob_append_xfer(p->pOut, &p->aCol[2]);
  blob_append(p->pOut, "</pre></td><td class=\"difftxt difftxtr\"><pre>\n",-1);
  blob_append_xfer(p->pOut, &p->aCol[3]);
  blob_append(p->pOut, "</pre></td></tr>\n", -1);
}
static void dfsplitStartRow(DiffBuilder *p){
  if( blob_size(&p->aCol[0])>0 ) return;
  blob_appendf(p->pOut,"<tr id=\"chunk%d\">"
                       "<td class=\"diffln difflnl\"><pre>\n", ++nChunk);
  p->eState = 0;
}
static void dfsplitSkip(DiffBuilder *p, unsigned int n, int isFinal){
  dfsplitFinishRow(p);
  if( p->pCfg && p->pCfg->zLeftHash ){
    blob_appendf(p->pOut,
       "<tr class=\"diffskip\" data-startln=\"%d\" data-endln=\"%d\""
       " id=\"skip%xh%xi%x\">\n",
       p->lnLeft+1, p->lnLeft+n,
       nChunk,p->lnLeft,n);
  }else{
    blob_append(p->pOut, "<tr>", 4);
  }
  blob_append(p->pOut,
       "<td class=\"diffln difflnl difflne\">&#xfe19;</td>"
       "<td></td><td></td>"
       "<td class=\"diffln difflnr difflne\">&#xfe19;</td>"
       "<td/td></tr>\n", -1);
  p->lnLeft += n;
  p->lnRight += n;
}
static void dfsplitCommon(DiffBuilder *p, const DLine *pLine){
  dfsplitStartRow(p);
  dfsplitChangeState(p, 0);
  p->lnLeft++;
  p->lnRight++;
  blob_appendf(p->pOut,"%d\n", p->lnLeft);
  htmlize_to_blob(&p->aCol[0], pLine->z, (int)pLine->n);
  blob_append_char(&p->aCol[0], '\n');
  blob_append_char(&p->aCol[1], '\n');
  blob_appendf(&p->aCol[2],"%d\n",p->lnRight);
  htmlize_to_blob(&p->aCol[3], pLine->z, (int)pLine->n);
  blob_append_char(&p->aCol[3], '\n');
}
static void dfsplitInsert(DiffBuilder *p, const DLine *pLine){
  dfsplitStartRow(p);
  dfsplitChangeState(p, 2);
  p->lnRight++;
  blob_append_char(p->pOut, '\n');
  blob_append_char(&p->aCol[0], '\n');
  blob_append(&p->aCol[1], "&gt;\n", -1);
  blob_appendf(&p->aCol[2],"%d\n", p->lnRight);
  blob_append(&p->aCol[3], "<ins>", 5);
  htmlize_to_blob(&p->aCol[3], pLine->z, (int)pLine->n);
  blob_append(&p->aCol[3], "</ins>\n", 7);
}
static void dfsplitDelete(DiffBuilder *p, const DLine *pLine){
  dfsplitStartRow(p);
  dfsplitChangeState(p, 1);
  p->lnLeft++;
  blob_appendf(p->pOut,"%d\n", p->lnLeft);
  blob_append(&p->aCol[0], "<del>", 5);
  htmlize_to_blob(&p->aCol[0], pLine->z, (int)pLine->n);
  blob_append(&p->aCol[0], "</del>\n", 7);
  blob_append(&p->aCol[1], "&lt;\n", -1);
  blob_append_char(&p->aCol[2],'\n');
  blob_append_char(&p->aCol[3],'\n');
}
static void dfsplitReplace(DiffBuilder *p, const DLine *pX, const DLine *pY){
  dfsplitStartRow(p);
  dfsplitChangeState(p, 3);
  p->lnLeft++;
  p->lnRight++;
  blob_appendf(p->pOut,"%d\n", p->lnLeft);
  htmlize_to_blob(&p->aCol[0], pX->z,  pX->n);
  blob_append_char(&p->aCol[0], '\n');

  blob_append(&p->aCol[1], "|\n", 2);

  blob_appendf(&p->aCol[2],"%d\n", p->lnRight);

  htmlize_to_blob(&p->aCol[3], pY->z,  pY->n);
  blob_append_char(&p->aCol[3], '\n');
}
static void dfsplitEdit(DiffBuilder *p, const DLine *pX, const DLine *pY){
  int i;
  int x;
  LineChange chng;
  oneLineChange(pX, pY, &chng);
  dfsplitStartRow(p);
  dfsplitChangeState(p, 3);
  p->lnLeft++;
  p->lnRight++;
  blob_appendf(p->pOut,"%d\n", p->lnLeft);
  for(i=x=0; i<chng.n; i++){
    int ofst = chng.a[i].iStart1;
    int len = chng.a[i].iLen1;
    if( len ){
      htmlize_to_blob(&p->aCol[0], pX->z+x, ofst - x);
      x = ofst;
      if( chng.a[i].iLen2 ){
        blob_append(&p->aCol[0], "<del class='edit'>", -1);
      }else{
        blob_append(&p->aCol[0], "<del>", 5);
      }
      htmlize_to_blob(&p->aCol[0], pX->z+x, len);
      x += len;
      blob_append(&p->aCol[0], "</del>", 6);
    }
  }
  htmlize_to_blob(&p->aCol[0], pX->z+x,  pX->n - x);
  blob_append_char(&p->aCol[0], '\n');

  blob_append(&p->aCol[1], "|\n", 2);

  blob_appendf(&p->aCol[2],"%d\n", p->lnRight);
  for(i=x=0; i<chng.n; i++){
    int ofst = chng.a[i].iStart2;
    int len = chng.a[i].iLen2;
    if( len ){
      htmlize_to_blob(&p->aCol[3], pY->z+x, ofst - x);
      x = ofst;
      if( chng.a[i].iLen1 ){
        blob_append(&p->aCol[3], "<ins class='edit'>", -1);
      }else{
        blob_append(&p->aCol[3], "<ins>", 5);
      }
      htmlize_to_blob(&p->aCol[3], pY->z+x, len);
      x += len;
      blob_append(&p->aCol[3], "</ins>", 6);
    }
  }
  htmlize_to_blob(&p->aCol[3], pY->z+x,  pY->n - x);
  blob_append_char(&p->aCol[3], '\n');
}
static void dfsplitEnd(DiffBuilder *p){
  dfsplitFinishRow(p);
  blob_append(p->pOut, "</table>\n",-1);
  fossil_free(p);
}
static DiffBuilder *dfsplitNew(Blob *pOut, DiffConfig *pCfg){
  DiffBuilder *p = fossil_malloc(sizeof(*p));
  p->xSkip = dfsplitSkip;
  p->xCommon = dfsplitCommon;
  p->xInsert = dfsplitInsert;
  p->xDelete = dfsplitDelete;
  p->xReplace = dfsplitReplace;
  p->xEdit = dfsplitEdit;
  p->xEnd = dfsplitEnd;
  p->lnLeft = p->lnRight = 0;
  p->eState = 0;
  p->pOut = pOut;
  if( pCfg->zLeftHash ){
    blob_appendf(pOut,
      "<table class=\"diff splitdiff\" data-lefthash=\"%s\">\n",
      pCfg->zLeftHash);
  }else{
    blob_append(pOut, "<table class=\"diff splitdiff\">\n", -1);
  }
  blob_init(&p->aCol[0], 0, 0);
  blob_init(&p->aCol[1], 0, 0);
  blob_init(&p->aCol[2], 0, 0);
  blob_init(&p->aCol[3], 0, 0);
  blob_init(&p->aCol[4], 0, 0);
  p->pCfg = pCfg;
  return p;
}

/************************* DiffBuilderSbs  ******************************/
/* This formatter creates a side-by-side diff in text.
*/
static void dfsbsSkip(DiffBuilder *p, unsigned int n, int isFinal){
  if( (p->lnLeft || p->lnRight) && !isFinal ){
    blob_appendf(p->pOut, "%.*c\n", p->width*2 + 16, '.');
  }
  p->lnLeft += n;
  p->lnRight += n;
}

/*
** Append at least iMin characters (not bytes) and at most iMax characters
** from pX onto the into of p.
**
** This comment contains multibyte unicode characters (ü, Æ, ð) in order
** to test the ability of the diff code to handle such characters.
*/
static void sbs_append_chars(Blob *p, int iMin, int iMax, const DLine *pX){
  int i;
  const char *z = pX->z;
  for(i=0; i<iMax && i<pX->n; i++){
    char c = z[i];
    blob_append_char(p, c);
    if( (c&0xc0)==0x80 ){ iMin++; iMax++; }
  }
  while( i<iMin ){
    blob_append_char(p, ' ');
    i++;
  }
}

static void dfsbsCommon(DiffBuilder *p, const DLine *pLine){
  p->lnLeft++;
  p->lnRight++;
  blob_appendf(p->pOut,"%6u ", p->lnLeft);
  sbs_append_chars(p->pOut, p->width, p->width, pLine);
  blob_appendf(p->pOut,"   %6u ", p->lnRight);
  sbs_append_chars(p->pOut, 0, p->width, pLine);
  blob_append_char(p->pOut, '\n');
}
static void dfsbsInsert(DiffBuilder *p, const DLine *pLine){
  p->lnRight++;
  blob_appendf(p->pOut,"%6s %*s > %6u ",
     "", p->width, "", p->lnRight);
  sbs_append_chars(p->pOut, 0, p->width, pLine);
  blob_append_char(p->pOut, '\n');
}
static void dfsbsDelete(DiffBuilder *p, const DLine *pLine){
  p->lnLeft++;
  blob_appendf(p->pOut,"%6u ", p->lnLeft);
  sbs_append_chars(p->pOut, p->width, p->width, pLine);
  blob_append(p->pOut," <\n", 3);
}
static void dfsbsEdit(DiffBuilder *p, const DLine *pX, const DLine *pY){
  p->lnLeft++;
  p->lnRight++;
  blob_appendf(p->pOut,"%6u ", p->lnLeft);
  sbs_append_chars(p->pOut, p->width, p->width, pX);
  blob_appendf(p->pOut, " | %6u ", p->lnRight);
  sbs_append_chars(p->pOut, 0, p->width, pY);
  blob_append_char(p->pOut, '\n');
}
static void dfsbsEnd(DiffBuilder *p){
  fossil_free(p);
}
static DiffBuilder *dfsbsNew(Blob *pOut, DiffConfig *pCfg){
  DiffBuilder *p = fossil_malloc(sizeof(*p));
  p->xSkip = dfsbsSkip;
  p->xCommon = dfsbsCommon;
  p->xInsert = dfsbsInsert;
  p->xDelete = dfsbsDelete;
  p->xReplace = dfsbsEdit;
  p->xEdit = dfsbsEdit;
  p->xEnd = dfsbsEnd;
  p->lnLeft = p->lnRight = 0;
  p->width = diff_width(pCfg);
  p->pOut = pOut;
  return p;
}
/****************************************************************************/
/*
** Return the number between 0 and 100 that is smaller the closer pA and
** pB match.  Return 0 for a perfect match.  Return 100 if pA and pB are
** completely different.
**
** The current algorithm is as follows:
**
** (1) Remove leading and trailing whitespace.
** (2) Truncate both strings to at most 250 characters
** (3) If the two strings have a common prefix, measure that prefix
** (4) Find the length of the longest common subsequence that is
**     at least 150% longer than the common prefix.
** (5) Longer common subsequences yield lower scores.
*/
static int match_dline(const DLine *pA, const DLine *pB){
  const char *zA;            /* Left string */
  const char *zB;            /* right string */
  int nA;                    /* Bytes in zA[] */
  int nB;                    /* Bytes in zB[] */
  int nMin;
  int nPrefix;
  int avg;                   /* Average length of A and B */
  int i, j, k;               /* Loop counters */
  int best = 0;              /* Longest match found so far */
  int score;                 /* Final score.  0..100 */
  unsigned char c;           /* Character being examined */
  unsigned char aFirst[256]; /* aFirst[X] = index in zB[] of first char X */
  unsigned char aNext[252];  /* aNext[i] = index in zB[] of next zB[i] char */

  zA = pA->z;
  zB = pB->z;
  nA = pA->n;
  nB = pB->n;
  while( nA>0 && (unsigned char)zA[0]<=' ' ){ nA--; zA++; }
  while( nA>0 && (unsigned char)zA[nA-1]<=' ' ){ nA--; }
  while( nB>0 && (unsigned char)zB[0]<=' ' ){ nB--; zB++; }
  while( nB>0 && (unsigned char)zB[nB-1]<=' ' ){ nB--; }
  if( nA>250 ) nA = 250;
  if( nB>250 ) nB = 250;
  avg = (nA+nB)/2;
  if( avg==0 ) return 0;
  nMin = nA;
  if( nB<nMin ) nMin = nB;
  if( nMin==0 ) return 68;
  for(nPrefix=0; nPrefix<nMin && zA[nPrefix]==zB[nPrefix]; nPrefix++){}
  best = 0;
  if( nPrefix>5 && nPrefix>nMin/2 ){
    best = nPrefix*3/2;
    if( best>=avg - 2 ) best = avg - 2;
  }
  if( nA==nB && memcmp(zA, zB, nA)==0 ) return 0;
  memset(aFirst, 0xff, sizeof(aFirst));
  zA--; zB--;   /* Make both zA[] and zB[] 1-indexed */
  for(i=nB; i>0; i--){
    c = (unsigned char)zB[i];
    aNext[i] = aFirst[c];
    aFirst[c] = i;
  }

  for(i=1; i<=nA-best; i++){
    c = (unsigned char)zA[i];
    for(j=aFirst[c]; j<nB-best && memcmp(&zA[i],&zB[j],best)==0; j = aNext[j]){
      int limit = minInt(nA-i, nB-j);
      for(k=best; k<=limit && zA[k+i]==zB[k+j]; k++){}
      if( k>best ) best = k;
    }
  }
  score = (best>=avg) ? 0 : (avg - best)*100/avg;

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

  /* Return the result */
  return score;
}

/*
** COMMAND:  test-line-match
** Usage: %fossil test-line-match STRING1 STRING2
**
** Return a score from 0 to 100 that is how similar STRING1 is to
** STRING2.  Smaller numbers mean more similar.  0 is an exact match.
**
** This command is used to test to match_dline() function in the
** internal Fossil diff logic.
*/
void test_dline_match(void){
  DLine a, b;
  int x;
  if( g.argc!=4 ) usage("STRING1 STRING2");
  a.z = g.argv[2];
  a.n = (int)strlen(a.z);
  b.z = g.argv[3];
  b.n = (int)strlen(b.z);
  x = match_dline(&a, &b);
  fossil_print("%d\n", x);
}

/*
** The threshold at which diffBlockAlignment transitions from the
** O(N*N) Wagner minimum-edit-distance algorithm to a less process
** O(NlogN) divide-and-conquer approach.
*/
#define DIFF_ALIGN_MX  1225

/*
** There is a change block in which nLeft lines of text on the left are
** converted into nRight lines of text on the right.  This routine computes
** how the lines on the left line up with the lines on the right.
**
** The return value is a buffer of unsigned characters, obtained from
** fossil_malloc().  (The caller needs to free the return value using
** fossil_free().)  Entries in the returned array have values as follows:
**
**    1.  Delete the next line of pLeft.
**    2.  Insert the next line of pRight.
**    3.  The next line of pLeft changes into the next line of pRight.
**    4.  Delete one line from pLeft and add one line to pRight.
**


** The length of the returned array will be at most nLeft+nRight bytes.
** If the first bytes is 4,  that means we could not compute reasonable
** alignment between the two blocks.
**
** Algorithm:  Wagner's minimum edit-distance algorithm, modified by
** adding a cost to each match based on how well the two rows match
** each other.  Insertion and deletion costs are 50.  Match costs
** are between 0 and 100 where 0 is a perfect match 100 is a complete
** mismatch.
*/
static unsigned char *diffBlockAlignment(
  const DLine *aLeft, int nLeft,     /* Text on the left */
  const DLine *aRight, int nRight,   /* Text on the right */
  DiffConfig *pCfg,                  /* Configuration options */
  int *pNResult                      /* OUTPUT: Bytes of result */
){
  int i, j, k;                 /* Loop counters */
  int *a;                      /* One row of the Wagner matrix */
  int *pToFree;                /* Space that needs to be freed */
  unsigned char *aM;           /* Wagner result matrix */
  int nMatch, iMatch;          /* Number of matching lines and match score */


  int aBuf[100];               /* Stack space for a[] if nRight not to big */


  if( nLeft==0 ){
    aM = fossil_malloc( nRight + 2 );
    memset(aM, 2, nRight);
    *pNResult = nRight;
    return aM;
  }
  if( nRight==0 ){
    aM = fossil_malloc( nLeft + 2 );
    memset(aM, 1, nLeft);
    *pNResult = nLeft;
    return aM;
  }

  /* For large alignments, use a divide and conquer algorithm that is
  ** O(NlogN).  The result is not as precise, but this whole thing is an
  ** approximation anyhow, and the faster response time is an acceptable
  ** trade-off for reduced precision.
  */
  if( nLeft*nRight>DIFF_ALIGN_MX && (pCfg->diffFlags & DIFF_SLOW_SBS)==0 ){
    const DLine *aSmall;   /* The smaller of aLeft and aRight */
    const DLine *aBig;     /* The larger of aLeft and aRight */
    int nSmall, nBig;      /* Size of aSmall and aBig.  nSmall<=nBig */
    int iDivSmall, iDivBig;  /* Divider point for aSmall and aBig */
    int iDivLeft, iDivRight; /* Divider point for aLeft and aRight */
    unsigned char *a1, *a2;  /* Results of the alignments on two halves */
    int n1, n2;              /* Number of entries in a1 and a2 */
    int score, bestScore;    /* Score and best score seen so far */
    if( nLeft>nRight ){
      aSmall = aRight;
      nSmall = nRight;
      aBig = aLeft;
      nBig = nLeft;
    }else{
      aSmall = aLeft;
      nSmall = nLeft;
      aBig = aRight;
      nBig = nRight;
    }


    iDivBig = nBig/2;
    iDivSmall = nSmall/2;
    bestScore = 10000;
    for(i=0; i<nSmall; i++){
      score = match_dline(aBig+iDivBig, aSmall+i) + abs(i-nSmall/2)*2;
      if( score<bestScore ){
        bestScore = score;
        iDivSmall = i;
      }
    }
    if( aSmall==aRight ){
      iDivRight = iDivSmall;
      iDivLeft = iDivBig;
    }else{
      iDivRight = iDivBig;
      iDivLeft = iDivSmall;
    }
    a1 = diffBlockAlignment(aLeft,iDivLeft,aRight,iDivRight,pCfg,&n1);
    a2 = diffBlockAlignment(aLeft+iDivLeft, nLeft-iDivLeft,
                            aRight+iDivRight, nRight-iDivRight,
                            pCfg, &n2);
    a1 = fossil_realloc(a1, n1+n2 );
    memcpy(a1+n1,a2,n2);
    fossil_free(a2);
    *pNResult = n1+n2;
    return a1;
  }

  /* If we reach this point, we will be doing an O(N*N) Wagner minimum
  ** edit distance to compute the alignment.
  */
  if( nRight < count(aBuf)-1 ){
    pToFree = 0;
    a = aBuf;
  }else{
    a = pToFree = fossil_malloc( sizeof(a[0])*(nRight+1) );
  }
  aM = fossil_malloc( (nLeft+1)*(nRight+1) );


  /* Compute the best alignment */
  for(i=0; i<=nRight; i++){
    aM[i] = 2;
    a[i] = i*50;
  }
  aM[0] = 0;
  for(j=1; j<=nLeft; j++){
    int p = a[0];
    a[0] = p+50;
    aM[j*(nRight+1)] = 1;
    for(i=1; i<=nRight; i++){
      int m = a[i-1]+50;
      int d = 2;
      if( m>a[i]+50 ){
        m = a[i]+50;
        d = 1;
      }
      if( m>p ){
        int score = match_dline(&aLeft[j-1], &aRight[i-1]);
        if( (score<=90 || (i<j+1 && i>j-1)) && m>p+score ){
          m = p+score;
          d = 3 | score*4;
        }
      }
      p = a[i];
      a[i] = m;
      aM[j*(nRight+1)+i] = d;
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174




1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186

1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261

1262
1263
1264
1265
1266
1267
1268
    }
    k--;
    aM[k] = aM[j*(nRight+1)+i];
  }
  k++;
  i = (nRight+1)*(nLeft+1) - k;
  memmove(aM, &aM[k], i);

  /* If:
  **   (1) the alignment is more than 25% longer than the longest side, and
  **   (2) the average match cost exceeds 15
  ** Then this is probably an alignment that will be difficult for humans
  ** to read.  So instead, just show all of the right side inserted followed
  ** by all of the left side deleted.
  **
  ** The coefficients for conditions (1) and (2) above are determined by
  ** experimentation.
  */
  mxLen = nLeft>nRight ? nLeft : nRight;
  if( i*4>mxLen*5 && (nMatch==0 || iMatch/nMatch>15) ){
    memset(aM, 4, mnLen);
    if( nLeft>mnLen )  memset(aM+mnLen, 1, nLeft-mnLen);
    if( nRight>mnLen ) memset(aM+mnLen, 2, nRight-mnLen);
  }

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

/*
** R[] is an array of six integer, two COPY/DELETE/INSERT triples for a
** pair of adjacent differences.  Return true if the gap between these
** two differences is so small that they should be rendered as a single
** edit.
*/
static int smallGap(int *R){




  return R[3]<=2 || R[3]<=(R[1]+R[2]+R[4]+R[5])/8;
}

/*
** Given a diff context in which the aEdit[] array has been filled
** in, compute a side-by-side diff into pOut.
*/
static void sbsDiff(
  DContext *p,       /* The computed diff */
  Blob *pOut,        /* Write the results here */
  ReCompiled *pRe,   /* Only show changes that match this regex */
  u64 diffFlags      /* Flags controlling the diff */

){
  DLine *A;     /* Left side of the diff */
  DLine *B;     /* Right side of the diff */
  int a = 0;    /* Index of next line in A[] */
  int b = 0;    /* Index of next line in B[] */
  int *R;       /* Array of COPY/DELETE/INSERT triples */
  int r;        /* Index into R[] */
  int nr;       /* Number of COPY/DELETE/INSERT triples to process */
  int mxr;      /* Maximum value for r */
  int na, nb;   /* Number of lines shown from A and B */
  int i, j;     /* Loop counters */
  int m, ma, mb;/* Number of lines to output */
  int skip;     /* Number of lines to skip */
  static int nChunk = 0; /* Number of chunks of diff output seen so far */
  SbsLine s;    /* Output line buffer */
  int nContext; /* Lines of context above and below each change */
  int showDivider = 0;  /* True to show the divider */
  Blob aCols[5]; /* Array of column blobs */

  memset(&s, 0, sizeof(s));
  s.width = diff_width(diffFlags);
  nContext = diff_context_lines(diffFlags);
  s.escHtml = (diffFlags & DIFF_HTML)!=0;
  if( s.escHtml ){
    for(i=SBS_LNA; i<=SBS_TXTB; i++){
      blob_zero(&aCols[i]);
      s.apCols[i] = &aCols[i];
    }
  }else{
    for(i=SBS_LNA; i<=SBS_TXTB; i++){
      s.apCols[i] = pOut;
    }
  }
  s.pRe = pRe;
  s.iStart = -1;
  s.iStart2 = 0;
  s.iEnd = -1;
  A = p->aFrom;
  B = p->aTo;
  R = p->aEdit;
  mxr = p->nEdit;
  while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; }

  for(r=0; r<mxr; r += 3*nr){
    /* Figure out how many triples to show in a single block */
    for(nr=1; R[r+nr*3]>0 && R[r+nr*3]<nContext*2; nr++){}
    /* printf("r=%d nr=%d\n", r, nr); */

    /* If there is a regex, skip this block (generate no diff output)
    ** if the regex matches or does not match both insert and delete.
    ** Only display the block if one side matches but the other side does
    ** not.
    */
    if( pRe ){
      int hideBlock = 1;
      int xa = a, xb = b;
      for(i=0; hideBlock && i<nr; i++){
        int c1, c2;
        xa += R[r+i*3];
        xb += R[r+i*3];
        c1 = re_dline_match(pRe, &A[xa], R[r+i*3+1]);
        c2 = re_dline_match(pRe, &B[xb], R[r+i*3+2]);
        hideBlock = c1==c2;
        xa += R[r+i*3+1];
        xb += R[r+i*3+2];
      }
      if( hideBlock ){
        a = xa;
        b = xb;
        continue;
      }
    }

    /* For the current block comprising nr triples, figure out
    ** how many lines of A and B are to be displayed

    */
    if( R[r]>nContext ){
      na = nb = nContext;
      skip = R[r] - nContext;
    }else{
      na = nb = R[r];
      skip = 0;







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












|
>
>
>
>
|



<
|

|
|
|
<
<
>

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

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









<






|






|
|











<
|
>







1991
1992
1993
1994
1995
1996
1997
1998
















1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019

2020
2021
2022
2023
2024


2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038


2039


2040


2041















2042
2043
2044
2045
2046
2047
2048
2049
2050

2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076

2077
2078
2079
2080
2081
2082
2083
2084
2085
    }
    k--;
    aM[k] = aM[j*(nRight+1)+i];
  }
  k++;
  i = (nRight+1)*(nLeft+1) - k;
  memmove(aM, &aM[k], i);
  *pNResult = i;

















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

/*
** R[] is an array of six integer, two COPY/DELETE/INSERT triples for a
** pair of adjacent differences.  Return true if the gap between these
** two differences is so small that they should be rendered as a single
** edit.
*/
static int smallGap(const int *R, int ma, int mb){
  int m = R[3];
  ma += R[4] + m;
  mb += R[5] + m;
  if( ma*mb>DIFF_ALIGN_MX ) return 0;
  return m<=2 || m<=(R[1]+R[2]+R[4]+R[5])/8;
}

/*

** Format a diff using a DiffBuilder object
*/
static void formatDiff(
  DContext *p,           /* The computed diff */
  DiffConfig *pCfg,      /* Configuration options */


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


  unsigned int nContext; /* Lines of context above and below each change */





  nContext = diff_context_lines(pCfg);















  A = p->aFrom;
  B = p->aTo;
  R = p->aEdit;
  mxr = p->nEdit;
  while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; }

  for(r=0; r<mxr; r += 3*nr){
    /* Figure out how many triples to show in a single block */
    for(nr=1; R[r+nr*3]>0 && R[r+nr*3]<nContext*2; nr++){}


    /* If there is a regex, skip this block (generate no diff output)
    ** if the regex matches or does not match both insert and delete.
    ** Only display the block if one side matches but the other side does
    ** not.
    */
    if( pCfg->pRe ){
      int hideBlock = 1;
      int xa = a, xb = b;
      for(i=0; hideBlock && i<nr; i++){
        int c1, c2;
        xa += R[r+i*3];
        xb += R[r+i*3];
        c1 = re_dline_match(pCfg->pRe, &A[xa], R[r+i*3+1]);
        c2 = re_dline_match(pCfg->pRe, &B[xb], R[r+i*3+2]);
        hideBlock = c1==c2;
        xa += R[r+i*3+1];
        xb += R[r+i*3+2];
      }
      if( hideBlock ){
        a = xa;
        b = xb;
        continue;
      }
    }


    /* Figure out how many lines of A and B are to be displayed
    ** for this change block.
    */
    if( R[r]>nContext ){
      na = nb = nContext;
      skip = R[r] - nContext;
    }else{
      na = nb = R[r];
      skip = 0;
1279
1280
1281
1282
1283
1284
1285
1286



1287
1288
1289
1290
1291
1292
1293

1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323

1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337

1338

1339

1340

1341
1342
1343
1344
1345
1346
1347




1348

1349
1350
1351


1352
1353



1354

1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389

1390

1391
1392


1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427

1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
      nb += R[r+nr*3];
    }
    for(i=1; i<nr; i++){
      na += R[r+i*3];
      nb += R[r+i*3];
    }

    /* Draw the separator between blocks */



    if( showDivider ){
      if( s.escHtml ){
        char zLn[10];
        sqlite3_snprintf(sizeof(zLn), zLn, "%d", a+skip+1);
        sbsWriteSep(&s, strlen(zLn), SBS_LNA);
        sbsWriteSep(&s, s.width, SBS_TXTA);
        sbsWriteSep(&s, 0, SBS_MKR);

        sqlite3_snprintf(sizeof(zLn), zLn, "%d", b+skip+1);
        sbsWriteSep(&s, strlen(zLn), SBS_LNB);
        sbsWriteSep(&s, s.width, SBS_TXTB);
      }else{
        blob_appendf(pOut, "%.*c\n", s.width*2+16, '.');
      }
    }
    showDivider = 1;
    nChunk++;
    if( s.escHtml ){
      blob_appendf(s.apCols[SBS_LNA], "<span id=\"chunk%d\"></span>", nChunk);
    }

    /* Show the initial common area */
    a += skip;
    b += skip;
    m = R[r] - skip;
    for(j=0; j<m; j++){
      sbsWriteLineno(&s, a+j, SBS_LNA);
      s.iStart = s.iEnd = -1;
      sbsWriteText(&s, &A[a+j], SBS_TXTA);
      sbsWriteMarker(&s, "   ", "");
      sbsWriteLineno(&s, b+j, SBS_LNB);
      sbsWriteText(&s, &B[b+j], SBS_TXTB);
    }
    a += m;
    b += m;

    /* Show the differences */
    for(i=0; i<nr; i++){

      unsigned char *alignment;
      ma = R[r+i*3+1];   /* Lines on left but not on right */
      mb = R[r+i*3+2];   /* Lines on right but not on left */

      /* If the gap between the current diff and then next diff within the
      ** same block is not too great, then render them as if they are a
      ** single diff. */
      while( i<nr-1 && smallGap(&R[r+i*3]) ){
        i++;
        m = R[r+i*3];
        ma += R[r+i*3+1] + m;
        mb += R[r+i*3+2] + m;
      }


      alignment = sbsAlignment(&A[a], ma, &B[b], mb, diffFlags);

      for(j=0; ma+mb>0; j++){

        if( alignment[j]==1 ){

          /* Delete one line from the left */
          sbsWriteLineno(&s, a, SBS_LNA);
          s.iStart = 0;
          s.zStart = "<span class=\"diffrm\">";
          s.iEnd = LENGTH(&A[a]);
          sbsWriteText(&s, &A[a], SBS_TXTA);
          sbsWriteMarker(&s, " <", "&lt;");




          sbsWriteNewlines(&s);

          assert( ma>0 );
          ma--;
          a++;


        }else if( alignment[j]==3 ){
          /* The left line is changed into the right line */



          sbsWriteLineChange(&s, &A[a], a, &B[b], b);

          assert( ma>0 && mb>0 );
          ma--;
          mb--;
          a++;
          b++;
        }else if( alignment[j]==2 ){
          /* Insert one line on the right */
          if( !s.escHtml ){
            sbsWriteSpace(&s, s.width + 7, SBS_TXTA);
          }
          sbsWriteMarker(&s, " > ", "&gt;");
          sbsWriteLineno(&s, b, SBS_LNB);
          s.iStart = 0;
          s.zStart = "<span class=\"diffadd\">";
          s.iEnd = LENGTH(&B[b]);
          sbsWriteText(&s, &B[b], SBS_TXTB);
          assert( mb>0 );
          mb--;
          b++;
        }else{
          /* Delete from the left and insert on the right */
          sbsWriteLineno(&s, a, SBS_LNA);
          s.iStart = 0;
          s.zStart = "<span class=\"diffrm\">";
          s.iEnd = LENGTH(&A[a]);
          sbsWriteText(&s, &A[a], SBS_TXTA);
          sbsWriteMarker(&s, " | ", "|");
          sbsWriteLineno(&s, b, SBS_LNB);
          s.iStart = 0;
          s.zStart = "<span class=\"diffadd\">";
          s.iEnd = LENGTH(&B[b]);
          sbsWriteText(&s, &B[b], SBS_TXTB);
          ma--;
          mb--;
          a++;

          b++;

        }
      }


      fossil_free(alignment);
      if( i<nr-1 ){
        m = R[r+i*3+3];
        for(j=0; j<m; j++){
          sbsWriteLineno(&s, a+j, SBS_LNA);
          s.iStart = s.iEnd = -1;
          sbsWriteText(&s, &A[a+j], SBS_TXTA);
          sbsWriteMarker(&s, "   ", "");
          sbsWriteLineno(&s, b+j, SBS_LNB);
          sbsWriteText(&s, &B[b+j], SBS_TXTB);
        }
        b += m;
        a += m;
      }
    }

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

  if( s.escHtml && blob_size(s.apCols[SBS_LNA])>0 ){
    blob_append(pOut, "<table class=\"sbsdiffcols\"><tr>\n", -1);
    for(i=SBS_LNA; i<=SBS_TXTB; i++){
      sbsWriteColumn(pOut, s.apCols[i], i);
      blob_reset(s.apCols[i]);

    }
    blob_append(pOut, "</tr></table>\n", -1);
  }
}

/*
** Compute the optimal longest common subsequence (LCS) using an
** exhaustive search.  This version of the LCS is only used for
** shorter input strings since runtime is O(N*N) where N is the
** input string length.
*/







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

<
<
|
<
<
<






>




|
|
|
|






>
|
>

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

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




<
<
|
<
<
<










|
<
<
|
<
<
<


|
<
<
<
<
<
>
|
|
|
|







2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108

2109


2110
2111
2112

2113


2114
2115
2116



2117
2118




2119


2120



2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149



2150

2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175



2176









2177
2178




2179






2180

2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192


2193



2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204


2205



2206
2207
2208





2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
      nb += R[r+nr*3];
    }
    for(i=1; i<nr; i++){
      na += R[r+i*3];
      nb += R[r+i*3];
    }

    /* Show the initial common area */
    a += skip;
    b += skip;
    m = R[r] - skip;
    if( r ) skip -= nContext;
    if( skip>0 ){

      if( skip<nContext ){


        /* If the amount to skip is less that the context band, then
        ** go ahead and show the skip band as it is not worth eliding */
        for(j=0; j<skip; j++){

          pBuilder->xCommon(pBuilder, &A[a+j-skip]);


        }
      }else{
        pBuilder->xSkip(pBuilder, skip, 0);



      }
    }




    for(j=0; j<m; j++){


      pBuilder->xCommon(pBuilder, &A[a+j]);



    }
    a += m;
    b += m;

    /* Show the differences */
    for(i=0; i<nr; i++){
      int nAlign;
      unsigned char *alignment;
      ma = R[r+i*3+1];   /* Lines on left but not on right */
      mb = R[r+i*3+2];   /* Lines on right but not on left */

      /* Try merging the current block with subsequent blocks, if the
      ** subsequent blocks are nearby and there result isn't too big.
      */
      while( i<nr-1 && smallGap(&R[r+i*3],ma,mb) ){
        i++;
        m = R[r+i*3];
        ma += R[r+i*3+1] + m;
        mb += R[r+i*3+2] + m;
      }

      /* Try to find an alignment for the lines within this one block */
      alignment = diffBlockAlignment(&A[a], ma, &B[b], mb, pCfg, &nAlign);

      for(j=0; ma+mb>0; j++){
        assert( j<nAlign );
        switch( alignment[j] ){
          case 1: {
            /* Delete one line from the left */



            pBuilder->xDelete(pBuilder, &A[a]);

            ma--;
            a++;
            break;
          }
          case 2: {
            /* Insert one line on the right */
            pBuilder->xInsert(pBuilder, &B[b]);
            assert( mb>0 );
            mb--;
            b++;
            break;
          }
          case 3: {
            /* The left line is changed into the right line */
            if( p->xDiffer(&A[a], &B[b])==0 ){
              pBuilder->xCommon(pBuilder, &A[a]);
            }else{
              pBuilder->xEdit(pBuilder, &A[a], &B[b]);
            }
            assert( ma>0 && mb>0 );
            ma--;
            mb--;
            a++;
            b++;
            break;



          }









          case 4: {
            /* Delete from left then separately insert on the right */




            pBuilder->xReplace(pBuilder, &A[a], &B[b]);






            ma--;

            a++;
            mb--;
            b++;
            break;
          }
        }
      }
      assert( nAlign==j );
      fossil_free(alignment);
      if( i<nr-1 ){
        m = R[r+i*3+3];
        for(j=0; j<m; j++){


          pBuilder->xCommon(pBuilder, &A[a+j]);



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

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


      pBuilder->xCommon(pBuilder, &A[a+j]);



    }
  }
  if( R[r]>nContext ){





    pBuilder->xSkip(pBuilder, R[r] - nContext, 1);
  }
  pBuilder->xEnd(pBuilder);
}


/*
** Compute the optimal longest common subsequence (LCS) using an
** exhaustive search.  This version of the LCS is only used for
** shorter input strings since runtime is O(N*N) where N is the
** input string length.
*/
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
){
  int i, j, k;               /* Loop counters */
  int n;                     /* Loop limit */
  DLine *pA, *pB;            /* Pointers to lines */
  int iSX, iSY, iEX, iEY;    /* Current match */
  int skew = 0;              /* How lopsided is the match */
  int dist = 0;              /* Distance of match from center */
  int mid;                   /* Center of the span */
  int iSXb, iSYb, iEXb, iEYb;   /* Best match so far */
  int iSXp, iSYp, iEXp, iEYp;   /* Previous match */
  sqlite3_int64 bestScore;      /* Best score so far */
  sqlite3_int64 score;          /* Score for current candidate LCS */
  int span;                     /* combined width of the input sequences */

  span = (iE1 - iS1) + (iE2 - iS2);







|







2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
){
  int i, j, k;               /* Loop counters */
  int n;                     /* Loop limit */
  DLine *pA, *pB;            /* Pointers to lines */
  int iSX, iSY, iEX, iEY;    /* Current match */
  int skew = 0;              /* How lopsided is the match */
  int dist = 0;              /* Distance of match from center */
  int mid;                   /* Center of the chng */
  int iSXb, iSYb, iEXb, iEYb;   /* Best match so far */
  int iSXp, iSYp, iEXp, iEYp;   /* Previous match */
  sqlite3_int64 bestScore;      /* Best score so far */
  sqlite3_int64 score;          /* Score for current candidate LCS */
  int span;                     /* combined width of the input sequences */

  span = (iE1 - iS1) + (iE2 - iS2);
1813
1814
1815
1816
1817
1818
1819
1820


1821
1822


1823
1824
1825



1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
    lnFrom += del;
    lnTo += ins;
  }
}

/*
** Extract the number of lines of context from diffFlags.  Supply an
** appropriate default if no context width is specified.


*/
int diff_context_lines(u64 diffFlags){


  int n = diffFlags & DIFF_CONTEXT_MASK;
  if( n==0 && (diffFlags & DIFF_CONTEXT_EX)==0 ) n = 5;
  return n;



}

/*
** Extract the width of columns for side-by-side diff.  Supply an
** appropriate default if no width is given.
**
** Calculate the default automatically, based on terminal's current width:
**   term-width = 2*diff-col + diff-marker + 1
**   diff-col = lineno + lmargin + text-width + rmargin
**
**   text-width = (term-width - diff-marker - 1)/2 - lineno - lmargin - rmargin
*/
int diff_width(u64 diffFlags){
  int w = (diffFlags & DIFF_WIDTH_MASK)/(DIFF_CONTEXT_MASK+1);
  if( w==0 ){
    static struct {
      unsigned int lineno, lmargin, text, rmargin, marker;
    } sbsW = { 5, 2, 0, 0, 3 };
    const unsigned int wMin = 24, wMax = 132;
    unsigned int tw = terminal_get_width(80);
    unsigned int twMin =







|
>
>

|
>
>
|
|
|
>
>
>












|
|







2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
    lnFrom += del;
    lnTo += ins;
  }
}

/*
** Extract the number of lines of context from diffFlags.  Supply an
** appropriate default if no context width is specified. If pCfg is
** NULL then the compile-time default is used (which gets propagated
** to JS-side state by certain pages).
*/
int diff_context_lines(DiffConfig *pCfg){
  const int dflt = 5;
  if(pCfg!=0){
    int n = pCfg->nContext;
    if( n<=0 && (pCfg->diffFlags & DIFF_CONTEXT_EX)==0 ) n = dflt;
    return n;
  }else{
    return dflt;
  }
}

/*
** Extract the width of columns for side-by-side diff.  Supply an
** appropriate default if no width is given.
**
** Calculate the default automatically, based on terminal's current width:
**   term-width = 2*diff-col + diff-marker + 1
**   diff-col = lineno + lmargin + text-width + rmargin
**
**   text-width = (term-width - diff-marker - 1)/2 - lineno - lmargin - rmargin
*/
int diff_width(DiffConfig *pCfg){
  int w = pCfg->wColumn;
  if( w==0 ){
    static struct {
      unsigned int lineno, lmargin, text, rmargin, marker;
    } sbsW = { 5, 2, 0, 0, 3 };
    const unsigned int wMin = 24, wMax = 132;
    unsigned int tw = terminal_get_width(80);
    unsigned int twMin =
1868
1869
1870
1871
1872
1873
1874
1875

1876

1877


1878
1879

1880
1881


1882

1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965














1966






1967






1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985


1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006


2007
2008
2009
2010
2011
2012
2013
2014
2015

2016
2017
2018
2019

2020






2021

2022


2023
2024
2025
2026

2027







2028
2029
2030


2031
2032
2033
2034
2035












2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064



2065

2066
2067
2068
2069









2070


2071
2072
2073


2074
2075
2076
2077
2078
2079

2080
2081
2082
2083
2084
2085
2086

2087
2088
2089
2090
2091
2092
2093
2094


2095
2096
2097
2098
2099
2100

2101
2102
2103
2104
2105
2106
2107
2108
    blob_appendf(pOut, "<p class=\"generalError\">%s</p>", msg);
  }else{
    blob_append(pOut, msg, -1);
  }
}

/*
** Generate a report of the differences between files pA and pB.

** If pOut is not NULL then a unified diff is appended there.  It

** is assumed that pOut has already been initialized.  If pOut is


** NULL, then a pointer to an array of integers is returned.
** The integers come in triples.  For each triple,

** the elements are the number of lines copied, the number of
** lines deleted, and the number of lines inserted.  The vector


** is terminated by a triple of all zeros.

**
** This diff utility does not work on binary files.  If a binary
** file is encountered, 0 is returned and pOut is written with
** text "cannot compute difference between binary files".
*/
int *text_diff(
  Blob *pA_Blob,   /* FROM file */
  Blob *pB_Blob,   /* TO file */
  Blob *pOut,      /* Write diff here if not NULL */
  ReCompiled *pRe, /* Only output changes where this Regexp matches */
  u64 diffFlags    /* DIFF_* flags defined above */
){
  int ignoreWs; /* Ignore whitespace */
  DContext c;

  if( diffFlags & DIFF_INVERT ){
    Blob *pTemp = pA_Blob;
    pA_Blob = pB_Blob;
    pB_Blob = pTemp;
  }
  ignoreWs = (diffFlags & DIFF_IGNORE_ALLWS)!=0;
  blob_to_utf8_no_bom(pA_Blob, 0);
  blob_to_utf8_no_bom(pB_Blob, 0);

  /* Prepare the input files */
  memset(&c, 0, sizeof(c));
  if( (diffFlags & DIFF_IGNORE_ALLWS)==DIFF_IGNORE_ALLWS ){
    c.xDiffer = same_dline_ignore_allws;
  }else{
    c.xDiffer = same_dline;
  }
  c.aFrom = break_into_lines(blob_str(pA_Blob), blob_size(pA_Blob),
                             &c.nFrom, diffFlags);
  c.aTo = break_into_lines(blob_str(pB_Blob), blob_size(pB_Blob),
                           &c.nTo, diffFlags);
  if( c.aFrom==0 || c.aTo==0 ){
    fossil_free(c.aFrom);
    fossil_free(c.aTo);
    if( pOut ){
      diff_errmsg(pOut, DIFF_CANNOT_COMPUTE_BINARY, diffFlags);
    }
    return 0;
  }

  /* Compute the difference */
  diff_all(&c);
  if( ignoreWs && c.nEdit==6 && c.aEdit[1]==0 && c.aEdit[2]==0 ){
    fossil_free(c.aFrom);
    fossil_free(c.aTo);
    fossil_free(c.aEdit);
    if( pOut ) diff_errmsg(pOut, DIFF_WHITESPACE_ONLY, diffFlags);
    return 0;
  }
  if( (diffFlags & DIFF_NOTTOOBIG)!=0 ){
    int i, m, n;
    int *a = c.aEdit;
    int mx = c.nEdit;
    for(i=m=n=0; i<mx; i+=3){ m += a[i]; n += a[i+1]+a[i+2]; }
    if( n>10000 ){
      fossil_free(c.aFrom);
      fossil_free(c.aTo);
      fossil_free(c.aEdit);
      if( pOut ) diff_errmsg(pOut, DIFF_TOO_MANY_CHANGES, diffFlags);
      return 0;
    }
  }
  if( (diffFlags & DIFF_NOOPT)==0 ){
    diff_optimize(&c);
  }

  if( pOut ){
    if( diffFlags & DIFF_NUMSTAT ){
      int nDel = 0, nIns = 0, i;
      for(i=0; c.aEdit[i] || c.aEdit[i+1] || c.aEdit[i+2]; i+=3){
        nDel += c.aEdit[i+1];
        nIns += c.aEdit[i+2];
      }
      g.diffCnt[1] += nIns;
      g.diffCnt[2] += nDel;
      if( nIns+nDel ){
        g.diffCnt[0]++;
        blob_appendf(pOut, "%10d %10d", nIns, nDel);
      }














    }else if( diffFlags & DIFF_SIDEBYSIDE ){






      sbsDiff(&c, pOut, pRe, diffFlags);






    }else{
      contextDiff(&c, pOut, pRe, diffFlags);
    }
    fossil_free(c.aFrom);
    fossil_free(c.aTo);
    fossil_free(c.aEdit);
    return 0;
  }else{
    /* If a context diff is not requested, then return the
    ** array of COPY/DELETE/INSERT triples.
    */
    free(c.aFrom);
    free(c.aTo);
    return c.aEdit;
  }
}

/*


** Process diff-related command-line options and return an appropriate
** "diffFlags" integer.
**
**   --brief                    Show filenames only    DIFF_BRIEF
**   -c|--context N             N lines of context.    DIFF_CONTEXT_MASK
**   --html                     Format for HTML        DIFF_HTML
**   --invert                   Invert the diff        DIFF_INVERT
**   -n|--linenum               Show line numbers      DIFF_LINENO
**   --noopt                    Disable optimization   DIFF_NOOPT
**   --numstat                  Show change counts     DIFF_NUMSTAT
**   --strip-trailing-cr        Strip trailing CR      DIFF_STRIP_EOLCR
**   --unified                  Unified diff.          ~DIFF_SIDEBYSIDE
**   -w|--ignore-all-space      Ignore all whitespaces DIFF_IGNORE_ALLWS
**   -W|--width N               N character lines.     DIFF_WIDTH_MASK
**   -y|--side-by-side          Side-by-side diff.     DIFF_SIDEBYSIDE
**   -Z|--ignore-trailing-space Ignore eol-whitespaces DIFF_IGNORE_EOLWS
*/
u64 diff_options(void){
  u64 diffFlags = 0;
  const char *z;
  int f;


  if( find_option("ignore-trailing-space","Z",0)!=0 ){
    diffFlags = DIFF_IGNORE_EOLWS;
  }
  if( find_option("ignore-all-space","w",0)!=0 ){
    diffFlags = DIFF_IGNORE_ALLWS; /* stronger than DIFF_IGNORE_EOLWS */
  }
  if( find_option("strip-trailing-cr",0,0)!=0 ){
    diffFlags |= DIFF_STRIP_EOLCR;
  }

  if( find_option("side-by-side","y",0)!=0 ) diffFlags |= DIFF_SIDEBYSIDE;
  if( find_option("yy",0,0)!=0 ){
    diffFlags |= DIFF_SIDEBYSIDE | DIFF_SLOW_SBS;
  }

  if( find_option("unified",0,0)!=0 ) diffFlags &= ~DIFF_SIDEBYSIDE;






  if( (z = find_option("context","c",1))!=0 && (f = atoi(z))>=0 ){

    if( f > DIFF_CONTEXT_MASK ) f = DIFF_CONTEXT_MASK;


    diffFlags |= f + DIFF_CONTEXT_EX;
  }
  if( (z = find_option("width","W",1))!=0 && (f = atoi(z))>0 ){
    f *= DIFF_CONTEXT_MASK+1;

    if( f > DIFF_WIDTH_MASK ) f = DIFF_CONTEXT_MASK;







    diffFlags |= f;
  }
  if( find_option("html",0,0)!=0 ) diffFlags |= DIFF_HTML;


  if( find_option("linenum","n",0)!=0 ) diffFlags |= DIFF_LINENO;
  if( find_option("noopt",0,0)!=0 ) diffFlags |= DIFF_NOOPT;
  if( find_option("numstat",0,0)!=0 ) diffFlags |= DIFF_NUMSTAT;
  if( find_option("invert",0,0)!=0 ) diffFlags |= DIFF_INVERT;
  if( find_option("brief",0,0)!=0 ) diffFlags |= DIFF_BRIEF;












  return diffFlags;
}

/*
** COMMAND: test-rawdiff
**
** Usage: %fossil test-rawdiff FILE1 FILE2
**
** Show a minimal sequence of Copy/Delete/Insert operations needed to convert
** FILE1 into FILE2.  This command is intended for use in testing and debugging
** the built-in difference engine of Fossil.
*/
void test_rawdiff_cmd(void){
  Blob a, b;
  int r;
  int i;
  int *R;
  u64 diffFlags = diff_options();
  if( g.argc<4 ) usage("FILE1 FILE2 ...");
  blob_read_from_file(&a, g.argv[2], ExtFILE);
  for(i=3; i<g.argc; i++){
    if( i>3 ) fossil_print("-------------------------------\n");
    blob_read_from_file(&b, g.argv[i], ExtFILE);
    R = text_diff(&a, &b, 0, 0, diffFlags);
    for(r=0; R[r] || R[r+1] || R[r+2]; r += 3){
      fossil_print(" copy %4d  delete %4d  insert %4d\n", R[r], R[r+1], R[r+2]);
    }
    /* free(R); */
    blob_reset(&b);



  }

}

/*
** COMMAND: test-diff









**


** Usage: %fossil [options] FILE1 FILE2
**
** Print the difference between two files.  The usual diff options apply.


*/
void test_diff_cmd(void){
  Blob a, b, out;
  u64 diffFlag;
  const char *zRe;           /* Regex filter for diff output */
  ReCompiled *pRe = 0;       /* Regex filter for diff output */


  if( find_option("tk",0,0)!=0 ){
    diff_tk("test-diff", 2);
    return;
  }
  find_option("i",0,0);
  find_option("v",0,0);

  zRe = find_option("regexp","e",1);
  if( zRe ){
    const char *zErr = re_compile(&pRe, zRe, 0);
    if( zErr ) fossil_fatal("regex error: %s", zErr);
  }
  diffFlag = diff_options();
  verify_all_options();
  if( g.argc!=4 ) usage("FILE1 FILE2");


  diff_print_filenames(g.argv[2], g.argv[3], diffFlag, 0);
  blob_read_from_file(&a, g.argv[2], ExtFILE);
  blob_read_from_file(&b, g.argv[3], ExtFILE);
  blob_zero(&out);
  text_diff(&a, &b, &out, pRe, diffFlag);
  blob_write_to_file(&out, "-");

  re_free(pRe);
}

/**************************************************************************
** The basic difference engine is above.  What follows is the annotation
** engine.  Both are in the same file since they share many components.
*/








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









|
<




|




|





|
|

|


|

|




|










|


|








|



|




|











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

|
















>
>



|
|
|
|
|
|
|
|
|
|
|
|
|

|



>
>









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

|
>
>





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




>
>
>
>
>
>
>
>
>

>
>
|

<
>
>

|

<

<
>


|




>


|


<


>
>
|


<
|

>
|







2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689

2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897























2898


2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921

2922
2923
2924
2925
2926

2927

2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941

2942
2943
2944
2945
2946
2947
2948

2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
    blob_appendf(pOut, "<p class=\"generalError\">%s</p>", msg);
  }else{
    blob_append(pOut, msg, -1);
  }
}

/*
** Generate a report of the differences between files pA_Blob and pB_Blob.
**
** If pOut!=NULL then append text to pOut that will be the difference,
** formatted according to flags in diffFlags.  The pOut Blob must have
** already been initialized.
**
** If pOut==NULL then no formatting occurs.  Instead, this routine
** returns a pointer to an array of integers.  The integers come in
** triples.  The elements of each triple are:
**
**   1.  The number of lines to copy
**   2.  The number of lines to delete
**   3.  The number of lines to insert
**
** The return vector is terminated bin a triple of all zeros.  The caller
** should free the returned vector using fossil_free().
**
** This diff utility does not work on binary files.  If a binary
** file is encountered, 0 is returned and pOut is written with
** text "cannot compute difference between binary files".
*/
int *text_diff(
  Blob *pA_Blob,   /* FROM file */
  Blob *pB_Blob,   /* TO file */
  Blob *pOut,      /* Write diff here if not NULL */
  DiffConfig *pCfg /* Configuration options */

){
  int ignoreWs; /* Ignore whitespace */
  DContext c;

  if( pCfg->diffFlags & DIFF_INVERT ){
    Blob *pTemp = pA_Blob;
    pA_Blob = pB_Blob;
    pB_Blob = pTemp;
  }
  ignoreWs = (pCfg->diffFlags & DIFF_IGNORE_ALLWS)!=0;
  blob_to_utf8_no_bom(pA_Blob, 0);
  blob_to_utf8_no_bom(pB_Blob, 0);

  /* Prepare the input files */
  memset(&c, 0, sizeof(c));
  if( (pCfg->diffFlags & DIFF_IGNORE_ALLWS)==DIFF_IGNORE_ALLWS ){
    c.xDiffer = compare_dline_ignore_allws;
  }else{
    c.xDiffer = compare_dline;
  }
  c.aFrom = break_into_lines(blob_str(pA_Blob), blob_size(pA_Blob),
                             &c.nFrom, pCfg->diffFlags);
  c.aTo = break_into_lines(blob_str(pB_Blob), blob_size(pB_Blob),
                           &c.nTo, pCfg->diffFlags);
  if( c.aFrom==0 || c.aTo==0 ){
    fossil_free(c.aFrom);
    fossil_free(c.aTo);
    if( pOut ){
      diff_errmsg(pOut, DIFF_CANNOT_COMPUTE_BINARY, pCfg->diffFlags);
    }
    return 0;
  }

  /* Compute the difference */
  diff_all(&c);
  if( ignoreWs && c.nEdit==6 && c.aEdit[1]==0 && c.aEdit[2]==0 ){
    fossil_free(c.aFrom);
    fossil_free(c.aTo);
    fossil_free(c.aEdit);
    if( pOut ) diff_errmsg(pOut, DIFF_WHITESPACE_ONLY, pCfg->diffFlags);
    return 0;
  }
  if( (pCfg->diffFlags & DIFF_NOTTOOBIG)!=0 ){
    int i, m, n;
    int *a = c.aEdit;
    int mx = c.nEdit;
    for(i=m=n=0; i<mx; i+=3){ m += a[i]; n += a[i+1]+a[i+2]; }
    if( n>10000 ){
      fossil_free(c.aFrom);
      fossil_free(c.aTo);
      fossil_free(c.aEdit);
      if( pOut ) diff_errmsg(pOut, DIFF_TOO_MANY_CHANGES, pCfg->diffFlags);
      return 0;
    }
  }
  if( (pCfg->diffFlags & DIFF_NOOPT)==0 ){
    diff_optimize(&c);
  }

  if( pOut ){
    if( pCfg->diffFlags & DIFF_NUMSTAT ){
      int nDel = 0, nIns = 0, i;
      for(i=0; c.aEdit[i] || c.aEdit[i+1] || c.aEdit[i+2]; i+=3){
        nDel += c.aEdit[i+1];
        nIns += c.aEdit[i+2];
      }
      g.diffCnt[1] += nIns;
      g.diffCnt[2] += nDel;
      if( nIns+nDel ){
        g.diffCnt[0]++;
        blob_appendf(pOut, "%10d %10d", nIns, nDel);
      }
    }else if( pCfg->diffFlags & DIFF_RAW ){
      const int *R = c.aEdit;
      unsigned int r;
      for(r=0; R[r] || R[r+1] || R[r+2]; r += 3){
        blob_appendf(pOut, " copy %6d  delete %6d  insert %6d\n",
                     R[r], R[r+1], R[r+2]);
      }
    }else if( pCfg->diffFlags & DIFF_JSON ){
      DiffBuilder *pBuilder = dfjsonNew(pOut);
      formatDiff(&c, pCfg, pBuilder);
      blob_append_char(pOut, '\n');
    }else if( pCfg->diffFlags & DIFF_TCL ){
      DiffBuilder *pBuilder = dftclNew(pOut);
      formatDiff(&c, pCfg, pBuilder);
    }else if( pCfg->diffFlags & DIFF_SIDEBYSIDE ){
      DiffBuilder *pBuilder;
      if( pCfg->diffFlags & DIFF_HTML ){
        pBuilder = dfsplitNew(pOut, pCfg);
      }else{
        pBuilder = dfsbsNew(pOut, pCfg);
      }
      formatDiff(&c, pCfg, pBuilder);
    }else if( pCfg->diffFlags & DIFF_DEBUG ){
      DiffBuilder *pBuilder = dfdebugNew(pOut);
      formatDiff(&c, pCfg, pBuilder);
    }else if( pCfg->diffFlags & DIFF_HTML ){
      DiffBuilder *pBuilder = dfunifiedNew(pOut, pCfg);
      formatDiff(&c, pCfg, pBuilder);
    }else{
      contextDiff(&c, pOut, pCfg);
    }
    fossil_free(c.aFrom);
    fossil_free(c.aTo);
    fossil_free(c.aEdit);
    return 0;
  }else{
    /* If a context diff is not requested, then return the
    ** array of COPY/DELETE/INSERT triples.
    */
    free(c.aFrom);
    free(c.aTo);
    return c.aEdit;
  }
}

/*
** Initialize the DiffConfig object using command-line options.
**
** Process diff-related command-line options and return an appropriate
** "diffFlags" integer.
**
**   --brief                      Show filenames only        DIFF_BRIEF
**   -c|--context N               N lines of context.        nContext
**   --html                       Format for HTML            DIFF_HTML
**   --invert                     Invert the diff            DIFF_INVERT
**   -n|--linenum                 Show line numbers          DIFF_LINENO
**   --noopt                      Disable optimization       DIFF_NOOPT
**   --numstat                    Show change counts         DIFF_NUMSTAT
**   --strip-trailing-cr          Strip trailing CR          DIFF_STRIP_EOLCR
**   --unified                    Unified diff.              ~DIFF_SIDEBYSIDE
**   -w|--ignore-all-space        Ignore all whitespaces     DIFF_IGNORE_ALLWS
**   -W|--width N                 N character lines.         wColumn
**   -y|--side-by-side            Side-by-side diff.         DIFF_SIDEBYSIDE
**   -Z|--ignore-trailing-space   Ignore eol-whitespaces     DIFF_IGNORE_EOLWS
*/
void diff_options(DiffConfig *pCfg, int isGDiff, int bUnifiedTextOnly){
  u64 diffFlags = 0;
  const char *z;
  int f;

  memset(pCfg, 0, sizeof(*pCfg));
  if( find_option("ignore-trailing-space","Z",0)!=0 ){
    diffFlags = DIFF_IGNORE_EOLWS;
  }
  if( find_option("ignore-all-space","w",0)!=0 ){
    diffFlags = DIFF_IGNORE_ALLWS; /* stronger than DIFF_IGNORE_EOLWS */
  }
  if( find_option("strip-trailing-cr",0,0)!=0 ){
    diffFlags |= DIFF_STRIP_EOLCR;
  }
  if( !bUnifiedTextOnly ){
    if( find_option("side-by-side","y",0)!=0 ) diffFlags |= DIFF_SIDEBYSIDE;
    if( find_option("yy",0,0)!=0 ){
      diffFlags |= DIFF_SIDEBYSIDE | DIFF_SLOW_SBS;
    }
    if( find_option("html",0,0)!=0 ) diffFlags |= DIFF_HTML;
    if( find_option("unified",0,0)!=0 ) diffFlags &= ~DIFF_SIDEBYSIDE;
    if( find_option("webpage",0,0)!=0 ){
      diffFlags |= DIFF_HTML|DIFF_WEBPAGE|DIFF_LINENO;
    }
    if( find_option("browser","b",0)!=0 ){
      diffFlags |= DIFF_HTML|DIFF_WEBPAGE|DIFF_LINENO|DIFF_BROWSER;
    }
    if( find_option("by",0,0)!=0 ){
      diffFlags |= DIFF_HTML|DIFF_WEBPAGE|DIFF_LINENO|DIFF_BROWSER
                     |DIFF_SIDEBYSIDE;
    }
    if( find_option("json",0,0)!=0 ){
      diffFlags |= DIFF_JSON;
    }
    if( find_option("tcl",0,0)!=0 ){
      diffFlags |= DIFF_TCL;
    }

    /* Undocumented and unsupported flags used for development
    ** debugging and analysis: */
    if( find_option("debug",0,0)!=0 ) diffFlags |= DIFF_DEBUG;
    if( find_option("raw",0,0)!=0 )   diffFlags |= DIFF_RAW;
  }
  if( (z = find_option("context","c",1))!=0 && (f = atoi(z))>=0 ){
    pCfg->nContext = f;
    diffFlags |= DIFF_CONTEXT_EX;
  }
  if( (z = find_option("width","W",1))!=0 && (f = atoi(z))>0 ){
    pCfg->wColumn = f;
  }
  if( find_option("linenum","n",0)!=0 ) diffFlags |= DIFF_LINENO;
  if( find_option("noopt",0,0)!=0 ) diffFlags |= DIFF_NOOPT;
  if( find_option("numstat",0,0)!=0 ) diffFlags |= DIFF_NUMSTAT;
  if( find_option("invert",0,0)!=0 ) diffFlags |= DIFF_INVERT;
  if( find_option("brief",0,0)!=0 ) diffFlags |= DIFF_BRIEF;
  if( find_option("internal","i",0)==0
   && (diffFlags & (DIFF_HTML|DIFF_TCL|DIFF_DEBUG|DIFF_JSON))==0
  ){
    pCfg->zDiffCmd = find_option("command", 0, 1);
    if( pCfg->zDiffCmd==0 ) pCfg->zDiffCmd = diff_command_external(isGDiff);
    if( pCfg->zDiffCmd ){
      const char *zDiffBinary;
      pCfg->zBinGlob = diff_get_binary_glob();
      zDiffBinary = find_option("diff-binary", 0, 1);
      if( zDiffBinary ){
        if( is_truth(zDiffBinary) ) diffFlags |= DIFF_INCBINARY;
      }else if( db_get_boolean("diff-binary", 1) ){
        diffFlags |= DIFF_INCBINARY;
      }
    }























  }


  if( find_option("verbose","v",0)!=0 ) diffFlags |= DIFF_VERBOSE;
  /* Deprecated, but retained for script compatibility. */
  else if( find_option("new-file","N",0)!=0 ) diffFlags |= DIFF_VERBOSE;

  pCfg->diffFlags = diffFlags;
}

/*
** COMMAND: test-diff
** COMMAND: xdiff
**
** Usage: %fossil xdiff [options] FILE1 FILE2
**
** Compute an "external diff" between two files. By "external diff" we mean
** a diff between two disk files that are not necessarily under management.
** In other words, this command provides a mechanism to use Fossil's file
** difference engine on arbitrary disk files.  See the "diff" command for
** computing differences between files that are* under management.
**
** This command prints the differences between the two files FILE1 and FILE2.
** all of the usual diff formatting options (--tk, --by, -c N, etc.) apply.
** See the "diff" command for a full list of command-line options.
**

** This command used to be called "test-diff".  The older "test-diff" spelling
** still works, for compatibility.
*/
void xdiff_cmd(void){
  Blob a, b, out;

  const char *zRe;           /* Regex filter for diff output */

  DiffConfig DCfg;

  if( find_option("tk",0,0)!=0 ){
    diff_tk("xdiff", 2);
    return;
  }
  find_option("i",0,0);
  find_option("v",0,0);
  diff_options(&DCfg, 0, 0);
  zRe = find_option("regexp","e",1);
  if( zRe ){
    const char *zErr = re_compile(&DCfg.pRe, zRe, 0);
    if( zErr ) fossil_fatal("regex error: %s", zErr);
  }

  verify_all_options();
  if( g.argc!=4 ) usage("FILE1 FILE2");
  blob_zero(&out);
  diff_begin(&DCfg);
  diff_print_filenames(g.argv[2], g.argv[3], &DCfg, &out);
  blob_read_from_file(&a, g.argv[2], ExtFILE);
  blob_read_from_file(&b, g.argv[3], ExtFILE);

  text_diff(&a, &b, &out, &DCfg);
  blob_write_to_file(&out, "-");
  diff_end(&DCfg, 0);
  re_free(DCfg.pRe);
}

/**************************************************************************
** The basic difference engine is above.  What follows is the annotation
** engine.  Both are in the same file since they share many components.
*/

2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
** will release it when it is finished with it.
*/
static int annotation_start(Annotator *p, Blob *pInput, u64 diffFlags){
  int i;

  memset(p, 0, sizeof(*p));
  if( (diffFlags & DIFF_IGNORE_ALLWS)==DIFF_IGNORE_ALLWS ){
    p->c.xDiffer = same_dline_ignore_allws;
  }else{
    p->c.xDiffer = same_dline;
  }
  p->c.aTo = break_into_lines(blob_str(pInput), blob_size(pInput),&p->c.nTo,
                              diffFlags);
  if( p->c.aTo==0 ){
    return 1;
  }
  p->aOrig = fossil_malloc( sizeof(p->aOrig[0])*p->c.nTo );







|

|







2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
** will release it when it is finished with it.
*/
static int annotation_start(Annotator *p, Blob *pInput, u64 diffFlags){
  int i;

  memset(p, 0, sizeof(*p));
  if( (diffFlags & DIFF_IGNORE_ALLWS)==DIFF_IGNORE_ALLWS ){
    p->c.xDiffer = compare_dline_ignore_allws;
  }else{
    p->c.xDiffer = compare_dline;
  }
  p->c.aTo = break_into_lines(blob_str(pInput), blob_size(pInput),&p->c.nTo,
                              diffFlags);
  if( p->c.aTo==0 ){
    return 1;
  }
  p->aOrig = fossil_malloc( sizeof(p->aOrig[0])*p->c.nTo );
Added src/diff.js.


















































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
/* Refinements to the display of unified and side-by-side diffs.
**
** In all cases, the table columns tagged with "difftxt" are expanded,
** where possible, to fill the width of the screen.
**
** For a side-by-side diff, if either column is two wide to fit on the
** display, scrollbars are added.  The scrollbars are linked, so that
** both sides scroll together.  Left and right arrows also scroll.
*/
window.addEventListener('load',function(){
  var SCROLL_LEN = 25;
  function initDiff(diff){
    var txtCols = diff.querySelectorAll('td.difftxt');
    var txtPres = diff.querySelectorAll('td.difftxt pre');
    var width = 0;
    if(txtPres.length>=2){
      width = Math.max(txtPres[0].scrollWidth, txtPres[1].scrollWidth);
    }
    var i;
    for(i=0; i<txtCols.length; i++){
      txtCols[i].style.width = width + 'px';
      txtPres[i].style.maxWidth = width + 'px';
      txtPres[i].style.width = width + 'px';
      txtPres[i].onscroll = function(e){
        for(var j=0; j<txtPres.length; j++) txtPres[j].scrollLeft = this.scrollLeft;
      };
    }
    diff.tabIndex = 0;
    diff.onkeydown = function(e){
      e = e || event;
      var len = {37: -SCROLL_LEN, 39: SCROLL_LEN}[e.keyCode];
      if( !len ) return;
      txtPres[0].scrollLeft += len;
      return false;
    };
  }
  var i, diffs = document.querySelectorAll('table.splitdiff')
  for(i=0; i<diffs.length; i++){
    initDiff(diffs[i]);
  }
  const checkWidth = function f(){
    if(undefined === f.lastWidth){
      f.lastWidth = 0;
    }
    if( document.body.clientWidth===f.lastWidth ) return;
    f.lastWidth = document.body.clientWidth;
    var w = f.lastWidth*0.5 - 100;
    if(!f.colsL){
      f.colsL = document.querySelectorAll('td.difftxtl pre');
    }
    for(let i=0; i<f.colsL.length; i++){
      f.colsL[i].style.width = w + "px";
      f.colsL[i].style.maxWidth = w + "px";
    }
    if(!f.colsR){
      f.colsR = document.querySelectorAll('td.difftxtr pre');
    }
    for(let i=0; i<f.colsR.length; i++){
      f.colsR[i].style.width = w + "px";
      f.colsR[i].style.maxWidth = w + "px";
    }
    if(!f.allDiffs){
      f.allDiffs = document.querySelectorAll('table.diff');
    }
    w = f.lastWidth;
    for(let i=0; i<f.allDiffs.length; i++){
      f.allDiffs[i].style.width = '100%'; // setting to w causes unsightly horiz. scrollbar
      f.allDiffs[i].style.maxWidth = w + "px";
    }
  };
  checkWidth();
  window.addEventListener('resize', checkWidth);
}, false);
Changes to src/diff.tcl.
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
  TXT_COL_BG #ffffff
  TXT_COL_FG #000000
  MKR_COL_BG #444444
  MKR_COL_FG #dddddd
  CHNG_BG    #d0d0ff
  ADD_BG     #c0ffc0
  RM_BG      #ffc0c0
  HR_FG      #888888
  HR_PAD_TOP 4
  HR_PAD_BTM 8
  FN_BG      #444444
  FN_FG      #ffffff
  FN_PAD     5
  ERR_FG     #ee0000
  PADX       5







|







17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
  TXT_COL_BG #ffffff
  TXT_COL_FG #000000
  MKR_COL_BG #444444
  MKR_COL_FG #dddddd
  CHNG_BG    #d0d0ff
  ADD_BG     #c0ffc0
  RM_BG      #ffc0c0
  HR_FG      #444444
  HR_PAD_TOP 4
  HR_PAD_BTM 8
  FN_BG      #444444
  FN_FG      #ffffff
  FN_PAD     5
  ERR_FG     #ee0000
  PADX       5
68
69
70
71
72
73
74


75
76
77
78
79
80
81


82
83
84


85
86
87

88


89

90

91


92

93


94

95


96
97


98
99
100
101



102
103








104
105
106





107
108
109
110
111
112
113
114
115



116
117
118
119
120
121
122
123
124
125

126
127
128


129
130





131

132



133
134
135
136
137
138
139
    fconfigure $in -encoding utf-8
    set difftxt [split [read $in] \n]
    close $in
  }
  set N [llength $difftxt]
  set ii 0
  set nDiffs 0


  array set widths {txt 0 ln 0 mkr 0}
  while {[set line [getLine $difftxt $N ii]] != -1} {
    set fn2 {}
    if {![regexp {^=+ (.*?) =+ versus =+ (.*?) =+$} $line all fn fn2]
     && ![regexp {^=+ (.*?) =+$} $line all fn]
    } {
      continue


    }
    set errMsg ""
    set line [getLine $difftxt $N ii]


    if {[string compare -length 6 $line "<table"]
     && ![regexp {<p[^>]*>(.+)} $line - errMsg]} {
      continue

    }


    incr nDiffs

    set idx [expr {$nDiffs > 1 ? [.txtA index end] : "1.0"}]

    .wfiles.lb insert end $fn




    foreach c [cols] {


      if {$nDiffs > 1} {

        $c insert end \n -


      }
      if {[colType $c] eq "txt"} {


        $c insert end $fn\n fn
        if {$fn2!=""} {set fn $fn2}
      } else {
        $c insert end \n fn



      }
      $c insert end \n -









      if {$errMsg ne ""} continue
      while {[getLine $difftxt $N ii] ne "<pre>"} continue





      set type [colType $c]
      set str {}
      while {[set line [getLine $difftxt $N ii]] ne "</pre>"} {
        set len [string length [dehtml $line]]
        if {$len > $widths($type)} {
          set widths($type) $len
        }
        append str $line\n
      }




      set re {<span class="diff([a-z]+)">([^<]*)</span>}
      # Use \r as separator since it can't appear in the diff output (it gets
      # converted to a space).
      set str [regsub -all $re $str "\r\\1\r\\2\r"]
      foreach {pre class mid} [split $str \r] {
        if {$class ne ""} {
          $c insert end [dehtml $pre] - [dehtml $mid] [list $class -]
        } else {
          $c insert end [dehtml $pre] -

        }
      }
    }



    if {$errMsg ne ""} {





      foreach c {.txtA .txtB} {$c insert end [string trim $errMsg] err}

      foreach c [cols] {$c insert end \n -}



    }
  }

  foreach c [cols] {
    set type [colType $c]
    if {$type ne "txt"} {
      $c config -width $widths($type)







>
>
|

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

|
>
>
|
<
<
|
>
>
>

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







68
69
70
71
72
73
74
75
76
77
78


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


118
119
120
121
122

123
124
125
126
127
128
129
130
131
132

133
134
135
136
137
138
139

140
141
142

143
144
145
146
147
148


149


150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
    fconfigure $in -encoding utf-8
    set difftxt [split [read $in] \n]
    close $in
  }
  set N [llength $difftxt]
  set ii 0
  set nDiffs 0
  set n1 0
  set n2 0  
  array set widths {txt 3 ln 3 mkr 1}
  while {[set line [getLine $difftxt $N ii]] != -1} {


    switch -- [lindex $line 0] {
      FILE {
        incr nDiffs
        foreach wx [list [string length $n1] [string length $n2]] {
          if {$wx>$widths(ln)} {set widths(ln) $wx}
        }
        .lnA insert end \n fn \n -
        .txtA insert end [lindex $line 1]\n fn \n -
        .mkr insert end \n fn \n -
        .lnB insert end \n fn \n -
        .txtB insert end [lindex $line 2]\n fn \n -
        .wfiles.lb insert end [lindex $line 2]
        set n1 0
        set n2 0
      }
      SKIP {
        set n [lindex $line 1]
        incr n1 $n
        incr n2 $n
        .lnA insert end ...\n hrln
        .txtA insert end [string repeat . 30]\n hrtxt
        .mkr insert end \n hrln
        .lnB insert end ...\n hrln
        .txtB insert end [string repeat . 30]\n hrtxt
      }
      COM {
        set x [lindex $line 1]
        incr n1
        incr n2
        .lnA insert end $n1\n -
        .txtA insert end $x\n -
        .mkr insert end \n -
        .lnB insert end $n2\n -
        .txtB insert end $x\n -
      }
      INS {
        set x [lindex $line 1]
        incr n2
        .lnA insert end \n -


        .txtA insert end \n -
        .mkr insert end >\n -
        .lnB insert end $n2\n -
        .txtB insert end $x add \n -
      }

      DEL {
        set x [lindex $line 1]
        incr n1
        .lnA insert end $n1\n -
        .txtA insert end $x rm \n -
        .mkr insert end <\n -
        .lnB insert end \n -
        .txtB insert end \n -
      }
      EDIT {

        incr n1
        incr n2
        .lnA insert end $n1\n -
        .lnB insert end $n2\n -
        .mkr insert end |\n -
        set nn [llength $line]
        for {set i 1} {$i<$nn} {incr i 3} {

          set x [lindex $line $i]
          if {$x ne ""} {
            .txtA insert end $x -

            .txtB insert end $x -
          }
          if {$i+2<$nn} {
            set x1 [lindex $line [expr {$i+1}]]
            set x2 [lindex $line [expr {$i+2}]]
            if {"$x1" eq ""} {


              .txtB insert end $x2 add


            } elseif {"$x2" eq ""} {
              .txtA insert end $x1 rm
            } else {
              .txtA insert end $x1 chng
              .txtB insert end $x2 chng
            }
          }
        }
        .txtA insert end \n -
        .txtB insert end \n -
      }
      "" {
        foreach wx [list [string length $n1] [string length $n2]] {
          if {$wx>$widths(ln)} {set widths(ln) $wx}
        }
      }
      default {
        .lnA insert end \n -
        .txtA insert end $line\n err
        .mkr insert end \n -
        .lnB insert end \n -
        .txtB insert end $line\n err
      }
    }
  }

  foreach c [cols] {
    set type [colType $c]
    if {$type ne "txt"} {
      $c config -width $widths($type)
328
329
330
331
332
333
334
335
336


337
338
339
340
341
342
343
text .mkr

foreach c [cols] {
  set keyPrefix [string toupper [colType $c]]_COL_
  if {[tk windowingsystem] eq "win32"} {$c config -font {courier 9}}
  $c config -bg $CFG(${keyPrefix}BG) -fg $CFG(${keyPrefix}FG) -borderwidth 0 \
    -padx $CFG(PADX) -yscroll sync-y
  $c tag config hr -spacing1 $CFG(HR_PAD_TOP) -spacing3 $CFG(HR_PAD_BTM) \
     -foreground $CFG(HR_FG)


  $c tag config fn -spacing1 $CFG(FN_PAD) -spacing3 $CFG(FN_PAD)
  bindtags $c ". $c Text all"
  bind $c <1> {focus %W}
}

::ttk::scrollbar .sby -command {.txtA yview} -orient vertical
::ttk::scrollbar .sbxA -command {.txtA xview} -orient horizontal







|
|
>
>







368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
text .mkr

foreach c [cols] {
  set keyPrefix [string toupper [colType $c]]_COL_
  if {[tk windowingsystem] eq "win32"} {$c config -font {courier 9}}
  $c config -bg $CFG(${keyPrefix}BG) -fg $CFG(${keyPrefix}FG) -borderwidth 0 \
    -padx $CFG(PADX) -yscroll sync-y
  $c tag config hrln -spacing1 $CFG(HR_PAD_TOP) -spacing3 $CFG(HR_PAD_BTM) \
     -foreground $CFG(HR_FG) -justify right
  $c tag config hrtxt  -spacing1 $CFG(HR_PAD_TOP) -spacing3 $CFG(HR_PAD_BTM) \
     -foreground $CFG(HR_FG) -justify center
  $c tag config fn -spacing1 $CFG(FN_PAD) -spacing3 $CFG(FN_PAD)
  bindtags $c ". $c Text all"
  bind $c <1> {focus %W}
}

::ttk::scrollbar .sby -command {.txtA yview} -orient vertical
::ttk::scrollbar .sbxA -command {.txtA xview} -orient horizontal
Changes to src/diffcmd.c.
17
18
19
20
21
22
23







24
25
26
27
28
29
30
**
** This file contains code used to implement the "diff" command
*/
#include "config.h"
#include "diffcmd.h"
#include <assert.h>








/*
** Use the right null device for the platform.
*/
#if defined(_WIN32)
#  define NULL_DEVICE "NUL"
#else
#  define NULL_DEVICE "/dev/null"







>
>
>
>
>
>
>







17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
**
** This file contains code used to implement the "diff" command
*/
#include "config.h"
#include "diffcmd.h"
#include <assert.h>

/* includes needed to catch interrupts */
#ifdef _WIN32
# include <windows.h>
#else
# include <signal.h>
#endif

/*
** Use the right null device for the platform.
*/
#if defined(_WIN32)
#  define NULL_DEVICE "NUL"
#else
#  define NULL_DEVICE "/dev/null"
104
105
106
107
108
109
110
111

112


113
114
115
116
117
118
119
120
121
122
123
124

125
126





127
128
129
130

























131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151

152
153










































































































































154








155















156







157









158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
  }
  return 0;
}

/*
** Print the "Index:" message that patches wants to see at the top of a diff.
*/
void diff_print_index(const char *zFile, u64 diffFlags, Blob *diffBlob){

  if( (diffFlags & (DIFF_SIDEBYSIDE|DIFF_BRIEF|DIFF_NUMSTAT))==0 ){


    char *z = mprintf("Index: %s\n%.66c\n", zFile, '=');
    if( !diffBlob ){
      fossil_print("%s", z);
    }else{
      blob_appendf(diffBlob, "%s", z);
    }
    fossil_free(z);
  }
}

/*
** Print the +++/--- filename lines for a diff operation.

*/
void diff_print_filenames(const char *zLeft, const char *zRight,





 u64 diffFlags, Blob *diffBlob){
  char *z = 0;
  if( diffFlags & DIFF_BRIEF ){
    /* no-op */

























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

  if( !diffBlob ){
    fossil_print("%s", z);










































































































































  }else{








    blob_appendf(diffBlob, "%s", z);















  }







  fossil_free(z);









}

/*
** Show the difference between two files, one in memory and one on disk.
**
** The difference is the set of edits needed to transform pFile1 into
** zFile2.  The content of pFile1 is in memory.  zFile2 exists on disk.
**
** If fSwapDiff is 1, show the set of edits to transform zFile2 into pFile1
** instead of the opposite.
**
** Use the internal diff logic if zDiffCmd is NULL.  Otherwise call the
** command zDiffCmd to do the diffing.
**
** When using an external diff program, zBinGlob contains the GLOB patterns
** for file names to treat as binary.  If fIncludeBinary is zero, these files
** will be skipped in addition to files that may contain binary content.
*/
void diff_file(
  Blob *pFile1,             /* In memory content to compare from */
  int isBin1,               /* Does the 'from' content appear to be binary */
  const char *zFile2,       /* On disk content to compare to */
  const char *zName,        /* Display name of the file */
  const char *zDiffCmd,     /* Command for comparison */
  const char *zBinGlob,     /* Treat file names matching this as binary */
  int fIncludeBinary,       /* Include binary files for external diff */
  u64 diffFlags,            /* Flags to control the diff */
  int fSwapDiff,            /* Diff from Zfile2 to Pfile1 */
  Blob *diffBlob            /* Blob to store diff output */
){
  if( zDiffCmd==0 ){
    Blob out;                 /* Diff output text */
    Blob file2;               /* Content of zFile2 */
    const char *zName2;       /* Name of zFile2 for display */

    /* Read content of zFile2 into memory */
    blob_zero(&file2);
    if( file_size(zFile2, ExtFILE)<0 ){
      zName2 = NULL_DEVICE;
    }else{
      blob_read_from_file(&file2, zFile2, ExtFILE);
      zName2 = zName;
    }

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

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

    if( !fIncludeBinary ){
      Blob file2;
      if( isBin1 ){
        fossil_print("%s",DIFF_CANNOT_COMPUTE_BINARY);
        return;
      }
      if( zBinGlob ){
        Glob *pBinary = glob_create(zBinGlob);
        if( glob_match(pBinary, zName) ){
          fossil_print("%s",DIFF_CANNOT_COMPUTE_BINARY);
          glob_free(pBinary);
          return;
        }
        glob_free(pBinary);
      }







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




|
>

|
>
>
>
>
>
|
<
|

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

|






|
|




|
|
|


|

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







<
<
<
<
<
<
<
<
<
<



<


<
<
<
|
<
|

|














|





<
<
<
|
<

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











|

|



|
|







111
112
113
114
115
116
117
118
119
120
121
122
123






124
125
126
127
128
129
130
131
132
133
134
135
136
137

138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376










377
378
379

380
381



382

383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405



406

407
408

409
410




411
412




413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
  }
  return 0;
}

/*
** Print the "Index:" message that patches wants to see at the top of a diff.
*/
void diff_print_index(const char *zFile, DiffConfig *pCfg, Blob *pOut){
  if( (pCfg->diffFlags &
          (DIFF_SIDEBYSIDE|DIFF_BRIEF|DIFF_NUMSTAT|DIFF_JSON|
           DIFF_WEBPAGE|DIFF_TCL))==0
  ){
    blob_appendf(pOut, "Index: %s\n%.66c\n", zFile, '=');






  }
}

/*
** Print the +++/--- filename lines or whatever filename information
** is appropriate for the output format.
*/
void diff_print_filenames(
  const char *zLeft,      /* Name of the left file */
  const char *zRight,     /* Name of the right file */
  DiffConfig *pCfg,       /* Diff configuration */
  Blob *pOut              /* Write to this blob, or stdout of this is NULL */
){
  u64 diffFlags = pCfg->diffFlags;

  if( diffFlags & (DIFF_BRIEF|DIFF_RAW) ){
    /* no-op */
  }else if( diffFlags & DIFF_DEBUG ){
    blob_appendf(pOut, "FILE-LEFT   %s\nFILE-RIGHT  %s\n", zLeft, zRight);
  }else if( diffFlags & DIFF_WEBPAGE ){
    if( fossil_strcmp(zLeft,zRight)==0 ){
      blob_appendf(pOut,"<h1>%h</h1>\n", zLeft);
    }else{
      blob_appendf(pOut,"<h1>%h &lrarr; %h</h1>\n", zLeft, zRight);
    }
  }else if( diffFlags & (DIFF_TCL|DIFF_JSON) ){
    if( diffFlags & DIFF_TCL ){
      blob_append(pOut, "FILE ", 5);
      blob_append_tcl_literal(pOut, zLeft, (int)strlen(zLeft));
      blob_append_char(pOut, ' ');
      blob_append_tcl_literal(pOut, zRight, (int)strlen(zRight));
      blob_append_char(pOut, '\n');
    }else{
      if( pOut ) blob_trim(pOut);
      blob_append(pOut, (pCfg->nFile==0 ? "[{" : ",\n{"), -1);
      pCfg->nFile++;
      blob_append(pOut, "\n  \"leftname\":", -1);
      blob_append_json_literal(pOut, zLeft, (int)strlen(zLeft));
      blob_append(pOut, ",\n  \"rightname\":", -1);
      blob_append_json_literal(pOut, zRight, (int)strlen(zRight));
      blob_append(pOut, ",\n  \"diff\":\n", -1);
    }
  }else if( diffFlags & DIFF_SIDEBYSIDE ){
    int w = diff_width(pCfg);
    int n1 = strlen(zLeft);
    int n2 = strlen(zRight);
    int x;
    if( n1==n2 && fossil_strcmp(zLeft,zRight)==0 ){
      if( n1>w*2 ) n1 = w*2;
      x = w*2+17 - (n1+2);
      blob_appendf(pOut, "%.*c %.*s %.*c\n",
                   x/2, '=', n1, zLeft, (x+1)/2, '=');
    }else{
      if( w<20 ) w = 20;
      if( n1>w-10 ) n1 = w - 10;
      if( n2>w-10 ) n2 = w - 10;
      blob_appendf(pOut, "%.*c %.*s %.*c versus %.*c %.*s %.*c\n",
                         (w-n1+10)/2, '=', n1, zLeft, (w-n1+1)/2, '=',
                         (w-n2)/2, '=', n2, zRight, (w-n2+1)/2, '=');
    }
  }else{
    blob_appendf(pOut, "--- %s\n+++ %s\n", zLeft, zRight);
  }
}


/*
** Default header text for diff with --webpage
*/
static const char zWebpageHdr[] = 
@ <!DOCTYPE html>
@ <html>
@ <head>
@ <meta charset="UTF-8">
@ <style>
@ h1 {
@   font-size: 150%;
@ }
@
@ table.diff {
@   width: 100%;
@   border-spacing: 0;
@   border: 1px solid black;
@ }
@ table.diff td {
@   vertical-align: top;
@ }
@ table.diff pre {
@   margin: 0 0 0 0;
@ }
@ td.diffln {
@   width: 1px;
@   text-align: right;
@   padding: 0 1em 0 0;
@ }
@ td.difflne {
@   padding-bottom: 0.4em;
@ }
@ td.diffsep {
@   width: 1px;
@   padding: 0 0.3em 0 1em;
@ }
@ td.difftxt pre {
@   overflow-x: auto;
@ }
@ td.diffln ins {
@   background-color: #a0e4b2;
@   text-decoration: none;
@ }
@ td.diffln del {
@   background-color: #ffc0c0;
@   text-decoration: none;
@ }
@ td.difftxt del {
@   background-color: #ffe8e8;
@   text-decoration: none;
@ }
@ td.difftxt del > del {
@   background-color: #ffc0c0;
@   text-decoration: none;
@   font-weight: bold;
@ }
@ td.difftxt del > del.edit {
@   background-color: #c0c0ff;
@   text-decoration: none;
@   font-weight: bold;
@ }
@ td.difftxt ins {
@   background-color: #dafbe1;
@   text-decoration: none;
@ }
@ td.difftxt ins > ins {
@   background-color: #a0e4b2;
@   text-decoration: none;
@   font-weight: bold;
@ }
@ td.difftxt ins > ins.edit {
@   background-color: #c0c0ff;
@   text-decoration: none;
@   font-weight: bold;
@ }
@ 
@ </style>
@ </head>
@ <body>
;
const char zWebpageEnd[] = 
@ </body>
@ </html>
;

/*
** State variables used by the --browser option for diff.  These must
** be static variables, not elements of DiffConfig, since they are
** used by the interrupt handler.
*/
static char *tempDiffFilename;  /* File holding the diff HTML */
static FILE *diffOut;           /* Open to write into tempDiffFilename */

/* Amount of delay (in milliseconds) between launching the
** web browser and deleting the temporary file used by --browser
*/
#ifndef FOSSIL_BROWSER_DIFF_DELAY
# define FOSSIL_BROWSER_DIFF_DELAY 5000  /* 5 seconds by default */
#endif

/*
** If we catch a single while writing the temporary file for the --browser
** diff output, then delete the temporary file and exit.
*/
static void diff_www_interrupt(int NotUsed){
  (void)NotUsed;
  if( diffOut ) fclose(diffOut);
  if( tempDiffFilename ) file_delete(tempDiffFilename);
  exit(1);
}
#ifdef _WIN32
static BOOL WINAPI diff_console_ctrl_handler(DWORD dwCtrlType){
  if( dwCtrlType==CTRL_C_EVENT ) diff_www_interrupt(0);
  return FALSE;
}
#endif


/*
** Do preliminary setup and output before computing a diff.
**
** For --browser, redirect stdout to a temporary file that will
** hold the result.  Make arrangements to delete that temporary
** file if the diff is interrupted.
**
** For --browser and --webpage, output the HTML header.
*/
void diff_begin(DiffConfig *pCfg){
  if( (pCfg->diffFlags & DIFF_BROWSER)!=0 ){
    tempDiffFilename = fossil_temp_filename();
    tempDiffFilename = sqlite3_mprintf("%z.html", tempDiffFilename);
    diffOut = fossil_freopen(tempDiffFilename,"wb",stdout);
    if( diffOut==0 ){
      fossil_fatal("unable to create temporary file \"%s\"", 
                   tempDiffFilename);
    }
#ifndef _WIN32
    signal(SIGINT, diff_www_interrupt);
#else
    SetConsoleCtrlHandler(diff_console_ctrl_handler, TRUE);
#endif
  }
  if( (pCfg->diffFlags & DIFF_WEBPAGE)!=0 ){
    fossil_print("%s",zWebpageHdr);
    fflush(stdout);
  }
}

/* Do any final output required by a diff and complete the diff
** process.
**
** For --browser and --webpage, output any javascript required by 
** the diff.  (Currently JS is only needed for side-by-side diffs).
**
** For --browser, close the connection to the temporary file, then
** launch a web browser to view the file.  After a delay
** of FOSSIL_BROWSER_DIFF_DELAY milliseconds, delete the temp file.
*/
void diff_end(DiffConfig *pCfg, int nErr){
  if( (pCfg->diffFlags & DIFF_WEBPAGE)!=0 ){
    if( pCfg->diffFlags & DIFF_SIDEBYSIDE ){
      const unsigned char *zJs = builtin_file("diff.js", 0);
      fossil_print("<script>\n%s</script>\n", zJs);
    }
    fossil_print("%s", zWebpageEnd);
  }
  if( (pCfg->diffFlags & DIFF_BROWSER)!=0 && nErr==0 ){
    char *zCmd = mprintf("%s %$", fossil_web_browser(), tempDiffFilename);
    fclose(diffOut);
    diffOut = fossil_freopen(NULL_DEVICE, "wb", stdout);
    fossil_system(zCmd);
    fossil_free(zCmd);
    diffOut = 0;
    sqlite3_sleep(FOSSIL_BROWSER_DIFF_DELAY);
    file_delete(tempDiffFilename);
    sqlite3_free(tempDiffFilename);
    tempDiffFilename = 0;
  }
  if( (pCfg->diffFlags & DIFF_JSON)!=0 && pCfg->nFile>0 ){
    fossil_print("]\n");
  }
}

/*
** Show the difference between two files, one in memory and one on disk.
**
** The difference is the set of edits needed to transform pFile1 into
** zFile2.  The content of pFile1 is in memory.  zFile2 exists on disk.










*/
void diff_file(
  Blob *pFile1,             /* In memory content to compare from */

  const char *zFile2,       /* On disk content to compare to */
  const char *zName,        /* Display name of the file */



  DiffConfig *pCfg,         /* Flags to control the diff */

  Blob *pOut            /* Blob to store diff output */
){
  if( pCfg->zDiffCmd==0 ){
    Blob out;                 /* Diff output text */
    Blob file2;               /* Content of zFile2 */
    const char *zName2;       /* Name of zFile2 for display */

    /* Read content of zFile2 into memory */
    blob_zero(&file2);
    if( file_size(zFile2, ExtFILE)<0 ){
      zName2 = NULL_DEVICE;
    }else{
      blob_read_from_file(&file2, zFile2, ExtFILE);
      zName2 = zName;
    }

    /* Compute and output the differences */
    if( pCfg->diffFlags & DIFF_BRIEF ){
      if( blob_compare(pFile1, &file2) ){
        fossil_print("CHANGED  %s\n", zName);
      }
    }else{
      blob_zero(&out);



      text_diff(pFile1, &file2, &out, pCfg);

      if( blob_size(&out) ){
        if( pCfg->diffFlags & DIFF_NUMSTAT ){

          blob_appendf(pOut, "%s %s\n", blob_str(&out), zName);
        }else{




          diff_print_filenames(zName, zName2, pCfg, pOut);
          blob_appendf(pOut, "%s\n", blob_str(&out));




        }
      }
      blob_reset(&out);
    }

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

    if( (pCfg->diffFlags & DIFF_INCBINARY)==0 ){
      Blob file2;
      if( looks_like_binary(pFile1) ){
        fossil_print("%s",DIFF_CANNOT_COMPUTE_BINARY);
        return;
      }
      if( pCfg->zBinGlob ){
        Glob *pBinary = glob_create(pCfg->zBinGlob);
        if( glob_match(pBinary, zName) ){
          fossil_print("%s",DIFF_CANNOT_COMPUTE_BINARY);
          glob_free(pBinary);
          return;
        }
        glob_free(pBinary);
      }
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
    /* Construct a temporary file to hold pFile1 based on the name of
    ** zFile2 */
    file_tempname(&nameFile1, zFile2, "orig");
    blob_write_to_file(pFile1, blob_str(&nameFile1));

    /* Construct the external diff command */
    blob_zero(&cmd);
    blob_append(&cmd, zDiffCmd, -1);
    if( fSwapDiff ){
      blob_append_escaped_arg(&cmd, zFile2, 1);
      blob_append_escaped_arg(&cmd, blob_str(&nameFile1), 1);
    }else{
      blob_append_escaped_arg(&cmd, blob_str(&nameFile1), 1);
      blob_append_escaped_arg(&cmd, zFile2, 1);
    }








|
|







451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
    /* Construct a temporary file to hold pFile1 based on the name of
    ** zFile2 */
    file_tempname(&nameFile1, zFile2, "orig");
    blob_write_to_file(pFile1, blob_str(&nameFile1));

    /* Construct the external diff command */
    blob_zero(&cmd);
    blob_append(&cmd, pCfg->zDiffCmd, -1);
    if( pCfg->diffFlags & DIFF_INVERT ){
      blob_append_escaped_arg(&cmd, zFile2, 1);
      blob_append_escaped_arg(&cmd, blob_str(&nameFile1), 1);
    }else{
      blob_append_escaped_arg(&cmd, blob_str(&nameFile1), 1);
      blob_append_escaped_arg(&cmd, zFile2, 1);
    }

302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
** When using an external diff program, zBinGlob contains the GLOB patterns
** for file names to treat as binary.  If fIncludeBinary is zero, these files
** will be skipped in addition to files that may contain binary content.
*/
void diff_file_mem(
  Blob *pFile1,             /* In memory content to compare from */
  Blob *pFile2,             /* In memory content to compare to */
  int isBin1,               /* Does the 'from' content appear to be binary */
  int isBin2,               /* Does the 'to' content appear to be binary */
  const char *zName,        /* Display name of the file */
  const char *zDiffCmd,     /* Command for comparison */
  const char *zBinGlob,     /* Treat file names matching this as binary */
  int fIncludeBinary,       /* Include binary files for external diff */
  u64 diffFlags             /* Diff flags */
){
  if( diffFlags & DIFF_BRIEF ) return;
  if( zDiffCmd==0 ){
    Blob out;      /* Diff output text */

    blob_zero(&out);
    text_diff(pFile1, pFile2, &out, 0, diffFlags);
    if( diffFlags & DIFF_NUMSTAT ){
      fossil_print("%s %s\n", blob_str(&out), zName);
    }else{
      diff_print_filenames(zName, zName, diffFlags, 0);
      fossil_print("%s\n", blob_str(&out));
    }

    /* Release memory resources */
    blob_reset(&out);
  }else{
    Blob cmd;
    Blob temp1;
    Blob temp2;

    if( !fIncludeBinary ){
      if( isBin1 || isBin2 ){
        fossil_print("%s",DIFF_CANNOT_COMPUTE_BINARY);
        return;
      }
      if( zBinGlob ){
        Glob *pBinary = glob_create(zBinGlob);
        if( glob_match(pBinary, zName) ){
          fossil_print("%s",DIFF_CANNOT_COMPUTE_BINARY);
          glob_free(pBinary);
          return;
        }
        glob_free(pBinary);
      }
    }

    /* Construct a temporary file names */
    file_tempname(&temp1, zName, "before");
    file_tempname(&temp2, zName, "after");
    blob_write_to_file(pFile1, blob_str(&temp1));
    blob_write_to_file(pFile2, blob_str(&temp2));

    /* Construct the external diff command */
    blob_zero(&cmd);
    blob_append(&cmd, zDiffCmd, -1);
    blob_append_escaped_arg(&cmd, blob_str(&temp1), 1);
    blob_append_escaped_arg(&cmd, blob_str(&temp2), 1);

    /* Run the external diff command */
    fossil_system(blob_str(&cmd));

    /* Delete the temporary file and clean up memory used */







<
<

<
<
<
|

|
|



|
|


|










|
|



|
|

















|







486
487
488
489
490
491
492


493



494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
** When using an external diff program, zBinGlob contains the GLOB patterns
** for file names to treat as binary.  If fIncludeBinary is zero, these files
** will be skipped in addition to files that may contain binary content.
*/
void diff_file_mem(
  Blob *pFile1,             /* In memory content to compare from */
  Blob *pFile2,             /* In memory content to compare to */


  const char *zName,        /* Display name of the file */



  DiffConfig *pCfg          /* Diff flags */
){
  if( pCfg->diffFlags & DIFF_BRIEF ) return;
  if( pCfg->zDiffCmd==0 ){
    Blob out;      /* Diff output text */

    blob_zero(&out);
    text_diff(pFile1, pFile2, &out, pCfg);
    if( pCfg->diffFlags & DIFF_NUMSTAT ){
      fossil_print("%s %s\n", blob_str(&out), zName);
    }else{
      diff_print_filenames(zName, zName, pCfg, 0);
      fossil_print("%s\n", blob_str(&out));
    }

    /* Release memory resources */
    blob_reset(&out);
  }else{
    Blob cmd;
    Blob temp1;
    Blob temp2;

    if( (pCfg->diffFlags & DIFF_INCBINARY)==0 ){
      if( looks_like_binary(pFile1) || looks_like_binary(pFile2) ){
        fossil_print("%s",DIFF_CANNOT_COMPUTE_BINARY);
        return;
      }
      if( pCfg->zBinGlob ){
        Glob *pBinary = glob_create(pCfg->zBinGlob);
        if( glob_match(pBinary, zName) ){
          fossil_print("%s",DIFF_CANNOT_COMPUTE_BINARY);
          glob_free(pBinary);
          return;
        }
        glob_free(pBinary);
      }
    }

    /* Construct a temporary file names */
    file_tempname(&temp1, zName, "before");
    file_tempname(&temp2, zName, "after");
    blob_write_to_file(pFile1, blob_str(&temp1));
    blob_write_to_file(pFile2, blob_str(&temp2));

    /* Construct the external diff command */
    blob_zero(&cmd);
    blob_append(&cmd, pCfg->zDiffCmd, -1);
    blob_append_escaped_arg(&cmd, blob_str(&temp1), 1);
    blob_append_escaped_arg(&cmd, blob_str(&temp2), 1);

    /* Run the external diff command */
    fossil_system(blob_str(&cmd));

    /* Delete the temporary file and clean up memory used */
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
**
** When using an external diff program, zBinGlob contains the GLOB patterns
** for file names to treat as binary.  If fIncludeBinary is zero, these files
** will be skipped in addition to files that may contain binary content.
*/
void diff_against_disk(
  const char *zFrom,        /* Version to difference from */
  const char *zDiffCmd,     /* Use this diff command.  NULL for built-in */
  const char *zBinGlob,     /* Treat file names matching this as binary */
  int fIncludeBinary,       /* Treat file names matching this as binary */
  u64 diffFlags,            /* Flags controlling diff output */
  FileDirList *pFileDir,    /* Which files to diff */
  Blob *diffBlob            /* Blob to output diff instead of stdout */
){
  int vid;
  Blob sql;
  Stmt q;
  int asNewFile;            /* Treat non-existant files as empty files */
  int isNumStat;            /* True for --numstat */

  asNewFile = (diffFlags & (DIFF_VERBOSE|DIFF_NUMSTAT))!=0;
  isNumStat = (diffFlags & DIFF_NUMSTAT)!=0;
  vid = db_lget_int("checkout", 0);
  vfile_check_signature(vid, CKSIG_ENOTFILE);
  blob_zero(&sql);
  db_begin_transaction();
  if( zFrom ){
    int rid = name_to_typed_rid(zFrom, "ci");
    if( !is_a_version(rid) ){







<
<
<
|

|







|
|







564
565
566
567
568
569
570



571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
**
** When using an external diff program, zBinGlob contains the GLOB patterns
** for file names to treat as binary.  If fIncludeBinary is zero, these files
** will be skipped in addition to files that may contain binary content.
*/
void diff_against_disk(
  const char *zFrom,        /* Version to difference from */



  DiffConfig *pCfg,         /* Flags controlling diff output */
  FileDirList *pFileDir,    /* Which files to diff */
  Blob *pOut            /* Blob to output diff instead of stdout */
){
  int vid;
  Blob sql;
  Stmt q;
  int asNewFile;            /* Treat non-existant files as empty files */
  int isNumStat;            /* True for --numstat */

  asNewFile = (pCfg->diffFlags & (DIFF_VERBOSE|DIFF_NUMSTAT|DIFF_HTML))!=0;
  isNumStat = (pCfg->diffFlags & (DIFF_NUMSTAT|DIFF_TCL|DIFF_HTML))!=0;
  vid = db_lget_int("checkout", 0);
  vfile_check_signature(vid, CKSIG_ENOTFILE);
  blob_zero(&sql);
  db_begin_transaction();
  if( zFrom ){
    int rid = name_to_typed_rid(zFrom, "ci");
    if( !is_a_version(rid) ){
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653

654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
    }else if( isChnged==5 ){
      if( !isNumStat ){ fossil_print("ADDED_BY_INTEGRATE %s\n", zPathname); }
      srcid = 0;
      if( !asNewFile ){ showDiff = 0; }
    }
    if( showDiff ){
      Blob content;
      int isBin;
      if( !isLink != !file_islink(zFullName) ){
        diff_print_index(zPathname, diffFlags, 0);
        diff_print_filenames(zPathname, zPathname, diffFlags, 0);
        fossil_print("%s",DIFF_CANNOT_COMPUTE_SYMLINK);
        continue;
      }
      if( srcid>0 ){
        content_get(srcid, &content);
      }else{
        blob_zero(&content);
      }
      isBin = fIncludeBinary ? 0 : looks_like_binary(&content);
      diff_print_index(zPathname, diffFlags, diffBlob);
      diff_file(&content, isBin, zFullName, zPathname, zDiffCmd,
                zBinGlob, fIncludeBinary, diffFlags, 0, diffBlob);
      blob_reset(&content);
    }
    blob_reset(&fname);
  }
  db_finalize(&q);
  db_end_transaction(1);  /* ROLLBACK */
}

/*
** Run a diff between the undo buffer and files on disk.
**
** Use the internal diff logic if zDiffCmd is NULL.  Otherwise call the
** command zDiffCmd to do the diffing.
**
** When using an external diff program, zBinGlob contains the GLOB patterns
** for file names to treat as binary.  If fIncludeBinary is zero, these files
** will be skipped in addition to files that may contain binary content.
*/
static void diff_against_undo(
  const char *zDiffCmd,     /* Use this diff command.  NULL for built-in */
  const char *zBinGlob,     /* Treat file names matching this as binary */
  int fIncludeBinary,       /* Treat file names matching this as binary */
  u64 diffFlags,            /* Flags controlling diff output */
  FileDirList *pFileDir     /* List of files and directories to diff */
){
  Stmt q;
  Blob content;
  db_prepare(&q, "SELECT pathname, content FROM undo");
  blob_init(&content, 0, 0);
  while( db_step(&q)==SQLITE_ROW ){
    char *zFullName;
    const char *zFile = (const char*)db_column_text(&q, 0);
    if( !file_dir_match(pFileDir, zFile) ) continue;
    zFullName = mprintf("%s%s", g.zLocalRoot, zFile);
    db_column_blob(&q, 1, &content);
    diff_file(&content, 0, zFullName, zFile,
              zDiffCmd, zBinGlob, fIncludeBinary, diffFlags, 0, 0);
    fossil_free(zFullName);
    blob_reset(&content);
  }
  db_finalize(&q);
}

/*
** Show the difference between two files identified by ManifestFile
** entries.
**
** Use the internal diff logic if zDiffCmd is NULL.  Otherwise call the
** command zDiffCmd to do the diffing.
**
** When using an external diff program, zBinGlob contains the GLOB patterns
** for file names to treat as binary.  If fIncludeBinary is zero, these files
** will be skipped in addition to files that may contain binary content.
*/
static void diff_manifest_entry(
  struct ManifestFile *pFrom,
  struct ManifestFile *pTo,
  const char *zDiffCmd,
  const char *zBinGlob,
  int fIncludeBinary,
  u64 diffFlags
){
  Blob f1, f2;
  int isBin1, isBin2;
  int rid;
  const char *zName;
  if( pFrom ){
    zName = pFrom->zName;
  }else if( pTo ){
    zName = pTo->zName;
  }else{
    zName = DIFF_NO_NAME;
  }
  if( diffFlags & DIFF_BRIEF ) return;
  diff_print_index(zName, diffFlags, 0);
  if( pFrom ){
    rid = uuid_to_rid(pFrom->zUuid, 0);
    content_get(rid, &f1);
  }else{
    blob_zero(&f1);
  }
  if( pTo ){
    rid = uuid_to_rid(pTo->zUuid, 0);
    content_get(rid, &f2);
  }else{
    blob_zero(&f2);
  }
  isBin1 = fIncludeBinary ? 0 : looks_like_binary(&f1);
  isBin2 = fIncludeBinary ? 0 : looks_like_binary(&f2);
  diff_file_mem(&f1, &f2, isBin1, isBin2, zName, zDiffCmd,
                zBinGlob, fIncludeBinary, diffFlags);
  blob_reset(&f1);
  blob_reset(&f2);
}

/*
** Output the differences between two check-ins.
**
** Use the internal diff logic if zDiffCmd is NULL.  Otherwise call the
** command zDiffCmd to do the diffing.
**
** When using an external diff program, zBinGlob contains the GLOB patterns
** for file names to treat as binary.  If fIncludeBinary is zero, these files
** will be skipped in addition to files that may contain binary content.
*/
static void diff_two_versions(
  const char *zFrom,
  const char *zTo,
  const char *zDiffCmd,
  const char *zBinGlob,
  int fIncludeBinary,
  u64 diffFlags,
  FileDirList *pFileDir
){
  Manifest *pFrom, *pTo;
  ManifestFile *pFromFile, *pToFile;
  int asNewFlag = (diffFlags & (DIFF_VERBOSE|DIFF_NUMSTAT))!=0 ? 1 : 0;

  pFrom = manifest_get_by_name(zFrom, 0);
  manifest_file_rewind(pFrom);
  pFromFile = manifest_file_next(pFrom,0);
  pTo = manifest_get_by_name(zTo, 0);
  manifest_file_rewind(pTo);
  pToFile = manifest_file_next(pTo,0);

  while( pFromFile || pToFile ){
    int cmp;
    if( pFromFile==0 ){
      cmp = +1;
    }else if( pToFile==0 ){
      cmp = -1;
    }else{
      cmp = fossil_strcmp(pFromFile->zName, pToFile->zName);
    }
    if( cmp<0 ){
      if( file_dir_match(pFileDir, pFromFile->zName) ){
        if( (diffFlags & DIFF_NUMSTAT)==0 ){
          fossil_print("DELETED %s\n", pFromFile->zName);
        }
        if( asNewFlag ){
          diff_manifest_entry(pFromFile, 0, zDiffCmd, zBinGlob,
                              fIncludeBinary, diffFlags);
        }
      }
      pFromFile = manifest_file_next(pFrom,0);
    }else if( cmp>0 ){
      if( file_dir_match(pFileDir, pToFile->zName) ){
        if( (diffFlags & DIFF_NUMSTAT)==0 ){

          fossil_print("ADDED   %s\n", pToFile->zName);
        }
        if( asNewFlag ){
          diff_manifest_entry(0, pToFile, zDiffCmd, zBinGlob,
                              fIncludeBinary, diffFlags);
        }
      }
      pToFile = manifest_file_next(pTo,0);
    }else if( fossil_strcmp(pFromFile->zUuid, pToFile->zUuid)==0 ){
      /* No changes */
      (void)file_dir_match(pFileDir, pFromFile->zName); /* Record name usage */
      pFromFile = manifest_file_next(pFrom,0);
      pToFile = manifest_file_next(pTo,0);
    }else{
      if( file_dir_match(pFileDir, pToFile->zName) ){
        if( diffFlags & DIFF_BRIEF ){
          fossil_print("CHANGED %s\n", pFromFile->zName);
        }else{
          diff_manifest_entry(pFromFile, pToFile, zDiffCmd, zBinGlob,
                              fIncludeBinary, diffFlags);
        }
      }
      pFromFile = manifest_file_next(pFrom,0);
      pToFile = manifest_file_next(pTo,0);
    }
  }
  manifest_destroy(pFrom);







<

|
|








<
|
|
<



















<
<
<
|












|
<




















|
<
<
<


<









|
|












<
<
|
<

















|
<
<
<




|



















|



|
<





|
>



|
<










|


|
<







659
660
661
662
663
664
665

666
667
668
669
670
671
672
673
674
675
676

677
678

679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697



698
699
700
701
702
703
704
705
706
707
708
709
710
711

712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732



733
734

735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757


758

759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776



777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805

806
807
808
809
810
811
812
813
814
815
816

817
818
819
820
821
822
823
824
825
826
827
828
829
830

831
832
833
834
835
836
837
    }else if( isChnged==5 ){
      if( !isNumStat ){ fossil_print("ADDED_BY_INTEGRATE %s\n", zPathname); }
      srcid = 0;
      if( !asNewFile ){ showDiff = 0; }
    }
    if( showDiff ){
      Blob content;

      if( !isLink != !file_islink(zFullName) ){
        diff_print_index(zPathname, pCfg, 0);
        diff_print_filenames(zPathname, zPathname, pCfg, 0);
        fossil_print("%s",DIFF_CANNOT_COMPUTE_SYMLINK);
        continue;
      }
      if( srcid>0 ){
        content_get(srcid, &content);
      }else{
        blob_zero(&content);
      }

      diff_print_index(zPathname, pCfg, pOut);
      diff_file(&content, zFullName, zPathname, pCfg, pOut);

      blob_reset(&content);
    }
    blob_reset(&fname);
  }
  db_finalize(&q);
  db_end_transaction(1);  /* ROLLBACK */
}

/*
** Run a diff between the undo buffer and files on disk.
**
** Use the internal diff logic if zDiffCmd is NULL.  Otherwise call the
** command zDiffCmd to do the diffing.
**
** When using an external diff program, zBinGlob contains the GLOB patterns
** for file names to treat as binary.  If fIncludeBinary is zero, these files
** will be skipped in addition to files that may contain binary content.
*/
static void diff_against_undo(



  DiffConfig *pCfg,         /* Flags controlling diff output */
  FileDirList *pFileDir     /* List of files and directories to diff */
){
  Stmt q;
  Blob content;
  db_prepare(&q, "SELECT pathname, content FROM undo");
  blob_init(&content, 0, 0);
  while( db_step(&q)==SQLITE_ROW ){
    char *zFullName;
    const char *zFile = (const char*)db_column_text(&q, 0);
    if( !file_dir_match(pFileDir, zFile) ) continue;
    zFullName = mprintf("%s%s", g.zLocalRoot, zFile);
    db_column_blob(&q, 1, &content);
    diff_file(&content, zFullName, zFile, pCfg, 0);

    fossil_free(zFullName);
    blob_reset(&content);
  }
  db_finalize(&q);
}

/*
** Show the difference between two files identified by ManifestFile
** entries.
**
** Use the internal diff logic if zDiffCmd is NULL.  Otherwise call the
** command zDiffCmd to do the diffing.
**
** When using an external diff program, zBinGlob contains the GLOB patterns
** for file names to treat as binary.  If fIncludeBinary is zero, these files
** will be skipped in addition to files that may contain binary content.
*/
static void diff_manifest_entry(
  struct ManifestFile *pFrom,
  struct ManifestFile *pTo,
  DiffConfig *pCfg



){
  Blob f1, f2;

  int rid;
  const char *zName;
  if( pFrom ){
    zName = pFrom->zName;
  }else if( pTo ){
    zName = pTo->zName;
  }else{
    zName = DIFF_NO_NAME;
  }
  if( pCfg->diffFlags & DIFF_BRIEF ) return;
  diff_print_index(zName, pCfg, 0);
  if( pFrom ){
    rid = uuid_to_rid(pFrom->zUuid, 0);
    content_get(rid, &f1);
  }else{
    blob_zero(&f1);
  }
  if( pTo ){
    rid = uuid_to_rid(pTo->zUuid, 0);
    content_get(rid, &f2);
  }else{
    blob_zero(&f2);
  }


  diff_file_mem(&f1, &f2, zName, pCfg);

  blob_reset(&f1);
  blob_reset(&f2);
}

/*
** Output the differences between two check-ins.
**
** Use the internal diff logic if zDiffCmd is NULL.  Otherwise call the
** command zDiffCmd to do the diffing.
**
** When using an external diff program, zBinGlob contains the GLOB patterns
** for file names to treat as binary.  If fIncludeBinary is zero, these files
** will be skipped in addition to files that may contain binary content.
*/
static void diff_two_versions(
  const char *zFrom,
  const char *zTo,
  DiffConfig *pCfg,



  FileDirList *pFileDir
){
  Manifest *pFrom, *pTo;
  ManifestFile *pFromFile, *pToFile;
  int asNewFlag = (pCfg->diffFlags & (DIFF_VERBOSE|DIFF_NUMSTAT))!=0 ? 1 : 0;

  pFrom = manifest_get_by_name(zFrom, 0);
  manifest_file_rewind(pFrom);
  pFromFile = manifest_file_next(pFrom,0);
  pTo = manifest_get_by_name(zTo, 0);
  manifest_file_rewind(pTo);
  pToFile = manifest_file_next(pTo,0);

  while( pFromFile || pToFile ){
    int cmp;
    if( pFromFile==0 ){
      cmp = +1;
    }else if( pToFile==0 ){
      cmp = -1;
    }else{
      cmp = fossil_strcmp(pFromFile->zName, pToFile->zName);
    }
    if( cmp<0 ){
      if( file_dir_match(pFileDir, pFromFile->zName) ){
        if( (pCfg->diffFlags & (DIFF_NUMSTAT|DIFF_HTML))==0 ){
          fossil_print("DELETED %s\n", pFromFile->zName);
        }
        if( asNewFlag ){
          diff_manifest_entry(pFromFile, 0, pCfg);

        }
      }
      pFromFile = manifest_file_next(pFrom,0);
    }else if( cmp>0 ){
      if( file_dir_match(pFileDir, pToFile->zName) ){
        if( (pCfg->diffFlags &
             (DIFF_NUMSTAT|DIFF_HTML|DIFF_TCL|DIFF_JSON))==0 ){
          fossil_print("ADDED   %s\n", pToFile->zName);
        }
        if( asNewFlag ){
          diff_manifest_entry(0, pToFile, pCfg);

        }
      }
      pToFile = manifest_file_next(pTo,0);
    }else if( fossil_strcmp(pFromFile->zUuid, pToFile->zUuid)==0 ){
      /* No changes */
      (void)file_dir_match(pFileDir, pFromFile->zName); /* Record name usage */
      pFromFile = manifest_file_next(pFrom,0);
      pToFile = manifest_file_next(pTo,0);
    }else{
      if( file_dir_match(pFileDir, pToFile->zName) ){
        if( pCfg->diffFlags & DIFF_BRIEF ){
          fossil_print("CHANGED %s\n", pFromFile->zName);
        }else{
          diff_manifest_entry(pFromFile, pToFile, pCfg);

        }
      }
      pFromFile = manifest_file_next(pFrom,0);
      pToFile = manifest_file_next(pTo,0);
    }
  }
  manifest_destroy(pFrom);
717
718
719
720
721
722
723
724
725

726
727
728
729
730
731
732
void diff_tk(const char *zSubCmd, int firstArg){
  int i;
  Blob script;
  const char *zTempFile = 0;
  char *zCmd;
  const char *zTclsh;
  blob_zero(&script);
  blob_appendf(&script, "set fossilcmd {| \"%/\" %s --html -y -i -v",
               g.nameOfExe, zSubCmd);

  find_option("html",0,0);
  find_option("side-by-side","y",0);
  find_option("internal","i",0);
  find_option("verbose","v",0);
  zTclsh = find_option("tclsh",0,1);
  if( zTclsh==0 ){
    zTclsh = db_get("tclsh",0);







|

>







874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
void diff_tk(const char *zSubCmd, int firstArg){
  int i;
  Blob script;
  const char *zTempFile = 0;
  char *zCmd;
  const char *zTclsh;
  blob_zero(&script);
  blob_appendf(&script, "set fossilcmd {| \"%/\" %s -tcl -i -v",
               g.nameOfExe, zSubCmd);
  find_option("tcl",0,0);
  find_option("html",0,0);
  find_option("side-by-side","y",0);
  find_option("internal","i",0);
  find_option("verbose","v",0);
  zTclsh = find_option("tclsh",0,1);
  if( zTclsh==0 ){
    zTclsh = db_get("tclsh",0);
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811











812
813
814
815
816
817
818
819
820
821
822

823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839



840
841
842
843
844


845
846
847
848
849
850
851

852


853
854
855

856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880

881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
    fossil_system(zCmd);
    file_delete(zTempFile);
    fossil_free(zCmd);
  }
  blob_reset(&script);
}

/*
** Returns non-zero if files that may be binary should be used with external
** diff programs.
*/
int diff_include_binary_files(void){
  const char* zArgIncludeBinary = find_option("diff-binary", 0, 1);

  /* Command line argument have priority on settings */
  if( zArgIncludeBinary ){
    return is_truth(zArgIncludeBinary);
  }else{
    return db_get_boolean("diff-binary", 1);
  }
}

/*
** Returns the GLOB pattern for file names that should be treated as binary
** by the diff subsystem, if any.
*/
const char *diff_get_binary_glob(void){
  const char *zBinGlob = find_option("binary", 0, 1);
  if( zBinGlob==0 ) zBinGlob = db_get("binary-glob",0);
  return zBinGlob;
}

/*
** COMMAND: diff
** COMMAND: gdiff
**
** Usage: %fossil diff|gdiff ?OPTIONS? ?FILE1? ?FILE2 ...?
**
** Show the difference between the current version of each of the FILEs
** specified (as they exist on disk) and that same file as it was checked
** out.  Or if the FILE arguments are omitted, show the unsaved changes
** currently in the working check-out.
**











** If the "--from VERSION" or "-r VERSION" option is used it specifies
** the source check-in for the diff operation.  If not specified, the
** source check-in is the base check-in for the current check-out.
**
** If the "--to VERSION" option appears, it specifies the check-in from
** which the second version of the file or files is taken.  If there is
** no "--to" option then the (possibly edited) files in the current check-out
** are used.
**
** The "--checkin VERSION" option shows the changes made by
** check-in VERSION relative to its primary parent.

**
** The "-i" command-line option forces the use of the internal diff logic
** rather than any external diff program that might be configured using
** the "setting" command.  If no external diff program is configured, then
** the "-i" option is a no-op.  The "-i" option converts "gdiff" into "diff".
**
** The "-v" or "--verbose" option causes the complete text of added or
** deleted files to be displayed. -N and --new-file are aliases for
** verbose mode.
**
** The "--diff-binary" option enables or disables the inclusion of binary files
** when using an external diff program.
**
** The "--binary" option causes files matching the glob PATTERN to be treated
** as binary when considering if they should be used with external diff program.
** This option overrides the "binary-glob" setting.
**



** Options:
**   --binary PATTERN            Treat files that match the glob PATTERN
**                               as binary
**   --branch BRANCH             Show diff of all changes on BRANCH
**   --brief                     Show filenames only


**   --checkin VERSION           Show diff of all changes in VERSION
**   --command PROG              External diff program. Overrides "diff-command"
**   -c|--context N              Use N lines of context
**   --diff-binary BOOL          Include binary files with external commands
**   --exec-abs-paths            Force absolute path names on external commands
**   --exec-rel-paths            Force relative path names on external commands
**   -r|--from VERSION           Select VERSION as source for the diff

**   -i|--internal               Use internal diff logic


**   --numstat                   Show only the number of lines delete and added
**   -y|--side-by-side           Side-by-side diff
**   --strip-trailing-cr         Strip trailing CR

**   --tclsh PATH                Tcl/Tk used for --tk (default: "tclsh")
**   --tk                        Launch a Tcl/Tk GUI for display
**   --to VERSION                Select VERSION as target for the diff
**   --undo                      Diff against the "undo" buffer
**   --unified                   Unified diff
**   -v|--verbose                Output complete text of added or deleted files
**   -N|--new-file               Alias for --verbose
**   -w|--ignore-all-space       Ignore white space when comparing lines
**   -W|--width N                Width of lines in side-by-side diff
**   -Z|--ignore-trailing-space  Ignore changes to end-of-line whitespace
*/
void diff_cmd(void){
  int isGDiff;               /* True for gdiff.  False for normal diff */
  int isInternDiff;          /* True for internal diff */
  int verboseFlag;           /* True if -v or --verbose flag is used */
  const char *zFrom;         /* Source version number */
  const char *zTo;           /* Target version number */
  const char *zCheckin;      /* Check-in version number */
  const char *zBranch;       /* Branch to diff */
  const char *zDiffCmd = 0;  /* External diff command. NULL for internal diff */
  const char *zBinGlob = 0;  /* Treat file names matching this as binary */
  int fIncludeBinary = 0;    /* Include binary files for external diff */
  int againstUndo = 0;       /* Diff against files in the undo buffer */
  u64 diffFlags = 0;         /* Flags to control the DIFF */
  FileDirList *pFileDir = 0; /* Restrict the diff to these files */


  if( find_option("tk",0,0)!=0 || has_option("tclsh") ){
    diff_tk("diff", 2);
    return;
  }
  isGDiff = g.argv[1][0]=='g';
  isInternDiff = find_option("internal","i",0)!=0;
  zFrom = find_option("from", "r", 1);
  zTo = find_option("to", 0, 1);
  zCheckin = find_option("checkin", 0, 1);
  zBranch = find_option("branch", 0, 1);
  againstUndo = find_option("undo",0,0)!=0;
  diffFlags = diff_options();
  verboseFlag = find_option("verbose","v",0)!=0;
  if( !verboseFlag ){
    verboseFlag = find_option("new-file","N",0)!=0; /* deprecated */
  }
  if( verboseFlag ) diffFlags |= DIFF_VERBOSE;
  if( againstUndo && ( zFrom!=0 || zTo!=0 || zCheckin!=0 || zBranch!=0) ){
    fossil_fatal("cannot use --undo together with --from, --to, --checkin,"
                 " or --branch");
  }
  if( zBranch ){
    if( zTo || zFrom || zCheckin ){
      fossil_fatal("cannot use --from, --to, or --checkin with --branch");







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


















|


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

|
|
|
|
|
<
<
<








>
>
>





>
>


|




>

>
>



>
|





|
<





<
<




<
<
<

<

>






<





<
<
<
<
<
<







927
928
929
930
931
932
933















934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968


969
970


971
972
973
974
975
976
977
978
979



980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019

1020
1021
1022
1023
1024


1025
1026
1027
1028



1029

1030
1031
1032
1033
1034
1035
1036
1037

1038
1039
1040
1041
1042






1043
1044
1045
1046
1047
1048
1049
    fossil_system(zCmd);
    file_delete(zTempFile);
    fossil_free(zCmd);
  }
  blob_reset(&script);
}
















/*
** Returns the GLOB pattern for file names that should be treated as binary
** by the diff subsystem, if any.
*/
const char *diff_get_binary_glob(void){
  const char *zBinGlob = find_option("binary", 0, 1);
  if( zBinGlob==0 ) zBinGlob = db_get("binary-glob",0);
  return zBinGlob;
}

/*
** COMMAND: diff
** COMMAND: gdiff
**
** Usage: %fossil diff|gdiff ?OPTIONS? ?FILE1? ?FILE2 ...?
**
** Show the difference between the current version of each of the FILEs
** specified (as they exist on disk) and that same file as it was checked
** out.  Or if the FILE arguments are omitted, show all unsaved changes
** currently in the working check-out.
**
** The default output format is a "unified patch" (the same as the
** output of "diff -u" on most unix systems).  Many alternative formats
** are available.  A few of the more useful alternatives:
**
**    --tk              Pop up a TCL/TK-based GUI to show the diff
**    --by              Show a side-by-side diff in the default web browser
**    -b                Show a linear diff in the default web browser
**    -y                Show a text side-by-side diff
**    --webpage         Format output as HTML
**    --webpage -y      HTML output in the side-by-side format
**
** The "--from VERSION" option is used it specifies the source check-in
** for the diff operation.  If not specified, the source check-in is the
** base check-in for the current check-out. Similarly, the "--to VERSION"


** option specifies the check-in from which the second version of the file
** or files is taken.  If there is no "--to" option then the (possibly edited)


** files in the current check-out are used.  The "--checkin VERSION" option
** shows the changes made by check-in VERSION relative to its primary parent.
** The "--branch BRANCHNAME" shows all the changes on the branch BRANCHNAME.
**
** The "-i" command-line option forces the use of Fossils own the internal
** diff logic rather than any external diff program that might be configured
** using the "setting" command.  If no external diff program is configured,
** then the "-i" option is a no-op.  The "-i" option converts "gdiff" into
** "diff".



**
** The "--diff-binary" option enables or disables the inclusion of binary files
** when using an external diff program.
**
** The "--binary" option causes files matching the glob PATTERN to be treated
** as binary when considering if they should be used with external diff program.
** This option overrides the "binary-glob" setting.
**
** These command show differences between managed files. Use the "fossil xdiff"
** command to see differences in unmanaged files.
**
** Options:
**   --binary PATTERN            Treat files that match the glob PATTERN
**                               as binary
**   --branch BRANCH             Show diff of all changes on BRANCH
**   --brief                     Show filenames only
**   -b|--browser                Show the diff output in a web-browser
**   --by                        Shorthand for "--browser -y"
**   --checkin VERSION           Show diff of all changes in VERSION
**   --command PROG              External diff program. Overrides "diff-command"
**   -c|--context N              Show N lines of context around each change
**   --diff-binary BOOL          Include binary files with external commands
**   --exec-abs-paths            Force absolute path names on external commands
**   --exec-rel-paths            Force relative path names on external commands
**   -r|--from VERSION           Select VERSION as source for the diff
**   -w|--ignore-all-space       Ignore white space when comparing lines
**   -i|--internal               Use internal diff logic
**   --json                      Output formatted as JSON
**   -N|--new-file               Alias for --verbose
**   --numstat                   Show only the number of lines delete and added
**   -y|--side-by-side           Side-by-side diff
**   --strip-trailing-cr         Strip trailing CR
**   --tcl                       TCL-formated output used internally by --tk
**   --tclsh PATH                TCL/TK used for --tk (default: "tclsh")
**   --tk                        Launch a Tcl/Tk GUI for display
**   --to VERSION                Select VERSION as target for the diff
**   --undo                      Diff against the "undo" buffer
**   --unified                   Unified diff
**   -v|--verbose                Output complete text of added or deleted files
**   --webpage                   Format output as a stand-alone HTML webpage

**   -W|--width N                Width of lines in side-by-side diff
**   -Z|--ignore-trailing-space  Ignore changes to end-of-line whitespace
*/
void diff_cmd(void){
  int isGDiff;               /* True for gdiff.  False for normal diff */


  const char *zFrom;         /* Source version number */
  const char *zTo;           /* Target version number */
  const char *zCheckin;      /* Check-in version number */
  const char *zBranch;       /* Branch to diff */



  int againstUndo = 0;       /* Diff against files in the undo buffer */

  FileDirList *pFileDir = 0; /* Restrict the diff to these files */
  DiffConfig DCfg;           /* Diff configuration object */

  if( find_option("tk",0,0)!=0 || has_option("tclsh") ){
    diff_tk("diff", 2);
    return;
  }
  isGDiff = g.argv[1][0]=='g';

  zFrom = find_option("from", "r", 1);
  zTo = find_option("to", 0, 1);
  zCheckin = find_option("checkin", 0, 1);
  zBranch = find_option("branch", 0, 1);
  againstUndo = find_option("undo",0,0)!=0;






  if( againstUndo && ( zFrom!=0 || zTo!=0 || zCheckin!=0 || zBranch!=0) ){
    fossil_fatal("cannot use --undo together with --from, --to, --checkin,"
                 " or --branch");
  }
  if( zBranch ){
    if( zTo || zFrom || zCheckin ){
      fossil_fatal("cannot use --from, --to, or --checkin with --branch");
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
  if( zTo==0 || againstUndo ){
    db_must_be_within_tree();
  }else if( zFrom==0 ){
    fossil_fatal("must use --from if --to is present");
  }else{
    db_find_and_open_repository(0, 0);
  }
  if( !isInternDiff ){
    zDiffCmd = find_option("command", 0, 1);
    if( zDiffCmd==0 ) zDiffCmd = diff_command_external(isGDiff);
  }
  zBinGlob = diff_get_binary_glob();
  fIncludeBinary = diff_include_binary_files();
  determine_exec_relative_option(1);
  verify_all_options();
  if( g.argc>=3 ){
    int i;
    Blob fname;
    pFileDir = fossil_malloc( sizeof(*pFileDir) * (g.argc-1) );
    memset(pFileDir, 0, sizeof(*pFileDir) * (g.argc-1));







<
|
<
<
<
<







1058
1059
1060
1061
1062
1063
1064

1065




1066
1067
1068
1069
1070
1071
1072
  if( zTo==0 || againstUndo ){
    db_must_be_within_tree();
  }else if( zFrom==0 ){
    fossil_fatal("must use --from if --to is present");
  }else{
    db_find_and_open_repository(0, 0);
  }

  diff_options(&DCfg, isGDiff, 0);




  determine_exec_relative_option(1);
  verify_all_options();
  if( g.argc>=3 ){
    int i;
    Blob fname;
    pFileDir = fossil_malloc( sizeof(*pFileDir) * (g.argc-1) );
    memset(pFileDir, 0, sizeof(*pFileDir) * (g.argc-1));
951
952
953
954
955
956
957

958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984

985
986
987
988
989
990
991
992
993
994
995
996
997
998
999

1000
1001
1002
1003
1004

1005
1006
      "SELECT uuid FROM blob, plink"
      " WHERE plink.cid=%d AND plink.isprim AND plink.pid=blob.rid",
      ridTo);
    if( zFrom==0 ){
      fossil_fatal("check-in %s has no parent", zTo);
    }
  }

  if( againstUndo ){
    if( db_lget_int("undo_available",0)==0 ){
      fossil_print("No undo or redo is available\n");
      return;
    }
    diff_against_undo(zDiffCmd, zBinGlob, fIncludeBinary,
                      diffFlags, pFileDir);
  }else if( zTo==0 ){
    diff_against_disk(zFrom, zDiffCmd, zBinGlob, fIncludeBinary,
                      diffFlags, pFileDir, 0);
  }else{
    diff_two_versions(zFrom, zTo, zDiffCmd, zBinGlob, fIncludeBinary,
                      diffFlags, pFileDir);
  }
  if( pFileDir ){
    int i;
    for(i=0; pFileDir[i].zName; i++){
      if( pFileDir[i].nUsed==0
       && strcmp(pFileDir[0].zName,".")!=0
       && !file_isdir(g.argv[i+2], ExtFILE)
      ){
        fossil_fatal("not found: '%s'", g.argv[i+2]);
      }
      fossil_free(pFileDir[i].zName);
    }
    fossil_free(pFileDir);
  }

  if ( diffFlags & DIFF_NUMSTAT ){
    fossil_print("%10d %10d TOTAL over %d changed files\n", 
                 g.diffCnt[1], g.diffCnt[2], g.diffCnt[0]);
  }
}

/*
** WEBPAGE: vpatch
** URL: /vpatch?from=FROM&to=TO
**
** Show a patch that goes from check-in FROM to check-in TO.
*/
void vpatch_page(void){
  const char *zFrom = P("from");
  const char *zTo = P("to");

  login_check_credentials();
  if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
  if( zFrom==0 || zTo==0 ) fossil_redirect_home();

  cgi_set_content_type("text/plain");

  diff_two_versions(zFrom, zTo, 0, 0, 0, DIFF_VERBOSE, 0);
}







>





|
<

|
<

|
<














>
|














>





>
|

1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103

1104
1105

1106
1107

1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
      "SELECT uuid FROM blob, plink"
      " WHERE plink.cid=%d AND plink.isprim AND plink.pid=blob.rid",
      ridTo);
    if( zFrom==0 ){
      fossil_fatal("check-in %s has no parent", zTo);
    }
  }
  diff_begin(&DCfg);
  if( againstUndo ){
    if( db_lget_int("undo_available",0)==0 ){
      fossil_print("No undo or redo is available\n");
      return;
    }
    diff_against_undo(&DCfg, pFileDir);

  }else if( zTo==0 ){
    diff_against_disk(zFrom, &DCfg, pFileDir, 0);

  }else{
    diff_two_versions(zFrom, zTo, &DCfg, pFileDir);

  }
  if( pFileDir ){
    int i;
    for(i=0; pFileDir[i].zName; i++){
      if( pFileDir[i].nUsed==0
       && strcmp(pFileDir[0].zName,".")!=0
       && !file_isdir(g.argv[i+2], ExtFILE)
      ){
        fossil_fatal("not found: '%s'", g.argv[i+2]);
      }
      fossil_free(pFileDir[i].zName);
    }
    fossil_free(pFileDir);
  }
  diff_end(&DCfg, 0);
  if ( DCfg.diffFlags & DIFF_NUMSTAT ){
    fossil_print("%10d %10d TOTAL over %d changed files\n", 
                 g.diffCnt[1], g.diffCnt[2], g.diffCnt[0]);
  }
}

/*
** WEBPAGE: vpatch
** URL: /vpatch?from=FROM&to=TO
**
** Show a patch that goes from check-in FROM to check-in TO.
*/
void vpatch_page(void){
  const char *zFrom = P("from");
  const char *zTo = P("to");
  DiffConfig DCfg;
  login_check_credentials();
  if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
  if( zFrom==0 || zTo==0 ) fossil_redirect_home();

  cgi_set_content_type("text/plain");
  diff_config_init(&DCfg, DIFF_VERBOSE);
  diff_two_versions(zFrom, zTo, &DCfg, 0);
}
Changes to src/dispatch.c.
46
47
48
49
50
51
52


53
54
55
56
57
58
59
#define CMDFLAG_WEBPAGE     0x0008      /* Web pages */
#define CMDFLAG_COMMAND     0x0010      /* A command */
#define CMDFLAG_SETTING     0x0020      /* A setting */
#define CMDFLAG_VERSIONABLE 0x0040      /* A versionable setting */
#define CMDFLAG_BLOCKTEXT   0x0080      /* Multi-line text setting */
#define CMDFLAG_BOOLEAN     0x0100      /* A boolean setting */
#define CMDFLAG_RAWCONTENT  0x0200      /* Do not interpret POST content */


/**************************************************************************/

/* Values for the 2nd parameter to dispatch_name_search() */
#define CMDFLAG_ANY         0x0038      /* Match anything */
#define CMDFLAG_PREFIX      0x0200      /* Prefix match is ok */

#endif /* INTERFACE */







>
>







46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#define CMDFLAG_WEBPAGE     0x0008      /* Web pages */
#define CMDFLAG_COMMAND     0x0010      /* A command */
#define CMDFLAG_SETTING     0x0020      /* A setting */
#define CMDFLAG_VERSIONABLE 0x0040      /* A versionable setting */
#define CMDFLAG_BLOCKTEXT   0x0080      /* Multi-line text setting */
#define CMDFLAG_BOOLEAN     0x0100      /* A boolean setting */
#define CMDFLAG_RAWCONTENT  0x0200      /* Do not interpret POST content */
/* NOTE:                    0x0400 = CMDFLAG_SENSITIVE in mkindex.c! */
#define CMDFLAG_HIDDEN      0x0800      /* Elide from most listings */
/**************************************************************************/

/* Values for the 2nd parameter to dispatch_name_search() */
#define CMDFLAG_ANY         0x0038      /* Match anything */
#define CMDFLAG_PREFIX      0x0200      /* Prefix match is ok */

#endif /* INTERFACE */
549
550
551
552
553
554
555

556
557
558
559
560
561
562
    fossil_print("-->\n");
    fossil_print("<!-- start_all_help -->\n");
  }else{
    fossil_print("---\n");
  }
  for(i=0; i<MX_COMMAND; i++){
    if( (aCommand[i].eCmdFlags & mask)==0 ) continue;

    if( useHtml ){
      Blob html;
      blob_init(&html, 0, 0);
      help_to_html(aCommand[i].zHelp, &html);
      fossil_print("<h1>%h</h1>\n", aCommand[i].zName);
      fossil_print("%s\n<hr>\n", blob_str(&html));
      blob_reset(&html);







>







551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
    fossil_print("-->\n");
    fossil_print("<!-- start_all_help -->\n");
  }else{
    fossil_print("---\n");
  }
  for(i=0; i<MX_COMMAND; i++){
    if( (aCommand[i].eCmdFlags & mask)==0 ) continue;
    else if(aCommand[i].eCmdFlags & CMDFLAG_HIDDEN) continue;
    if( useHtml ){
      Blob html;
      blob_init(&html, 0, 0);
      help_to_html(aCommand[i].zHelp, &html);
      fossil_print("<h1>%h</h1>\n", aCommand[i].zName);
      fossil_print("%s\n<hr>\n", blob_str(&html));
      blob_reset(&html);
827
828
829
830
831
832
833

834
835
836
837
838
839
840
841
842
843
844

845
846
847
848
849
850
851
852
853
854
855
856
857
858
859

860
861
862
863
864
865
866
867
868
869
870
871
872
873
874

875
876
877
878
879
880
881
    @ <ul>
    for(i=0; i<MX_COMMAND; i++){
      const char *z = aCommand[i].zName;
      const char *zBoldOn  = aCommand[i].eCmdFlags&CMDFLAG_1ST_TIER?"<b>" :"";
      const char *zBoldOff = aCommand[i].eCmdFlags&CMDFLAG_1ST_TIER?"</b>":"";
      if( '/'==*z || strncmp(z,"test",4)==0 ) continue;
      if( (aCommand[i].eCmdFlags & CMDFLAG_SETTING)!=0 ) continue;

      @ <li><a href="%R/help?cmd=%s(z)">%s(zBoldOn)%s(z)%s(zBoldOff)</a></li>
    }
    @ </ul></div>

    @ <a name='webpages'></a>
    @ <h1>Available web UI pages:</h1>
    @ <div class="columns" style="column-width: 18ex;">
    @ <ul>
    for(i=0; i<MX_COMMAND; i++){
      const char *z = aCommand[i].zName;
      if( '/'!=*z ) continue;

      if( aCommand[i].zHelp[0] ){
        @ <li><a href="%R/help?cmd=%s(z)">%s(z+1)</a></li>
      }else{
        @ <li>%s(z+1)</li>
      }
    }
    @ </ul></div>

    @ <a name='unsupported'></a>
    @ <h1>Unsupported commands:</h1>
    @ <div class="columns" style="column-width: 20ex;">
    @ <ul>
    for(i=0; i<MX_COMMAND; i++){
      const char *z = aCommand[i].zName;
      if( strncmp(z,"test",4)!=0 ) continue;

      if( aCommand[i].zHelp[0] ){
        @ <li><a href="%R/help?cmd=%s(z)">%s(z)</a></li>
      }else{
        @ <li>%s(z)</li>
      }
    }
    @ </ul></div>

    @ <a name='settings'></a>
    @ <h1>Settings:</h1>
    @ <div class="columns" style="column-width: 20ex;">
    @ <ul>
    for(i=0; i<MX_COMMAND; i++){
      const char *z = aCommand[i].zName;
      if( (aCommand[i].eCmdFlags & CMDFLAG_SETTING)==0 ) continue;

      if( aCommand[i].zHelp[0] ){
        @ <li><a href="%R/help?cmd=%s(z)">%s(z)</a></li>
      }else{
        @ <li>%s(z)</li>
      }
    }
    @ </ul></div>







>











>















>















>







830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
    @ <ul>
    for(i=0; i<MX_COMMAND; i++){
      const char *z = aCommand[i].zName;
      const char *zBoldOn  = aCommand[i].eCmdFlags&CMDFLAG_1ST_TIER?"<b>" :"";
      const char *zBoldOff = aCommand[i].eCmdFlags&CMDFLAG_1ST_TIER?"</b>":"";
      if( '/'==*z || strncmp(z,"test",4)==0 ) continue;
      if( (aCommand[i].eCmdFlags & CMDFLAG_SETTING)!=0 ) continue;
      else if( (aCommand[i].eCmdFlags & CMDFLAG_HIDDEN)!=0 ) continue;
      @ <li><a href="%R/help?cmd=%s(z)">%s(zBoldOn)%s(z)%s(zBoldOff)</a></li>
    }
    @ </ul></div>

    @ <a name='webpages'></a>
    @ <h1>Available web UI pages:</h1>
    @ <div class="columns" style="column-width: 18ex;">
    @ <ul>
    for(i=0; i<MX_COMMAND; i++){
      const char *z = aCommand[i].zName;
      if( '/'!=*z ) continue;
      else if( (aCommand[i].eCmdFlags & CMDFLAG_HIDDEN)!=0 ) continue;
      if( aCommand[i].zHelp[0] ){
        @ <li><a href="%R/help?cmd=%s(z)">%s(z+1)</a></li>
      }else{
        @ <li>%s(z+1)</li>
      }
    }
    @ </ul></div>

    @ <a name='unsupported'></a>
    @ <h1>Unsupported commands:</h1>
    @ <div class="columns" style="column-width: 20ex;">
    @ <ul>
    for(i=0; i<MX_COMMAND; i++){
      const char *z = aCommand[i].zName;
      if( strncmp(z,"test",4)!=0 ) continue;
      else if( (aCommand[i].eCmdFlags & CMDFLAG_HIDDEN)!=0 ) continue;
      if( aCommand[i].zHelp[0] ){
        @ <li><a href="%R/help?cmd=%s(z)">%s(z)</a></li>
      }else{
        @ <li>%s(z)</li>
      }
    }
    @ </ul></div>

    @ <a name='settings'></a>
    @ <h1>Settings:</h1>
    @ <div class="columns" style="column-width: 20ex;">
    @ <ul>
    for(i=0; i<MX_COMMAND; i++){
      const char *z = aCommand[i].zName;
      if( (aCommand[i].eCmdFlags & CMDFLAG_SETTING)==0 ) continue;
      else if( (aCommand[i].eCmdFlags & CMDFLAG_HIDDEN)!=0 ) continue;
      if( aCommand[i].zHelp[0] ){
        @ <li><a href="%R/help?cmd=%s(z)">%s(z)</a></li>
      }else{
        @ <li>%s(z)</li>
      }
    }
    @ </ul></div>
983
984
985
986
987
988
989

990
991
992
993
994
995
996
  if( verboseFlag ){
    display_all_help(cmdMask, useHtml, 0);
  }else{
    int i, nCmd;
    const char *aCmd[MX_COMMAND];
    for(i=nCmd=0; i<MX_COMMAND; i++){
      if( (aCommand[i].eCmdFlags & cmdMask)==0 ) continue;

      aCmd[nCmd++] = aCommand[i].zName;
    }
    multi_column_list(aCmd, nCmd);
  }
}

/*







>







990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
  if( verboseFlag ){
    display_all_help(cmdMask, useHtml, 0);
  }else{
    int i, nCmd;
    const char *aCmd[MX_COMMAND];
    for(i=nCmd=0; i<MX_COMMAND; i++){
      if( (aCommand[i].eCmdFlags & cmdMask)==0 ) continue;
      else if(aCommand[i].eCmdFlags & CMDFLAG_HIDDEN) continue;
      aCmd[nCmd++] = aCommand[i].zName;
    }
    multi_column_list(aCmd, nCmd);
  }
}

/*
Changes to src/file.c.
2158
2159
2160
2161
2162
2163
2164
















2165
2166
2167
2168
2169
2170
2171
  fossil_path_free(uName);
  fossil_unicode_free(uMode);
#else
  FILE *f = fopen(zName, zMode);
#endif
  return f;
}

















/*
** Works like fclose() except that:
**
** 1) is a no-op if f is 0 or if it is stdin.
**
** 2) If f is one of (stdout, stderr), it is flushed but not closed.







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







2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
  fossil_path_free(uName);
  fossil_unicode_free(uMode);
#else
  FILE *f = fopen(zName, zMode);
#endif
  return f;
}

/*
** Wrapper for freopen() that understands UTF8 arguments.
*/
FILE *fossil_freopen(const char *zName, const char *zMode, FILE *stream){
#ifdef _WIN32
  wchar_t *uMode = fossil_utf8_to_unicode(zMode);
  wchar_t *uName = fossil_utf8_to_path(zName, 0);
  FILE *f = _wfreopen(uName, uMode, stream);
  fossil_path_free(uName);
  fossil_unicode_free(uMode);
#else
  FILE *f = freopen(zName, zMode, stream);
#endif
  return f;
}

/*
** Works like fclose() except that:
**
** 1) is a no-op if f is 0 or if it is stdin.
**
** 2) If f is one of (stdout, stderr), it is flushed but not closed.
Changes to src/fileedit.c.
1142
1143
1144
1145
1146
1147
1148

1149
1150

1151
1152
1153
1154
1155
1156
1157
  if(!zContent){
    zContent = "";
  }
  cgi_set_content_type("text/html");
  blob_init(&content, zContent, -1);
  {
    Blob orig = empty_blob;

    content_get(frid, &orig);
    ajax_render_diff(&orig, &content, diffFlags);

    blob_reset(&orig);
  }
  fossil_free(zRevUuid);
  blob_reset(&content);
}

/*







>

|
>







1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
  if(!zContent){
    zContent = "";
  }
  cgi_set_content_type("text/html");
  blob_init(&content, zContent, -1);
  {
    Blob orig = empty_blob;
    char * const zOrigUuid = rid_to_uuid(frid);
    content_get(frid, &orig);
    ajax_render_diff(&orig, zOrigUuid, &content, diffFlags);
    fossil_free(zOrigUuid);
    blob_reset(&orig);
  }
  fossil_free(zRevUuid);
  blob_reset(&content);
}

/*
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
     ">");
  {
    /******* Commit flags/options *******/
    CX("<div class='fileedit-options flex-container flex-row'>");
    style_labeled_checkbox("cb-dry-run",
                           "dry_run", "Dry-run?", "1",
                           0,
                           "In dry-run mode, the Commit button performs"
                           "all work needed for committing changes but "
                           "then rolls back the transaction, and thus "
                           "does not really commit.");
    style_labeled_checkbox("cb-allow-fork",
                           "allow_fork", "Allow fork?", "1",
                           cimi.flags & CIMINI_ALLOW_FORK,
                           "Allow committing to create a fork?");







|







1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
     ">");
  {
    /******* Commit flags/options *******/
    CX("<div class='fileedit-options flex-container flex-row'>");
    style_labeled_checkbox("cb-dry-run",
                           "dry_run", "Dry-run?", "1",
                           0,
                           "In dry-run mode, the Commit button performs "
                           "all work needed for committing changes but "
                           "then rolls back the transaction, and thus "
                           "does not really commit.");
    style_labeled_checkbox("cb-allow-fork",
                           "allow_fork", "Allow fork?", "1",
                           cimi.flags & CIMINI_ALLOW_FORK,
                           "Allow committing to create a fork?");
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
  ** used for dynamically toggling certain UI components on and off.
  ** Must come after window.fossil has been intialized and before
  ** fossil.page.fileedit.js. Potential TODO: move this into the
  ** window.fossil bootstrapping so that we don't have to "fulfill"
  ** the JS multiple times.
  */
  ajax_emit_js_preview_modes(1);
  builtin_request_js("sbsdiff.js");
  builtin_request_js("fossil.page.fileedit.js");
  builtin_fulfill_js_requests();
  {
    /* Dynamically populate the editor, display any error in the err
    ** blob, and/or switch to tab #0, where the file selector
    ** lives. The extra C scopes here correspond to JS-level scopes,
    ** to improve grokability. */







|







1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
  ** used for dynamically toggling certain UI components on and off.
  ** Must come after window.fossil has been intialized and before
  ** fossil.page.fileedit.js. Potential TODO: move this into the
  ** window.fossil bootstrapping so that we don't have to "fulfill"
  ** the JS multiple times.
  */
  ajax_emit_js_preview_modes(1);
  builtin_fossil_js_bundle_or("diff", NULL);
  builtin_request_js("fossil.page.fileedit.js");
  builtin_fulfill_js_requests();
  {
    /* Dynamically populate the editor, display any error in the err
    ** blob, and/or switch to tab #0, where the file selector
    ** lives. The extra C scopes here correspond to JS-level scopes,
    ** to improve grokability. */
Changes to src/finfo.c.
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
**    ci=HASH         identify a particular version of a file and then
**                    track changes to that file across renames
**    m=HASH          Mark this particular file version.
**    n=NUM           Show the first NUM changes only
**    name=FILENAME   (Required) name of file whose history to show
**    brbg            Background color by branch name
**    ubg             Background color by user name
**    from=HASH       Ancestors only (not descendents) of the version of
**                    the file in this particular check-in.
**    to=HASH         If both from= and to= are supplied, only show those
**                    changes on the direct path between the two given
**                    checkins.
**    showid          Show RID values for debugging
**    showsql         Show the SQL query used to gather the data for
**                    the graph







|







317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
**    ci=HASH         identify a particular version of a file and then
**                    track changes to that file across renames
**    m=HASH          Mark this particular file version.
**    n=NUM           Show the first NUM changes only
**    name=FILENAME   (Required) name of file whose history to show
**    brbg            Background color by branch name
**    ubg             Background color by user name
**    from=HASH       Ancestors only (not descendants) of the version of
**                    the file in this particular check-in.
**    to=HASH         If both from= and to= are supplied, only show those
**                    changes on the direct path between the two given
**                    checkins.
**    showid          Show RID values for debugging
**    showsql         Show the SQL query used to gather the data for
**                    the graph
Changes to src/forum.c.
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
  char *zGoto;
  login_check_credentials();
  if( !g.perm.WrForum ){
    login_needed(g.anon.WrForum);
    return;
  }
  if( sqlite3_strglob("*edit*", g.zPath)==0 ){
    zGoto = mprintf("%R/forume2?fpid=%S",PD("fpid",""));
    isEdit = 1;
  }else{
    zGoto = mprintf("%R/forume1");
    isEdit = 0;
  }
  if( login_is_individual() ){
    if( isEdit ){
      forumedit_page();
    }else{
      forumnew_page();







|


|







1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
  char *zGoto;
  login_check_credentials();
  if( !g.perm.WrForum ){
    login_needed(g.anon.WrForum);
    return;
  }
  if( sqlite3_strglob("*edit*", g.zPath)==0 ){
    zGoto = mprintf("forume2?fpid=%S",PD("fpid",""));
    isEdit = 1;
  }else{
    zGoto = mprintf("forume1");
    isEdit = 0;
  }
  if( login_is_individual() ){
    if( isEdit ){
      forumedit_page();
    }else{
      forumnew_page();
Name change from src/fossil.info-diff.js to src/fossil.diff.js.



1
2




3
4
5
6
7
8
9
10
11
12













































































































































































































































































































































































































































































































































































































13
















14
























































































































"use strict";
window.fossil.onPageLoad(function(){




  const F = window.fossil, D = F.dom;
  const addToggle = function(diffElem){
    const sib = diffElem.previousElementSibling,
          btn = sib ? D.addClass(D.checkbox(true), 'diff-toggle') : 0;
    if(!sib) return;
    D.append(sib,btn);
    btn.addEventListener('click', function(){
      diffElem.classList.toggle('hidden');
    }, false);
  };













































































































































































































































































































































































































































































































































































































  document.querySelectorAll('pre.udiff, table.sbsdiffcols').forEach(addToggle);
















});





















































































































>
>
>


>
>
>
>
|









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

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
/**
   diff-related JS APIs for fossil.
*/
"use strict";
window.fossil.onPageLoad(function(){
  /**
     Adds toggle checkboxes to each file entry in the diff views for
     /info and similar pages.
  */
  const D = window.fossil.dom;
  const addToggle = function(diffElem){
    const sib = diffElem.previousElementSibling,
          btn = sib ? D.addClass(D.checkbox(true), 'diff-toggle') : 0;
    if(!sib) return;
    D.append(sib,btn);
    btn.addEventListener('click', function(){
      diffElem.classList.toggle('hidden');
    }, false);
  };
  document.querySelectorAll('table.diff').forEach(addToggle);
});

window.fossil.onPageLoad(function(){
  const F = window.fossil, D = F.dom;
  const Diff = F.diff = {
    e:{/*certain cached DOM elements*/},
    config: {
      chunkLoadLines: (
        F.config.diffContextLines * 3
        /*per /chat discussion*/
      ) || 20,
      chunkFetch: {
        /* Default callack handlers for Diff.fetchArtifactChunk(),
           unless overridden by options passeed to that function. */
        beforesend: function(){},
        aftersend: function(){},
        onerror: function(e){
          console.error("XHR error: ",e);
        }
      }
    }
  };
  /**
     Uses the /jchunk AJAX route to fetch specific lines of a given
     artifact. The argument must be an Object suitable for passing as
     the second argument to fossil.fetch(). Its urlParams property
     must be an object with these properties:

     {
       name: full hash of the target file,
       from: first 1-based line number of the file to fetch (inclusive),
       to: last 1-based line number of the file to fetch (inclusive)
     }

     The fetchOpt object is NOT cloned for use by the call: it is used
     as-is and may be modified by this call. Thus callers "really
     should" pass a temporary object, not a long-lived one.

     If fetchOpt does not define any of the (beforesend, aftersend,
     onerror) callbacks, the defaults from fossil.diff.config.chunkFetch
     are used, so any given client page may override those to provide
     page-level default handling.

     Note that onload callback is ostensibly optional but this
     function is not of much use without an onload
     handler. Conversely, the default onerror handler is often
     customized on a per-page basis to send the error output somewhere
     where the user can see it.

     The response, on success, will be an array of strings, each entry
     being one line from the requested artifact. If the 'to' line is
     greater than the length of the file, the array will be shorter
     than (to-from) lines.

     The /jchunk route reports errors via JSON objects with
     an "error" string property describing the problem.

     This is an async operation. Returns the fossil object.
  */
  Diff.fetchArtifactChunk = function(fetchOpt){
    if(!fetchOpt.beforesend) fetchOpt.beforesend = Diff.config.chunkFetch.beforesend;
    if(!fetchOpt.aftersend) fetchOpt.aftersend = Diff.config.chunkFetch.aftersend;
    if(!fetchOpt.onerror) fetchOpt.onerror = Diff.config.chunkFetch.onerror;
    fetchOpt.responseType = 'json';
    return F.fetch('jchunk', fetchOpt);
  };


  /**
     Extracts either the starting or ending line number from a
     line-numer column in the given tr. isSplit must be true if tr
     represents a split diff, else false. Expects its tr to be valid:
     GIGO applies.  Returns the starting line number if getStart, else
     the ending line number. Returns the line number from the LHS file
     if getLHS is true, else the RHS.
  */
  const extractLineNo = function f(getLHS, getStart, tr, isSplit){
    if(!f.rx){
      f.rx = {
        start: /^\s*(\d+)/,
        end: /(\d+)\n?$/
      }
    }
    const td = tr.querySelector('td:nth-child('+(
      /* TD element with the line numbers */
      getLHS ? 1 : (isSplit ? 4 : 2)
    )+')');
    const m = f.rx[getStart ? 'start' : 'end'].exec(td.innerText);
    return m ? +m[1] : undefined/*"shouldn't happen"*/;
  };
  
  /**
     Installs chunk-loading controls into TR.diffskip element tr.
     Each instance corresponds to a single TR.diffskip element.

     The goal is to base these controls roughly on github's, a good
     example of which, for use as a model, is:

     https://github.com/msteveb/autosetup/commit/235925e914a52a542
  */
  const ChunkLoadControls = function(tr){
    this.$fetchQueue = [];
    this.e = {/*DOM elements*/
      tr: tr,
      table: tr.parentElement/*TBODY*/.parentElement
    };
    this.isSplit = this.e.table.classList.contains('splitdiff')/*else udiff*/;
    this.fileHash = this.e.table.dataset.lefthash;
    tr.$chunker = this /* keep GC from reaping this */;
    this.pos = {
      /* These line numbers correspond to the LHS file. Because the
         contents are common to both sides, we have the same number
         for the RHS, but need to extract those line numbers from the
         neighboring TR blocks */
      startLhs: +tr.dataset.startln,
      endLhs: +tr.dataset.endln
    };
    D.clearElement(tr);
    this.e.td = D.addClass(
      /* Holder for our UI controls */
      D.attr(D.td(tr), 'colspan', this.isSplit ? 5 : 4),
      'chunkctrl'
    );
    this.e.msgWidget = D.addClass(D.span(), 'hidden');
    this.e.btnWrapper = D.div();
    D.append(this.e.td, this.e.btnWrapper);
    /**
       Depending on various factors, we need one or more of:

       - A single button to load the initial chunk incrementally

       - A single button to load all lines then remove this control

       - Two buttons: one to load upwards, one to load downwards

       - A single button to load the final chunk incrementally
    */
    if(tr.nextElementSibling){
      this.pos.next = {
        startLhs: extractLineNo(true, true, tr.nextElementSibling, this.isSplit),
        startRhs: extractLineNo(false, true, tr.nextElementSibling, this.isSplit)
      };
    }
    if(tr.previousElementSibling){
      this.pos.prev = {
        endLhs: extractLineNo(true, false, tr.previousElementSibling, this.isSplit),
        endRhs: extractLineNo(false, false, tr.previousElementSibling, this.isSplit)
      };
    }
    let btnUp = false, btnDown = false;
    /**
       this.pos.next refers to the line numbers in the next TR's chunk.
       this.pos.prev refers to the line numbers in the previous TR's chunk.
    */
    if(this.pos.prev && this.pos.next
       && ((this.pos.next.startLhs - this.pos.prev.endLhs)
           <= Diff.config.chunkLoadLines)){
      /* Place a single button to load the whole block, rather
         than separate up/down buttons. */
      btnDown = false;
      btnUp = this.createButton(this.FetchType.FillGap);
    }else{
      /* Figure out which chunk-load buttons to add... */
      if(this.pos.prev){
        btnDown = this.createButton(this.FetchType.PrevDown);
      }
      if(this.pos.next){
        btnUp = this.createButton(this.FetchType.NextUp);
      }
    }
    //this.e.btnUp = btnUp;
    //this.e.btnDown = btnDown;
    if(btnUp) D.append(this.e.btnWrapper, btnUp);
    if(btnDown) D.append(this.e.btnWrapper, btnDown);
    D.append(this.e.btnWrapper, this.e.msgWidget);
    /* For debugging only... */
    this.e.posState = D.span();
    D.append(this.e.btnWrapper, this.e.posState);
    this.updatePosDebug();
  };

  ChunkLoadControls.prototype = {
    /** An "enum" of values describing the types of context
        fetches/operations performed by this type. The values in this
        object must not be changed without modifying all logic which
        relies on their relative order. */
    FetchType:{
      /** Append context to the bottom of the previous diff chunk. */
      PrevDown: 1,
      /** Fill a complete gap between the previous/next diff chunks
          or at the start of the next chunk or end of the previous
          chunks. */
      FillGap: 0,
      /** Prepend context to the start of the next diff chunk. */
      NextUp: -1,
      /** Process the next queued action. */
      ProcessQueue: 0x7fffffff
    },

    /**
       Creates and returns a button element for fetching a chunk in
       the given fetchType (as documented for fetchChunk()).
    */
    createButton: function(fetchType){
      let b;
      switch(fetchType){
      case this.FetchType.PrevDown:
        b = D.append(
          D.addClass(D.span(), 'down'),
          D.span(/*glyph holder*/)
        );
        break;
      case this.FetchType.FillGap:
        b = D.append(
          D.addClass(D.span(), 'up', 'down'),
          D.span(/*glyph holder*/)
        );
        break;
      case this.FetchType.NextUp:
        b = D.append(
          D.addClass(D.span(), 'up'),
          D.span(/*glyph holder*/)
        );
        break;
      default:
        throw new Error("Internal API misuse: unexpected fetchType value "+fetchType);
      }
      D.addClass(b, 'jcbutton');
      b.addEventListener('click', ()=>this.fetchChunk(fetchType),false);
      return b;
    },

    updatePosDebug: function(){
      if(this.e.posState){
        D.clearElement(this.e.posState);
        //D.append(D.clearElement(this.e.posState), JSON.stringify(this.pos));
      }
      return this;
    },

    /* Attempt to clean up resources and remove some circular references to
       that GC can do the right thing. */
    destroy: function(){
      delete this.$fetchQueue;
      D.remove(this.e.tr);
      delete this.e.tr.$chunker;
      delete this.e.tr;
      delete this.e;
      delete this.pos;
    },

    /**
       If the gap between this.pos.endLhs/startLhs is less than or equal to
       Diff.config.chunkLoadLines then this function replaces any up/down buttons
       with a gap-filler button, else it's a no-op. Returns this object.

       As a special case, do not apply this at the start or bottom
       of the diff, only between two diff chunks.
    */
    maybeReplaceButtons: function(){
      if(this.pos.next && this.pos.prev
         && (this.pos.endLhs - this.pos.startLhs <= Diff.config.chunkLoadLines)){
        D.clearElement(this.e.btnWrapper);
        D.append(this.e.btnWrapper, this.createButton(this.FetchType.FillGap));
        if( this.$fetchQueue && this.$fetchQueue.length>1 ){
          this.$fetchQueue[1] = this.FetchType.FillGap;
          this.$fetchQueue.length = 2;
        }
      }
      return this;
    },

    /**
       Callack for /jchunk responses.
    */
    injectResponse: function f(fetchType/*as for fetchChunk()*/,
                               urlParam/*from fetchChunk()*/,
                               lines/*response lines*/){
      if(!lines.length){
        /* No more data to load */
        this.destroy();
        return this;
      }
      this.msg(false);
      //console.debug("Loaded line range ",
      //urlParam.from,"-",urlParam.to, "fetchType ",fetchType);
      const lineno = [],
            trPrev = this.e.tr.previousElementSibling,
            trNext = this.e.tr.nextElementSibling,
            doAppend = (
              !!trPrev && fetchType>=this.FetchType.FillGap
            ) /* true to append to previous TR, else prepend to NEXT TR */;
      const tr = doAppend ? trPrev : trNext;
      const joinTr = (
        this.FetchType.FillGap===fetchType && trPrev && trNext
      ) ? trNext : false
      /* Truthy if we want to combine trPrev, the new content, and
         trNext into trPrev and then remove trNext. */;
      let i, td;
      if(!f.convertLines){
        /* Reminder: string.replaceAll() is a relatively new
           JS feature, not available in some still-widely-used
           browser versions. */
        f.rx = [[/&/g, '&amp;'], [/</g, '&lt;']];
        f.convertLines = function(li){
          var s = li.join('\n');
          f.rx.forEach((a)=>s=s.replace(a[0],a[1]));
          return s + '\n';
        };
      }
      if(1){ // LHS line numbers...
        const selector = '.difflnl > pre';
        td = tr.querySelector(selector);
        const lnTo = Math.min(urlParam.to,
                              urlParam.from +
                              lines.length - 1/*b/c request range is inclusive*/);
        for( i = urlParam.from; i <= lnTo; ++i ){
          lineno.push(i);
        }
        const lineNoTxt = lineno.join('\n')+'\n';
        const content = [td.innerHTML];
        if(doAppend) content.push(lineNoTxt);
        else content.unshift(lineNoTxt);
        if(joinTr){
          content.push(trNext.querySelector(selector).innerHTML);
        }
        td.innerHTML = content.join('');
      }

      if(1){// code block(s)...
        const selector = '.difftxt > pre';
        td = tr.querySelectorAll(selector);
        const code = f.convertLines(lines);
        let joinNdx = 0/*selector[X] index to join together*/;
        td.forEach(function(e){
          const content = [e.innerHTML];
          if(doAppend) content.push(code);
          else content.unshift(code);
          if(joinTr){
            content.push(trNext.querySelectorAll(selector)[joinNdx++].innerHTML)
          }
          e.innerHTML = content.join('');
        });
      }

      if(1){// Add blank lines in (.diffsep>pre)
        const selector = '.diffsep > pre';
        td = tr.querySelector(selector);
        for(i = 0; i < lineno.length; ++i) lineno[i] = '';
        const blanks = lineno.join('\n')+'\n';
        const content = [td.innerHTML];
        if(doAppend) content.push(blanks);
        else content.unshift(blanks);
        if(joinTr){
          content.push(trNext.querySelector(selector).innerHTML);
        }
        td.innerHTML = content.join('');
      }

      if(this.FetchType.FillGap===fetchType){
        /* Closing the whole gap between two chunks or a whole gap
           at the start or end of a diff. */
        // RHS line numbers...
        let startLnR = this.pos.prev
            ? this.pos.prev.endRhs+1 /* Closing the whole gap between two chunks
                                        or end-of-file gap. */
            : this.pos.next.startRhs - lines.length /* start-of-file gap */;
        lineno.length = lines.length;
        for( i = startLnR; i < startLnR + lines.length; ++i ){
          lineno[i-startLnR] = i;
        }
        const selector = '.difflnr > pre';
        td = tr.querySelector(selector);
        const lineNoTxt = lineno.join('\n')+'\n';
        lineno.length = 0;
        const content = [td.innerHTML];
        if(doAppend) content.push(lineNoTxt);
        else content.unshift(lineNoTxt);
        if(joinTr){
          content.push(trNext.querySelector(selector).innerHTML);
        }
        td.innerHTML = content.join('');
        if(joinTr) D.remove(joinTr);
        Diff.checkTableWidth(true);
        this.destroy();
        return this;
      }else if(this.FetchType.PrevDown===fetchType){
        /* Append context to previous TR. */
        // RHS line numbers...
        let startLnR = this.pos.prev.endRhs+1;
        lineno.length = lines.length;
        for( i = startLnR; i < startLnR + lines.length; ++i ){
          lineno[i-startLnR] = i;
        }
        this.pos.startLhs += lines.length;
        this.pos.prev.endRhs += lines.length;
        this.pos.prev.endLhs += lines.length;
        const selector = '.difflnr > pre';
        td = tr.querySelector(selector);
        const lineNoTxt = lineno.join('\n')+'\n';
        lineno.length = 0;
        const content = [td.innerHTML];
        if(doAppend) content.push(lineNoTxt);
        else content.unshift(lineNoTxt);
        td.innerHTML = content.join('');
        if(lines.length < (urlParam.to - urlParam.from)){
          /* No more data. */
          this.destroy();
        }else{
          this.maybeReplaceButtons();
          this.updatePosDebug();
        }
        Diff.checkTableWidth(true);
        return this;
      }else if(this.FetchType.NextUp===fetchType){
        /* Prepend content to next TR. */
        // RHS line numbers...
        if(doAppend){
          throw new Error("Internal precondition violation: doAppend is true.");
        }
        let startLnR = this.pos.next.startRhs - lines.length;
        lineno.length = lines.length;
        for( i = startLnR; i < startLnR + lines.length; ++i ){
          lineno[i-startLnR] = i;
        }
        this.pos.endLhs -= lines.length;
        this.pos.next.startRhs -= lines.length;
        this.pos.next.startLhs -= lines.length;
        const selector = '.difflnr > pre';
        td = tr.querySelector(selector);
        const lineNoTxt = lineno.join('\n')+'\n';
        lineno.length = 0;
        td.innerHTML = lineNoTxt + td.innerHTML;
        if(this.pos.endLhs<1
           || lines.length < (urlParam.to - urlParam.from)){
          /* No more data. */
          this.destroy();
        }else{
          this.maybeReplaceButtons();
          this.updatePosDebug();
        }
        Diff.checkTableWidth(true);
        return this;
      }else{
        throw new Error("Unexpected 'fetchType' value.");
      }
    },

    /**
       Sets this widget's message to the given text. If the message
       represents an error, the first argument must be truthy, else it
       must be falsy. Returns this object.
    */
    msg: function(isError,txt){
      if(txt){
        if(isError) D.addClass(this.e.msgWidget, 'error');
        else D.removeClass(this.e.msgWidget, 'error');
        D.append(
          D.removeClass(D.clearElement(this.e.msgWidget), 'hidden'),
          txt);
      }else{
        D.addClass(D.clearElement(this.e.msgWidget), 'hidden');
      }
      return this;
    },

    /**
       Fetches and inserts a line chunk. fetchType is:

       this.FetchType.NextUp = upwards from next chunk (this.pos.next)

       this.FetchType.FillGap = the whole gap between this.pos.prev
       and this.pos.next, or the whole gap before/after the
       initial/final chunk in the diff.

       this.FetchType.PrevDown = downwards from the previous chunk
       (this.pos.prev)

       Those values are set at the time this object is initialized but
       one instance of this class may have 2 buttons, one each for
       fetchTypes NextUp and PrevDown.

       This is an async operation. While it is in transit, any calls
       to this function will have no effect except (possibly) to emit
       a warning. Returns this object.
    */
    fetchChunk: function(fetchType){
      if( !this.$fetchQueue ) return this;  // HACKHACK: are we destroyed?
      if( fetchType==this.FetchType.ProcessQueue ){
        this.$fetchQueue.shift();
        if( this.$fetchQueue.length==0 ) return this;
        //console.log('fetchChunk: processing queue ...');
      }
      else{
        this.$fetchQueue.push(fetchType);
        if( this.$fetchQueue.length!=1 ) return this;
        //console.log('fetchChunk: processing user input ...');
      }
      fetchType = this.$fetchQueue[0];
      if( fetchType==this.FetchType.ProcessQueue ){
        /* Unexpected! Clear queue so recovery (manual restart) is possible. */
        this.$fetchQueue.length = 0;
        return this;
      }
      /* Forewarning, this is a bit confusing: when fetching the
         previous lines, we're doing so on behalf of the *next* diff
         chunk (this.pos.next), and vice versa. */
      if(fetchType===this.FetchType.NextUp && !this.pos.next
        || fetchType===this.FetchType.PrevDown && !this.pos.prev){
        console.error("Attempt to fetch diff lines but don't have any.");
        return this;
      }
      this.msg(false,"Fetching diff chunk...");
      const self = this;
      const fOpt = {
        urlParams:{
          name: this.fileHash, from: 0, to: 0
        },
        aftersend: ()=>this.msg(false),
        onload: function(list){
          self.injectResponse(fetchType,up,list);
          if( !self.$fetchQueue || self.$fetchQueue.length==0 ) return;
          /* Keep queue length > 0, or clicks stalled during (unusually lengthy)
             injectResponse() may sneak in as soon as setTimeout() allows, find
             an empty queue, and therefore start over with queue processing. */
          self.$fetchQueue[0] = self.FetchType.ProcessQueue;
          setTimeout(self.fetchChunk.bind(self,self.FetchType.ProcessQueue));
        }
      };
      const up = fOpt.urlParams;
      if(fetchType===this.FetchType.FillGap){
        /* Easiest case: filling a whole gap. */
        up.from = this.pos.startLhs;
        up.to = this.pos.endLhs;
      }else if(this.FetchType.PrevDown===fetchType){
        /* Append to previous TR. */
        if(!this.pos.prev){
          console.error("Attempt to fetch next diff lines but don't have any.");
          return this;
        }
        up.from = this.pos.prev.endLhs + 1;
        up.to = up.from +
          Diff.config.chunkLoadLines - 1/*b/c request range is inclusive*/;
        if( this.pos.next && this.pos.next.startLhs <= up.to ){
          up.to = this.pos.next.startLhs - 1;
          fetchType = this.FetchType.FillGap;
        }
      }else{
        /* Prepend to next TR */
        if(!this.pos.next){
          console.error("Attempt to fetch previous diff lines but don't have any.");
          return this;
        }
        up.to = this.pos.next.startLhs - 1;
        up.from = Math.max(1, up.to - Diff.config.chunkLoadLines + 1);
        if( this.pos.prev && this.pos.prev.endLhs >= up.from ){
          up.from = this.pos.prev.endLhs + 1;
          fetchType = this.FetchType.FillGap;
        }
      }
      //console.debug("fetchChunk(",fetchType,")",up);
      fOpt.onerror = function(err){
        if(self.e/*guard against a late-stage onerror() call*/){
          self.msg(true,err.message);
          self.$fetchQueue.length = 0;
        }else{
          Diff.config.chunkFetch.onerror.call(this,err);
        }
      };
      Diff.fetchArtifactChunk(fOpt);
      return this;
    }
  };

  /**
     Adds context-loading buttons to one or more tables. The argument
     may be a forEach-capable list of diff table elements, a query
     selector string matching 0 or more diff tables, or falsy, in
     which case all relevant diff tables are set up. It tags each
     table it processes to that it will not be processed multiple
     times by subsequent calls to this function.

     Note that this only works for diffs which have been marked up
     with certain state, namely table.dataset.lefthash and TR
     entries which hold state related to browsing context.
  */
  Diff.setupDiffContextLoad = function(tables){
    if('string'===typeof tables){
      tables = document.querySelectorAll(tables);
    }else if(!tables){
      tables = document.querySelectorAll('table.diff[data-lefthash]:not(.diffskipped)');
    }
    /* Potential performance-related TODO: instead of installing all
       of these at once, install them as the corresponding TR is
       scrolled into view. */
    tables.forEach(function(table){
      if(table.classList.contains('diffskipped') || !table.dataset.lefthash) return;
      D.addClass(table, 'diffskipped'/*avoid processing these more than once */);
      table.querySelectorAll('tr.diffskip[data-startln]').forEach(function(tr){
        new ChunkLoadControls(D.addClass(tr, 'jchunk'));
      });
    });
    return F;
  };
  Diff.setupDiffContextLoad();
});

/* Refinements to the display of unified and side-by-side diffs.
**
** In all cases, the table columns tagged with "difftxt" are expanded,
** where possible, to fill the width of the screen.
**
** For a side-by-side diff, if either column is two wide to fit on the
** display, scrollbars are added.  The scrollbars are linked, so that
** both sides scroll together.  Left and right arrows also scroll.
*/
window.fossil.onPageLoad(function(){
  const SCROLL_LEN = 25;
  const F = window.fossil, D = F.dom, Diff = F.diff;
  var lastWidth;
  Diff.checkTableWidth = function f(force){
    if(undefined === f.contentNode){
      f.contentNode = document.querySelector('div.content');
    }
    force = true;
    const parentCS = window.getComputedStyle(f.contentNode);
    const parentWidth = (
      //document.body.clientWidth;
      //parentCS.width;
      f.contentNode.clientWidth
        - parseFloat(parentCS.marginLeft) - parseFloat(parentCS.marginRight)
    );
    if( !force && parentWidth===lastWidth ) return this;
    lastWidth = parentWidth;
    let w = lastWidth*0.5 - 100;
    //console.debug( "w = ",w,", lastWidth =",lastWidth," body = ",document.body.clientWidth);
    if(force || !f.colsL){
      f.colsL = document.querySelectorAll('td.difftxtl pre');
    }
    f.colsL.forEach(function(e){
      e.style.width = w + "px";
      e.style.maxWidth = w + "px";
    });
    if(force || !f.colsR){
      f.colsR = document.querySelectorAll('td.difftxtr pre');
    }
    f.colsR.forEach(function(e){
      e.style.width = w + "px";
      e.style.maxWidth = w + "px";
    });
    if(0){ // seems to be unnecessary
      if(!f.allDiffs){
        f.allDiffs = document.querySelectorAll('table.diff');
      }
      w = lastWidth;
      f.allDiffs.forEach(function f(e){
        if(0 && !f.$){
          f.$ = e.getClientRects()[0];
          console.debug("diff table w =",w," f.$x",f.$);
          w - 2*f.$.x /* left margin (assume right==left, for simplicity) */;
        }
        e.style.maxWidth = w + "px";
      });
      //console.debug("checkTableWidth(",force,") lastWidth =",lastWidth);
    }
    return this;
  };

  const scrollLeft = function(event){
    //console.debug("scrollLeft",this,event);
    const table = this.parentElement/*TD*/.parentElement/*TR*/.
      parentElement/*TBODY*/.parentElement/*TABLE*/;
    table.$txtPres.forEach((e)=>(e===this) ? 1 : (e.scrollLeft = this.scrollLeft));
    return false;
  };
  Diff.initTableDiff = function f(diff){
    if(!diff){
      let i, diffs = document.querySelectorAll('table.splitdiff');
      for(i=0; i<diffs.length; ++i){
        f.call(this, diffs[i]);
      }
      return this;
    }
    diff.$txtCols = diff.querySelectorAll('td.difftxt');
    diff.$txtPres = diff.querySelectorAll('td.difftxt pre');
    var width = 0;
    diff.$txtPres.forEach(function(e){
      if(width < e.scrollWidth) width = e.scrollWidth;
    });
    //console.debug("diff.$txtPres =",diff.$txtPres);
    diff.$txtCols.forEach((e)=>e.style.width = width + 'px');
    diff.$txtPres.forEach(function(e){
      e.style.maxWidth = width + 'px';
      e.style.width = width + 'px';
      if(!e.classList.contains('scroller')){
        D.addClass(e, 'scroller');
        e.addEventListener('scroll', scrollLeft, false);
      }
    });
    diff.tabIndex = 0;
    if(!diff.classList.contains('scroller')){
      D.addClass(diff, 'scroller');
      diff.addEventListener('keydown', function(e){
        e = e || event;
        const len = {37: -SCROLL_LEN, 39: SCROLL_LEN}[e.keyCode];
        if( !len ) return;
        this.$txtPres[0].scrollLeft += len;
        /* ^^^ bug: if there is a 2nd column and it has a scrollbar
           but txtPres[0] does not, no scrolling happens here. We need
           to find the widest of txtPres and scroll that one. Example:
           Checkin a7fbefee38a1c522 file diff.c */
        return false;
      }, false);
    }
    return this;
  }
  window.fossil.page.tweakSbsDiffs = function(){
    document.querySelectorAll('table.splitdiff').forEach((e)=>Diff.initTableDiff(e));
    Diff.checkTableWidth();
  };
  Diff.initTableDiff().checkTableWidth();
  window.addEventListener('resize', ()=>Diff.checkTableWidth());
}, false);
Changes to src/fossil.dom.js.
70
71
72
73
74
75
76


77
78
79
80
81
82
83
  dom.pre = dom.createElemFactory('pre');
  dom.header = dom.createElemFactory('header');
  dom.footer = dom.createElemFactory('footer');
  dom.section = dom.createElemFactory('section');
  dom.span = dom.createElemFactory('span');
  dom.strong = dom.createElemFactory('strong');
  dom.em = dom.createElemFactory('em');


  /**
     Returns a LABEL element. If passed an argument,
     it must be an id or an HTMLElement with an id,
     and that id is set as the 'for' attribute of the
     label. If passed 2 arguments, the 2nd is text or
     a DOM element to append to the label.
  */







>
>







70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
  dom.pre = dom.createElemFactory('pre');
  dom.header = dom.createElemFactory('header');
  dom.footer = dom.createElemFactory('footer');
  dom.section = dom.createElemFactory('section');
  dom.span = dom.createElemFactory('span');
  dom.strong = dom.createElemFactory('strong');
  dom.em = dom.createElemFactory('em');
  dom.ins = dom.createElemFactory('ins');
  dom.del = dom.createElemFactory('del');
  /**
     Returns a LABEL element. If passed an argument,
     it must be an id or an HTMLElement with an id,
     and that id is set as the 'for' attribute of the
     label. If passed 2 arguments, the 2nd is text or
     a DOM element to append to the label.
  */
115
116
117
118
119
120
121


122
123
124



125
126
127
128
129
130
131
  dom.hr = dom.createElemFactory('hr');
  dom.br = dom.createElemFactory('br');
  /** Returns a new TEXT node which contains the text of all of the
      arguments appended together. */
  dom.text = function(/*...*/){
    return document.createTextNode(argsToArray(arguments).join(''));
  };


  dom.button = function(label){
    const b = this.create('button');
    if(label) b.appendChild(this.text(label));



    return b;
  };
  /**
     Returns a TEXTAREA element.

     Usages:








>
>
|


>
>
>







117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
  dom.hr = dom.createElemFactory('hr');
  dom.br = dom.createElemFactory('br');
  /** Returns a new TEXT node which contains the text of all of the
      arguments appended together. */
  dom.text = function(/*...*/){
    return document.createTextNode(argsToArray(arguments).join(''));
  };
  /** Returns a new Button element with the given optional
      label and on-click event listener function. */
  dom.button = function(label,callback){
    const b = this.create('button');
    if(label) b.appendChild(this.text(label));
    if('function' === typeof callback){
      b.addEventListener('click', callback, false);
    }
    return b;
  };
  /**
     Returns a TEXTAREA element.

     Usages:

427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
    const a = argsToArray(arguments);
    a.unshift('remove');
    return domAddRemoveClass.apply(this, a);
  };

  /**
     Toggles CSS class c on e (a single element for forEach-capable
     collection of elements. Returns its first argument.
  */
  dom.toggleClass = function f(e,c){
    if(e.forEach){
      e.forEach((x)=>x.classList.toggle(c));
    }else{
      e.classList.toggle(c);
    }







|







434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
    const a = argsToArray(arguments);
    a.unshift('remove');
    return domAddRemoveClass.apply(this, a);
  };

  /**
     Toggles CSS class c on e (a single element for forEach-capable
     collection of elements). Returns its first argument.
  */
  dom.toggleClass = function f(e,c){
    if(e.forEach){
      e.forEach((x)=>x.classList.toggle(c));
    }else{
      e.classList.toggle(c);
    }
673
674
675
676
677
678
679






































































680
681
682
683
684
685
686
  dom.flashOnce.defaultTimeMs = 400;
  /**
     A DOM event handler which simply passes event.target
     to dom.flashOnce().
  */
  dom.flashOnce.eventHandler = (event)=>dom.flashOnce(event.target)







































































  /**
     Attempts to copy the given text to the system clipboard. Returns
     true if it succeeds, else false.
  */
  dom.copyTextToClipboard = function(text){
    if( window.clipboardData && window.clipboardData.setData ){
      window.clipboardData.setData('Text',text);







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







680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
  dom.flashOnce.defaultTimeMs = 400;
  /**
     A DOM event handler which simply passes event.target
     to dom.flashOnce().
  */
  dom.flashOnce.eventHandler = (event)=>dom.flashOnce(event.target)

  /**
     This variant of flashOnce() flashes the element e n times
     for a duration of howLongMs milliseconds then calls the
     afterFlashCallback() callback. It may also be called with 2
     or 3 arguments, in which case:

     2 arguments: default flash time and no callback.

     3 arguments: 3rd may be a flash delay time or a callback
     function.

     Returns this object but the flashing is asynchronous.

     Depending on system load and related factors, a multi-flash
     animation might stutter and look suboptimal.
  */
  dom.flashNTimes = function(e,n,howLongMs,afterFlashCallback){
    const args = argsToArray(arguments);
    args.splice(1,1);
    if(arguments.length===3 && 'function'===typeof howLongMs){
      afterFlashCallback = howLongMs;
      howLongMs = args[1] = this.flashOnce.defaultTimeMs;
    }else if(arguments.length<3){
      args[1] = this.flashOnce.defaultTimeMs;
    }
    n = +n;
    const self = this;
    const cb = args[2] = function f(){
      if(--n){
        setTimeout(()=>self.flashOnce(e, howLongMs, f),
                   howLongMs+(howLongMs*0.1)/*we need a slight gap here*/);
      }else if(afterFlashCallback){
        afterFlashCallback();
      }
    };
    this.flashOnce.apply(this, args);
    return this;
  };

  /**
     Adds the given CSS class or array of CSS classes to the given
     element or forEach-capable list of elements for howLongMs, then
     removes it. If afterCallack is a function, it is called after the
     CSS class is removed from all elements. If called with 3
     arguments and the 3rd is a function, the 3rd is treated as a
     callback and the default time (addClassBriefly.defaultTimeMs) is
     used. If called with only 2 arguments, a time of
     addClassBriefly.defaultTimeMs is used.

     Passing a value of 0 for howLongMs causes the default value
     to be applied.

     Returns this object but the CSS removal is asynchronous.
  */
  dom.addClassBriefly = function f(e, className, howLongMs, afterCallback){
    if(arguments.length<4 && 'function'===typeof howLongMs){
      afterCallback = howLongMs;
      howLongMs = f.defaultTimeMs;
    }else if(arguments.length<3 || !+howLongMs){
      howLongMs = f.defaultTimeMs;
    }
    this.addClass(e, className);
    setTimeout(function(){
      dom.removeClass(e, className);
      if(afterCallback) afterCallback();
    }, howLongMs);
    return this;
  };
  dom.addClassBriefly.defaultTimeMs = 1000;

  /**
     Attempts to copy the given text to the system clipboard. Returns
     true if it succeeds, else false.
  */
  dom.copyTextToClipboard = function(text){
    if( window.clipboardData && window.clipboardData.setData ){
      window.clipboardData.setData('Text',text);
Changes to src/fossil.fetch.js.
25
26
27
28
29
30
31
32
33

34




35
36
37
38
39
40
41
   - onload: callback(responseData) (default = output response to the
   console). In the context of the callback, the options object is
   "this", noting that this call may have amended the options object
   with state other than what the caller provided.

   - onerror: callback(Error object) (default = output error message
   to console.error() and fossil.error()). Triggered if the request
   generates any response other than HTTP 200 or suffers a connection
   error or timeout while awaiting a response. In the context of the

   callback, the options object is "this".





   - method: 'POST' | 'GET' (default = 'GET'). CASE SENSITIVE!

   - payload: anything acceptable by XHR2.send(ARG) (DOMString,
   Document, FormData, Blob, File, ArrayBuffer), or a plain object or
   array, either of which gets JSON.stringify()'d. If payload is set
   then the method is automatically set to 'POST'. By default XHR2







|
|
>
|
>
>
>
>







25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
   - onload: callback(responseData) (default = output response to the
   console). In the context of the callback, the options object is
   "this", noting that this call may have amended the options object
   with state other than what the caller provided.

   - onerror: callback(Error object) (default = output error message
   to console.error() and fossil.error()). Triggered if the request
   generates any response other than HTTP 200, suffers a connection
   error or timeout while awaiting a response, or if the onload()
   handler throws an exception. In the context of the callback, the
   options object is "this". Note that this function is intended to be
   used solely for error reporting, not error recovery. Because
   onerror() may be called if onload() throws, it is up to the caller
   to ensure that their onerror() callback references only state which
   is valid in such a case.

   - method: 'POST' | 'GET' (default = 'GET'). CASE SENSITIVE!

   - payload: anything acceptable by XHR2.send(ARG) (DOMString,
   Document, FormData, Blob, File, ArrayBuffer), or a plain object or
   array, either of which gets JSON.stringify()'d. If payload is set
   then the method is automatically set to 'POST'. By default XHR2
Name change from src/chat.js to src/fossil.page.chat.js.
1
2
3
4
5
6
7
8
9
10
11
12
/**
   This file contains the client-side implementation of fossil's /chat
   application. 
*/
(function(){
  const F = window.fossil, D = F.dom;
  const E1 = function(selector){
    const e = document.querySelector(selector);
    if(!e) throw new Error("missing required DOM element: "+selector);
    return e;
  };
  /**




|







1
2
3
4
5
6
7
8
9
10
11
12
/**
   This file contains the client-side implementation of fossil's /chat
   application. 
*/
window.fossil.onPageLoad(function(){
  const F = window.fossil, D = F.dom;
  const E1 = function(selector){
    const e = document.querySelector(selector);
    if(!e) throw new Error("missing required DOM element: "+selector);
    return e;
  };
  /**
30
31
32
33
34
35
36






















37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53



54
55
56
57
58
59
60
61
62
63

64
65
66
67
68
69
70
71
72
73



74
75
76
77
78
79
80
81
82
83
84
85


86
87
88
89
90
91
92
93
94
95

96
97
98
99
100
101
102
103
104
105

106
107
108
109
110
111
112
113
114







115
116
117
118
119
120
121
122
123
124
125













126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
  const overlapsElemView = function(e,v) {
    const r1 = e.getBoundingClientRect(),
          r2 = v.getBoundingClientRect();
    if(r1.top<=r2.bottom && r1.top>=r2.top) return true;
    else if(r1.bottom<=r2.bottom && r1.bottom>=r2.top) return true;
    return false;
  };























  (function(){
    let dbg = document.querySelector('#debugMsg');
    if(dbg){
      /* This can inadvertently influence our flexbox layouts, so move
         it out of the way. */
      D.append(document.body,dbg);
    }
  })();
  const ForceResizeKludge = 0 ? function(){} : (function f(){
    /* Workaround for Safari mayhem regarding use of vh CSS units....
       We tried to use vh units to set the content area size for the
       chat layout, but Safari chokes on that, so we calculate that
       height here: 85% when in "normal" mode and 95% in chat-only
       mode. Larger than ~95% is too big for Firefox on Android,
       causing the input area to move off-screen. */
    if(!f.elemsToCount){



      f.elemsToCount = [
        document.querySelector('body > div.header'),
        document.querySelector('body > div.mainmenu'),
        document.querySelector('body > #hbdrop'),
        document.querySelector('body > div.footer')
      ];
      f.contentArea = E1('div.content');
    }
    const bcl = document.body.classList;
    const resized = function(){

      const wh = window.innerHeight,
            com = bcl.contains('chat-only-mode');
      var ht;
      var extra = 0;
      if(com){
        ht = wh;
      }else{
        f.elemsToCount.forEach((e)=>e ? extra += D.effectiveHeight(e) : false);
        ht = wh - extra;
      }



      f.contentArea.style.height =
        f.contentArea.style.maxHeight = [
          "calc(", (ht>=100 ? ht : 100), "px",
          " - 1em"/*fudge value*/,")"
          /* ^^^^ hypothetically not needed, but both Chrome/FF on
             Linux will force scrollbars on the body if this value is
             too small (<0.75em in my tests). */
        ].join('');
      if(false){
        console.debug("resized.",wh, extra, ht,
                      window.getComputedStyle(f.contentArea).maxHeight,
                      f.contentArea);


      }
    };
    var doit;
    window.addEventListener('resize',function(ev){
      clearTimeout(doit);
      doit = setTimeout(resized, 100);
    }, false);
    resized();
    return resized;
  })();

  fossil.FRK = ForceResizeKludge/*for debugging*/;
  const Chat = (function(){
    const cs = {
      verboseErrors: false /* if true then certain, mostly extraneous,
                              error messages may be sent to the console. */,
      e:{/*map of certain DOM elements.*/
        messageInjectPoint: E1('#message-inject-point'),
        pageTitle: E1('head title'),
        loadOlderToolbar: undefined /* the load-posts toolbar (dynamically created) */,
        inputWrapper: E1("#chat-input-area"),

        fileSelectWrapper: E1('#chat-input-file-area'),
        messagesWrapper: E1('#chat-messages-wrapper'),
        inputForm: E1('#chat-form'),
        btnSubmit: E1('#chat-message-submit'),
        inputSingle: E1('#chat-input-single'),
        inputMulti: E1('#chat-input-multi'),
        inputCurrent: undefined/*one of inputSingle or inputMulti*/,
        inputFile: E1('#chat-input-file'),
        contentDiv: E1('div.content')







      },
      me: F.user.name,
      mxMsg: F.config.chat.initSize ? -F.config.chat.initSize : -50,
      mnMsg: undefined/*lowest message ID we've seen so far (for history loading)*/,
      pageIsActive: 'visible'===document.visibilityState,
      changesSincePageHidden: 0,
      notificationBubbleColor: 'white',
      totalMessageCount: 0, // total # of inbound messages
      //! Number of messages to load for the history buttons
      loadMessageCount: Math.abs(F.config.chat.initSize || 20),
      ajaxInflight: 0,













      /** Gets (no args) or sets (1 arg) the current input text field value,
          taking into account single- vs multi-line input. The getter returns
          a string and the setter returns this object. */
      inputValue: function(){
        const e = this.inputElement();
        if(arguments.length){
          e.value = arguments[0];
          return this;
        }
        return e.value;
      },
      /** Asks the current user input field to take focus. Returns this. */
      inputFocus: function(){
        this.inputElement().focus();
        return this;
      },
      /** Returns the current message input element. */
      inputElement: function(){
        return this.e.inputCurrent;
      },
      /** Toggles between single- and multi-line edit modes. Returns this. */
      inputToggleSingleMulti: function(){
        const old = this.e.inputCurrent;
        if(this.e.inputCurrent === this.e.inputSingle){
          this.e.inputCurrent = this.e.inputMulti;
        }else{
          this.e.inputCurrent = this.e.inputSingle;
        }
        const m = this.e.messagesWrapper,
              sTop = m.scrollTop,
              mh1 = m.clientHeight;
        D.addClass(old, 'hidden');
        D.removeClass(this.e.inputCurrent, 'hidden');
        const mh2 = m.clientHeight;
        m.scrollTo(0, sTop + (mh1-mh2));
        this.e.inputCurrent.value = old.value;
        old.value = '';
        return this;
      },
      /**
         If passed true or no arguments, switches to multi-line mode
         if currently in single-line mode. If passed false, switches
         to single-line mode if currently in multi-line mode. Returns
         this.
      */
      inputMultilineMode: function(yes){
        if(!arguments.length) yes = true;
        if(yes && this.e.inputCurrent === this.e.inputMulti) return this;
        else if(!yes && this.e.inputCurrent === this.e.inputSingle) return this;
        else return this.inputToggleSingleMulti();
      },
      /** Enables (if yes is truthy) or disables all elements in
       * this.disableDuringAjax. */
      enableAjaxComponents: function(yes){
        D[yes ? 'enable' : 'disable'](this.disableDuringAjax);
        return this;
      },







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









|





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

|
>







|


>
>
>
|
|

|






|
|
>
>







<


>

|








>

|
<
|
|
|
<

|
>
>
>
>
>
>
>











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






|


|








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







30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85

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

123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138

139
140
141

142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193































194
195
196
197
198
199
200
  const overlapsElemView = function(e,v) {
    const r1 = e.getBoundingClientRect(),
          r2 = v.getBoundingClientRect();
    if(r1.top<=r2.bottom && r1.top>=r2.top) return true;
    else if(r1.bottom<=r2.bottom && r1.bottom>=r2.top) return true;
    return false;
  };

  const addAnchorTargetBlank = (e)=>D.attr(e, 'target','_blank');

  /**
     Returns an almost-ISO8601 form of Date object d.
  */
  const iso8601ish = function(d){
    return d.toISOString()
        .replace('T',' ').replace(/\.\d+/,'')
        .replace('Z', ' zulu');
  };
  /** Returns the local time string of Date object d, defaulting
      to the current time. */
  const localTimeString = function ff(d){
    d || (d = new Date());
    return [
      d.getFullYear(),'-',pad2(d.getMonth()+1/*sigh*/),
      '-',pad2(d.getDate()),
      ' ',pad2(d.getHours()),':',pad2(d.getMinutes()),
      ':',pad2(d.getSeconds())
    ].join('');
  };

  (function(){
    let dbg = document.querySelector('#debugMsg');
    if(dbg){
      /* This can inadvertently influence our flexbox layouts, so move
         it out of the way. */
      D.append(document.body,dbg);
    }
  })();
  const ForceResizeKludge = (function(){
    /* Workaround for Safari mayhem regarding use of vh CSS units....
       We tried to use vh units to set the content area size for the
       chat layout, but Safari chokes on that, so we calculate that
       height here: 85% when in "normal" mode and 95% in chat-only
       mode. Larger than ~95% is too big for Firefox on Android,
       causing the input area to move off-screen.

       While we're here, we also use this to cap the max-height
       of the input field so that pasting huge text does not scroll
       the upper area of the input widget off-screen. */
    const elemsToCount = [
      document.querySelector('body > div.header'),
      document.querySelector('body > div.mainmenu'),
      document.querySelector('body > #hbdrop'),
      document.querySelector('body > div.footer')
    ];
    const contentArea = E1('div.content');

    const bcl = document.body.classList;
    const resized = function f(){
      if(f.$disabled) return;
      const wh = window.innerHeight,
            com = bcl.contains('chat-only-mode');
      var ht;
      var extra = 0;
      if(com){
        ht = wh;
      }else{
        elemsToCount.forEach((e)=>e ? extra += D.effectiveHeight(e) : false);
        ht = wh - extra;
      }
      f.chat.e.inputField.style.maxHeight = (ht/2)+"px";
      /* ^^^^ this is a middle ground between having no size cap
         on the input field and having a fixed arbitrary cap. */;
      contentArea.style.height =
        contentArea.style.maxHeight = [
          "calc(", (ht>=100 ? ht : 100), "px",
          " - 0.75em"/*fudge value*/,")"
          /* ^^^^ hypothetically not needed, but both Chrome/FF on
             Linux will force scrollbars on the body if this value is
             too small (<0.75em in my tests). */
        ].join('');
      if(false){
        console.debug("resized.",wh, extra, ht,
                      window.getComputedStyle(contentArea).maxHeight,
                      contentArea);
        console.debug("Set input max height to: ",
                      f.chat.e.inputField.style.maxHeight);
      }
    };
    var doit;
    window.addEventListener('resize',function(ev){
      clearTimeout(doit);
      doit = setTimeout(resized, 100);
    }, false);

    return resized;
  })();
  ForceResizeKludge.$disabled = true/*gets deleted when setup is finished*/;
  fossil.FRK = ForceResizeKludge/*for debugging*/;
  const Chat = ForceResizeKludge.chat = (function(){
    const cs = {
      verboseErrors: false /* if true then certain, mostly extraneous,
                              error messages may be sent to the console. */,
      e:{/*map of certain DOM elements.*/
        messageInjectPoint: E1('#message-inject-point'),
        pageTitle: E1('head title'),
        loadOlderToolbar: undefined /* the load-posts toolbar (dynamically created) */,
        inputWrapper: E1("#chat-input-area"),
        inputLine: E1('#chat-input-line'),
        fileSelectWrapper: E1('#chat-input-file-area'),
        viewMessages: E1('#chat-messages-wrapper'),

        btnSubmit: E1('#chat-button-submit'),
        btnAttach: E1('#chat-button-attach'),
        inputField: E1('#chat-input-field'),

        inputFile: E1('#chat-input-file'),
        contentDiv: E1('div.content'),
        viewConfig: E1('#chat-config'),
        viewPreview: E1('#chat-preview'),
        previewContent: E1('#chat-preview-content'),
        btnPreview: E1('#chat-button-preview'),
        views: document.querySelectorAll('.chat-view'),
        activeUserListWrapper: E1('#chat-user-list-wrapper'),
        activeUserList: E1('#chat-user-list')
      },
      me: F.user.name,
      mxMsg: F.config.chat.initSize ? -F.config.chat.initSize : -50,
      mnMsg: undefined/*lowest message ID we've seen so far (for history loading)*/,
      pageIsActive: 'visible'===document.visibilityState,
      changesSincePageHidden: 0,
      notificationBubbleColor: 'white',
      totalMessageCount: 0, // total # of inbound messages
      //! Number of messages to load for the history buttons
      loadMessageCount: Math.abs(F.config.chat.initSize || 20),
      ajaxInflight: 0,
      usersLastSeen:{
        /* Map of user names to their most recent message time
           (JS Date object). Only messages received by the chat client
           are considered. */
        /* Reminder: to convert a Julian time J to JS:
           new Date((J - 2440587.5) * 86400000) */
      },
      filterState:{
        activeUser: undefined,
        match: function(uname){
          return this.activeUser===uname || !this.activeUser;
        }
      },
      /** Gets (no args) or sets (1 arg) the current input text field value,
          taking into account single- vs multi-line input. The getter returns
          a string and the setter returns this object. */
      inputValue: function(){
        const e = this.inputElement();
        if(arguments.length){
          e.innerText = arguments[0];
          return this;
        }
        return e.innerText;
      },
      /** Asks the current user input field to take focus. Returns this. */
      inputFocus: function(){
        this.inputElement().focus();
        return this;
      },
      /** Returns the current message input element. */
      inputElement: function(){
        return this.e.inputField;































      },
      /** Enables (if yes is truthy) or disables all elements in
       * this.disableDuringAjax. */
      enableAjaxComponents: function(yes){
        D[yes ? 'enable' : 'disable'](this.disableDuringAjax);
        return this;
      },
231
232
233
234
235
236
237
238
239



240
241
242
243
244
245
246
        return this;
      },
      /* Injects DOM element e as a new row in the chat, at the oldest
         end of the list if atEnd is truthy, else at the newest end of
         the list. */
      injectMessageElem: function f(e, atEnd){
        const mip = atEnd ? this.e.loadOlderToolbar : this.e.messageInjectPoint,
              holder = this.e.messagesWrapper,
              prevMessage = this.e.newestMessage;



        if(atEnd){
          const fe = mip.nextElementSibling;
          if(fe) mip.parentNode.insertBefore(e, fe);
          else D.append(mip.parentNode, e);
        }else{
          D.append(holder,e);
          this.e.newestMessage = e;







|

>
>
>







249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
        return this;
      },
      /* Injects DOM element e as a new row in the chat, at the oldest
         end of the list if atEnd is truthy, else at the newest end of
         the list. */
      injectMessageElem: function f(e, atEnd){
        const mip = atEnd ? this.e.loadOlderToolbar : this.e.messageInjectPoint,
              holder = this.e.viewMessages,
              prevMessage = this.e.newestMessage;
        if(!this.filterState.match(e.dataset.xfrom)){
          e.classList.add('hidden');
        }
        if(atEnd){
          const fe = mip.nextElementSibling;
          if(fe) mip.parentNode.insertBefore(e, fe);
          else D.append(mip.parentNode, e);
        }else{
          D.append(holder,e);
          this.e.newestMessage = e;
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349

350


351
352
353
354
355
356
357







358


359


360







361


362




363











364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391









392





























393





































































































394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
      },
      /** Tries to scroll the message area to...
          <0 = top of the message list, >0 = bottom of the message list,
          0 == the newest message (normally the same position as >1).
      */
      scrollMessagesTo: function(where){
        if(where<0){
          Chat.e.messagesWrapper.scrollTop = 0;
        }else if(where>0){
          Chat.e.messagesWrapper.scrollTop = Chat.e.messagesWrapper.scrollHeight;
        }else if(Chat.e.newestMessage){
          Chat.e.newestMessage.scrollIntoView(false);
        }
      },
      toggleChatOnlyMode: function(){
        return this.chatOnlyMode(!this.isChatOnlyMode());
      },
      messageIsInView: function(e){
        return e ? overlapsElemView(e, this.e.messagesWrapper) : false;
      },
      settings:{
        get: (k,dflt)=>F.storage.get(k,dflt),
        getBool: (k,dflt)=>F.storage.getBool(k,dflt),

        set: (k,v)=>F.storage.set(k,v),


        /* Toggles the boolean setting specified by k. Returns the
           new value.*/
        toggle: function(k){
          const v = this.getBool(k);
          this.set(k, !v);
          return !v;
        },







        defaults:{


          "images-inline": !!F.config.chat.imagesInline,


          "edit-multiline": false,







          "monospace-messages": false,


          "chat-only-mode": false,




          "audible-alert": true











        }
      },
      /** Plays a new-message notification sound IF the audible-alert
          setting is true, else this is a no-op. Returns this.
      */
      playNewMessageSound: function f(){
        if(f.uri){
          try{
            if(!f.audio) f.audio = new Audio(f.uri);
            f.audio.currentTime = 0;
            f.audio.play();
          }catch(e){
            console.error("Audio playblack failed.",e);
          }
        }
        return this;
      },
      /**
         Sets the current new-message audio alert URI (must be a
         repository-relative path which responds with an audio
         file). Pass a falsy value to disable audio alerts. Returns
         this.
      */
      setNewMessageSound: function f(uri){
        delete this.playNewMessageSound.audio;
        this.playNewMessageSound.uri = uri;
        this.settings.set('audible-alert', !!uri);
        return this;









      }





























    };





































































































    F.fetch.beforesend = ()=>cs.ajaxStart();
    F.fetch.aftersend = ()=>cs.ajaxEnd();
    cs.e.inputCurrent = cs.e.inputSingle;
    /* Install default settings... */
    Object.keys(cs.settings.defaults).forEach(function(k){
      const v = cs.settings.get(k,cs);
      if(cs===v) cs.settings.set(k,cs.settings.defaults[k]);
    });
    if(window.innerWidth<window.innerHeight){
      /* Alignment of 'my' messages: right alignment is conventional
         for mobile chat apps but can be difficult to read in wide
         windows (desktop/tablet landscape mode), so we default to a
         layout based on the apparent "orientation" of the window:
         tall vs wide. Can be toggled via settings popup. */
      document.body.classList.add('my-messages-right');
    }
    if(cs.settings.getBool('monospace-messages',false)){
      document.body.classList.add('monospace-messages');
    }
    cs.inputMultilineMode(cs.settings.getBool('edit-multiline',false));
    cs.chatOnlyMode(cs.settings.getBool('chat-only-mode'));
    cs.pageTitleOrig = cs.e.pageTitle.innerText;
    const qs = (e)=>document.querySelector(e);
    const argsToArray = function(args){
      return Array.prototype.slice.call(args,0);
    };
    /**
       Reports an error via console.error() and as a toast message.







|

|








|




>
|
>
>







>
>
>
>
>
>
>

>
>

>
>
|
>
>
>
>
>
>
>

>
>

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












|













|

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


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







348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593



















594
595
596
597
598
599
600
      },
      /** Tries to scroll the message area to...
          <0 = top of the message list, >0 = bottom of the message list,
          0 == the newest message (normally the same position as >1).
      */
      scrollMessagesTo: function(where){
        if(where<0){
          Chat.e.viewMessages.scrollTop = 0;
        }else if(where>0){
          Chat.e.viewMessages.scrollTop = Chat.e.viewMessages.scrollHeight;
        }else if(Chat.e.newestMessage){
          Chat.e.newestMessage.scrollIntoView(false);
        }
      },
      toggleChatOnlyMode: function(){
        return this.chatOnlyMode(!this.isChatOnlyMode());
      },
      messageIsInView: function(e){
        return e ? overlapsElemView(e, this.e.viewMessages) : false;
      },
      settings:{
        get: (k,dflt)=>F.storage.get(k,dflt),
        getBool: (k,dflt)=>F.storage.getBool(k,dflt),
        set: function(k,v){
          F.storage.set(k,v);
          F.page.dispatchEvent('chat-setting',{key: k, value: v});
        },
        /* Toggles the boolean setting specified by k. Returns the
           new value.*/
        toggle: function(k){
          const v = this.getBool(k);
          this.set(k, !v);
          return !v;
        },
        addListener: function(setting, f){
          F.page.addEventListener('chat-setting', function(ev){
            if(ev.detail.key===setting) f(ev.detail);
          }, false);
        },
        /* Default values of settings. These are used for intializing
           the setting event listeners and config view UI. */
        defaults:{
          /* When on, inbound images are displayed inlined, else as a
             link to download the image. */
          "images-inline": !!F.config.chat.imagesInline,
          /* When on, ctrl-enter sends messages, else enter and
             ctrl-enter both send them. */
          "edit-ctrl-send": false,
          /* When on, the edit field starts as a single line and
             expands as the user types, and the relevant buttons are
             laid out in a compact form. When off, the edit field and
             buttons are larger. */
          "edit-compact-mode": true,
          /* When on, sets the font-family on messages and the edit
             field to monospace. */
          "monospace-messages": false,
          /* When on, non-chat UI elements (page header/footer) are
             hidden */
          "chat-only-mode": false,
          /* When set to a URI, it is assumed to be an audio file,
             which gets played when new messages arrive. When true,
             the first entry in the audio file selection list will be
             used. */
          "audible-alert": true,
          /* When on, show the list of "active" users - those from
             whom we have messages in the currently-loaded history
             (noting that deletions are also messages). */
          "active-user-list": false,
          /* When on, the [active-user-list] setting includes the
             timestamp of each user's most recent message. */
          "active-user-list-timestamps": false,
          /* When on, the [audible-alert] is played for one's own
             messages, else it is only played for other users'
             messages. */
          "alert-own-messages": false
        }
      },
      /** Plays a new-message notification sound IF the audible-alert
          setting is true, else this is a no-op. Returns this.
      */
      playNewMessageSound: function f(){
        if(f.uri){
          try{
            if(!f.audio) f.audio = new Audio(f.uri);
            f.audio.currentTime = 0;
            f.audio.play();
          }catch(e){
            console.error("Audio playblack failed.", f.uri, e);
          }
        }
        return this;
      },
      /**
         Sets the current new-message audio alert URI (must be a
         repository-relative path which responds with an audio
         file). Pass a falsy value to disable audio alerts. Returns
         this.
      */
      setNewMessageSound: function f(uri){
        delete this.playNewMessageSound.audio;
        this.playNewMessageSound.uri = uri;
        this.settings.set('audible-alert', uri);
        return this;
      },
      /**
         Expects e to be one of the elements in this.e.views.
         The 'hidden' class is removed from e and added to
         all other elements in that list. Returns e.
      */
      setCurrentView: function(e){
        if(e===this.e.currentView){
          return e;
        }
        this.e.views.forEach(function(E){
          if(e!==E) D.addClass(E,'hidden');
        });
        this.e.currentView = e;
        if(this.e.currentView.$beforeShow) this.e.currentView.$beforeShow();
        D.removeClass(e,'hidden');
        this.animate(this.e.currentView, 'anim-fade-in-fast');
        return this.e.currentView;
      },
      /**
         Updates the "active user list" view if we are not currently
         batch-loading messages and if the active user list UI element
         is active.
      */
      updateActiveUserList: function callee(){
        if(this._isBatchLoading
           || this.e.activeUserListWrapper.classList.contains('hidden')){
          return this;
        }else if(!callee.sortUsersSeen){
          /** Array.sort() callback. Expects an array of user names and
              sorts them in last-received message order (newest first). */
          const self = this;
          callee.sortUsersSeen = function(l,r){
            l = self.usersLastSeen[l];
            r = self.usersLastSeen[r];
            if(l && r) return r - l;
            else if(l) return -1;
            else if(r) return 1;
            else return 0;
          };
          callee.addUserElem = function(u){
            const uSpan = D.addClass(D.span(), 'chat-user');
            const uDate = self.usersLastSeen[u];
            if(self.filterState.activeUser===u){
              uSpan.classList.add('selected');
            }
            uSpan.dataset.uname = u;
            D.append(uSpan, u, "\n", 
                     D.append(
                       D.addClass(D.span(),'timestamp'),
                       localTimeString(uDate)//.substr(5/*chop off year*/)
                     ));
            if(uDate.$uColor){
              uSpan.style.backgroundColor = uDate.$uColor;
            }
            D.append(self.e.activeUserList, uSpan);
          };
        }
        //D.clearElement(this.e.activeUserList);
        D.remove(this.e.activeUserList.querySelectorAll('.chat-user'));
        Object.keys(this.usersLastSeen).sort(
          callee.sortUsersSeen
        ).forEach(callee.addUserElem);
        return this;
      },
      /** Show or hide the active user list. Returns this object. */
      showActiveUserList: function(yes){
        if(0===arguments.length) yes = true;
        this.e.activeUserListWrapper.classList[
          yes ? 'remove' : 'add'
        ]('hidden');
        D.removeClass(Chat.e.activeUserListWrapper, 'collapsed');
        if(Chat.e.activeUserListWrapper.classList.contains('hidden')){
          /* When hiding this element, undo all filtering */
          Chat.setUserFilter(false);
          /*Ideally we'd scroll the final message into view
            now, but because viewMessages is currently hidden behind
            viewConfig, scrolling is a no-op. */
          Chat.scrollMessagesTo(1);
        }else{
          Chat.updateActiveUserList();
          Chat.animate(Chat.e.activeUserListWrapper, 'anim-flip-v');
        }
        return this;
      },
      showActiveUserTimestamps: function(yes){
        if(0===arguments.length) yes = true;
        this.e.activeUserList.classList[yes ? 'add' : 'remove']('timestamps');
        return this;
      },
      /**
         Applies user name filter to all current messages, or clears
         the filter if uname is falsy.
      */
      setUserFilter: function(uname){
        this.filterState.activeUser = uname;
        const mw = this.e.viewMessages.querySelectorAll('.message-widget');
        const self = this;
        let eLast;
        if(!uname){
          D.removeClass(Chat.e.viewMessages.querySelectorAll('.message-widget.hidden'),
                        'hidden');
        }else{
          mw.forEach(function(w){
            if(self.filterState.match(w.dataset.xfrom)){
              w.classList.remove('hidden');
              eLast = w;
            }else{
              w.classList.add('hidden');
            }
          });
        }
        if(eLast) eLast.scrollIntoView(false);
        else this.scrollMessagesTo(1);
        cs.e.activeUserList.querySelectorAll('.chat-user').forEach(function(e){
          e.classList[uname===e.dataset.uname ? 'add' : 'remove']('selected');
        });
        return this;
      },

      /**
         If animations are enabled, passes its arguments
         to D.addClassBriefly(), else this is a no-op.
         If cb is a function, it is called after the
         CSS class is removed. Returns this object; 
      */
      animate: function f(e,a,cb){
        if(!f.$disabled){
          D.addClassBriefly(e, a, 0, cb);
        }
        return this;
      }
    };
    if(D.attr(cs.e.inputField,'contenteditable','plaintext-only').isContentEditable){
      cs.$browserHasPlaintextOnly = true;
    }else{
      /* Only the Chrome family supports contenteditable=plaintext-only */
      cs.$browserHasPlaintextOnly = false;
      D.attr(cs.e.inputField,'contenteditable','true');
    }
    cs.animate.$disabled = true;
    F.fetch.beforesend = ()=>cs.ajaxStart();
    F.fetch.aftersend = ()=>cs.ajaxEnd();



















    cs.pageTitleOrig = cs.e.pageTitle.innerText;
    const qs = (e)=>document.querySelector(e);
    const argsToArray = function(args){
      return Array.prototype.slice.call(args,0);
    };
    /**
       Reports an error via console.error() and as a toast message.
482
483
484
485
486
487
488

























































489
490
491
492
493
494
495
          this.fetchLastMessageElem();
        }
        F.toast.message("Deleted message "+id+".");
      }
      return !!e;
    };


























































    /** Given a .message-row element, this function returns whethe the
        current user may, at least hypothetically, delete the message
        globally.  A user may always delete a local copy of a
        post. The server may trump this, e.g. if the login has been
        cancelled after this page was loaded.
    */
    cs.userMayDelete = function(eMsg){







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







661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
          this.fetchLastMessageElem();
        }
        F.toast.message("Deleted message "+id+".");
      }
      return !!e;
    };

    /**
       Toggles the given message between its parsed and plain-text
       representations. It requires a server round-trip to collect the
       plain-text form but caches it for subsequent toggles.

       Expects the ID of a currently-loaded message or a
       message-widget DOM elment from which it can extract an id.
       This is an aync operation the first time it's passed a given
       message and synchronous on subsequent calls for that
       message. It is a no-op if id does not resolve to a loaded
       message.
    */
    cs.toggleTextMode = function(id){
      var e;
      if(id instanceof HTMLElement){
        e = id;
        id = e.dataset.msgid;
      }else{
        e = this.getMessageElemById(id);
      }
      if(!e || !id) return false;
      else if(e.$isToggling) return;
      e.$isToggling = true;
      const content = e.querySelector('.message-widget-content');
      if(!content.$elems){
        content.$elems = [
          content.firstElementChild, // parsed elem
          undefined // plaintext elem
        ];
      }else if(content.$elems[1]){
        // We have both content types. Simply toggle them.
        const child = (
          content.firstElementChild===content.$elems[0]
            ? content.$elems[1]
            : content.$elems[0]
        );
        delete e.$isToggling;
        D.append(D.clearElement(content), child);
        return;
      }
      // We need to fetch the plain-text version...
      const self = this;
      F.fetch('chat-fetch-one',{
        urlParams:{ name: id, raw: true},
        responseType: 'json',
        onload: function(msg){
          content.$elems[1] = D.append(D.pre(),msg.xmsg);
          self.toggleTextMode(e);
        },
        aftersend:function(){
          delete e.$isToggling;
          Chat.ajaxEnd();
        }
      });
      return true;
    };
    
    /** Given a .message-row element, this function returns whethe the
        current user may, at least hypothetically, delete the message
        globally.  A user may always delete a local copy of a
        post. The server may trump this, e.g. if the login has been
        cancelled after this page was loaded.
    */
    cs.userMayDelete = function(eMsg){
542
543
544
545
546
547
548









549

550



























551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
        this.deleteMessageElem(id);
      }
    };
    document.addEventListener('visibilitychange', function(ev){
      cs.pageIsActive = ('visible' === document.visibilityState);
      if(cs.pageIsActive){
        cs.e.pageTitle.innerText = cs.pageTitleOrig;









      }

    }, true);



























    return cs;
  })()/*Chat initialization*/;

  /**
     Custom widget type for rendering messages (one message per
     instance). These are modelled after FIELDSET elements but we
     don't use FIELDSET because of cross-browser inconsistencies in
     features of the FIELDSET/LEGEND combination, e.g. inability to
     align legends via CSS in Firefox and clicking-related
     deficiencies in Safari.
  */
  Chat.MessageWidget = (function(){
    /**
       Constructor. If passed an argument, it is passed to
       this.setMessage() after initialization.
    */
    const cf = function(){
      this.e = {
        body: D.addClass(D.div(), 'message-widget'),
        tab: D.addClass(D.span(), 'message-widget-tab'),
        content: D.addClass(D.div(), 'message-widget-content')
      };
      D.append(this.e.body, this.e.tab, this.e.content);
      this.e.tab.setAttribute('role', 'button');
      if(arguments.length){
        this.setMessage(arguments[0]);
      }







>
>
>
>
>
>
>
>
>
|
>

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



















|







778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
        this.deleteMessageElem(id);
      }
    };
    document.addEventListener('visibilitychange', function(ev){
      cs.pageIsActive = ('visible' === document.visibilityState);
      if(cs.pageIsActive){
        cs.e.pageTitle.innerText = cs.pageTitleOrig;
        if(document.activeElement!==cs.inputElement()){
          /* An attempt to resolve usability problem reported by Joe
             M. where the Pale Moon browser is giving input focus to
             the Preview button. The down-side of this is that it will
             deselect any text which was previously selected on this
             page. This also, unfortunately, places the focus at the
             start of the element, rather than the last cursor position
             (like a textarea would). */
          setTimeout(()=>cs.inputFocus(), 0);
        }
      }
    }, true);
    cs.setCurrentView(cs.e.viewMessages);

    cs.e.activeUserList.addEventListener('click', function f(ev){
      /* Filter messages on a user clicked in activeUserList */
      ev.stopPropagation();
      ev.preventDefault();
      let eUser = ev.target;
      while(eUser!==this && !eUser.classList.contains('chat-user')){
        eUser = eUser.parentNode;
      }
      if(eUser==this || !eUser) return false;
      const uname = eUser.dataset.uname;
      let eLast;
      cs.setCurrentView(cs.e.viewMessages);
      if(eUser.classList.contains('selected')){
        /* If curently selected, toggle filter off */
        eUser.classList.remove('selected');
        cs.setUserFilter(false);
        delete f.$eSelected;
      }else{
        if(f.$eSelected) f.$eSelected.classList.remove('selected');
        f.$eSelected = eUser;
        eUser.classList.add('selected');
        cs.setUserFilter(uname);
      }
      return false;
    }, false);
    return cs;
  })()/*Chat initialization*/;

  /**
     Custom widget type for rendering messages (one message per
     instance). These are modelled after FIELDSET elements but we
     don't use FIELDSET because of cross-browser inconsistencies in
     features of the FIELDSET/LEGEND combination, e.g. inability to
     align legends via CSS in Firefox and clicking-related
     deficiencies in Safari.
  */
  Chat.MessageWidget = (function(){
    /**
       Constructor. If passed an argument, it is passed to
       this.setMessage() after initialization.
    */
    const cf = function(){
      this.e = {
        body: D.addClass(D.div(), 'message-widget'),
        tab: D.addClass(D.div(), 'message-widget-tab'),
        content: D.addClass(D.div(), 'message-widget-content')
      };
      D.append(this.e.body, this.e.tab, this.e.content);
      this.e.tab.setAttribute('role', 'button');
      if(arguments.length){
        this.setMessage(arguments[0]);
      }
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
        //d.getFullYear(),'-',pad2(d.getMonth()+1/*sigh*/),
        //'-',pad2(d.getDate()), ' ',
        d.getHours(),":",
        (d.getMinutes()+100).toString().slice(1,3),
        ' ', dowMap[d.getDay()]
      ].join('');
    };
    /** Returns the local time string of Date object d, defaulting
        to the current time. */
    const localTimeString = function ff(d){
      d || (d = new Date());
      return [
        d.getFullYear(),'-',pad2(d.getMonth()+1/*sigh*/),
        '-',pad2(d.getDate()),
        ' ',pad2(d.getHours()),':',pad2(d.getMinutes()),
        ':',pad2(d.getSeconds())
      ].join('');
    };
    cf.prototype = {
      scrollIntoView: function(){
        this.e.content.scrollIntoView();
      },
      setMessage: function(m){
        const ds = this.e.body.dataset;
        ds.timestamp = m.mtime;







<
<
<
<
<
<
<
<
<
<
<







864
865
866
867
868
869
870











871
872
873
874
875
876
877
        //d.getFullYear(),'-',pad2(d.getMonth()+1/*sigh*/),
        //'-',pad2(d.getDate()), ' ',
        d.getHours(),":",
        (d.getMinutes()+100).toString().slice(1,3),
        ' ', dowMap[d.getDay()]
      ].join('');
    };











    cf.prototype = {
      scrollIntoView: function(){
        this.e.content.scrollIntoView();
      },
      setMessage: function(m){
        const ds = this.e.body.dataset;
        ds.timestamp = m.mtime;
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
        }
        const d = new Date(m.mtime);
        D.clearElement(this.e.tab);
        var contentTarget = this.e.content;
        var eXFrom /* element holding xfrom name */;
        if(m.xfrom){
          eXFrom = D.append(D.addClass(D.span(), 'xfrom'), m.xfrom);
          D.append(
            this.e.tab, eXFrom,
            D.text(" #",(m.msgid||'???'),' @ ',theTime(d))
          );
        }else{/*notification*/
          D.addClass(this.e.body, 'notification');
          if(m.isError){
            D.addClass([contentTarget, this.e.tab], 'error');
          }
          D.append(
            this.e.tab,







|
|
|
|







887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
        }
        const d = new Date(m.mtime);
        D.clearElement(this.e.tab);
        var contentTarget = this.e.content;
        var eXFrom /* element holding xfrom name */;
        if(m.xfrom){
          eXFrom = D.append(D.addClass(D.span(), 'xfrom'), m.xfrom);
          const wrapper = D.append(
            D.span(), eXFrom,
            D.text(" #",(m.msgid||'???'),' @ ',theTime(d)))
          D.append(this.e.tab, wrapper);
        }else{/*notification*/
          D.addClass(this.e.body, 'notification');
          if(m.isError){
            D.addClass([contentTarget, this.e.tab], 'error');
          }
          D.append(
            this.e.tab,
678
679
680
681
682
683
684



685
686

687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
          // Hence, even though innerHTML is normally frowned upon, it is
          // perfectly safe to use in this context.
          if(m.xmsg instanceof Array){
            // Used by Chat.reportErrorAsMessage()
            D.append(contentTarget, m.xmsg);
          }else{
            contentTarget.innerHTML = m.xmsg;



          }
        }

        this.e.tab.addEventListener('click', this._handleLegendClicked, false);
        if(eXFrom){
          eXFrom.addEventListener('click', ()=>this.e.tab.click(), false);
        }
        return this;
      },
      /* Event handler for clicking .message-user elements to show their
         timestamps. */
      _handleLegendClicked: function f(ev){
        if(!f.popup){
          /* Timestamp popup widget */
          f.popup = new F.PopupWidget({
            cssClass: ['fossil-tooltip', 'chat-message-popup'],
            refresh:function(){
              const eMsg = this._eMsg;
              if(!eMsg) return;
              D.clearElement(this.e);
              const d = new Date(eMsg.dataset.timestamp);
              if(d.getMinutes().toString()!=="NaN"){
                // Date works, render informative timestamps
                const xfrom = eMsg.dataset.xfrom || 'server';
                D.append(this.e,







>
>
>
|
|
>
|
|

|



|


|
|
|

|







940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
          // Hence, even though innerHTML is normally frowned upon, it is
          // perfectly safe to use in this context.
          if(m.xmsg instanceof Array){
            // Used by Chat.reportErrorAsMessage()
            D.append(contentTarget, m.xmsg);
          }else{
            contentTarget.innerHTML = m.xmsg;
            contentTarget.querySelectorAll('a').forEach(addAnchorTargetBlank);
            if(F.pikchr){
              F.pikchr.addSrcView(contentTarget.querySelectorAll('svg.pikchr'));
            }
          }
        }
        this.e.tab.firstElementChild.addEventListener('click', this._handleLegendClicked, false);
        /*if(eXFrom){
          eXFrom.addEventListener('click', ()=>this.e.tab.click(), false);
        }*/
        return this;
      },
      /* Event handler for clicking .message-user elements to show their
         timestamps and a set of actions. */
      _handleLegendClicked: function f(ev){
        if(!f.popup){
          /* "Popup" widget */
          f.popup = {
            e: D.addClass(D.div(), 'chat-message-popup'),
            refresh:function(){
              const eMsg = this.$eMsg/*.message-widget element*/;
              if(!eMsg) return;
              D.clearElement(this.e);
              const d = new Date(eMsg.dataset.timestamp);
              if(d.getMinutes().toString()!=="NaN"){
                // Date works, render informative timestamps
                const xfrom = eMsg.dataset.xfrom || 'server';
                D.append(this.e,
731
732
733
734
735
736
737
738




739
740

741
742






743
744









745
746







747
748
749
750
751
752
753
754

























755




756
757
758
759
760

761




762




763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797

798
799
800
801
802
803
804
805
806



807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826

827
828
829
830



831

832
833





834
835
836
837
838
839
840
841
842
843




844
845
846

847








848

849
850
851
852
853
854
855
856
857
858

859

860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875





876





877
878
879
880
881


















882
883
884
885
886
887
888
              btnDeleteLocal.addEventListener('click', function(){
                self.hide();
                Chat.deleteMessageElem(eMsg);
              });
              if(Chat.userMayDelete(eMsg)){
                const btnDeleteGlobal = D.button("Delete globally");
                D.append(toolbar, btnDeleteGlobal);
                btnDeleteGlobal.addEventListener('click', function(){




                  self.hide();
                  Chat.deleteMessage(eMsg);

                });
              }






              if(eMsg.dataset.xfrom){
                /* Add a link to the /timeline filtered on this user. */









                const toolbar2 = D.addClass(D.div(), 'toolbar');
                D.append(this.e, toolbar2);







                const timelineLink = D.attr(
                  D.a(F.repoUrl('timeline',{
                    u: eMsg.dataset.xfrom,
                    y: 'a'
                  }), "User's Timeline"),
                  'target', '_blank'
                );
                D.append(toolbar2, timelineLink);

























              }




            }/*refresh()*/
          });
          f.popup.installHideHandlers();
          f.popup.hide = function(){
            delete this._eMsg;

            D.clearElement(this.e);




            return this.show(false);




          };
        }/*end static init*/
        const rect = ev.target.getBoundingClientRect();
        const eMsg = ev.target.parentNode/*the owning .message-widget element*/;
        f.popup._eMsg = eMsg;
        let x = rect.left, y = rect.topm;
        f.popup.show(ev.target)/*so we can get its computed size*/;
        if(eMsg.dataset.xfrom===Chat.me
           && document.body.classList.contains('my-messages-right')){
          // Shift popup to the left for right-aligned messages to avoid
          // truncation off the right edge of the page.
          const pRect = f.popup.e.getBoundingClientRect();
          x = rect.right - pRect.width;
        }
        f.popup.show(x, y);
      }/*_handleLegendClicked()*/
    };
    return cf;
  })()/*MessageWidget*/;

  const BlobXferState = (function(){/*drag/drop bits...*/
    /* State for paste and drag/drop */
    const bxs = {
      dropDetails: document.querySelector('#chat-drop-details'),
      blob: undefined,
      clear: function(){
        this.blob = undefined;
        D.clearElement(this.dropDetails);
        Chat.e.inputFile.value = "";
      }
    };
    /** Updates the paste/drop zone with details of the pasted/dropped
        data. The argument must be a Blob or Blob-like object (File) or
        it can be falsy to reset/clear that state.*/
    const updateDropZoneContent = function(blob){

      const dd = bxs.dropDetails;
      bxs.blob = blob;
      D.clearElement(dd);
      if(!blob){
        Chat.e.inputFile.value = '';
        return;
      }
      D.append(dd, "Name: ", blob.name,
               D.br(), "Size: ",blob.size);



      if(blob.type && blob.type.startsWith("image/")){
        const img = D.img();
        D.append(dd, D.br(), img);
        const reader = new FileReader();
        reader.onload = (e)=>img.setAttribute('src', e.target.result);
        reader.readAsDataURL(blob);
      }
      const btn = D.button("Cancel");
      D.append(dd, D.br(), btn);
      btn.addEventListener('click', ()=>updateDropZoneContent(), false);
    };
    Chat.e.inputFile.addEventListener('change', function(ev){
      updateDropZoneContent(this.files && this.files[0] ? this.files[0] : undefined)
    });
    /* Handle image paste from clipboard. TODO: figure out how we can
       paste non-image binary data as if it had been selected via the
       file selection element. */
    document.addEventListener('paste', function(event){
      const items = event.clipboardData.items,
            item = items[0];

      if(!item || !item.type) return;
      else if('file'===item.kind){
        updateDropZoneContent(false/*clear prev state*/);
        updateDropZoneContent(items[0].getAsFile());



      }

    }, false);
    /* Add help button for drag/drop/paste zone */





    Chat.e.inputFile.parentNode.insertBefore(
      F.helpButtonlets.create(
        Chat.e.fileSelectWrapper.querySelector('.help-buttonlet')
      ), Chat.e.inputFile
    );
    ////////////////////////////////////////////////////////////
    // File drag/drop visual notification.
    const dropHighlight = Chat.e.inputFile /* target zone */;
    const dropEvents = {
      drop: function(ev){




        D.removeClass(dropHighlight, 'dragover');
      },
      dragenter: function(ev){

        ev.preventDefault();








        ev.dataTransfer.dropEffect = "copy";

        D.addClass(dropHighlight, 'dragover');
      },
      dragleave: function(ev){
        D.removeClass(dropHighlight, 'dragover');
      },
      dragend: function(ev){
        D.removeClass(dropHighlight, 'dragover');
      }
    };
    Object.keys(dropEvents).forEach(

      (k)=>Chat.e.inputFile.addEventListener(k, dropEvents[k], true)

    );
    return bxs;
  })()/*drag/drop*/;

  const tzOffsetToString = function(off){
    const hours = Math.round(off/60), min = Math.round(off % 30);
    return ''+(hours + (min ? '.5' : ''));
  };
  const pad2 = (x)=>('0'+x).substr(-2);
  const localTime8601 = function(d){
    return [
      d.getYear()+1900, '-', pad2(d.getMonth()+1), '-', pad2(d.getDate()),
      'T', pad2(d.getHours()),':', pad2(d.getMinutes()),':',pad2(d.getSeconds())
    ].join('');
  };
    





  Chat.submitMessage = function(){





    const fd = new FormData(this.e.inputForm)
    /* ^^^^ we don't really want/need the FORM element, but when
       FormData() is default-constructed here then the server
       segfaults, and i have no clue why! */;
    const msg = this.inputValue().trim();


















    if(msg) fd.set('msg',msg);
    const file = BlobXferState.blob || this.e.inputFile.files[0];
    if(file) fd.set("file", file);
    if( !msg && !file ) return;
    const self = this;
    fd.set("lmtime", localTime8601(new Date()));
    F.fetch("chat-send",{







|
>
>
>
>
|
|
>


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








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

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

<
<
|
<
<
<
|
<
<
<
|

|





|














>







|

>
>
>
|






<
<
<







|


>
|
|

|
>
>
>

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


|












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







997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020

1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077


1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092


1093



1094



1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137



1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165


1166




1167
1168
1169
1170
1171
1172
1173

1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187

1188

1189


1190

1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222



1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
              btnDeleteLocal.addEventListener('click', function(){
                self.hide();
                Chat.deleteMessageElem(eMsg);
              });
              if(Chat.userMayDelete(eMsg)){
                const btnDeleteGlobal = D.button("Delete globally");
                D.append(toolbar, btnDeleteGlobal);
                F.confirmer(btnDeleteGlobal,{
                  pinSize: true,
                  ticks: F.config.confirmerButtonTicks,
                  confirmText: "Confirm delete?",
                  onconfirm:function(){
                    self.hide();
                    Chat.deleteMessage(eMsg);
                  }
                });
              }
              const toolbar3 = D.addClass(D.div(), 'toolbar');
              D.append(this.e, toolbar3);
              D.append(toolbar3, D.button(
                "Locally remove all previous messages",
                function(){
                  self.hide();
                  Chat.mnMsg = +eMsg.dataset.msgid;

                  var e = eMsg.previousElementSibling;
                  while(e && e.classList.contains('message-widget')){
                    const n = e.previousElementSibling;
                    D.remove(e);
                    e = n;
                  }
                  eMsg.scrollIntoView();
                }
              ));
              const toolbar2 = D.addClass(D.div(), 'toolbar');
              D.append(this.e, toolbar2);
              D.append(toolbar2, D.button(
                "Toggle text mode", function(){
                  self.hide();
                  Chat.toggleTextMode(eMsg);
                }));
              if(eMsg.dataset.xfrom){
                /* Add a link to the /timeline filtered on this user. */
                const timelineLink = D.attr(
                  D.a(F.repoUrl('timeline',{
                    u: eMsg.dataset.xfrom,
                    y: 'a'
                  }), "User's Timeline"),
                  'target', '_blank'
                );
                D.append(toolbar2, timelineLink);
                if(Chat.filterState.activeUser &&
                   Chat.filterState.match(eMsg.dataset.xfrom)){
                  /* Add a button to clear user filter and jump to
                     this message in its original context. */
                  D.append(
                    this.e,
                    D.append(
                      D.addClass(D.div(), 'toolbar'),
                      D.button(
                        "Message in context",
                        function(){
                          self.hide();
                          Chat.setUserFilter(false);
                          eMsg.scrollIntoView(false);
                          Chat.animate(
                            eMsg.firstElementChild, 'anim-flip-h'
                            //eMsg.firstElementChild, 'anim-flip-v'
                            //eMsg.childNodes, 'anim-rotate-360'
                            //eMsg.childNodes, 'anim-flip-v'
                            //eMsg, 'anim-flip-v'
                          );
                        })
                    )
                  );
                }/*jump-to button*/
              }
              const tab = eMsg.querySelector('.message-widget-tab');
              D.append(tab, this.e);
              D.removeClass(this.e, 'hidden');
              Chat.animate(this.e, 'anim-fade-in-fast');
            }/*refresh()*/,


            hide: function(){
              delete this.$eMsg;
              D.addClass(this.e, 'hidden');
              D.clearElement(this.e);
            },
            show: function(tgtMsg){
              if(tgtMsg === this.$eMsg){
                this.hide();
                return;
              }
              this.$eMsg = tgtMsg;
              this.refresh();
            }
          }/*f.popup*/;
        }/*end static init*/


        let theMsg = ev.target;



        while( theMsg && !theMsg.classList.contains('message-widget')){



          theMsg = theMsg.parentNode;
        }
        if(theMsg) f.popup.show(theMsg);
      }/*_handleLegendClicked()*/
    };
    return cf;
  })()/*MessageWidget*/;

  const BlobXferState = (function(){
    /* State for paste and drag/drop */
    const bxs = {
      dropDetails: document.querySelector('#chat-drop-details'),
      blob: undefined,
      clear: function(){
        this.blob = undefined;
        D.clearElement(this.dropDetails);
        Chat.e.inputFile.value = "";
      }
    };
    /** Updates the paste/drop zone with details of the pasted/dropped
        data. The argument must be a Blob or Blob-like object (File) or
        it can be falsy to reset/clear that state.*/
    const updateDropZoneContent = function(blob){
      //console.debug("updateDropZoneContent()",blob);
      const dd = bxs.dropDetails;
      bxs.blob = blob;
      D.clearElement(dd);
      if(!blob){
        Chat.e.inputFile.value = '';
        return;
      }
      D.append(dd, "Attached: ", blob.name,
               D.br(), "Size: ",blob.size);
      const btn = D.button("Cancel");
      D.append(dd, D.br(), btn);
      btn.addEventListener('click', ()=>updateDropZoneContent(), false);
      if(blob.type && (blob.type.startsWith("image/") || blob.type==='BITMAP')){
        const img = D.img();
        D.append(dd, D.br(), img);
        const reader = new FileReader();
        reader.onload = (e)=>img.setAttribute('src', e.target.result);
        reader.readAsDataURL(blob);
      }



    };
    Chat.e.inputFile.addEventListener('change', function(ev){
      updateDropZoneContent(this.files && this.files[0] ? this.files[0] : undefined)
    });
    /* Handle image paste from clipboard. TODO: figure out how we can
       paste non-image binary data as if it had been selected via the
       file selection element. */
    const pasteListener = function(event){
      const items = event.clipboardData.items,
            item = items[0];
      //console.debug("paste event",event.target,item,event);
      //console.debug("paste event item",item);
      if(item && item.type && ('file'===item.kind || 'BITMAP'===item.type)){
        updateDropZoneContent(false/*clear prev state*/);
        updateDropZoneContent(item.getAsFile());
        event.stopPropagation();
        event.preventDefault(true);
        return false;
      }
      /* else continue propagating */
    };
    document.addEventListener('paste', pasteListener, true);
    if(window.Selection && window.Range && !Chat.$browserHasPlaintextOnly){
      /* Acrobatics to keep *some* installations of Firefox
         from pasting formatting into contenteditable fields.
         This also works on Chrome, but chrome has the
         contenteditable=plaintext-only property which does this
         for us. */


      Chat.inputElement().addEventListener(




        'paste',
        function(ev){
          if (ev.clipboardData && ev.clipboardData.getData) {
            const pastedText = ev.clipboardData.getData('text/plain');
            const selection = window.getSelection();
            if (!selection.rangeCount) return false;
            selection.deleteFromDocument(/*remove selected content*/);

            selection.getRangeAt(0).insertNode(document.createTextNode(pastedText));
            selection.collapseToEnd(/*deselect pasted text and set cursor at the end*/);
            ev.preventDefault();
            return false;
          }
        }, false);
    }
    const noDragDropEvents = function(ev){
      /* contenteditable tries to do its own thing with dropped data,
         which is not compatible with how we use it, so... */
      ev.dataTransfer.effectAllowed = 'none';
      ev.dataTransfer.dropEffect = 'none';
      ev.preventDefault();
      ev.stopPropagation();

      return false;

    };




    ['drop','dragenter','dragleave','dragend'].forEach(
      (k)=>{
        Chat.inputElement().addEventListener(k, noDragDropEvents, false);
      }
    );
    return bxs;
  })()/*drag/drop/paste*/;

  const tzOffsetToString = function(off){
    const hours = Math.round(off/60), min = Math.round(off % 30);
    return ''+(hours + (min ? '.5' : ''));
  };
  const pad2 = (x)=>('0'+x).substr(-2);
  const localTime8601 = function(d){
    return [
      d.getYear()+1900, '-', pad2(d.getMonth()+1), '-', pad2(d.getDate()),
      'T', pad2(d.getHours()),':', pad2(d.getMinutes()),':',pad2(d.getSeconds())
    ].join('');
  };

  /**
     Submits the contents of the message input field (if not empty)
     and/or the file attachment field to the server. If both are
     empty, this is a no-op.
  */
  Chat.submitMessage = function f(){
    if(!f.spaces){
      f.spaces = /\s+$/;
      f.markdownContinuation = /\\\s+$/;
    }
    this.setCurrentView(this.e.viewMessages);
    const fd = new FormData();



    var msg = this.inputValue().trim();
    if(msg && (msg.indexOf('\n')>0 || f.spaces.test(msg))){
      /* Cosmetic: trim whitespace from the ends of lines to try to
         keep copy/paste from terminals, especially wide ones, from
         forcing a horizontal scrollbar on all clients. This breaks
         markdown's use of blackslash-space-space for paragraph
         continuation, but *not* doing this affects all clients every
         time someone pastes in console copy/paste from an affected
         platform. We seem to have narrowed to the console pasting
         problem to users of tmux. Most consoles don't behave
         that way. */
      const xmsg = msg.split('\n');
      xmsg.forEach(function(line,ndx){
        if(!f.markdownContinuation.test(line)){
          xmsg[ndx] = line.trimRight();
        }
      });
      msg = xmsg.join('\n');
    }
    if(msg) fd.set('msg',msg);
    const file = BlobXferState.blob || this.e.inputFile.files[0];
    if(file) fd.set("file", file);
    if( !msg && !file ) return;
    const self = this;
    fd.set("lmtime", localTime8601(new Date()));
    F.fetch("chat-send",{
900
901
902
903
904
905
906
907










908





909
910


911







912
913





914









915






916

917
918
919
920
921

922
923
924
925
926
927


928
929












930




931



932








933

















934

935


936
937
938
939
940





941


942
943





944





945





946
947



948
949
950
951
952
953
954


955
956
957
958

959
960
961
962
963
964
965
966
967
968
969
970
971
972
973

974
975

976
977
978

979
















980
981
982

983
984
985

986
987
988
989
990
991
992
993
994
995
996


997
998
999
1000
1001



1002









1003
1004
1005
1006

1007
1008
1009
1010







1011
1012
1013







1014
1015
1016
1017




1018
1019





1020
1021
1022
1023
1024
1025
1026
1027
1028
1029







1030
1031


1032
1033
1034
1035
1036

1037
1038
1039
1040

1041


1042
1043





1044

1045



1046

1047




1048




1049

1050


1051


1052

1053
1054
1055
1056
1057
1058
1059

1060
1061
1062

1063
1064
1065
1066

1067
1068



1069


1070


1071
1072
1073
1074





1075
1076
1077
1078
1079

1080



1081


1082
1083

1084
1085
1086




1087
1088

1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103








1104
1105
1106
1107
1108
1109


1110
1111
1112
1113
1114
1115
1116
1117
1118
1119

1120
1121
1122
1123
1124
1125
1126
        }
      }
    });
    BlobXferState.clear();
    Chat.inputValue("").inputFocus();
  };

  Chat.e.inputSingle.addEventListener('keydown',function(ev){










    if(13===ev.keyCode/*ENTER*/){





      ev.preventDefault();
      ev.stopPropagation();


      Chat.submitMessage();







      return false;
    }





  }, false);









  Chat.e.inputMulti.addEventListener('keydown',function(ev){






    if(ev.ctrlKey && 13 === ev.keyCode){

      ev.preventDefault();
      ev.stopPropagation();
      Chat.submitMessage();
      return false;
    }

  }, false);
  Chat.e.btnSubmit.addEventListener('click',(e)=>{
    e.preventDefault();
    Chat.submitMessage();
    return false;
  });



  /* Returns an almost-ISO8601 form of Date object d. */












  const iso8601ish = function(d){




    return d.toISOString()



      .replace('T',' ').replace(/\.\d+/,'').replace('Z', ' zulu');








  };



















  (function(){/*Set up #chat-settings-button */


    const settingsButton = document.querySelector('#chat-settings-button');
    var popupSize = undefined/*placement workaround*/;
    const settingsPopup = new F.PopupWidget({
      cssClass: ['fossil-tooltip', 'chat-settings-popup']
    });





    /* Settings menu entries... */


    const settingsOps = [{
      label: "Multi-line input",





      boolValue: ()=>Chat.inputElement()===Chat.e.inputMulti,





      persistentSetting: 'edit-multiline',





      callback: function(){
        Chat.inputToggleSingleMulti();



      }
    },{
      label: "Monospace message font",
      boolValue: ()=>document.body.classList.contains('monospace-messages'),
      persistentSetting: 'monospace-messages',
      callback: function(){
        document.body.classList.toggle('monospace-messages');


      }
    },{
      label: "Chat-only mode",
      boolValue: ()=>Chat.isChatOnlyMode(),

      persistentSetting: 'chat-only-mode',
      callback: function(){
        Chat.toggleChatOnlyMode();
      }
    },{
      label: "Left-align my posts",
      boolValue: ()=>!document.body.classList.contains('my-messages-right'),
      callback: function f(){
        document.body.classList.toggle('my-messages-right');
      }
    },{
      label: "Images inline",
      boolValue: ()=>Chat.settings.getBool('images-inline'),
      callback: function(){
        const v = Chat.settings.toggle('images-inline');

        F.toast.message("Image mode set to "+(v ? "inline" : "hyperlink")+".");
      }

    }];

    /** Set up selection list of notification sounds. */

    if(true/*flip this to false to enable selection of audio files*/){
















      settingsOps.push({
        label: "Audible alerts",
        boolValue: ()=>Chat.settings.getBool('audible-alert'),

        callback: function(){
          const v = Chat.settings.toggle('audible-alert');
          Chat.setNewMessageSound(v ? F.config.chat.alertSound : false);

          if(v) setTimeout(()=>Chat.playNewMessageSound(), 50);
          F.toast.message("Audio notifications "+(v ? "enabled" : "disabled")+".");
        }
      });
      Chat.setNewMessageSound(
        Chat.settings.getBool('audible-alert') ? F.config.chat.alertSound : false
      );
    }else{
      /* Disabled per chatroom discussion: selection list of audio files for
         chat notification. */
      const selectSound = settingsOps.selectSound = D.addClass(D.select(), 'menu-entry');


      D.disable(D.option(selectSound, "0", "Audible alert..."));
      D.option(selectSound, "", "(no audio)");
      F.config.chat.alerts.forEach(function(a){
        D.option(selectSound, a);
      });



      if(true===Chat.settings.getBool('audible-alert')){









        selectSound.selectedIndex = 2/*first audio file in the list*/;
      }else{
        selectSound.value = Chat.settings.get('audible-alert','');
        if(selectSound.selectedIndex<0){

          /*Missing file - removed after this setting was applied. Fall back
            to the first sound in the list. */
          selectSound.selectedIndex = 2;
        }







      }
      selectSound.addEventListener('change',function(){
        const v = this.selectedIndex>1 ? this.value : '';







        Chat.setNewMessageSound(v);
        F.toast.message("Audio notifications "+(v ? "enabled" : "disabled")+".");
        if(v) setTimeout(()=>Chat.playNewMessageSound(), 50);
        settingsPopup.hide();




      }, false);
      Chat.setNewMessageSound(selectSound.value);





    }/*audio notification config*/
    /**
       Rebuild the menu each time it's shown so that the toggles can
       show their current values.
    */
    settingsPopup.options.refresh = function(){
      D.clearElement(this.e);
      settingsOps.forEach(function(op){
        const line = D.addClass(D.span(), 'menu-entry');
        const btn = D.append(D.addClass(D.span(), 'button'), op.label);







        const callback = function(ev){
          settingsPopup.hide();


          op.callback(ev);
          if(op.persistentSetting){
            Chat.settings.set(op.persistentSetting, op.boolValue());
          }
        };

        D.append(line, btn);
        if(op.hasOwnProperty('boolValue')){
          const check = D.attr(D.checkbox(1, op.boolValue()),
                                          'aria-label', op.label);

          D.append(line, check);


        }
        D.append(settingsPopup.e, line);





        line.addEventListener('click', callback);

      });



      if(settingsOps.selectSound){

        D.append(settingsPopup.e, settingsOps.selectSound);




      }




    };

    settingsPopup.installHideHandlers(


      false, settingsOps.selectSound ? false : true,


      true)

    /** Reminder: click-to-hide interferes with "?" embedded within
        the popup, so cannot be used together with those. Enabling
        this means, however, that tapping the menu button to toggle
        the menu cannot work because tapping the menu button while the
        menu is opened will, because of the click-to-hide handler,
        hide the menu before the button gets an event saying to toggle
        it.


        Reminder: because we need a SELECT element for the audio file
        selection (since that list can be arbitrarily long), we have

        to disable tap-outside-the-popup-to-close-it via passing false
        as the 2nd argument to installHideHandlers(). If we don't,
        tapping on the select element is unreliable on desktop
        browsers and doesn't seem to work at all on mobile. */;

    D.attr(settingsButton, 'role', 'button');
    settingsButton.addEventListener('click',function(ev){



      //ev.preventDefault();


      if(settingsPopup.isShown()) settingsPopup.hide();


      else settingsPopup.show(settingsButton);
      /* Reminder: we cannot toggle the visibility from her
       */
    }, false);






    /* Find an ideal X/Y position for the popup, directly above the settings
       button, based on the size of the popup... */
    settingsPopup.show(document.body);
    popupSize = settingsPopup.e.getBoundingClientRect();

    settingsPopup.hide();



    settingsPopup.options.adjustX = function(x){


      const rect = settingsButton.getBoundingClientRect();
      return rect.right - popupSize.width;

    };
    settingsPopup.options.adjustY = function(y){
      const rect = settingsButton.getBoundingClientRect();




      return rect.top - popupSize.height -2;
    };

  })()/*#chat-settings-button setup*/;
  
  /** Callback for poll() to inject new content into the page.  jx ==
      the response from /chat-poll. If atEnd is true, the message is
      appended to the end of the chat list (for loading older
      messages), else the beginning (the default). */
  const newcontent = function f(jx,atEnd){
    if(!f.processPost){
      /** Processes chat message m, placing it either the start (if atEnd
          is falsy) or end (if atEnd is truthy) of the chat history. atEnd
          should only be true when loading older messages. */
      f.processPost = function(m,atEnd){
        ++Chat.totalMessageCount;
        if( m.msgid>Chat.mxMsg ) Chat.mxMsg = m.msgid;
        if( !Chat.mnMsg || m.msgid<Chat.mnMsg) Chat.mnMsg = m.msgid;








        if( m.mdel ){
          /* A record deletion notice. */
          Chat.deleteMessageElem(m.mdel);
          return;
        }
        if(!Chat._isBatchLoading /*&& Chat.me!==m.xfrom*/ && Chat.playNewMessageSound){


          Chat.playNewMessageSound();
        }
        const row = new Chat.MessageWidget(m);
        Chat.injectMessageElem(row.e.body,atEnd);
        if(m.isError){
          Chat._gotServerError = m;
        }
      }/*processPost()*/;
    }/*end static init*/
    jx.msgs.forEach((m)=>f.processPost(m,atEnd));

    if('visible'===document.visibilityState){
      if(Chat.changesSincePageHidden){
        Chat.changesSincePageHidden = 0;
        Chat.e.pageTitle.innerText = Chat.pageTitleOrig;
      }
    }else{
      Chat.changesSincePageHidden += jx.msgs.length;







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


>
>
|
>
>
>
>
>
>
>


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





>
|





>
>

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

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

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



|
|
|
|
>
>



<
>
|
<
<
<

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



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

|
<
>
|
|
|
>
|
<


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

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

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

>
|














>
>
>
>
>
>
>
>





|
>
>










>







1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336

1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422

1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437

1438
1439



1440
1441





1442
1443
1444

1445
1446

1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470

1471
1472
1473
1474
1475
1476

1477
1478





1479
1480
1481
1482
1483
1484
1485

1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505

1506
1507
1508
1509
1510
1511
1512
1513
1514
1515

1516
1517
1518
1519
1520
1521
1522
1523
1524

1525

1526
1527
1528
1529
1530

1531
1532
1533
1534
1535
1536


1537

1538
1539
1540


1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553

1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600






1601
1602

1603
1604
1605
1606
1607

1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620


1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640

1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
        }
      }
    });
    BlobXferState.clear();
    Chat.inputValue("").inputFocus();
  };

  const inputWidgetKeydown = function f(ev){
    if(!f.$toggleCtrl){
      f.$toggleCtrl = function(currentMode){
        currentMode = !currentMode;
        Chat.settings.set('edit-ctrl-send', currentMode);
      };
      f.$toggleCompact = function(currentMode){
        currentMode = !currentMode;
        Chat.settings.set('edit-compact-mode', currentMode);
      };
    }
    if(13 !== ev.keyCode) return;
    const text = Chat.inputValue().trim();
    const ctrlMode = Chat.settings.getBool('edit-ctrl-send', false);
    //console.debug("Enter key event:", ctrlMode, ev.ctrlKey, ev.shiftKey, ev);
    if(ev.shiftKey){
      const compactMode = Chat.settings.getBool('edit-compact-mode', false);
      ev.preventDefault();
      ev.stopPropagation();
      /* Shift-enter will run preview mode UNLESS preview mode is
         active AND the input field is empty, in which case it will
         switch back to message view. */
      if(Chat.e.currentView===Chat.e.viewPreview && !text){
        Chat.setCurrentView(Chat.e.viewMessages);
      }else if(!text){
        f.$toggleCompact(compactMode);
      }else{
        Chat.e.btnPreview.click();
      }
      return false;
    }
    if(ev.ctrlKey && !text && !BlobXferState.blob){
      /* Ctrl-enter on empty input field(s) toggles Enter/Ctrl-enter mode */
      ev.preventDefault();
      ev.stopPropagation();
      f.$toggleCtrl(ctrlMode);
      return false;
    }
    if(!ctrlMode && ev.ctrlKey && text){
      //console.debug("!ctrlMode && ev.ctrlKey && text.");
      /* Ctrl-enter in Enter-sends mode SHOULD, with this logic add a
         newline, but that is not happening, for unknown reasons
         (possibly related to this element being a conteneditable DIV
         instead of a textarea). Forcibly appending a newline do the
         input area does not work, also for unknown reasons, and would
         only be suitable when we're at the end of the input.

         Strangely, this approach DOES work for shift-enter, but we
         need shift-enter as a hotkey for preview mode.
      */
      //return;
      // return here "should" cause newline to be added, but that doesn't work
    }
    if((!ctrlMode && !ev.ctrlKey) || (ev.ctrlKey/* && ctrlMode*/)){
      /* Ship it! */
      ev.preventDefault();
      ev.stopPropagation();
      Chat.submitMessage();
      return false;
    }
  };  
  Chat.e.inputField.addEventListener('keydown', inputWidgetKeydown, false);
  Chat.e.btnSubmit.addEventListener('click',(e)=>{
    e.preventDefault();
    Chat.submitMessage();
    return false;
  });
  Chat.e.btnAttach.addEventListener(
    'click', ()=>Chat.e.inputFile.click(), false);


  (function(){/*Set up #chat-button-settings and related bits */
    if(window.innerWidth<window.innerHeight){
      // Must be set up before config view is...
      /* Alignment of 'my' messages: right alignment is conventional
         for mobile chat apps but can be difficult to read in wide
         windows (desktop/tablet landscape mode), so we default to a
         layout based on the apparent "orientation" of the window:
         tall vs wide. Can be toggled via settings. */
      document.body.classList.add('my-messages-right');
    }
    const settingsButton = document.querySelector('#chat-button-settings');
    const optionsMenu = E1('#chat-config-options');
    const cbToggle = function(ev){
      ev.preventDefault();
      ev.stopPropagation();
      Chat.setCurrentView(Chat.e.currentView===Chat.e.viewConfig
                          ? Chat.e.viewMessages : Chat.e.viewConfig);
      return false;
    };
    D.attr(settingsButton, 'role', 'button').addEventListener('click', cbToggle, false);
    Chat.e.viewConfig.querySelector('button').addEventListener('click', cbToggle, false);

    /** Internal acrobatics to allow certain settings toggles to access
        related toggles. */
    const namedOptions = {
      activeUsers:{
        label: "Show active users list",
        hint: "List users who have messages in the currently-loaded chat history.",
        boolValue: 'active-user-list'
      }
    };
    if(1){
      /* Per user request, toggle the list of users on and off if the
         legend element is tapped. */
      const optAu = namedOptions.activeUsers;
      optAu.theLegend = Chat.e.activeUserListWrapper.firstElementChild/*LEGEND*/;
      optAu.theList = optAu.theLegend.nextElementSibling/*user list container*/;
      optAu.theLegend.addEventListener('click',function(){
        D.toggleClass(Chat.e.activeUserListWrapper, 'collapsed');
        if(!Chat.e.activeUserListWrapper.classList.contains('collapsed')){
          Chat.animate(optAu.theList,'anim-flip-v');
        }
      }, false);
    }/*namedOptions.activeUsers additional setup*/
    /* Settings menu entries... the most frequently-needed ones "should"
       (arguably) be closer to the start of this list. */
    /**
       Settings ops structure:

       label: string for the UI

       boolValue: string (name of Chat.settings setting) or a
       function which returns true or false.

       select: SELECT element (instead of boolValue)

       callback: optional handler to call after setting is modified.

       If a setting has a boolValue set, that gets transformed into a
       checkbox which toggles the given persistent setting (if
       boolValue is a string) AND listens for changes to that setting
       fired via Chat.settings.set() so that the checkbox can stay in
       sync with external changes to that setting. Various Chat UI
       elements stay in sync with the config UI via those settings
       events.
     */
    const settingsOps = [{
      label: "Ctrl-enter to Send",
      hint: "When on, only Ctrl-Enter will send messages and Enter adds "+
        "blank lines. "+
        "When off, both Enter and Ctrl-Enter send. "+
        "When the input field has focus, is empty, and preview "+
        "mode is NOT active then Ctrl-Enter toggles this setting.",
      boolValue: 'edit-ctrl-send'
    },{
      label: "Compact mode",
      hint: "Toggle between a space-saving or more spacious writing area. "+
        "When the input field has focus, is empty, and preview mode "+
        "is NOT active then Shift-Enter toggles this setting.",
      boolValue: 'edit-compact-mode'
    },{
      label: "Left-align my posts",
      hint: "Default alignment of your own messages is selected "
        +"based window width/height relationship.",
      boolValue: ()=>!document.body.classList.contains('my-messages-right'),
      callback: function f(){

        document.body.classList[
          this.checkbox.checked ? 'remove' : 'add'
        ]('my-messages-right');
      }
    },{
      label: "Monospace message font",
      hint: "Use monospace font for message text?",
      boolValue: 'monospace-messages',
      callback: function(setting){
        document.body.classList[
          setting.value ? 'add' : 'remove'
        ]('monospace-messages');
      }
    },{
      label: "Chat-only mode",

      hint: "Toggle the page between normal fossil view and chat-only view.",
      boolValue: 'chat-only-mode'



    },{
      label: "Show images inline",





      hint: "Whether to show images inline or as a hyperlink.",
      boolValue: 'images-inline'
    },namedOptions.activeUsers,{

      label: "Timestamps in active users list",
      hint: "Whether to show last-message timestamps.",

      boolValue: 'active-user-list-timestamps'
    }];

    /** Set up selection list of notification sounds. */
    if(1){
      const selectSound = D.select();
      D.option(selectSound, "", "(no audio)");
      const firstSoundIndex = selectSound.options.length;
      F.config.chat.alerts.forEach((a)=>D.option(selectSound, a));
      if(true===Chat.settings.getBool('audible-alert')){
        /* This setting used to be a plain bool. If we encounter
           such a setting, take the first sound in the list. */
        selectSound.selectedIndex = firstSoundIndex;
      }else{
        selectSound.value = Chat.settings.get('audible-alert','<none>');
        if(selectSound.selectedIndex<0){
          /* Missing file - removed after this setting was
            applied. Fall back to the first sound in the list. */
          selectSound.selectedIndex = firstSoundIndex;
        }
      }
      Chat.setNewMessageSound(selectSound.value);
      settingsOps.push({
        hint: "Audio alert. How to enable audio playback is browser-specific!",

        select: selectSound,
        callback: function(ev){
          const v = ev.target.value;
          Chat.setNewMessageSound(v);
          F.toast.message("Audio notifications "+(v ? "enabled" : "disabled")+".");
          if(v) setTimeout(()=>Chat.playNewMessageSound(), 0);

        }
      });





    }/*audio notification config*/
    settingsOps.push({
      label: "Play notification for your own messages.",
      hint: "When enabled, the audio notification will be played for all messages, "+
        "including your own. When disabled only messages from other users "+
        "will trigger a notification.",
      boolValue: 'alert-own-messages'

    });
    /**
       Build UI for config options...
    */
    settingsOps.forEach(function f(op){
      const line = D.addClass(D.div(), 'menu-entry');
      const label = op.label
            ? D.append(D.label(),op.label) : undefined;
      const labelWrapper = D.addClass(D.div(), 'label-wrapper');
      var hint;
      const col0 = D.span();
      if(op.hint){
        hint = D.append(D.addClass(D.span(),'hint'),op.hint);
      }
      if(op.hasOwnProperty('select')){
        D.append(line, col0, labelWrapper);
        D.append(labelWrapper, op.select);
        if(hint) D.append(labelWrapper, hint);
        if(label) D.append(col0, label);
        if(op.callback){

          op.select.addEventListener('change', (ev)=>op.callback(ev), false);
        }
      }else if(op.hasOwnProperty('boolValue')){
        if(undefined === f.$id) f.$id = 0;
        ++f.$id;
        if('string' ===typeof op.boolValue){
          const key = op.boolValue;
          op.boolValue = ()=>Chat.settings.getBool(key);
          op.persistentSetting = key;
        }

        const check = op.checkbox
              = D.attr(D.checkbox(1, op.boolValue()),
                       'aria-label', op.label);
        const id = 'cfgopt'+f.$id;
        check.checked = op.boolValue();
        op.checkbox = check;
        D.attr(check, 'id', id);
        D.append(line, col0, labelWrapper);
        D.append(col0, check);

        if(label){

          D.attr(label, 'for', id);
          D.append(labelWrapper, label);
        }
        if(hint) D.append(labelWrapper, hint);
      }else{

        line.addEventListener('click', callback);
        D.append(line, col0, labelWrapper);
        if(label) D.append(labelWrapper, label);
        if(hint) D.append(labelWrapper, hint);
      }
      D.append(optionsMenu, line);


      if(op.persistentSetting){

        Chat.settings.addListener(
          op.persistentSetting,
          function(setting){


            if(op.checkbox) op.checkbox.checked = !!setting.value;
            else if(op.select) op.select.value = setting.value;
            if(op.callback) op.callback(setting);
          }             
        );
        if(op.checkbox){
          op.checkbox.addEventListener(
            'change', function(){
              Chat.settings.set(op.persistentSetting, op.checkbox.checked)
            }, false);
        }
      }else if(op.callback && op.checkbox){
        op.checkbox.addEventListener('change', (ev)=>op.callback(ev), false);

      }
    });
  })()/*#chat-button-settings setup*/;

  (function(){
    /* Install default settings... must come after
       chat-button-settings setup so that the listeners which that
       installs are notified via the properties getting initialized
       here. */
    Chat.settings.addListener('monospace-messages',function(s){
      document.body.classList[s.value ? 'add' : 'remove']('monospace-messages');
    })
    Chat.settings.addListener('active-user-list',function(s){
      Chat.showActiveUserList(s.value);
    });
    Chat.settings.addListener('active-user-list-timestamps',function(s){
      Chat.showActiveUserTimestamps(s.value);
    });
    Chat.settings.addListener('chat-only-mode',function(s){
      Chat.chatOnlyMode(s.value);
    });
    Chat.settings.addListener('edit-compact-mode',function(s){
      Chat.e.inputLine.classList[
        s.value ? 'add' : 'remove'
      ]('compact');
    });
    Chat.settings.addListener('edit-ctrl-send',function(s){
      const label = (s.value ? "Ctrl-" : "")+"Enter submits messages.";
      const eInput = Chat.inputElement();
      eInput.dataset.placeholder = eInput.dataset.placeholder0 + " " +label;
      Chat.e.btnSubmit.title = label;
    });
    const valueKludges = {
      /* Convert certain string-format values to other types... */
      "false": false,
      "true": true
    };
    Object.keys(Chat.settings.defaults).forEach(function(k){
      var v = Chat.settings.get(k,Chat);
      if(Chat===v) v = Chat.settings.defaults[k];
      if(valueKludges.hasOwnProperty(v)) v = valueKludges[v];
      Chat.settings.set(k,v)
      /* fires event listeners so that the Config area checkboxes
         get in sync */;
    });
  })();
  






  (function(){/*set up message preview*/
    const btnPreview = Chat.e.btnPreview;

    Chat.setPreviewText = function(t){
      this.setCurrentView(this.e.viewPreview);
      this.e.previewContent.innerHTML = t;
      this.e.viewPreview.querySelectorAll('a').forEach(addAnchorTargetBlank);
      this.inputFocus();

    };
    Chat.e.viewPreview.querySelector('#chat-preview-close').
      addEventListener('click', ()=>Chat.setCurrentView(Chat.e.viewMessages), false);
    let previewPending = false;
    const elemsToEnable = [btnPreview, Chat.e.btnSubmit, Chat.e.inputField];
    const submit = function(ev){
      ev.preventDefault();
      ev.stopPropagation();
      if(previewPending) return false;
      const txt = Chat.inputValue();
      if(!txt){
        Chat.setPreviewText('');
        previewPending = false;


        return false;
      }
      const fd = new FormData();
      fd.append('content', txt);
      fd.append('filename','chat.md'
                /*filename needed for mimetype determination*/);
      fd.append('render_mode',F.page.previewModes.wiki);
      F.fetch('ajax/preview-text',{
        payload: fd,
        onload: (html)=>Chat.setPreviewText(html),
        onerror: function(e){
          F.fetch.onerror(e);
          Chat.setPreviewText("ERROR: "+(
            e.message || 'Unknown error fetching preview!'
          ));
        },
        beforesend: function(){
          D.disable(elemsToEnable);
          Chat.ajaxStart();
          previewPending = true;

          Chat.setPreviewText("Loading preview...");
        },
        aftersend:function(){
          previewPending = false;
          Chat.ajaxEnd();
          D.enable(elemsToEnable);
        }
      });
      return false;
    };
    btnPreview.addEventListener('click', submit, false);
  })()/*message preview setup*/;
  
  /** Callback for poll() to inject new content into the page.  jx ==
      the response from /chat-poll. If atEnd is true, the message is
      appended to the end of the chat list (for loading older
      messages), else the beginning (the default). */
  const newcontent = function f(jx,atEnd){
    if(!f.processPost){
      /** Processes chat message m, placing it either the start (if atEnd
          is falsy) or end (if atEnd is truthy) of the chat history. atEnd
          should only be true when loading older messages. */
      f.processPost = function(m,atEnd){
        ++Chat.totalMessageCount;
        if( m.msgid>Chat.mxMsg ) Chat.mxMsg = m.msgid;
        if( !Chat.mnMsg || m.msgid<Chat.mnMsg) Chat.mnMsg = m.msgid;
        if(m.xfrom && m.mtime){
          const d = new Date(m.mtime);
          const uls = Chat.usersLastSeen[m.xfrom];
          if(!uls || uls<d){
            d.$uColor = m.uclr;
            Chat.usersLastSeen[m.xfrom] = d;
          }
        }
        if( m.mdel ){
          /* A record deletion notice. */
          Chat.deleteMessageElem(m.mdel);
          return;
        }
        if(!Chat._isBatchLoading
           && (Chat.me!==m.xfrom
               || Chat.settings.getBool('alert-own-messages'))){
          Chat.playNewMessageSound();
        }
        const row = new Chat.MessageWidget(m);
        Chat.injectMessageElem(row.e.body,atEnd);
        if(m.isError){
          Chat._gotServerError = m;
        }
      }/*processPost()*/;
    }/*end static init*/
    jx.msgs.forEach((m)=>f.processPost(m,atEnd));
    Chat.updateActiveUserList();
    if('visible'===document.visibilityState){
      if(Chat.changesSincePageHidden){
        Chat.changesSincePageHidden = 0;
        Chat.e.pageTitle.innerText = Chat.pageTitleOrig;
      }
    }else{
      Chat.changesSincePageHidden += jx.msgs.length;
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163

1164
1165
1166
1167
1168
1169
1170
    const loadLegend = D.legend("Load...");
    const toolbar = Chat.e.loadOlderToolbar = D.attr(
      D.fieldset(loadLegend), "id", "load-msg-toolbar"
    );
    Chat.disableDuringAjax.push(toolbar);
    /* Loads the next n oldest messages, or all previous history if n is negative. */
    const loadOldMessages = function(n){
      Chat.e.messagesWrapper.classList.add('loading');
      Chat._isBatchLoading = true;
      const scrollHt = Chat.e.messagesWrapper.scrollHeight,
            scrollTop = Chat.e.messagesWrapper.scrollTop;
      F.fetch("chat-poll",{
        urlParams:{
          before: Chat.mnMsg,
          n: n
        },
        responseType: 'json',
        onerror:function(err){
          Chat.reportErrorAsMessage(err);
          Chat._isBatchLoading = false;
        },
        onload:function(x){
          let gotMessages = x.msgs.length;
          newcontent(x,true);
          Chat._isBatchLoading = false;

          if(Chat._gotServerError){
            Chat._gotServerError = false;
            return;
          }
          if(n<0/*we asked for all history*/
             || 0===gotMessages/*we found no history*/
             || (n>0 && gotMessages<n /*we got fewer history entries than requested*/)







|

|
|














>







1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
    const loadLegend = D.legend("Load...");
    const toolbar = Chat.e.loadOlderToolbar = D.attr(
      D.fieldset(loadLegend), "id", "load-msg-toolbar"
    );
    Chat.disableDuringAjax.push(toolbar);
    /* Loads the next n oldest messages, or all previous history if n is negative. */
    const loadOldMessages = function(n){
      Chat.e.viewMessages.classList.add('loading');
      Chat._isBatchLoading = true;
      const scrollHt = Chat.e.viewMessages.scrollHeight,
            scrollTop = Chat.e.viewMessages.scrollTop;
      F.fetch("chat-poll",{
        urlParams:{
          before: Chat.mnMsg,
          n: n
        },
        responseType: 'json',
        onerror:function(err){
          Chat.reportErrorAsMessage(err);
          Chat._isBatchLoading = false;
        },
        onload:function(x){
          let gotMessages = x.msgs.length;
          newcontent(x,true);
          Chat._isBatchLoading = false;
          Chat.updateActiveUserList();
          if(Chat._gotServerError){
            Chat._gotServerError = false;
            return;
          }
          if(n<0/*we asked for all history*/
             || 0===gotMessages/*we found no history*/
             || (n>0 && gotMessages<n /*we got fewer history entries than requested*/)
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
            if(ndx>=0) Chat.disableDuringAjax.splice(ndx,1);
            Chat.e.loadOlderToolbar.disabled = true;
          }
          if(gotMessages > 0){
            F.toast.message("Loaded "+gotMessages+" older messages.");
            /* Return scroll position to where it was when the history load
               was requested, per user request */
            Chat.e.messagesWrapper.scrollTo(
              0, Chat.e.messagesWrapper.scrollHeight - scrollHt + scrollTop
            );
          }
        },
        aftersend:function(){
          Chat.e.messagesWrapper.classList.remove('loading');
          Chat.ajaxEnd();
        }
      });
    };
    const wrapper = D.div(); /* browsers don't all properly handle >1 child in a fieldset */;
    D.append(toolbar, wrapper);
    var btn = D.button("Previous "+Chat.loadMessageCount+" messages");
    D.append(wrapper, btn);
    btn.addEventListener('click',()=>loadOldMessages(Chat.loadMessageCount));
    btn = D.button("All previous messages");
    D.append(wrapper, btn);
    btn.addEventListener('click',()=>loadOldMessages(-1));
    D.append(Chat.e.messagesWrapper, toolbar);
    toolbar.disabled = true /*will be enabled when msg load finishes */;
  })()/*end history loading widget setup*/;

  const afterFetch = function f(){
    if(true===f.isFirstCall){
      f.isFirstCall = false;
      Chat.ajaxEnd();
      Chat.e.messagesWrapper.classList.remove('loading');
      setTimeout(function(){
        Chat.scrollMessagesTo(1);
      }, 250);
    }
    if(Chat._gotServerError && Chat.intervalTimer){
      clearInterval(Chat.intervalTimer);
      Chat.reportErrorAsMessage(







|
|




|












|







|







1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
            if(ndx>=0) Chat.disableDuringAjax.splice(ndx,1);
            Chat.e.loadOlderToolbar.disabled = true;
          }
          if(gotMessages > 0){
            F.toast.message("Loaded "+gotMessages+" older messages.");
            /* Return scroll position to where it was when the history load
               was requested, per user request */
            Chat.e.viewMessages.scrollTo(
              0, Chat.e.viewMessages.scrollHeight - scrollHt + scrollTop
            );
          }
        },
        aftersend:function(){
          Chat.e.viewMessages.classList.remove('loading');
          Chat.ajaxEnd();
        }
      });
    };
    const wrapper = D.div(); /* browsers don't all properly handle >1 child in a fieldset */;
    D.append(toolbar, wrapper);
    var btn = D.button("Previous "+Chat.loadMessageCount+" messages");
    D.append(wrapper, btn);
    btn.addEventListener('click',()=>loadOldMessages(Chat.loadMessageCount));
    btn = D.button("All previous messages");
    D.append(wrapper, btn);
    btn.addEventListener('click',()=>loadOldMessages(-1));
    D.append(Chat.e.viewMessages, toolbar);
    toolbar.disabled = true /*will be enabled when msg load finishes */;
  })()/*end history loading widget setup*/;

  const afterFetch = function f(){
    if(true===f.isFirstCall){
      f.isFirstCall = false;
      Chat.ajaxEnd();
      Chat.e.viewMessages.classList.remove('loading');
      setTimeout(function(){
        Chat.scrollMessagesTo(1);
      }, 250);
    }
    if(Chat._gotServerError && Chat.intervalTimer){
      clearInterval(Chat.intervalTimer);
      Chat.reportErrorAsMessage(
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256

1257


1258
1259
1260
1261
1262
1263
1264
1265
1266
1267










1268
1269
  const poll = async function f(){
    if(f.running) return;
    f.running = true;
    Chat._isBatchLoading = f.isFirstCall;
    if(true===f.isFirstCall){
      f.isFirstCall = false;
      Chat.ajaxStart();
      Chat.e.messagesWrapper.classList.add('loading');
    }
    F.fetch("chat-poll",{
      timeout: 420 * 1000/*FIXME: get the value from the server*/,
      urlParams:{
        name: Chat.mxMsg
      },
      responseType: "json",
      // Disable the ajax start/end handling for this long-polling op:
      beforesend: function(){},
      aftersend: function(){},
      onerror:function(err){
        Chat._isBatchLoading = false;
        if(Chat.verboseErrors) console.error(err);
        /* ^^^ we don't use Chat.reportError() here b/c the polling
           fails exepectedly when it times out, but is then immediately
           resumed, and reportError() produces a loud error message. */
        afterFetch();
      },
      onload:function(y){
        newcontent(y);

        Chat._isBatchLoading = false;


        afterFetch();
      }
    });
  };
  poll.isFirstCall = true;
  Chat._gotServerError = poll.running = false;
  if( window.fossil.config.chat.fromcli ){
    Chat.chatOnlyMode(true);
  }
  Chat.intervalTimer = setInterval(poll, 1000);










  F.page.chat = Chat/* enables testing the APIs via the dev tools */;
})();







|




















>
|
>
>










>
>
>
>
>
>
>
>
>
>

|
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
  const poll = async function f(){
    if(f.running) return;
    f.running = true;
    Chat._isBatchLoading = f.isFirstCall;
    if(true===f.isFirstCall){
      f.isFirstCall = false;
      Chat.ajaxStart();
      Chat.e.viewMessages.classList.add('loading');
    }
    F.fetch("chat-poll",{
      timeout: 420 * 1000/*FIXME: get the value from the server*/,
      urlParams:{
        name: Chat.mxMsg
      },
      responseType: "json",
      // Disable the ajax start/end handling for this long-polling op:
      beforesend: function(){},
      aftersend: function(){},
      onerror:function(err){
        Chat._isBatchLoading = false;
        if(Chat.verboseErrors) console.error(err);
        /* ^^^ we don't use Chat.reportError() here b/c the polling
           fails exepectedly when it times out, but is then immediately
           resumed, and reportError() produces a loud error message. */
        afterFetch();
      },
      onload:function(y){
        newcontent(y);
        if(Chat._isBatchLoading){
          Chat._isBatchLoading = false;
          Chat.updateActiveUserList();
        }
        afterFetch();
      }
    });
  };
  poll.isFirstCall = true;
  Chat._gotServerError = poll.running = false;
  if( window.fossil.config.chat.fromcli ){
    Chat.chatOnlyMode(true);
  }
  Chat.intervalTimer = setInterval(poll, 1000);
  if(0){
    const flip = (ev)=>Chat.animate(ev.target,'anim-flip-h');
    document.querySelectorAll('#chat-buttons-wrapper .cbutton').forEach(function(e){
      e.addEventListener('click',flip, false);
    });
  }
  delete ForceResizeKludge.$disabled;
  ForceResizeKludge();
  Chat.animate.$disabled = false;
  setTimeout( ()=>Chat.inputFocus(), 0 );
  F.page.chat = Chat/* enables testing the APIs via the dev tools */;
});
Changes to src/fossil.page.fileedit.js.
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736

737
738
739
740
741
742
743
744
745
746
747
748

749
750
751
752
753
754
755
        }
      }
    );
    ////////////////////////////////////////////////////////////
    // Trigger preview on Ctrl-Enter. This only works on the built-in
    // editor widget, not a client-provided one.
    P.e.taEditor.addEventListener('keydown',function(ev){
      if(ev.ctrlKey && 13 === ev.keyCode){
        ev.preventDefault();
        ev.stopPropagation();
        P.e.taEditor.blur(/*force change event, if needed*/);
        P.tabs.switchToTab(P.e.tabs.preview);
        if(!P.e.cbAutoPreview.checked){/* If NOT in auto-preview mode, trigger an update. */
          P.preview();
        }

      }
    }, false);
    // If we're in the preview tab, have ctrl-enter switch back to the editor.
    document.body.addEventListener('keydown',function(ev){
      if(ev.ctrlKey && 13 === ev.keyCode){
        if(currentTab === P.e.tabs.preview){
          //ev.preventDefault();
          //ev.stopPropagation();
          P.tabs.switchToTab(P.e.tabs.content);
          P.e.taEditor.focus(/*doesn't work for client-supplied editor widget!
                              And it's slow as molasses for long docs, as focus()
                              forces a document reflow.*/);

        }
      }
    }, true);

    F.connectPagePreviewers(
      P.e.tabs.preview.querySelector(
        '#btn-preview-refresh'







|







>




|

|
|




>







722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
        }
      }
    );
    ////////////////////////////////////////////////////////////
    // Trigger preview on Ctrl-Enter. This only works on the built-in
    // editor widget, not a client-provided one.
    P.e.taEditor.addEventListener('keydown',function(ev){
      if(ev.shiftKey && 13 === ev.keyCode){
        ev.preventDefault();
        ev.stopPropagation();
        P.e.taEditor.blur(/*force change event, if needed*/);
        P.tabs.switchToTab(P.e.tabs.preview);
        if(!P.e.cbAutoPreview.checked){/* If NOT in auto-preview mode, trigger an update. */
          P.preview();
        }
        return false;
      }
    }, false);
    // If we're in the preview tab, have ctrl-enter switch back to the editor.
    document.body.addEventListener('keydown',function(ev){
      if(ev.shiftKey && 13 === ev.keyCode){
        if(currentTab === P.e.tabs.preview){
          ev.preventDefault();
          ev.stopPropagation();
          P.tabs.switchToTab(P.e.tabs.content);
          P.e.taEditor.focus(/*doesn't work for client-supplied editor widget!
                              And it's slow as molasses for long docs, as focus()
                              forces a document reflow.*/);
          return false;
        }
      }
    }, true);

    F.connectPagePreviewers(
      P.e.tabs.preview.querySelector(
        '#btn-preview-refresh'
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
        F.fetch.onerror(e);
        callback("Error fetching preview: "+e);
      }
    });
    return this;
  };

  /**
     Undo some of the SBS diff-rendering bits which hurt us more than
     they help...
  */
  P.tweakSbsDiffs2 = function(){
    if(1){
      const dt = this.e.diffTarget;
      dt.querySelectorAll('.sbsdiffcols .difftxtcol').forEach(
        (dtc)=>{
          const pre = dtc.querySelector('pre');
          pre.style.width = 'initial';
          //pre.removeAttribute('style');
          //console.debug("pre width =",pre.style.width);
        }
      );
    }
    this.tweakSbsDiffs();
  };

  /**
     Fetches the content diff based on the contents and settings of
     this page's input fields, and updates the UI with the diff view.

     Returns this object, noting that the operation is async.
  */
  P.diff = function f(sbs){







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







1201
1202
1203
1204
1205
1206
1207



















1208
1209
1210
1211
1212
1213
1214
        F.fetch.onerror(e);
        callback("Error fetching preview: "+e);
      }
    });
    return this;
  };




















  /**
     Fetches the content diff based on the contents and settings of
     this page's input fields, and updates the UI with the diff view.

     Returns this object, noting that the operation is async.
  */
  P.diff = function f(sbs){
1246
1247
1248
1249
1250
1251
1252

1253
1254
1255
1256
1257
1258
1259
1260
      onload: function(c){
        D.parseHtml(D.clearElement(target),[
          "<div>Diff <code>[",
          self.finfo.checkin,
          "]</code> &rarr; Local Edits</div>",
          c||'No changes.'
        ].join(''));

        if(sbs) P.tweakSbsDiffs2();
        F.message('Updated diff.');
        self.tabs.switchToTab(self.e.tabs.diff);
      }
    });
    return this;
  };








>
|







1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
      onload: function(c){
        D.parseHtml(D.clearElement(target),[
          "<div>Diff <code>[",
          self.finfo.checkin,
          "]</code> &rarr; Local Edits</div>",
          c||'No changes.'
        ].join(''));
        F.diff.setupDiffContextLoad();
        if(sbs) P.tweakSbsDiffs();
        F.message('Updated diff.');
        self.tabs.switchToTab(self.e.tabs.diff);
      }
    });
    return this;
  };

Changes to src/fossil.page.pikchrshow.js.
96
97
98
99
100
101
102
103
104
105





106
107
108
109
110
111
112
              P.e.previewModeToggle,
              '\u00a0',
              P.e.previewCopyButton,
              P.e.previewModeLabel,
              P.e.markupAlignWrapper );

    ////////////////////////////////////////////////////////////
    // Trigger preview on Ctrl-Enter.
    P.e.taContent.addEventListener('keydown',function(ev){
      if(ev.ctrlKey && 13 === ev.keyCode) P.preview();





    }, false);

    ////////////////////////////////////////////////////////////
    // Setup clipboard-copy of markup/SVG...
    F.copyButton(P.e.previewCopyButton, {copyFromElement: P.e.taPreviewText});
    P.e.previewModeLabel.addEventListener('click', ()=>P.e.previewCopyButton.click(), false);








|

|
>
>
>
>
>







96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
              P.e.previewModeToggle,
              '\u00a0',
              P.e.previewCopyButton,
              P.e.previewModeLabel,
              P.e.markupAlignWrapper );

    ////////////////////////////////////////////////////////////
    // Trigger preview on Shift-Enter.
    P.e.taContent.addEventListener('keydown',function(ev){
      if(ev.shiftKey && 13 === ev.keyCode){
        ev.preventDefault();
        ev.stopPropagation();
        P.preview();
        return false;
      }
    }, false);

    ////////////////////////////////////////////////////////////
    // Setup clipboard-copy of markup/SVG...
    F.copyButton(P.e.previewCopyButton, {copyFromElement: P.e.taPreviewText});
    P.e.previewModeLabel.addEventListener('click', ()=>P.e.previewCopyButton.click(), false);

383
384
385
386
387
388
389

390
391
392
393
394
395
396
          this.response.raw;
        console.error("svg parsed HTML nodes:",childs);
      }
      D.append(D.clearElement(preTgt), this.e.taPreviewText);
      break;
    }
    this.e.previewModeLabel.innerText = label;

  };

  /**
     Fetches the preview from the server and updates the preview to
     the rendered SVG content or error report.
  */
  P.preview = function fp(){







>







388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
          this.response.raw;
        console.error("svg parsed HTML nodes:",childs);
      }
      D.append(D.clearElement(preTgt), this.e.taPreviewText);
      break;
    }
    this.e.previewModeLabel.innerText = label;
    this.e.taContent.focus(/*not sure why this gets lost on preview!*/);
  };

  /**
     Fetches the preview from the server and updates the preview to
     the rendered SVG content or error report.
  */
  P.preview = function fp(){
Changes to src/fossil.page.wikiedit.js.
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939

940
941
942
943
944
945
946
        }
      }
    );
    ////////////////////////////////////////////////////////////
    // Trigger preview on Ctrl-Enter. This only works on the built-in
    // editor widget, not a client-provided one.
    P.e.taEditor.addEventListener('keydown',function(ev){
      if(ev.ctrlKey && 13 === ev.keyCode){
        ev.preventDefault();
        ev.stopPropagation();
        P.e.taEditor.blur(/*force change event, if needed*/);
        P.tabs.switchToTab(P.e.tabs.preview);
        if(!P.e.cbAutoPreview.checked){/* If NOT in auto-preview mode, trigger an update. */
          P.preview();
        }
      }
    }, false);
    // If we're in the preview tab, have ctrl-enter switch back to the editor.
    document.body.addEventListener('keydown',function(ev){
      if(ev.ctrlKey && 13 === ev.keyCode){
        if(currentTab === P.e.tabs.preview){
          //ev.preventDefault();
          //ev.stopPropagation();
          P.tabs.switchToTab(P.e.tabs.content);
          P.e.taEditor.focus(/*doesn't work for client-supplied editor widget!
                              And it's slow as molasses for long docs, as focus()
                              forces a document reflow. */);
          //console.debug("BODY ctrl-enter");

        }
      }
    }, true);

    F.connectPagePreviewers(
      P.e.tabs.preview.querySelector(
        '#btn-preview-refresh'







|











|

|
|





>







912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
        }
      }
    );
    ////////////////////////////////////////////////////////////
    // Trigger preview on Ctrl-Enter. This only works on the built-in
    // editor widget, not a client-provided one.
    P.e.taEditor.addEventListener('keydown',function(ev){
      if(ev.shiftKey && 13 === ev.keyCode){
        ev.preventDefault();
        ev.stopPropagation();
        P.e.taEditor.blur(/*force change event, if needed*/);
        P.tabs.switchToTab(P.e.tabs.preview);
        if(!P.e.cbAutoPreview.checked){/* If NOT in auto-preview mode, trigger an update. */
          P.preview();
        }
      }
    }, false);
    // If we're in the preview tab, have ctrl-enter switch back to the editor.
    document.body.addEventListener('keydown',function(ev){
      if(ev.shiftKey && 13 === ev.keyCode){
        if(currentTab === P.e.tabs.preview){
          ev.preventDefault();
          ev.stopPropagation();
          P.tabs.switchToTab(P.e.tabs.content);
          P.e.taEditor.focus(/*doesn't work for client-supplied editor widget!
                              And it's slow as molasses for long docs, as focus()
                              forces a document reflow. */);
          //console.debug("BODY ctrl-enter");
          return false;
        }
      }
    }, true);

    F.connectPagePreviewers(
      P.e.tabs.preview.querySelector(
        '#btn-preview-refresh'
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
        F.fetch.onerror(e);
        callback("Error fetching preview: "+e);
      }
    });
    return this;
  };

  /**
     Undo some of the SBS diff-rendering bits which hurt us more than
     they help...
  */
  P.tweakSbsDiffs2 = function(){
    if(1){
      const dt = this.e.diffTarget;
      dt.querySelectorAll('.sbsdiffcols .difftxtcol').forEach(
        (dtc)=>{
          const pre = dtc.querySelector('pre');
          pre.style.width = 'initial';
          //pre.removeAttribute('style');
          //console.debug("pre width =",pre.style.width);
        }
      );
    }
    this.tweakSbsDiffs();
  };

  /**
     Fetches the content diff based on the contents and settings of
     this page's input fields, and updates the UI with the diff view.

     Returns this object, noting that the operation is async.
  */
  P.diff = function f(sbs){







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







1495
1496
1497
1498
1499
1500
1501



















1502
1503
1504
1505
1506
1507
1508
        F.fetch.onerror(e);
        callback("Error fetching preview: "+e);
      }
    });
    return this;
  };




















  /**
     Fetches the content diff based on the contents and settings of
     this page's input fields, and updates the UI with the diff view.

     Returns this object, noting that the operation is async.
  */
  P.diff = function f(sbs){
1540
1541
1542
1543
1544
1545
1546

1547
1548
1549
1550
1551
1552
1553
1554
      onload: function(c){
        D.parseHtml(D.clearElement(target), [
          "<div>Diff <code>[",
          self.winfo.name,
          "]</code> &rarr; Local Edits</div>",
          c||'No changes.'
        ].join(''));

        if(sbs) P.tweakSbsDiffs2();
        F.message('Updated diff.');
        self.tabs.switchToTab(self.e.tabs.diff);
      }
    });
    return this;
  };








>
|







1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
      onload: function(c){
        D.parseHtml(D.clearElement(target), [
          "<div>Diff <code>[",
          self.winfo.name,
          "]</code> &rarr; Local Edits</div>",
          c||'No changes.'
        ].join(''));
        F.diff.setupDiffContextLoad();
        if(sbs) P.tweakSbsDiffs();
        F.message('Updated diff.');
        self.tabs.switchToTab(self.e.tabs.diff);
      }
    });
    return this;
  };

Changes to src/fossil.popupwidget.js.
353
354
355
356
357
358
359

360
361
362
363
364
365
366
       when the botton is clicked.

    */
    setup: function f(){
      if(!f.hasOwnProperty('clickHandler')){
        f.clickHandler = function fch(ev){
          ev.preventDefault();

          if(!fch.popup){
            fch.popup = new F.PopupWidget({
              cssClass: ['fossil-tooltip', 'help-buttonlet-content'],
              refresh: function(){
              }
            });
            fch.popup.e.style.maxWidth = '80%'/*of body*/;







>







353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
       when the botton is clicked.

    */
    setup: function f(){
      if(!f.hasOwnProperty('clickHandler')){
        f.clickHandler = function fch(ev){
          ev.preventDefault();
          ev.stopPropagation();
          if(!fch.popup){
            fch.popup = new F.PopupWidget({
              cssClass: ['fossil-tooltip', 'help-buttonlet-content'],
              refresh: function(){
              }
            });
            fch.popup.e.style.maxWidth = '80%'/*of body*/;
409
410
411
412
413
414
415

416
417
418
419
420
421
422
          }else{
            fch.popup.e.style.removeProperty('min-width');
            x -= popupRect.width/2;
          }
          if(x<0) x = 0;
          //console.debug("dimensions",x,y, popupRect, rectBody);
          fch.popup.show(x, y);

        };
        f.foreachElement = function(e){
          if(e.classList.contains('processed')) return;
          e.classList.add('processed');
          e.$helpContent = [];
          /* We have to move all child nodes out of the way because we
             cannot hide TEXT nodes via CSS (which cannot select TEXT







>







410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
          }else{
            fch.popup.e.style.removeProperty('min-width');
            x -= popupRect.width/2;
          }
          if(x<0) x = 0;
          //console.debug("dimensions",x,y, popupRect, rectBody);
          fch.popup.show(x, y);
          return false;
        };
        f.foreachElement = function(e){
          if(e.classList.contains('processed')) return;
          e.classList.add('processed');
          e.$helpContent = [];
          /* We have to move all child nodes out of the way because we
             cannot hide TEXT nodes via CSS (which cannot select TEXT
Changes to src/fossil.storage.js.
1
2
3
4
5
6
7
8
9
10
(function(F){
  /**
     fossil.store is a basic wrapper around localStorage
     or sessionStorage or a dummy proxy object if neither
     of those are available.
  */
  const tryStorage = function f(obj){
    if(!f.key) f.key = 'fossil.access.check';
    try{
      obj.setItem(f.key, 'f');


|







1
2
3
4
5
6
7
8
9
10
(function(F){
  /**
     fossil.storage is a basic wrapper around localStorage
     or sessionStorage or a dummy proxy object if neither
     of those are available.
  */
  const tryStorage = function f(obj){
    if(!f.key) f.key = 'fossil.access.check';
    try{
      obj.setItem(f.key, 'f');
Changes to src/hook.c.
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
** the hash of the artifact and continues with a description of the
** interpretation of the artifact.
*/
#include "config.h"
#include "hook.h"

/*
** SETTING: hooks sensitive
** The "hooks" setting contains JSON that describes all defined
** hooks.  The value is an array of objects.  Each object describes
** a single hook.  Example:
**
**
**    {
**    "type": "after-receive",  // type of hook







|







38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
** the hash of the artifact and continues with a description of the
** interpretation of the artifact.
*/
#include "config.h"
#include "hook.h"

/*
** SETTING: hooks sensitive width=40 block-text
** The "hooks" setting contains JSON that describes all defined
** hooks.  The value is an array of objects.  Each object describes
** a single hook.  Example:
**
**
**    {
**    "type": "after-receive",  // type of hook
Changes to src/http_ssl.c.
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
    ** command line */
    if( g.zSSLIdentity!=0 ){
      identityFile = g.zSSLIdentity;
    }else{
      identityFile = db_get("ssl-identity", 0);
    }
    if( identityFile!=0 && identityFile[0]!='\0' ){
      if( SSL_CTX_use_certificate_file(sslCtx,identityFile,SSL_FILETYPE_PEM)!=1
       || SSL_CTX_use_PrivateKey_file(sslCtx,identityFile,SSL_FILETYPE_PEM)!=1
      ){
        fossil_fatal("Could not load SSL identity from %s", identityFile);
      }
    }
    /* Register a callback to tell the user what to do when the server asks
    ** for a cert */







|







141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
    ** command line */
    if( g.zSSLIdentity!=0 ){
      identityFile = g.zSSLIdentity;
    }else{
      identityFile = db_get("ssl-identity", 0);
    }
    if( identityFile!=0 && identityFile[0]!='\0' ){
      if( SSL_CTX_use_certificate_chain_file(sslCtx,identityFile)!=1
       || SSL_CTX_use_PrivateKey_file(sslCtx,identityFile,SSL_FILETYPE_PEM)!=1
      ){
        fossil_fatal("Could not load SSL identity from %s", identityFile);
      }
    }
    /* Register a callback to tell the user what to do when the server asks
    ** for a cert */
395
396
397
398
399
400
401

402
403
404
405
406
407
408
        ssl_close();
        return 1;
      }
      ssl_one_time_exception(pUrlData, zHash);
      prompt_user("remember this exception (y/N)? ", &ans);
      cReply = blob_str(&ans)[0];
      if( cReply=='y' || cReply=='Y') {

        ssl_remember_certificate_exception(pUrlData, zHash);
      }
      blob_reset(&ans);
    }
  }

  /* Set the Global.zIpAddr variable to the server we are talking to.







>







395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
        ssl_close();
        return 1;
      }
      ssl_one_time_exception(pUrlData, zHash);
      prompt_user("remember this exception (y/N)? ", &ans);
      cReply = blob_str(&ans)[0];
      if( cReply=='y' || cReply=='Y') {
        db_open_config(0,0);
        ssl_remember_certificate_exception(pUrlData, zHash);
      }
      blob_reset(&ans);
    }
  }

  /* Set the Global.zIpAddr variable to the server we are talking to.
Changes to src/info.c.
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343

344
345

346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363


364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387

/*
** Append the difference between artifacts to the output
*/
static void append_diff(
  const char *zFrom,    /* Diff from this artifact */
  const char *zTo,      /*  ... to this artifact */
  u64 diffFlags,        /* Diff formatting flags */
  ReCompiled *pRe       /* Only show change matching this regex */
){
  int fromid;
  int toid;
  Blob from, to, out;
  if( zFrom ){
    fromid = uuid_to_rid(zFrom, 0);
    content_get(fromid, &from);

  }else{
    blob_zero(&from);

  }
  if( zTo ){
    toid = uuid_to_rid(zTo, 0);
    content_get(toid, &to);
  }else{
    blob_zero(&to);
  }
  blob_zero(&out);
  if( diffFlags & DIFF_SIDEBYSIDE ){
    text_diff(&from, &to, &out, pRe, diffFlags | DIFF_HTML | DIFF_NOTTOOBIG);
    @ %s(blob_str(&out))
  }else{
    text_diff(&from, &to, &out, pRe,
           diffFlags | DIFF_LINENO | DIFF_HTML | DIFF_NOTTOOBIG);
    @ <pre class="udiff">
    @ %s(blob_str(&out))
    @ </pre>
  }


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

/*
** Write a line of web-page output that shows changes that have occurred
** to a file between two check-ins.
*/
static void append_file_change_line(
  const char *zCkin,    /* The checkin on which the change occurs */
  const char *zName,    /* Name of the file that has changed */
  const char *zOld,     /* blob.uuid before change.  NULL for added files */
  const char *zNew,     /* blob.uuid after change.  NULL for deletes */
  const char *zOldName, /* Prior name.  NULL if no name change. */
  u64 diffFlags,        /* Flags for text_diff().  Zero to omit diffs */
  ReCompiled *pRe,      /* Only show diffs that match this regex, if not NULL */
  int mperm             /* executable or symlink permission for zNew */
){
  @ <p>
  if( !g.perm.Hyperlink ){
    if( zNew==0 ){
      @ Deleted %h(zName).
    }else if( zOld==0 ){







|
<



|



>


>







<
|
|
<

<
|
<
<
<

>
>


<












|
<







328
329
330
331
332
333
334
335

336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353

354
355

356

357



358
359
360
361
362

363
364
365
366
367
368
369
370
371
372
373
374
375

376
377
378
379
380
381
382

/*
** Append the difference between artifacts to the output
*/
static void append_diff(
  const char *zFrom,    /* Diff from this artifact */
  const char *zTo,      /*  ... to this artifact */
  DiffConfig *pCfg      /* The diff configuration */

){
  int fromid;
  int toid;
  Blob from, to;
  if( zFrom ){
    fromid = uuid_to_rid(zFrom, 0);
    content_get(fromid, &from);
    pCfg->zLeftHash = zFrom;
  }else{
    blob_zero(&from);
    pCfg->zLeftHash = 0;
  }
  if( zTo ){
    toid = uuid_to_rid(zTo, 0);
    content_get(toid, &to);
  }else{
    blob_zero(&to);
  }

  if( pCfg->diffFlags & DIFF_SIDEBYSIDE ){
    pCfg->diffFlags |= DIFF_HTML | DIFF_NOTTOOBIG;

  }else{

    pCfg->diffFlags |= DIFF_LINENO | DIFF_HTML | DIFF_NOTTOOBIG;



  }
  text_diff(&from, &to, cgi_output_blob(), pCfg);
  pCfg->zLeftHash = 0;
  blob_reset(&from);
  blob_reset(&to);

}

/*
** Write a line of web-page output that shows changes that have occurred
** to a file between two check-ins.
*/
static void append_file_change_line(
  const char *zCkin,    /* The checkin on which the change occurs */
  const char *zName,    /* Name of the file that has changed */
  const char *zOld,     /* blob.uuid before change.  NULL for added files */
  const char *zNew,     /* blob.uuid after change.  NULL for deletes */
  const char *zOldName, /* Prior name.  NULL if no name change. */
  DiffConfig *pCfg,     /* Flags for text_diff() or NULL to omit all */

  int mperm             /* executable or symlink permission for zNew */
){
  @ <p>
  if( !g.perm.Hyperlink ){
    if( zNew==0 ){
      @ Deleted %h(zName).
    }else if( zOld==0 ){
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
        @ %h(zName) became a symlink.
      }else{
        @ %h(zName) became a regular file.
      }
    }else{
      @ Changes to %h(zName).
    }
    if( diffFlags ){
      append_diff(zOld, zNew, diffFlags, pRe);
    }
  }else{
    if( zOld && zNew ){
      if( fossil_strcmp(zOld, zNew)!=0 ){
        @ Modified %z(href("%R/finfo?name=%T&m=%!S&ci=%!S",zName,zNew,zCkin))\
        @ %h(zName)</a>
        @ from %z(href("%R/artifact/%!S",zOld))[%S(zOld)]</a>







|
|







390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
        @ %h(zName) became a symlink.
      }else{
        @ %h(zName) became a regular file.
      }
    }else{
      @ Changes to %h(zName).
    }
    if( pCfg ){
      append_diff(zOld, zNew, pCfg);
    }
  }else{
    if( zOld && zNew ){
      if( fossil_strcmp(zOld, zNew)!=0 ){
        @ Modified %z(href("%R/finfo?name=%T&m=%!S&ci=%!S",zName,zNew,zCkin))\
        @ %h(zName)</a>
        @ from %z(href("%R/artifact/%!S",zOld))[%S(zOld)]</a>
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481


482

483
484
485
486
487
488
489
490
491
    }else if( zOld ){
      @ Deleted %z(href("%R/finfo?name=%T&m=%!S&ci=%!S",zName,zOld,zCkin))\
      @ %h(zName)</a> version %z(href("%R/artifact/%!S",zOld))[%S(zOld)]</a>.
    }else{
      @ Added %z(href("%R/finfo?name=%T&m=%!S&ci=%!S",zName,zNew,zCkin))\
      @ %h(zName)</a> version %z(href("%R/artifact/%!S",zNew))[%S(zNew)]</a>.
    }
    if( diffFlags ){
      append_diff(zOld, zNew, diffFlags, pRe);
    }else if( zOld && zNew && fossil_strcmp(zOld,zNew)!=0 ){
      @ &nbsp;&nbsp;
      @ %z(href("%R/fdiff?v1=%!S&v2=%!S",zOld,zNew))[diff]</a>
    }
  }
  @ </p>
}

/*
** Generate javascript to enhance HTML diffs.
*/
void append_diff_javascript(int sideBySide){
  if( !sideBySide ) return;
  builtin_request_js("sbsdiff.js");
}

/*
** Construct an appropriate diffFlag for text_diff() based on query
** parameters and the to boolean arguments.
*/
u64 construct_diff_flags(int diffType){
  u64 diffFlags = 0;  /* Zero means do not show any diff */
  if( diffType>0 ){
    int x;
    if( diffType==2 ){
      diffFlags = DIFF_SIDEBYSIDE;

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

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

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


    diffFlags |= DIFF_STRIP_EOLCR;

  }
  return diffFlags;
}

/*
** WEBPAGE: ci_tags
** URL:    /ci_tags?name=ARTIFACTID
**
** Show all tags and properties for a given check-in.







|
|











|
|
|






|



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


<
|


<
>
>
|
>

<







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



461

462


463
464
465

466
467
468

469
470
471
472
473

474
475
476
477
478
479
480
    }else if( zOld ){
      @ Deleted %z(href("%R/finfo?name=%T&m=%!S&ci=%!S",zName,zOld,zCkin))\
      @ %h(zName)</a> version %z(href("%R/artifact/%!S",zOld))[%S(zOld)]</a>.
    }else{
      @ Added %z(href("%R/finfo?name=%T&m=%!S&ci=%!S",zName,zNew,zCkin))\
      @ %h(zName)</a> version %z(href("%R/artifact/%!S",zNew))[%S(zNew)]</a>.
    }
    if( pCfg ){
      append_diff(zOld, zNew, pCfg);
    }else if( zOld && zNew && fossil_strcmp(zOld,zNew)!=0 ){
      @ &nbsp;&nbsp;
      @ %z(href("%R/fdiff?v1=%!S&v2=%!S",zOld,zNew))[diff]</a>
    }
  }
  @ </p>
}

/*
** Generate javascript to enhance HTML diffs.
*/
void append_diff_javascript(int diffType){
  if( diffType==0 ) return;
  builtin_fossil_js_bundle_or("diff", NULL);
}

/*
** Construct an appropriate diffFlag for text_diff() based on query
** parameters and the to boolean arguments.
*/
DiffConfig *construct_diff_flags(int diffType, DiffConfig *pCfg){
  u64 diffFlags = 0;  /* Zero means do not show any diff */
  if( diffType>0 ){
    int x;
    if( diffType==2 ) diffFlags = DIFF_SIDEBYSIDE;
    if( P("w") )      diffFlags |= DIFF_IGNORE_ALLWS;
    if( PD("noopt",0)!=0 ) diffFlags |= DIFF_NOOPT;



    diffFlags |= DIFF_STRIP_EOLCR;

    diff_config_init(pCfg, diffFlags);



    /* "dc" query parameter determines lines of context */
    x = atoi(PD("dc","7"));

    if( x>0 ) pCfg->nContext = x;

    /* The "noopt" parameter disables diff optimization */

    return pCfg;
  }else{
    diff_config_init(pCfg, 0);
    return 0;
  }

}

/*
** WEBPAGE: ci_tags
** URL:    /ci_tags?name=ARTIFACTID
**
** Show all tags and properties for a given check-in.
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634

635
636
637
638
639
640
641
** or a tag or branch name that identifies the check-in.
*/
void ci_page(void){
  Stmt q1, q2, q3;
  int rid;
  int isLeaf;
  int diffType;        /* 0: no diff,  1: unified,  2: side-by-side */
  u64 diffFlags;       /* Flag parameter for text_diff() */
  const char *zName;   /* Name of the check-in to be displayed */
  const char *zUuid;   /* Hash of zName, found via blob.uuid */
  const char *zParent; /* Hash of the parent check-in (if any) */
  const char *zRe;     /* regex parameter */
  ReCompiled *pRe = 0; /* regex */
  const char *zW;      /* URL param for ignoring whitespace */
  const char *zPage = "vinfo";  /* Page that shows diffs */
  const char *zPageHide = "ci"; /* Page that hides diffs */
  const char *zBrName; /* Branch name */


  login_check_credentials();
  if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
  style_set_current_feature("vinfo");
  zName = P("name");
  rid = name_to_rid_www("name");
  if( rid==0 ){







<





|


|
>







607
608
609
610
611
612
613

614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
** or a tag or branch name that identifies the check-in.
*/
void ci_page(void){
  Stmt q1, q2, q3;
  int rid;
  int isLeaf;
  int diffType;        /* 0: no diff,  1: unified,  2: side-by-side */

  const char *zName;   /* Name of the check-in to be displayed */
  const char *zUuid;   /* Hash of zName, found via blob.uuid */
  const char *zParent; /* Hash of the parent check-in (if any) */
  const char *zRe;     /* regex parameter */
  ReCompiled *pRe = 0; /* regex */
  const char *zW;               /* URL param for ignoring whitespace */
  const char *zPage = "vinfo";  /* Page that shows diffs */
  const char *zPageHide = "ci"; /* Page that hides diffs */
  const char *zBrName;          /* Branch name */
  DiffConfig DCfg,*pCfg;        /* Type of diff */

  login_check_credentials();
  if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
  style_set_current_feature("vinfo");
  zName = P("name");
  rid = name_to_rid_www("name");
  if( rid==0 ){
882
883
884
885
886
887
888
889

890
891
892
893
894
895
896
897
    wiki_render_associated("checkin", zUuid, 0);
  }
  render_backlink_graph(zUuid, "<div class=\"section\">References</div>\n");
  @ <div class="section">Context</div>
  render_checkin_context(rid, 0, 0, 0);
  @ <div class="section">Changes</div>
  @ <div class="sectionmenu">
  diffFlags = construct_diff_flags(diffType);

  zW = (diffFlags&DIFF_IGNORE_ALLWS)?"&w":"";
  if( diffType!=0 ){
    @ %z(chref("button","%R/%s/%T?diff=0",zPageHide,zName))\
    @ Hide&nbsp;Diffs</a>
  }
  if( diffType!=1 ){
    @ %z(chref("button","%R/%s/%T?diff=1%s",zPage,zName,zW))\
    @ Unified&nbsp;Diffs</a>







|
>
|







871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
    wiki_render_associated("checkin", zUuid, 0);
  }
  render_backlink_graph(zUuid, "<div class=\"section\">References</div>\n");
  @ <div class="section">Context</div>
  render_checkin_context(rid, 0, 0, 0);
  @ <div class="section">Changes</div>
  @ <div class="sectionmenu">
  pCfg = construct_diff_flags(diffType, &DCfg);
  DCfg.pRe = pRe;  
  zW = (DCfg.diffFlags&DIFF_IGNORE_ALLWS)?"&w":"";
  if( diffType!=0 ){
    @ %z(chref("button","%R/%s/%T?diff=0",zPageHide,zName))\
    @ Hide&nbsp;Diffs</a>
  }
  if( diffType!=1 ){
    @ %z(chref("button","%R/%s/%T?diff=1%s",zPage,zName,zW))\
    @ Unified&nbsp;Diffs</a>
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
  while( db_step(&q3)==SQLITE_ROW ){
    const char *zName = db_column_text(&q3,0);
    int mperm = db_column_int(&q3, 1);
    const char *zOld = db_column_text(&q3,2);
    const char *zNew = db_column_text(&q3,3);
    const char *zOldName = db_column_text(&q3, 4);
    append_file_change_line(zUuid, zName, zOld, zNew, zOldName, 
                            diffFlags,pRe,mperm);
  }
  db_finalize(&q3);
  append_diff_javascript(diffType==2);
  builtin_fossil_js_bundle_or("info-diff",NULL);
  style_finish_page();
}

/*
** WEBPAGE: winfo
** URL:  /winfo?name=HASH
**







|


|
<







927
928
929
930
931
932
933
934
935
936
937

938
939
940
941
942
943
944
  while( db_step(&q3)==SQLITE_ROW ){
    const char *zName = db_column_text(&q3,0);
    int mperm = db_column_int(&q3, 1);
    const char *zOld = db_column_text(&q3,2);
    const char *zNew = db_column_text(&q3,3);
    const char *zOldName = db_column_text(&q3, 4);
    append_file_change_line(zUuid, zName, zOld, zNew, zOldName, 
                            pCfg,mperm);
  }
  db_finalize(&q3);
  append_diff_javascript(diffType);

  style_finish_page();
}

/*
** WEBPAGE: winfo
** URL:  /winfo?name=HASH
**
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187

1188
1189
1190
1191
1192
1193
1194
**   inv             "Invert".  Exchange the roles of from= and to=
**
** Show all differences between two check-ins.
*/
void vdiff_page(void){
  int ridFrom, ridTo;
  int diffType = 0;        /* 0: none, 1: unified, 2: side-by-side */
  u64 diffFlags = 0;
  Manifest *pFrom, *pTo;
  ManifestFile *pFileFrom, *pFileTo;
  const char *zBranch;
  const char *zFrom;
  const char *zTo;
  const char *zRe;
  const char *zGlob;
  char *zMergeOrigin = 0;
  ReCompiled *pRe = 0;

  int graphFlags = 0;
  Blob qp;
  int bInvert = PB("inv");

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







<









>







1160
1161
1162
1163
1164
1165
1166

1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
**   inv             "Invert".  Exchange the roles of from= and to=
**
** Show all differences between two check-ins.
*/
void vdiff_page(void){
  int ridFrom, ridTo;
  int diffType = 0;        /* 0: none, 1: unified, 2: side-by-side */

  Manifest *pFrom, *pTo;
  ManifestFile *pFileFrom, *pFileTo;
  const char *zBranch;
  const char *zFrom;
  const char *zTo;
  const char *zRe;
  const char *zGlob;
  char *zMergeOrigin = 0;
  ReCompiled *pRe = 0;
  DiffConfig DCfg, *pCfg = 0;
  int graphFlags = 0;
  Blob qp;
  int bInvert = PB("inv");

  login_check_credentials();
  if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
  login_anonymous_available();
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
      blob_appendf(&qp, "&glob=%T", zGlob);
    }
  }
  if( PB("nc") ){
    graphFlags |= TIMELINE_NOCOLOR;
    blob_appendf(&qp, "&nc");
  }
  diffFlags = construct_diff_flags(diffType);
  if( diffFlags & DIFF_IGNORE_ALLWS ){
    blob_appendf(&qp, "&w");
  }
  style_set_current_feature("vdiff");
  if( zBranch==0 ){
    style_submenu_element("Path", "%R/timeline?me=%T&you=%T", zFrom, zTo);
  }
  if( diffType!=0 ){







|
|







1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
      blob_appendf(&qp, "&glob=%T", zGlob);
    }
  }
  if( PB("nc") ){
    graphFlags |= TIMELINE_NOCOLOR;
    blob_appendf(&qp, "&nc");
  }
  pCfg = construct_diff_flags(diffType, &DCfg);
  if( DCfg.diffFlags & DIFF_IGNORE_ALLWS ){
    blob_appendf(&qp, "&w");
  }
  style_set_current_feature("vdiff");
  if( zBranch==0 ){
    style_submenu_element("Path", "%R/timeline?me=%T&you=%T", zFrom, zTo);
  }
  if( diffType!=0 ){
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
  if( zBranch==0 ){
    style_submenu_element("Invert","%R/vdiff?diff=%d&inv&%b", diffType, &qp);
  }
  if( zGlob ){
    style_submenu_element("Clear glob", "%R/vdiff?diff=%d&%b", diffType, &qp);
  }else{
    style_submenu_element("Patch", "%R/vpatch?from=%T&to=%T%s", zFrom, zTo,
           (diffFlags & DIFF_IGNORE_ALLWS)?"&w":"");
  }
  if( diffType!=0 ){
    style_submenu_checkbox("w", "Ignore Whitespace", 0, 0);
  }
  if( zBranch ){
    style_header("Changes On Branch %h", zBranch);
  }else{







|







1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
  if( zBranch==0 ){
    style_submenu_element("Invert","%R/vdiff?diff=%d&inv&%b", diffType, &qp);
  }
  if( zGlob ){
    style_submenu_element("Clear glob", "%R/vdiff?diff=%d&%b", diffType, &qp);
  }else{
    style_submenu_element("Patch", "%R/vpatch?from=%T&to=%T%s", zFrom, zTo,
           (DCfg.diffFlags & DIFF_IGNORE_ALLWS)?"&w":"");
  }
  if( diffType!=0 ){
    style_submenu_checkbox("w", "Ignore Whitespace", 0, 0);
  }
  if( zBranch ){
    style_header("Changes On Branch %h", zBranch);
  }else{
1305
1306
1307
1308
1309
1310
1311

1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
  }
  blob_reset(&qp);

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

  while( pFileFrom || pFileTo ){
    int cmp;
    if( pFileFrom==0 ){
      cmp = +1;
    }else if( pFileTo==0 ){
      cmp = -1;
    }else{
      cmp = fossil_strcmp(pFileFrom->zName, pFileTo->zName);
    }
    if( cmp<0 ){
      if( !zGlob || sqlite3_strglob(zGlob, pFileFrom->zName)==0 ){
        append_file_change_line(zFrom, pFileFrom->zName,
                                pFileFrom->zUuid, 0, 0, diffFlags, pRe, 0);
      }
      pFileFrom = manifest_file_next(pFrom, 0);
    }else if( cmp>0 ){
      if( !zGlob || sqlite3_strglob(zGlob, pFileTo->zName)==0 ){
        append_file_change_line(zTo, pFileTo->zName,
                                0, pFileTo->zUuid, 0, diffFlags, pRe,
                                manifest_file_mperm(pFileTo));
      }
      pFileTo = manifest_file_next(pTo, 0);
    }else if( fossil_strcmp(pFileFrom->zUuid, pFileTo->zUuid)==0 ){
      pFileFrom = manifest_file_next(pFrom, 0);
      pFileTo = manifest_file_next(pTo, 0);
    }else{
      if(!zGlob || (sqlite3_strglob(zGlob, pFileFrom->zName)==0
                || sqlite3_strglob(zGlob, pFileTo->zName)==0) ){
        append_file_change_line(zFrom, pFileFrom->zName,
                                pFileFrom->zUuid,
                                pFileTo->zUuid, 0, diffFlags, pRe,
                                manifest_file_mperm(pFileTo));
      }
      pFileFrom = manifest_file_next(pFrom, 0);
      pFileTo = manifest_file_next(pTo, 0);
    }
  }
  manifest_destroy(pFrom);
  manifest_destroy(pTo);
  append_diff_javascript(diffType==2);
  builtin_fossil_js_bundle_or("info-diff",NULL);
  style_finish_page();
}

#if INTERFACE
/*
** Possible return values from object_description()
*/







>












|





|











|








|
<







1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341

1342
1343
1344
1345
1346
1347
1348
  }
  blob_reset(&qp);

  manifest_file_rewind(pFrom);
  pFileFrom = manifest_file_next(pFrom, 0);
  manifest_file_rewind(pTo);
  pFileTo = manifest_file_next(pTo, 0);
  DCfg.pRe = pRe;
  while( pFileFrom || pFileTo ){
    int cmp;
    if( pFileFrom==0 ){
      cmp = +1;
    }else if( pFileTo==0 ){
      cmp = -1;
    }else{
      cmp = fossil_strcmp(pFileFrom->zName, pFileTo->zName);
    }
    if( cmp<0 ){
      if( !zGlob || sqlite3_strglob(zGlob, pFileFrom->zName)==0 ){
        append_file_change_line(zFrom, pFileFrom->zName,
                                pFileFrom->zUuid, 0, 0, pCfg, 0);
      }
      pFileFrom = manifest_file_next(pFrom, 0);
    }else if( cmp>0 ){
      if( !zGlob || sqlite3_strglob(zGlob, pFileTo->zName)==0 ){
        append_file_change_line(zTo, pFileTo->zName,
                                0, pFileTo->zUuid, 0, pCfg,
                                manifest_file_mperm(pFileTo));
      }
      pFileTo = manifest_file_next(pTo, 0);
    }else if( fossil_strcmp(pFileFrom->zUuid, pFileTo->zUuid)==0 ){
      pFileFrom = manifest_file_next(pFrom, 0);
      pFileTo = manifest_file_next(pTo, 0);
    }else{
      if(!zGlob || (sqlite3_strglob(zGlob, pFileFrom->zName)==0
                || sqlite3_strglob(zGlob, pFileTo->zName)==0) ){
        append_file_change_line(zFrom, pFileFrom->zName,
                                pFileFrom->zUuid,
                                pFileTo->zUuid, 0, pCfg,
                                manifest_file_mperm(pFileTo));
      }
      pFileFrom = manifest_file_next(pFrom, 0);
      pFileTo = manifest_file_next(pTo, 0);
    }
  }
  manifest_destroy(pFrom);
  manifest_destroy(pTo);
  append_diff_javascript(diffType);

  style_finish_page();
}

#if INTERFACE
/*
** Possible return values from object_description()
*/
1726
1727
1728
1729
1730
1731
1732

1733
1734
1735
1736
1737
1738
1739
  char *zV1;
  char *zV2;
  const char *zRe;
  ReCompiled *pRe = 0;
  u64 diffFlags;
  u32 objdescFlags = 0;
  int verbose = PB("verbose");


  login_check_credentials();
  if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
  diffType = preferred_diff_type();
  if( P("from") && P("to") ){
    v1 = artifact_from_ci_and_filename("from");
    v2 = artifact_from_ci_and_filename("to");







>







1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
  char *zV1;
  char *zV2;
  const char *zRe;
  ReCompiled *pRe = 0;
  u64 diffFlags;
  u32 objdescFlags = 0;
  int verbose = PB("verbose");
  DiffConfig DCfg;

  login_check_credentials();
  if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
  diffType = preferred_diff_type();
  if( P("from") && P("to") ){
    v1 = artifact_from_ci_and_filename("from");
    v2 = artifact_from_ci_and_filename("to");
1772
1773
1774
1775
1776
1777
1778

1779
1780
1781
1782
1783


1784
1785
1786
1787
1788
1789
1790
1791
1792

1793
1794
1795
1796
1797
1798
1799
  }
  if( v1==0 || v2==0 ) fossil_redirect_home();
  zRe = P("regex");
  if( zRe ) re_compile(&pRe, zRe, 0);
  if( verbose ) objdescFlags |= OBJDESC_DETAIL;
  if( isPatch ){
    Blob c1, c2, *pOut;

    pOut = cgi_output_blob();
    cgi_set_content_type("text/plain");
    diffFlags = 4;
    content_get(v1, &c1);
    content_get(v2, &c2);


    text_diff(&c1, &c2, pOut, pRe, diffFlags);
    blob_reset(&c1);
    blob_reset(&c2);
    return;
  }

  zV1 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v1);
  zV2 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v2);
  diffFlags = construct_diff_flags(diffType) | DIFF_HTML;


  style_set_current_feature("fdiff");
  style_header("Diff");
  style_submenu_checkbox("w", "Ignore Whitespace", 0, 0);
  if( diffType==2 ){
    style_submenu_element("Unified Diff", "%R/fdiff?v1=%T&v2=%T&diff=1",
                           P("v1"), P("v2"));







>





>
>
|







|
>







1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
  }
  if( v1==0 || v2==0 ) fossil_redirect_home();
  zRe = P("regex");
  if( zRe ) re_compile(&pRe, zRe, 0);
  if( verbose ) objdescFlags |= OBJDESC_DETAIL;
  if( isPatch ){
    Blob c1, c2, *pOut;
    DiffConfig DCfg;
    pOut = cgi_output_blob();
    cgi_set_content_type("text/plain");
    diffFlags = 4;
    content_get(v1, &c1);
    content_get(v2, &c2);
    diff_config_init(&DCfg, diffFlags);
    DCfg.pRe = pRe;
    text_diff(&c1, &c2, pOut, &DCfg);
    blob_reset(&c1);
    blob_reset(&c2);
    return;
  }

  zV1 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v1);
  zV2 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v2);
  construct_diff_flags(diffType, &DCfg);
  DCfg.diffFlags |= DIFF_HTML;

  style_set_current_feature("fdiff");
  style_header("Diff");
  style_submenu_checkbox("w", "Ignore Whitespace", 0, 0);
  if( diffType==2 ){
    style_submenu_element("Unified Diff", "%R/fdiff?v1=%T&v2=%T&diff=1",
                           P("v1"), P("v2"));
1815
1816
1817
1818
1819
1820
1821

1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
    object_description(v1, objdescFlags,0, 0);
    @ <h2>To Artifact %z(href("%R/artifact/%!S",zV2))[%S(zV2)]</a>:</h2>
    object_description(v2, objdescFlags,0, 0);
  }
  if( pRe ){
    @ <b>Only differences that match regular expression "%h(zRe)"
    @ are shown.</b>

  }
  @ <hr />
  append_diff(zV1, zV2, diffFlags, pRe);
  append_diff_javascript(diffType);
  style_finish_page();
}

/*
** WEBPAGE: raw
** URL: /raw/ARTIFACTID







>


|







1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
    object_description(v1, objdescFlags,0, 0);
    @ <h2>To Artifact %z(href("%R/artifact/%!S",zV2))[%S(zV2)]</a>:</h2>
    object_description(v2, objdescFlags,0, 0);
  }
  if( pRe ){
    @ <b>Only differences that match regular expression "%h(zRe)"
    @ are shown.</b>
    DCfg.pRe = pRe;
  }
  @ <hr />
  append_diff(zV1, zV2, &DCfg);
  append_diff_javascript(diffType);
  style_finish_page();
}

/*
** WEBPAGE: raw
** URL: /raw/ARTIFACTID
1883
1884
1885
1886
1887
1888
1889
























































































1890
1891
1892
1893
1894
1895
1896
    @ Unknown artifact: "%h(zName)"
    return;
  }
  g.isConst = 1;
  deliver_artifact(rid, P("m"));
}


























































































/*
** Generate a verbatim artifact as the result of an HTTP request.
** If zMime is not NULL, use it as the mimetype.  If zMime is
** NULL, guess at the mimetype based on the filename
** associated with the artifact.
*/







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







1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
    @ Unknown artifact: "%h(zName)"
    return;
  }
  g.isConst = 1;
  deliver_artifact(rid, P("m"));
}


/*
** WEBPAGE: jchunk hidden
** URL: /jchunk/HASH?from=N&to=M
**
** Return lines of text from a file as a JSON array - one entry in the
** array for each line of text.
**
** **Warning:**  This is an internal-use-only interface that is subject to
** change at any moment.  External application should not use this interface
** since the application will break when this interface changes, and this
** interface will undoubtedly change.
**
** This page is intended to be used in an XHR from javascript on a
** diff page, to return unseen context to fill in additional context
** when the user clicks on the appropriate button. The response is
** always in JSON form and errors are reported as documented for
** ajax_route_error().
*/
void jchunk_page(void){
  int rid = 0;
  const char *zName = PD("name", "");
  int iFrom = atoi(PD("from","0"));
  int iTo = atoi(PD("to","0"));
  int ln;
  int go = 1;
  const char *zSep;
  Blob content;
  Blob line;
  Blob *pOut;

  if(0){
    ajax_route_error(400, "Just testing client-side error handling.");
    return;
  }

  login_check_credentials();
  if( !g.perm.Read ){
    ajax_route_error(403, "Access requires Read permissions.");
    return;
  }
#if 1
  /* Re-enable this block once this code is integrated somewhere into
     the UI. */
  rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%Q", zName);
  if( rid==0 ){
    ajax_route_error(404, "Unknown artifact: %h", zName);
    return;
  }
#else
  /* This impl is only to simplify "manual" testing via the JS
     console. */
  rid = symbolic_name_to_rid(zName, "*");
  if( rid==0 ){
    ajax_route_error(404, "Unknown artifact: %h", zName);
    return;
  }else if( rid<0 ){
    ajax_route_error(418, "Ambiguous artifact name: %h", zName);
    return;
  }
#endif
  if( iFrom<1 || iTo<iFrom ){
    ajax_route_error(500, "Invalid line range from=%d, to=%d.",
                     iFrom, iTo);
    return;
  }
  content_get(rid, &content);
  g.isConst = 1;
  cgi_set_content_type("application/json");
  ln = 0;
  while( go && ln<iFrom ){
    go = blob_line(&content, &line);
    ln++;
  }
  pOut = cgi_output_blob();
  blob_append(pOut, "[\n", 2);
  zSep = 0;
  while( go && ln<=iTo ){
    if( zSep ) blob_append(pOut, zSep, 2);
    blob_trim(&line);
    blob_append_json_literal(pOut, blob_buffer(&line), blob_size(&line));
    zSep = ",\n";
    go = blob_line(&content, &line);
    ln++;
  }
  blob_appendf(pOut,"]\n");
  blob_reset(&content);
}

/*
** Generate a verbatim artifact as the result of an HTTP request.
** If zMime is not NULL, use it as the mimetype.  If zMime is
** NULL, guess at the mimetype based on the filename
** associated with the artifact.
*/
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
      );
      ++nSpans;
      iStart = iEnd = atoi(&zLn[i++]);
    }while( zLn[i] && iStart && iEnd );
  }
  /*cgi_printf("<!-- ln span count=%d -->", nSpans);*/
  cgi_append_content("<table class='numbered-lines'><tbody>"
                     "<tr><td class='line-numbers'>", -1);
  iStart = iEnd = 0;
  count_lines(z, nZ, &nLine);
  for( n=1 ; n<=nLine; ++n ){
    const char * zAttr = "";
    const char * zId = "";
    if(nSpans>0 && iEnd==0){/*Grab the next range of zLn marking*/
      db_prepare(&q, "SELECT iStart, iEnd FROM lnos "







|







2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
      );
      ++nSpans;
      iStart = iEnd = atoi(&zLn[i++]);
    }while( zLn[i] && iStart && iEnd );
  }
  /*cgi_printf("<!-- ln span count=%d -->", nSpans);*/
  cgi_append_content("<table class='numbered-lines'><tbody>"
                     "<tr><td class='line-numbers'><pre>", -1);
  iStart = iEnd = 0;
  count_lines(z, nZ, &nLine);
  for( n=1 ; n<=nLine; ++n ){
    const char * zAttr = "";
    const char * zId = "";
    if(nSpans>0 && iEnd==0){/*Grab the next range of zLn marking*/
      db_prepare(&q, "SELECT iStart, iEnd FROM lnos "
2205
2206
2207
2208
2209
2210
2211
2212

2213
2214
2215
2216
2217
2218
2219
2220
2221
      iStart = 0;
    }else if(n==iEnd){
      zAttr = " class='selected-line end'";
      iEnd = 0;
    }else if( n>iStart && n<iEnd ){
      zAttr = " class='selected-line'";
    }
    cgi_printf("<span%s%s>%6d</span>", zId, zAttr, n);

  }
  cgi_append_content("</td><td class='file-content'><pre>",-1);
  if(zExt && *zExt){
    cgi_printf("<code class='language-%h'>",zExt);
  }else{
    cgi_append_content("<code>", -1);
  }
  cgi_printf("%z", htmlize(z, nZ));
  CX("</code></pre></td></tr></tbody></table>\n");







|
>

|







2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
      iStart = 0;
    }else if(n==iEnd){
      zAttr = " class='selected-line end'";
      iEnd = 0;
    }else if( n>iStart && n<iEnd ){
      zAttr = " class='selected-line'";
    }
    cgi_printf("<span%s%s>%6d</span>\n", zId, zAttr, n)
      /* ^^^ explicit \n is necessary for text-mode browsers. */;
  }
  cgi_append_content("</pre></td><td class='file-content'><pre>",-1);
  if(zExt && *zExt){
    cgi_printf("<code class='language-%h'>",zExt);
  }else{
    cgi_append_content("<code>", -1);
  }
  cgi_printf("%z", htmlize(z, nZ));
  CX("</code></pre></td></tr></tbody></table>\n");
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
  url_initialize(&url, g.zPath);
  url_add_parameter(&url, "name", zName);
  url_add_parameter(&url, "ci", zCI);     /* no-op if zCI is NULL */

  if( zCI==0 && !isFile ){
    /* If there is no ci= query parameter, then prefer to interpret
    ** name= as a hash for /artifact and /whatis.  But for not for /file.
    ** For /file, a name= without a ci= while prefer to use the default
    ** "tip" value for ci=. */
    rid = name_to_rid(zName);
  }
  if( rid==0 ){
    rid = artifact_from_ci_and_filename(0);
  }








|







2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
  url_initialize(&url, g.zPath);
  url_add_parameter(&url, "name", zName);
  url_add_parameter(&url, "ci", zCI);     /* no-op if zCI is NULL */

  if( zCI==0 && !isFile ){
    /* If there is no ci= query parameter, then prefer to interpret
    ** name= as a hash for /artifact and /whatis.  But for not for /file.
    ** For /file, a name= without a ci= will prefer to use the default
    ** "tip" value for ci=. */
    rid = name_to_rid(zName);
  }
  if( rid==0 ){
    rid = artifact_from_ci_and_filename(0);
  }

3219
3220
3221
3222
3223
3224
3225





3226
3227
3228
3229
3230
3231
3232
  @ <div><label>
  if( fNewPropagateColor ){
    @ <input type="checkbox" name="pclr" checked="checked" />
  }else{
    @ <input type="checkbox" name="pclr" />
  }
  @ Propagate color to descendants</label></div>





  @ </td></tr>

  @ <tr><th align="right" valign="top">Tags:</th>
  @ <td valign="top">
  @ <label><input type="checkbox" id="newtag" name="newtag"%s(zNewTagFlag) />
  @ Add the following new tag name to this check-in:</label>
  @ <input type="text" size='15' name="tagname" value="%h(zNewTag)" \







>
>
>
>
>







3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
  @ <div><label>
  if( fNewPropagateColor ){
    @ <input type="checkbox" name="pclr" checked="checked" />
  }else{
    @ <input type="checkbox" name="pclr" />
  }
  @ Propagate color to descendants</label></div>
  @ <div class='font-size-80'>Be aware that fixed background
  @ colors will not interact well with all available skins.
  @ It is recommended that fossil be allowed to select these
  @ colors automatically so that it can take the skin's
  @ preferences into account.</div>
  @ </td></tr>

  @ <tr><th align="right" valign="top">Tags:</th>
  @ <td valign="top">
  @ <label><input type="checkbox" id="newtag" name="newtag"%s(zNewTagFlag) />
  @ Add the following new tag name to this check-in:</label>
  @ <input type="text" size='15' name="tagname" value="%h(zNewTag)" \
Changes to src/json_diff.c.
36
37
38
39
40
41
42

43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

63
64
65
66
67
68
69
70
*/
cson_value * json_generate_diff(const char *zFrom, const char *zTo,
                                int nContext, char fSbs,
                                char fHtml){
  int fromid;
  int toid;
  int outLen;

  Blob from = empty_blob, to = empty_blob, out = empty_blob;
  cson_value * rc = NULL;
  int flags = (DIFF_CONTEXT_MASK & nContext)
    | (fSbs ? DIFF_SIDEBYSIDE : 0)
    | (fHtml ? DIFF_HTML : 0);
  fromid = name_to_typed_rid(zFrom, "*");
  if(fromid<=0){
      json_set_err(FSL_JSON_E_UNRESOLVED_UUID,
                   "Could not resolve 'from' ID.");
      return NULL;
  }
  toid = name_to_typed_rid(zTo, "*");
  if(toid<=0){
      json_set_err(FSL_JSON_E_UNRESOLVED_UUID,
                   "Could not resolve 'to' ID.");
      return NULL;
  }
  content_get(fromid, &from);
  content_get(toid, &to);
  blob_zero(&out);

  text_diff(&from, &to, &out, 0, flags);
  blob_reset(&from);
  blob_reset(&to);
  outLen = blob_size(&out);
  if(outLen>=0){
    rc = cson_value_new_string(blob_buffer(&out),
                               (unsigned int)blob_size(&out));
  }







>


<
|
















>
|







36
37
38
39
40
41
42
43
44
45

46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
*/
cson_value * json_generate_diff(const char *zFrom, const char *zTo,
                                int nContext, char fSbs,
                                char fHtml){
  int fromid;
  int toid;
  int outLen;
  DiffConfig DCfg;
  Blob from = empty_blob, to = empty_blob, out = empty_blob;
  cson_value * rc = NULL;

  int flags = (fSbs ? DIFF_SIDEBYSIDE : 0)
    | (fHtml ? DIFF_HTML : 0);
  fromid = name_to_typed_rid(zFrom, "*");
  if(fromid<=0){
      json_set_err(FSL_JSON_E_UNRESOLVED_UUID,
                   "Could not resolve 'from' ID.");
      return NULL;
  }
  toid = name_to_typed_rid(zTo, "*");
  if(toid<=0){
      json_set_err(FSL_JSON_E_UNRESOLVED_UUID,
                   "Could not resolve 'to' ID.");
      return NULL;
  }
  content_get(fromid, &from);
  content_get(toid, &to);
  blob_zero(&out);
  diff_config_init(&DCfg, flags);
  text_diff(&from, &to, &out, &DCfg);
  blob_reset(&from);
  blob_reset(&to);
  outLen = blob_size(&out);
  if(outLen>=0){
    rc = cson_value_new_string(blob_buffer(&out),
                               (unsigned int)blob_size(&out));
  }
Changes to src/json_wiki.c.
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
  char const * zV2 = NULL;
  cson_object * pay = NULL;
  int argPos = g.json.dispatchDepth;
  int r1 = 0, r2 = 0;
  Manifest * pW1 = NULL, *pW2 = NULL;
  Blob w1 = empty_blob, w2 = empty_blob, d = empty_blob;
  char const * zErrTag = NULL;
  u64 diffFlags;
  char * zUuid = NULL;
  if( !g.perm.Hyperlink ){
    json_set_err(FSL_JSON_E_DENIED,
                 "Requires 'h' permissions.");
    return NULL;
  }








|







517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
  char const * zV2 = NULL;
  cson_object * pay = NULL;
  int argPos = g.json.dispatchDepth;
  int r1 = 0, r2 = 0;
  Manifest * pW1 = NULL, *pW2 = NULL;
  Blob w1 = empty_blob, w2 = empty_blob, d = empty_blob;
  char const * zErrTag = NULL;
  DiffConfig DCfg;
  char * zUuid = NULL;
  if( !g.perm.Hyperlink ){
    json_set_err(FSL_JSON_E_DENIED,
                 "Requires 'h' permissions.");
    return NULL;
  }

565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
    goto manifest;
  }

  blob_init(&w1, pW1->zWiki, -1);
  blob_zero(&w2);
  blob_init(&w2, pW2->zWiki, -1);
  blob_zero(&d);
  diffFlags = DIFF_IGNORE_EOLWS | DIFF_STRIP_EOLCR;
  text_diff(&w1, &w2, &d, 0, diffFlags);
  blob_reset(&w1);
  blob_reset(&w2);

  pay = cson_new_object();

  zUuid = json_wiki_get_uuid_for_rid( pW1->rid );
  cson_object_set(pay, "v1", json_new_string(zUuid) );







|
|







565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
    goto manifest;
  }

  blob_init(&w1, pW1->zWiki, -1);
  blob_zero(&w2);
  blob_init(&w2, pW2->zWiki, -1);
  blob_zero(&d);
  diff_config_init(&DCfg, DIFF_IGNORE_EOLWS | DIFF_STRIP_EOLCR);
  text_diff(&w1, &w2, &d, &DCfg);
  blob_reset(&w1);
  blob_reset(&w2);

  pay = cson_new_object();

  zUuid = json_wiki_get_uuid_for_rid( pW1->rid );
  cson_object_set(pay, "v1", json_new_string(zUuid) );
Changes to src/login.c.
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/*
** Redirect to the page specified by the "g" query parameter.
** Or if there is no "g" query parameter, redirect to the homepage.
*/
static void redirect_to_g(void){
  const char *zGoto = P("g");
  if( zGoto ){
    cgi_redirect(zGoto);
  }else{
    fossil_redirect_home();
  }
}

/*
** Return an abbreviated project code.  The abbreviation is the first







|







103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/*
** Redirect to the page specified by the "g" query parameter.
** Or if there is no "g" query parameter, redirect to the homepage.
*/
static void redirect_to_g(void){
  const char *zGoto = P("g");
  if( zGoto ){
    cgi_redirectf("%R/%s",zGoto);
  }else{
    fossil_redirect_home();
  }
}

/*
** Return an abbreviated project code.  The abbreviation is the first
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
  const char *zAnonPw = 0;
  const char *zGoto = P("g");
  int anonFlag;                /* Login as "anonymous" would be useful */
  char *zErrMsg = "";
  int uid;                     /* User id logged in user */
  char *zSha1Pw;
  const char *zIpAddr;         /* IP address of requestor */
  const char *zReferer;
  const int noAnon = P("noanon")!=0;
  int rememberMe;              /* If true, use persistent cookie, else
                                  session cookie. Toggled per
                                  checkbox. */

  login_check_credentials();
  fossil_redirect_to_https_if_needed(1);







<







547
548
549
550
551
552
553

554
555
556
557
558
559
560
  const char *zAnonPw = 0;
  const char *zGoto = P("g");
  int anonFlag;                /* Login as "anonymous" would be useful */
  char *zErrMsg = "";
  int uid;                     /* User id logged in user */
  char *zSha1Pw;
  const char *zIpAddr;         /* IP address of requestor */

  const int noAnon = P("noanon")!=0;
  int rememberMe;              /* If true, use persistent cookie, else
                                  session cookie. Toggled per
                                  checkbox. */

  login_check_credentials();
  fossil_redirect_to_https_if_needed(1);
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
         @ The password cannot be changed for this type of login.
         @ The password is unchanged.
         @ </span></p>
      ;
    }
  }
  zIpAddr = PD("REMOTE_ADDR","nil");   /* Complete IP address for logging */
  zReferer = P("HTTP_REFERER");
  uid = login_is_valid_anonymous(zUsername, zPasswd, P("cs"));
  if(zUsername==0){
    /* Initial login page hit. */
    rememberMe = 0;
  }else{
    rememberMe = P("remember")!=0;
  }







<







637
638
639
640
641
642
643

644
645
646
647
648
649
650
         @ The password cannot be changed for this type of login.
         @ The password is unchanged.
         @ </span></p>
      ;
    }
  }
  zIpAddr = PD("REMOTE_ADDR","nil");   /* Complete IP address for logging */

  uid = login_is_valid_anonymous(zUsername, zPasswd, P("cs"));
  if(zUsername==0){
    /* Initial login page hit. */
    rememberMe = 0;
  }else{
    rememberMe = P("remember")!=0;
  }
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
  ){
    form_begin(0, "https:%s/login", g.zBaseURL+5);
  }else{
    form_begin(0, "%R/login");
  }
  if( zGoto ){
    @ <input type="hidden" name="g" value="%h(zGoto)" />
  }else if( zReferer && strncmp(g.zBaseURL, zReferer, strlen(g.zBaseURL))==0 ){
    @ <input type="hidden" name="g" value="%h(zReferer)" />
  }
  if( anonFlag ){
    @ <input type="hidden" name="anon" value="1" />
  }
  if( g.zLogin ){
    @ <p>Currently logged in as <b>%h(g.zLogin)</b>.
    @ <input type="submit" name="out" value="Logout"></p>







<
<







704
705
706
707
708
709
710


711
712
713
714
715
716
717
  ){
    form_begin(0, "https:%s/login", g.zBaseURL+5);
  }else{
    form_begin(0, "%R/login");
  }
  if( zGoto ){
    @ <input type="hidden" name="g" value="%h(zGoto)" />


  }
  if( anonFlag ){
    @ <input type="hidden" name="anon" value="1" />
  }
  if( g.zLogin ){
    @ <p>Currently logged in as <b>%h(g.zLogin)</b>.
    @ <input type="submit" name="out" value="Logout"></p>
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
    if( g.localOpen ) zLogin = db_lget("default-user",0);
    if( zLogin!=0 ){
      uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", zLogin);
    }else{
      uid = db_int(0, "SELECT uid FROM user WHERE cap LIKE '%%s%%'");
    }
    g.zLogin = db_text("?", "SELECT login FROM user WHERE uid=%d", uid);
    zCap = "sx";
    g.noPswd = 1;
    g.isHuman = 1;
    sqlite3_snprintf(sizeof(g.zCsrfToken), g.zCsrfToken, "localhost");
  }

  /* Check the login cookie to see if it matches a known valid user.
  */







|







1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
    if( g.localOpen ) zLogin = db_lget("default-user",0);
    if( zLogin!=0 ){
      uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", zLogin);
    }else{
      uid = db_int(0, "SELECT uid FROM user WHERE cap LIKE '%%s%%'");
    }
    g.zLogin = db_text("?", "SELECT login FROM user WHERE uid=%d", uid);
    zCap = "sxy";
    g.noPswd = 1;
    g.isHuman = 1;
    sqlite3_snprintf(sizeof(g.zCsrfToken), g.zCsrfToken, "localhost");
  }

  /* Check the login cookie to see if it matches a known valid user.
  */
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
        }
      }
    }
    if( zUser==0 ){
      /* Invalid cookie */
    }else if( fossil_strcmp(zUser, "anonymous")==0 ){
      /* Cookies of the form "HASH/TIME/anonymous".  The TIME must not be
      ** too old and the sha1 hash of TIME/IPADDR/SECRET must match HASH.
      ** SECRET is the "captcha-secret" value in the repository.
      */
      double rTime = atof(zArg);
      Blob b;
      blob_zero(&b);
      blob_appendf(&b, "%s/%s", zArg, db_get("captcha-secret",""));
      sha1sum_blob(&b, &b);







|







1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
        }
      }
    }
    if( zUser==0 ){
      /* Invalid cookie */
    }else if( fossil_strcmp(zUser, "anonymous")==0 ){
      /* Cookies of the form "HASH/TIME/anonymous".  The TIME must not be
      ** too old and the sha1 hash of TIME/SECRET must match HASH.
      ** SECRET is the "captcha-secret" value in the repository.
      */
      double rTime = atof(zArg);
      Blob b;
      blob_zero(&b);
      blob_appendf(&b, "%s/%s", zArg, db_get("captcha-secret",""));
      sha1sum_blob(&b, &b);
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491

1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
    json_err( FSL_JSON_E_DENIED, NULL, 1 );
    fossil_exit(0);
    /* NOTREACHED */
    assert(0);
  }else
#endif /* FOSSIL_ENABLE_JSON */
  {
    const char *zUrl = PD("REQUEST_URI", "index");
    const char *zQS = P("QUERY_STRING");
    char *zUrlNoQS;
    int i;
    Blob redir;
    blob_init(&redir, 0, 0);
    for(i=0; zUrl[i] && zUrl[i]!='?'; i++){}
    zUrlNoQS = fossil_strndup(zUrl, i);

    if( fossil_wants_https(1) ){
      blob_appendf(&redir, "%s/login?g=%T", g.zHttpsURL, zUrlNoQS);
    }else{
      blob_appendf(&redir, "%R/login?g=%T", zUrlNoQS);
    }
    if( zQS && zQS[0] ){
      blob_appendf(&redir, "%%3f%T", zQS);
    }
    if( anonOk ) blob_append(&redir, "&anon", 5);
    cgi_redirect(blob_str(&redir));
    /* NOTREACHED */
    assert(0);
  }
}

/*
** Call this routine if the user lacks g.perm.Hyperlink permission.  If
** the anonymous user has Hyperlink permission, then paint a mesage
** to inform the user that much more information is available by
** logging in as anonymous.
*/
void login_anonymous_available(void){
  if( !g.perm.Hyperlink && g.anon.Hyperlink ){
    const char *zUrl = PD("REQUEST_URI", "index");
    @ <p>Many <span class="disabled">hyperlinks are disabled.</span><br />
    @ Use <a href="%R/login?anon=1&amp;g=%T(zUrl)">anonymous login</a>
    @ to enable hyperlinks.</p>
  }
}

/*







<

|
<


<
<
>

|

|



















|







1473
1474
1475
1476
1477
1478
1479

1480
1481

1482
1483


1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
    json_err( FSL_JSON_E_DENIED, NULL, 1 );
    fossil_exit(0);
    /* NOTREACHED */
    assert(0);
  }else
#endif /* FOSSIL_ENABLE_JSON */
  {

    const char *zQS = P("QUERY_STRING");
    const char *zPathInfo = PD("PATH_INFO","");

    Blob redir;
    blob_init(&redir, 0, 0);


    if( zPathInfo[0]=='/' ) zPathInfo++; /* skip leading slash */
    if( fossil_wants_https(1) ){
      blob_appendf(&redir, "%s/login?g=%T", g.zHttpsURL, zPathInfo);
    }else{
      blob_appendf(&redir, "%R/login?g=%T", zPathInfo);
    }
    if( zQS && zQS[0] ){
      blob_appendf(&redir, "%%3f%T", zQS);
    }
    if( anonOk ) blob_append(&redir, "&anon", 5);
    cgi_redirect(blob_str(&redir));
    /* NOTREACHED */
    assert(0);
  }
}

/*
** Call this routine if the user lacks g.perm.Hyperlink permission.  If
** the anonymous user has Hyperlink permission, then paint a mesage
** to inform the user that much more information is available by
** logging in as anonymous.
*/
void login_anonymous_available(void){
  if( !g.perm.Hyperlink && g.anon.Hyperlink ){
    const char *zUrl = PD("PATH_INFO", "");
    @ <p>Many <span class="disabled">hyperlinks are disabled.</span><br />
    @ Use <a href="%R/login?anon=1&amp;g=%T(zUrl)">anonymous login</a>
    @ to enable hyperlinks.</p>
  }
}

/*
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
    style_finish_page();
    return;
  }
  zPerms = db_get("default-perms", "u");

  /* Prompt the user for email alerts if this repository is configured for
  ** email alerts and if the default permissions include "7" */
  canDoAlerts = alert_tables_exist() && db_int(0,
    "SELECT fullcap(%Q) GLOB '*7*'", zPerms
  );
  doAlerts = canDoAlerts && atoi(PD("alerts","1"))!=0;

  zUserID = PDT("u","");
  zPasswd = PDT("p","");
  zConfirm = PDT("cp","");
  zEAddr = PDT("ea","");
  zDName = PDT("dn","");







|

|







1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
    style_finish_page();
    return;
  }
  zPerms = db_get("default-perms", "u");

  /* Prompt the user for email alerts if this repository is configured for
  ** email alerts and if the default permissions include "7" */
  canDoAlerts = alert_tables_exist() && (db_int(0,
    "SELECT fullcap(%Q) GLOB '*7*'", zPerms
  ) || db_get_boolean("selfreg-verify",0));
  doAlerts = canDoAlerts && atoi(PD("alerts","1"))!=0;

  zUserID = PDT("u","");
  zPasswd = PDT("p","");
  zConfirm = PDT("cp","");
  zEAddr = PDT("ea","");
  zDName = PDT("dn","");
Changes to src/main.c.
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750

2751

















2752


2753
2754
2755
2756
2757
2758
2759

2760
2761
2762
2763
2764
2765
2766

2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
    process_one_web_page(0, FileGlob, 0);
    blob_reset(&g.cgiIn);
  } while ( g.fSshClient & CGI_SSH_FOSSIL ||
          g.fSshClient & CGI_SSH_COMPAT );
}

/*
** Note that the following command is used by ssh:// processing.
**
** COMMAND: test-http
**
** Works like the [[http]] command but gives setup permission to all users.

**

















** Options:


**   --th-trace          Trace TH1 execution (for debugging purposes)
**   --usercap   CAP     User capability string (Default: "sxy")
**
*/
void cmd_test_http(void){
  const char *zIpAddr;    /* IP address of remote client */
  const char *zUserCap;


  Th_InitTraceLog();
  zUserCap = find_option("usercap",0,1);
  if( zUserCap==0 ){
    g.useLocalauth = 1;
    zUserCap = "sxy";
  }

  login_set_capabilities(zUserCap, 0);
  g.httpIn = stdin;
  g.httpOut = stdout;
  fossil_binary_mode(g.httpOut);
  fossil_binary_mode(g.httpIn);
  g.zExtRoot = find_option("extroot",0,1);
  find_server_repository(2, 0);
  g.cgiOutput = 1;
  g.fNoHttpCompress = 1;
  g.fullHttpReply = 1;
  g.sslNotAvailable = 1;  /* Avoid attempts to redirect */
  zIpAddr = cgi_ssh_remote_addr(0);
  if( zIpAddr && zIpAddr[0] ){
    g.fSshClient |= CGI_SSH_CLIENT;
    ssh_request_loop(zIpAddr, 0);
  }else{
    cgi_set_parameter("REMOTE_ADDR", "127.0.0.1");
    cgi_handle_http_request(0);
    process_one_web_page(0, 0, 1);







<
<


|
>

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

>
>







>







>











|







2739
2740
2741
2742
2743
2744
2745


2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
    process_one_web_page(0, FileGlob, 0);
    blob_reset(&g.cgiIn);
  } while ( g.fSshClient & CGI_SSH_FOSSIL ||
          g.fSshClient & CGI_SSH_COMPAT );
}

/*


** COMMAND: test-http
**
** Works like the [[http]] command but gives setup permission to all users,
** or whatever permission is described by "--usercap CAP".
**
** This command can used for interactive debugging of web pages.  For
** example, one can put a simple HTTP request in a file like this:
**
**     echo 'GET /timeline' >request.txt
**
** Then run (in a debugger) a command like this:
**
**     fossil test-http --debug <request.txt
**
** This command is also used internally by the "ssh" sync protocol.  Some
** special processing to support sync happens when this command is run
** and the SSH_CONNECTION environment variable is set.  Use the --test
** option on interactive sessions to avoid that special processing when
** using this command interactively over SSH.  A better solution would be
** to use a different command for "ssh" sync, but we cannot do that without
** breaking legacy.
**
** Options:
**   --test              Do not do special "sync" processing when operating
**                       over an SSH link.
**   --th-trace          Trace TH1 execution (for debugging purposes)
**   --usercap   CAP     User capability string (Default: "sxy")
**
*/
void cmd_test_http(void){
  const char *zIpAddr;    /* IP address of remote client */
  const char *zUserCap;
  int bTest = 0;

  Th_InitTraceLog();
  zUserCap = find_option("usercap",0,1);
  if( zUserCap==0 ){
    g.useLocalauth = 1;
    zUserCap = "sxy";
  }
  bTest = find_option("test",0,0)!=0;
  login_set_capabilities(zUserCap, 0);
  g.httpIn = stdin;
  g.httpOut = stdout;
  fossil_binary_mode(g.httpOut);
  fossil_binary_mode(g.httpIn);
  g.zExtRoot = find_option("extroot",0,1);
  find_server_repository(2, 0);
  g.cgiOutput = 1;
  g.fNoHttpCompress = 1;
  g.fullHttpReply = 1;
  g.sslNotAvailable = 1;  /* Avoid attempts to redirect */
  zIpAddr = bTest ? 0 : cgi_ssh_remote_addr(0);
  if( zIpAddr && zIpAddr[0] ){
    g.fSshClient |= CGI_SSH_CLIENT;
    ssh_request_loop(zIpAddr, 0);
  }else{
    cgi_set_parameter("REMOTE_ADDR", "127.0.0.1");
    cgi_handle_http_request(0);
    process_one_web_page(0, 0, 1);
2857
2858
2859
2860
2861
2862
2863
2864
2865

2866
2867
2868
2869
2870
2871
2872
** such as ".txt" or ".html" or ".jpeg" and do not match the pattern
** "*.fossil*" will be served as static content.  With the "ui" command,
** the REPOSITORY can only be a directory if the --notfound option is
** also present.
**
** For the special case REPOSITORY name of "/", the global configuration
** database is consulted for a list of all known repositories.  The --repolist
** option is implied by this special case.  See also the "fossil all ui"
** command.

**
** By default, the "ui" command provides full administrative access without
** having to log in.  This can be disabled by turning off the "localauth"
** setting.  Automatic login for the "server" command is available if the
** --localauth option is present and the "localauth" setting is off and the
** connection is from localhost.  The "ui" command also enables --repolist
** by default.







|
|
>







2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
** such as ".txt" or ".html" or ".jpeg" and do not match the pattern
** "*.fossil*" will be served as static content.  With the "ui" command,
** the REPOSITORY can only be a directory if the --notfound option is
** also present.
**
** For the special case REPOSITORY name of "/", the global configuration
** database is consulted for a list of all known repositories.  The --repolist
** option is implied by this special case.  The "fossil ui /" command is
** equivalent to "fossil all ui".  To see all repositories owned by "user"
** on machine "remote" via ssh, run "fossil ui user@remote:/".
**
** By default, the "ui" command provides full administrative access without
** having to log in.  This can be disabled by turning off the "localauth"
** setting.  Automatic login for the "server" command is available if the
** --localauth option is present and the "localauth" setting is off and the
** connection is from localhost.  The "ui" command also enables --repolist
** by default.
2892
2893
2894
2895
2896
2897
2898


2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
**                                       each JavaScript file.
**                          bundled      One single separate HTTP fetches all
**                                       JavaScript concatenated together.
**                       Depending on the needs of any given page, inline
**                       and bundled modes might result in a single
**                       amalgamated script or several, but both approaches
**                       result in fewer HTTP requests than the separate mode.


**   --max-latency N     Do not let any single HTTP request run for more than N
**                       seconds (only works on unix)
**   --nobrowser         Do not automatically launch a web-browser for the
**                       "fossil ui" command.
**   --nocompress        Do not compress HTTP replies
**   --nojail            Drop root privileges but do not enter the chroot jail
**   --nossl             signal that no SSL connections are available (Always
**                       set by default for the "ui" command)
**   --notfound URL      Redirect
**   --page PAGE         Start "ui" on PAGE.  ex: --page "timeline?y=ci"
**   -P|--port TCPPORT   listen to request on port TCPPORT
**   --th-trace          trace TH1 execution (for debugging purposes)
**   --repolist          If REPOSITORY is dir, URL "/" lists repos.
**   --scgi              Accept SCGI rather than HTTP
**   --skin LABEL        Use override skin LABEL
**   --mainmenu FILE     Override the mainmenu config setting with the contents
**                       of the given file.
**   --usepidkey         Use saved encryption key from parent process.  This is
**                       only necessary when using SEE on Windows.
**
** See also: [[cgi]], [[http]], [[winsrv]]
*/
void cmd_webserver(void){
  int iPort, mxPort;        /* Range of TCP ports allowed */







>
>











<



|
<







2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932

2933
2934
2935
2936

2937
2938
2939
2940
2941
2942
2943
**                                       each JavaScript file.
**                          bundled      One single separate HTTP fetches all
**                                       JavaScript concatenated together.
**                       Depending on the needs of any given page, inline
**                       and bundled modes might result in a single
**                       amalgamated script or several, but both approaches
**                       result in fewer HTTP requests than the separate mode.
**   --mainmenu FILE     Override the mainmenu config setting with the contents
**                       of the given file.
**   --max-latency N     Do not let any single HTTP request run for more than N
**                       seconds (only works on unix)
**   --nobrowser         Do not automatically launch a web-browser for the
**                       "fossil ui" command.
**   --nocompress        Do not compress HTTP replies
**   --nojail            Drop root privileges but do not enter the chroot jail
**   --nossl             signal that no SSL connections are available (Always
**                       set by default for the "ui" command)
**   --notfound URL      Redirect
**   --page PAGE         Start "ui" on PAGE.  ex: --page "timeline?y=ci"
**   -P|--port TCPPORT   listen to request on port TCPPORT

**   --repolist          If REPOSITORY is dir, URL "/" lists repos.
**   --scgi              Accept SCGI rather than HTTP
**   --skin LABEL        Use override skin LABEL
**   --th-trace          trace TH1 execution (for debugging purposes)

**   --usepidkey         Use saved encryption key from parent process.  This is
**                       only necessary when using SEE on Windows.
**
** See also: [[cgi]], [[http]], [[winsrv]]
*/
void cmd_webserver(void){
  int iPort, mxPort;        /* Range of TCP ports allowed */
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
    if( zIpAddr==0 ){
      zBrowserArg = mprintf("http://localhost:%%d/%s", zInitPage);
    }else if( strchr(zIpAddr,':') ){
      zBrowserArg = mprintf("http://[%s]:%%d/%s", zIpAddr, zInitPage);
    }else{
      zBrowserArg = mprintf("http://%s:%%d/%s", zIpAddr, zInitPage);
    }
#ifdef _WIN32
    zBrowserCmd = mprintf("%s %s &", zBrowser, zBrowserArg);
#else
    zBrowserCmd = mprintf("%s %!$ &", zBrowser, zBrowserArg);
#endif
    fossil_free(zBrowserArg);
  }
  if( zRemote ){
    /* If a USER@HOST:REPO argument is supplied, then use SSH to run
    ** "fossil ui --nobrowser" on the remote system and to set up a
    ** tunnel from the local machine to the remote. */
    FILE *sshIn;







<
<
<

<







3091
3092
3093
3094
3095
3096
3097



3098

3099
3100
3101
3102
3103
3104
3105
    if( zIpAddr==0 ){
      zBrowserArg = mprintf("http://localhost:%%d/%s", zInitPage);
    }else if( strchr(zIpAddr,':') ){
      zBrowserArg = mprintf("http://[%s]:%%d/%s", zIpAddr, zInitPage);
    }else{
      zBrowserArg = mprintf("http://%s:%%d/%s", zIpAddr, zInitPage);
    }



    zBrowserCmd = mprintf("%s %!$ &", zBrowser, zBrowserArg);

    fossil_free(zBrowserArg);
  }
  if( zRemote ){
    /* If a USER@HOST:REPO argument is supplied, then use SSH to run
    ** "fossil ui --nobrowser" on the remote system and to set up a
    ** tunnel from the local machine to the remote. */
    FILE *sshIn;
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131





3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
        zBrowserCmd = 0;
      }
    }
    pclose(sshIn);
    fossil_free(zBrowserCmd);
    return;
  }
#if !defined(_WIN32)
  /* Unix implementation */
  if( g.repositoryOpen ) flags |= HTTP_SERVER_HAD_REPOSITORY;
  if( g.localOpen ) flags |= HTTP_SERVER_HAD_CHECKOUT;
  db_close(1);





  if( cgi_http_server(iPort, mxPort, zBrowserCmd, zIpAddr, flags) ){
    fossil_fatal("unable to listen on TCP socket %d", iPort);
  }
  /* For the parent process, the cgi_http_server() command above never
  ** returns (except in the case of an error).  Instead, for each incoming
  ** client connection, a child process is created, file descriptors 0
  ** and 1 are bound to that connection, and the child returns.
  **
  ** So, when control reaches this point, we are running as a
  ** child process, the HTTP or SCGI request is pending on file
  ** descriptor 0 and the reply should be written to file descriptor 1.
  */
  if( zTimeout ){
    fossil_set_timeout(atoi(zTimeout));
  }else{
    fossil_set_timeout(FOSSIL_DEFAULT_TIMEOUT);
  }
  g.httpIn = stdin;
  g.httpOut = stdout;

#if !defined(_WIN32)
  signal(SIGSEGV, sigsegv_handler);
  signal(SIGPIPE, sigpipe_handler);
#endif

  if( g.fAnyTrace ){
    fprintf(stderr, "/***** Subprocess %d *****/\n", getpid());
  }
  g.cgiOutput = 1;
  find_server_repository(2, 0);
  if( fossil_strcmp(g.zRepositoryName,"/")==0 ){
    allowRepoList = 1;







<
<



>
>
>
>
>



















<
<


<
<







3137
3138
3139
3140
3141
3142
3143


3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170


3171
3172


3173
3174
3175
3176
3177
3178
3179
        zBrowserCmd = 0;
      }
    }
    pclose(sshIn);
    fossil_free(zBrowserCmd);
    return;
  }


  if( g.repositoryOpen ) flags |= HTTP_SERVER_HAD_REPOSITORY;
  if( g.localOpen ) flags |= HTTP_SERVER_HAD_CHECKOUT;
  db_close(1);

  /* Start up an HTTP server
  */
#if !defined(_WIN32)
  /* Unix implementation */
  if( cgi_http_server(iPort, mxPort, zBrowserCmd, zIpAddr, flags) ){
    fossil_fatal("unable to listen on TCP socket %d", iPort);
  }
  /* For the parent process, the cgi_http_server() command above never
  ** returns (except in the case of an error).  Instead, for each incoming
  ** client connection, a child process is created, file descriptors 0
  ** and 1 are bound to that connection, and the child returns.
  **
  ** So, when control reaches this point, we are running as a
  ** child process, the HTTP or SCGI request is pending on file
  ** descriptor 0 and the reply should be written to file descriptor 1.
  */
  if( zTimeout ){
    fossil_set_timeout(atoi(zTimeout));
  }else{
    fossil_set_timeout(FOSSIL_DEFAULT_TIMEOUT);
  }
  g.httpIn = stdin;
  g.httpOut = stdout;


  signal(SIGSEGV, sigsegv_handler);
  signal(SIGPIPE, sigpipe_handler);


  if( g.fAnyTrace ){
    fprintf(stderr, "/***** Subprocess %d *****/\n", getpid());
  }
  g.cgiOutput = 1;
  find_server_repository(2, 0);
  if( fossil_strcmp(g.zRepositoryName,"/")==0 ){
    allowRepoList = 1;
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
  process_one_web_page(zNotFound, glob_create(zFileGlob), allowRepoList);
  if( g.fAnyTrace ){
    fprintf(stderr, "/***** Webpage finished in subprocess %d *****/\n",
            getpid());
  }
#else
  /* Win32 implementation */
  if( g.repositoryOpen ) flags |= HTTP_SERVER_HAD_REPOSITORY;
  if( g.localOpen ) flags |= HTTP_SERVER_HAD_CHECKOUT;
  db_close(1);
  if( allowRepoList ){
    flags |= HTTP_SERVER_REPOLIST;
  }
  if( win32_http_service(iPort, zAltBase, zNotFound, zFileGlob, flags) ){
    win32_http_server(iPort, mxPort, zBrowserCmd, zStopperFile,
                      zAltBase, zNotFound, zFileGlob, zIpAddr, flags);
  }







<
<
<







3188
3189
3190
3191
3192
3193
3194



3195
3196
3197
3198
3199
3200
3201
  process_one_web_page(zNotFound, glob_create(zFileGlob), allowRepoList);
  if( g.fAnyTrace ){
    fprintf(stderr, "/***** Webpage finished in subprocess %d *****/\n",
            getpid());
  }
#else
  /* Win32 implementation */



  if( allowRepoList ){
    flags |= HTTP_SERVER_REPOLIST;
  }
  if( win32_http_service(iPort, zAltBase, zNotFound, zFileGlob, flags) ){
    win32_http_server(iPort, mxPort, zBrowserCmd, zStopperFile,
                      zAltBase, zNotFound, zFileGlob, zIpAddr, flags);
  }
Changes to src/main.mk.
212
213
214
215
216
217
218
219
220
221
222

223
224
225
226
227
228
229
230
231
232

233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270

271
272
273
274
275
276
277
  $(SRCDIR)/../skins/xekri/footer.txt \
  $(SRCDIR)/../skins/xekri/header.txt \
  $(SRCDIR)/accordion.js \
  $(SRCDIR)/alerts/bflat2.wav \
  $(SRCDIR)/alerts/bflat3.wav \
  $(SRCDIR)/alerts/bloop.wav \
  $(SRCDIR)/alerts/plunk.wav \
  $(SRCDIR)/chat.js \
  $(SRCDIR)/ci_edit.js \
  $(SRCDIR)/copybtn.js \
  $(SRCDIR)/default.css \

  $(SRCDIR)/diff.tcl \
  $(SRCDIR)/forum.js \
  $(SRCDIR)/fossil.bootstrap.js \
  $(SRCDIR)/fossil.confirmer.js \
  $(SRCDIR)/fossil.copybutton.js \
  $(SRCDIR)/fossil.dom.js \
  $(SRCDIR)/fossil.fetch.js \
  $(SRCDIR)/fossil.info-diff.js \
  $(SRCDIR)/fossil.numbered-lines.js \
  $(SRCDIR)/fossil.page.brlist.js \

  $(SRCDIR)/fossil.page.fileedit.js \
  $(SRCDIR)/fossil.page.forumpost.js \
  $(SRCDIR)/fossil.page.pikchrshow.js \
  $(SRCDIR)/fossil.page.wcontent.js \
  $(SRCDIR)/fossil.page.whistory.js \
  $(SRCDIR)/fossil.page.wikiedit.js \
  $(SRCDIR)/fossil.pikchr.js \
  $(SRCDIR)/fossil.popupwidget.js \
  $(SRCDIR)/fossil.storage.js \
  $(SRCDIR)/fossil.tabs.js \
  $(SRCDIR)/fossil.wikiedit-wysiwyg.js \
  $(SRCDIR)/graph.js \
  $(SRCDIR)/hbmenu.js \
  $(SRCDIR)/href.js \
  $(SRCDIR)/login.js \
  $(SRCDIR)/markdown.md \
  $(SRCDIR)/menu.js \
  $(SRCDIR)/sbsdiff.js \
  $(SRCDIR)/scroll.js \
  $(SRCDIR)/skin.js \
  $(SRCDIR)/sorttable.js \
  $(SRCDIR)/sounds/0.wav \
  $(SRCDIR)/sounds/1.wav \
  $(SRCDIR)/sounds/2.wav \
  $(SRCDIR)/sounds/3.wav \
  $(SRCDIR)/sounds/4.wav \
  $(SRCDIR)/sounds/5.wav \
  $(SRCDIR)/sounds/6.wav \
  $(SRCDIR)/sounds/7.wav \
  $(SRCDIR)/sounds/8.wav \
  $(SRCDIR)/sounds/9.wav \
  $(SRCDIR)/sounds/a.wav \
  $(SRCDIR)/sounds/b.wav \
  $(SRCDIR)/sounds/c.wav \
  $(SRCDIR)/sounds/d.wav \
  $(SRCDIR)/sounds/e.wav \
  $(SRCDIR)/sounds/f.wav \
  $(SRCDIR)/style.admin_log.css \

  $(SRCDIR)/style.fileedit.css \
  $(SRCDIR)/style.wikiedit.css \
  $(SRCDIR)/tree.js \
  $(SRCDIR)/useredit.js \
  $(SRCDIR)/wiki.wiki

TRANS_SRC = \







<



>





|
|
|


>

















<




















>







212
213
214
215
216
217
218

219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250

251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
  $(SRCDIR)/../skins/xekri/footer.txt \
  $(SRCDIR)/../skins/xekri/header.txt \
  $(SRCDIR)/accordion.js \
  $(SRCDIR)/alerts/bflat2.wav \
  $(SRCDIR)/alerts/bflat3.wav \
  $(SRCDIR)/alerts/bloop.wav \
  $(SRCDIR)/alerts/plunk.wav \

  $(SRCDIR)/ci_edit.js \
  $(SRCDIR)/copybtn.js \
  $(SRCDIR)/default.css \
  $(SRCDIR)/diff.js \
  $(SRCDIR)/diff.tcl \
  $(SRCDIR)/forum.js \
  $(SRCDIR)/fossil.bootstrap.js \
  $(SRCDIR)/fossil.confirmer.js \
  $(SRCDIR)/fossil.copybutton.js \
  $(SRCDIR)/fossil.diff.js \
  $(SRCDIR)/fossil.dom.js \
  $(SRCDIR)/fossil.fetch.js \
  $(SRCDIR)/fossil.numbered-lines.js \
  $(SRCDIR)/fossil.page.brlist.js \
  $(SRCDIR)/fossil.page.chat.js \
  $(SRCDIR)/fossil.page.fileedit.js \
  $(SRCDIR)/fossil.page.forumpost.js \
  $(SRCDIR)/fossil.page.pikchrshow.js \
  $(SRCDIR)/fossil.page.wcontent.js \
  $(SRCDIR)/fossil.page.whistory.js \
  $(SRCDIR)/fossil.page.wikiedit.js \
  $(SRCDIR)/fossil.pikchr.js \
  $(SRCDIR)/fossil.popupwidget.js \
  $(SRCDIR)/fossil.storage.js \
  $(SRCDIR)/fossil.tabs.js \
  $(SRCDIR)/fossil.wikiedit-wysiwyg.js \
  $(SRCDIR)/graph.js \
  $(SRCDIR)/hbmenu.js \
  $(SRCDIR)/href.js \
  $(SRCDIR)/login.js \
  $(SRCDIR)/markdown.md \
  $(SRCDIR)/menu.js \

  $(SRCDIR)/scroll.js \
  $(SRCDIR)/skin.js \
  $(SRCDIR)/sorttable.js \
  $(SRCDIR)/sounds/0.wav \
  $(SRCDIR)/sounds/1.wav \
  $(SRCDIR)/sounds/2.wav \
  $(SRCDIR)/sounds/3.wav \
  $(SRCDIR)/sounds/4.wav \
  $(SRCDIR)/sounds/5.wav \
  $(SRCDIR)/sounds/6.wav \
  $(SRCDIR)/sounds/7.wav \
  $(SRCDIR)/sounds/8.wav \
  $(SRCDIR)/sounds/9.wav \
  $(SRCDIR)/sounds/a.wav \
  $(SRCDIR)/sounds/b.wav \
  $(SRCDIR)/sounds/c.wav \
  $(SRCDIR)/sounds/d.wav \
  $(SRCDIR)/sounds/e.wav \
  $(SRCDIR)/sounds/f.wav \
  $(SRCDIR)/style.admin_log.css \
  $(SRCDIR)/style.chat.css \
  $(SRCDIR)/style.fileedit.css \
  $(SRCDIR)/style.wikiedit.css \
  $(SRCDIR)/tree.js \
  $(SRCDIR)/useredit.js \
  $(SRCDIR)/wiki.wiki

TRANS_SRC = \
Changes to src/manifest.c.
351
352
353
354
355
356
357

358

359
360
361
362
363
364
365
  if( z[n-35]!='Z' || z[n-34]!=' ' ) return 0;
  md5sum_init();
  md5sum_step_text(z, n-35);
  zHash = md5sum_finish(0);
  if( memcmp(&z[n-33], zHash, 32)==0 ){
    return 1;
  }else{

    blob_appendf(pErr, "incorrect Z-card cksum: expected %.32s", zHash);

    return 2;
  }
}

/*
** A structure used for rapid parsing of the Manifest file
*/







>
|
>







351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
  if( z[n-35]!='Z' || z[n-34]!=' ' ) return 0;
  md5sum_init();
  md5sum_step_text(z, n-35);
  zHash = md5sum_finish(0);
  if( memcmp(&z[n-33], zHash, 32)==0 ){
    return 1;
  }else{
    if(pErr!=0){
      blob_appendf(pErr, "incorrect Z-card cksum: expected %.32s", zHash);
    }
    return 2;
  }
}

/*
** A structure used for rapid parsing of the Manifest file
*/
486
487
488
489
490
491
492

493

494
495
496
497
498
499
500
501
502
503
504
505

506

507
508
509
510
511
512
513
  ** if that is not the case for this artifact.
  */
  if( !isRepeat ) g.parseCnt[0]++;
  z = blob_materialize(pContent);
  n = blob_size(pContent);
  if( n<=0 || z[n-1]!='\n' ){
    blob_reset(pContent);

    blob_appendf(pErr, "%s", n ? "not terminated with \\n" : "zero-length");

    return 0;
  }

  /* Strip off the PGP signature if there is one.
  */
  remove_pgp_signature((const char**)&z, &n);

  /* Verify that the first few characters of the artifact look like
  ** a control artifact.
  */
  if( n<10 || z[0]<'A' || z[0]>'Z' || z[1]!=' ' ){
    blob_reset(pContent);

    blob_appendf(pErr, "line 1 not recognized");

    return 0;
  }
  /* Then verify the Z-card.
  */
#if 1
  /* Disable this ***ONLY*** (ONLY!) when testing hand-written inputs
     for card-related syntax errors. */







>
|
>












>
|
>







488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
  ** if that is not the case for this artifact.
  */
  if( !isRepeat ) g.parseCnt[0]++;
  z = blob_materialize(pContent);
  n = blob_size(pContent);
  if( n<=0 || z[n-1]!='\n' ){
    blob_reset(pContent);
    if(pErr!=0){
      blob_appendf(pErr, "%s", n ? "not terminated with \\n" : "zero-length");
    }
    return 0;
  }

  /* Strip off the PGP signature if there is one.
  */
  remove_pgp_signature((const char**)&z, &n);

  /* Verify that the first few characters of the artifact look like
  ** a control artifact.
  */
  if( n<10 || z[0]<'A' || z[0]>'Z' || z[1]!=' ' ){
    blob_reset(pContent);
    if(pErr!=0){
      blob_appendf(pErr, "line 1 not recognized");
    }
    return 0;
  }
  /* Then verify the Z-card.
  */
#if 1
  /* Disable this ***ONLY*** (ONLY!) when testing hand-written inputs
     for card-related syntax errors. */
1120
1121
1122
1123
1124
1125
1126

1127

1128
1129
1130

1131
1132
1133
1134

1135
1136
1137
1138
1139
1140
1141
  if( !isRepeat ) g.parseCnt[p->type]++;
  return p;

manifest_syntax_error:
  {
    char *zUuid = rid_to_uuid(rid);
    if( zUuid ){

      blob_appendf(pErr, "artifact [%s] ", zUuid);

      fossil_free(zUuid);
    }
  }

  if( zErr ){
    blob_appendf(pErr, "line %d: %s", lineNo, zErr);
  }else{
    blob_appendf(pErr, "unknown error on line %d", lineNo);

  }
  md5sum_init();
  manifest_destroy(p);
  return 0;
}

/*







>
|
>



>
|
|
|
|
>







1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
  if( !isRepeat ) g.parseCnt[p->type]++;
  return p;

manifest_syntax_error:
  {
    char *zUuid = rid_to_uuid(rid);
    if( zUuid ){
      if(pErr!=0){
        blob_appendf(pErr, "artifact [%s] ", zUuid);
      }
      fossil_free(zUuid);
    }
  }
  if(pErr!=0){
    if( zErr ){
      blob_appendf(pErr, "line %d: %s", lineNo, zErr);
    }else{
      blob_appendf(pErr, "unknown error on line %d", lineNo);
    }
  }
  md5sum_init();
  manifest_destroy(p);
  return 0;
}

/*
Changes to src/markdown.c.
1663
1664
1665
1666
1667
1668
1669

1670
1671
1672
1673
1674
1675
1676
  int level = 0;
  size_t i, end, skip, span_beg, span_size;

  if( !size || data[0]!='#' ) return 0;

  while( level<size && level<6 && data[level]=='#' ){ level++; }
  for(i=level; i<size && (data[i]==' ' || data[i]=='\t'); i++);

  span_beg = i;

  for(end=i; end<size && data[end]!='\n'; end++);
  skip = end;
  if( end<=i ) return parse_paragraph(ob, rndr, data, size);
  while( end && data[end-1]=='#' ){ end--; }
  while( end && (data[end-1]==' ' || data[end-1]=='\t') ){ end--; }







>







1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
  int level = 0;
  size_t i, end, skip, span_beg, span_size;

  if( !size || data[0]!='#' ) return 0;

  while( level<size && level<6 && data[level]=='#' ){ level++; }
  for(i=level; i<size && (data[i]==' ' || data[i]=='\t'); i++);
  if ( i == level ) return parse_paragraph(ob, rndr, data, size);
  span_beg = i;

  for(end=i; end<size && data[end]!='\n'; end++);
  skip = end;
  if( end<=i ) return parse_paragraph(ob, rndr, data, size);
  while( end && data[end-1]=='#' ){ end--; }
  while( end && (data[end-1]==' ' || data[end-1]=='\t') ){ end--; }
Changes to src/merge3.c.
194
195
196
197
198
199
200

201
202
203
204
205
206
207
  int *aC1;              /* Changes from pPivot to pV1 */
  int *aC2;              /* Changes from pPivot to pV2 */
  int i1, i2;            /* Index into aC1[] and aC2[] */
  int nCpy, nDel, nIns;  /* Number of lines to copy, delete, or insert */
  int limit1, limit2;    /* Sizes of aC1[] and aC2[] */
  int nConflict = 0;     /* Number of merge conflicts seen so far */
  int useCrLf = 0;


  blob_zero(pOut);         /* Merge results stored in pOut */
  
  /* If both pV1 and pV2 start with a UTF-8 byte-order-mark (BOM),
  ** keep it in the output. This should be secure enough not to cause
  ** unintended changes to the merged file and consistent with what
  ** users are using in their source files.







>







194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
  int *aC1;              /* Changes from pPivot to pV1 */
  int *aC2;              /* Changes from pPivot to pV2 */
  int i1, i2;            /* Index into aC1[] and aC2[] */
  int nCpy, nDel, nIns;  /* Number of lines to copy, delete, or insert */
  int limit1, limit2;    /* Sizes of aC1[] and aC2[] */
  int nConflict = 0;     /* Number of merge conflicts seen so far */
  int useCrLf = 0;
  DiffConfig DCfg;

  blob_zero(pOut);         /* Merge results stored in pOut */
  
  /* If both pV1 and pV2 start with a UTF-8 byte-order-mark (BOM),
  ** keep it in the output. This should be secure enough not to cause
  ** unintended changes to the merged file and consistent with what
  ** users are using in their source files.
222
223
224
225
226
227
228

229
230
231
232
233
234
235
236
237
  ** and pPivot => pV2 (into aC2).  Each of the aC1 and aC2 arrays is
  ** an array of integer triples.  Within each triple, the first integer
  ** is the number of lines of text to copy directly from the pivot,
  ** the second integer is the number of lines of text to omit from the
  ** pivot, and the third integer is the number of lines of text that are
  ** inserted.  The edit array ends with a triple of 0,0,0.
  */

  aC1 = text_diff(pPivot, pV1, 0, 0, 0);
  aC2 = text_diff(pPivot, pV2, 0, 0, 0);
  if( aC1==0 || aC2==0 ){
    free(aC1);
    free(aC2);
    return -1;
  }

  blob_rewind(pV1);        /* Rewind inputs:  Needed to reconstruct output */







>
|
|







223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
  ** and pPivot => pV2 (into aC2).  Each of the aC1 and aC2 arrays is
  ** an array of integer triples.  Within each triple, the first integer
  ** is the number of lines of text to copy directly from the pivot,
  ** the second integer is the number of lines of text to omit from the
  ** pivot, and the third integer is the number of lines of text that are
  ** inserted.  The edit array ends with a triple of 0,0,0.
  */
  diff_config_init(&DCfg, 0);
  aC1 = text_diff(pPivot, pV1, 0, &DCfg);
  aC2 = text_diff(pPivot, pV2, 0, &DCfg);
  if( aC1==0 || aC2==0 ){
    free(aC1);
    free(aC2);
    return -1;
  }

  blob_rewind(pV1);        /* Rewind inputs:  Needed to reconstruct output */
Changes to src/mkindex.c.
89
90
91
92
93
94
95

96
97
98
99
100
101
102
#define CMDFLAG_COMMAND     0x0010      /* A command */
#define CMDFLAG_SETTING     0x0020      /* A setting */
#define CMDFLAG_VERSIONABLE 0x0040      /* A versionable setting */
#define CMDFLAG_BLOCKTEXT   0x0080      /* Multi-line text setting */
#define CMDFLAG_BOOLEAN     0x0100      /* A boolean setting */
#define CMDFLAG_RAWCONTENT  0x0200      /* Do not interpret webpage content */
#define CMDFLAG_SENSITIVE   0x0400      /* Security-sensitive setting */

/**************************************************************************/

/*
** Each entry looks like this:
*/
typedef struct Entry {
  int eType;        /* CMDFLAG_* values */







>







89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#define CMDFLAG_COMMAND     0x0010      /* A command */
#define CMDFLAG_SETTING     0x0020      /* A setting */
#define CMDFLAG_VERSIONABLE 0x0040      /* A versionable setting */
#define CMDFLAG_BLOCKTEXT   0x0080      /* Multi-line text setting */
#define CMDFLAG_BOOLEAN     0x0100      /* A boolean setting */
#define CMDFLAG_RAWCONTENT  0x0200      /* Do not interpret webpage content */
#define CMDFLAG_SENSITIVE   0x0400      /* Security-sensitive setting */
#define CMDFLAG_HIDDEN      0x0800      /* Elide from most listings */
/**************************************************************************/

/*
** Each entry looks like this:
*/
typedef struct Entry {
  int eType;        /* CMDFLAG_* values */
255
256
257
258
259
260
261


262
263
264
265
266
267
268
      aEntry[nUsed].eType |= CMDFLAG_SENSITIVE;
    }else if( j>6 && strncmp(&zLine[i], "width=", 6)==0 ){
      aEntry[nUsed].iWidth = atoi(&zLine[i+6]);
    }else if( j>8 && strncmp(&zLine[i], "default=", 8)==0 ){
      aEntry[nUsed].zDflt = string_dup(&zLine[i+8], j-8);
    }else if( j>9 && strncmp(&zLine[i], "variable=", 9)==0 ){
      aEntry[nUsed].zVar = string_dup(&zLine[i+9], j-9);


    }else{
      fprintf(stderr, "%s:%d: unknown option: '%.*s'\n",
              zFile, nLine, j, &zLine[i]);
      nErr++;
    }
  }








>
>







256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
      aEntry[nUsed].eType |= CMDFLAG_SENSITIVE;
    }else if( j>6 && strncmp(&zLine[i], "width=", 6)==0 ){
      aEntry[nUsed].iWidth = atoi(&zLine[i+6]);
    }else if( j>8 && strncmp(&zLine[i], "default=", 8)==0 ){
      aEntry[nUsed].zDflt = string_dup(&zLine[i+8], j-8);
    }else if( j>9 && strncmp(&zLine[i], "variable=", 9)==0 ){
      aEntry[nUsed].zVar = string_dup(&zLine[i+9], j-9);
    }else if( j==6 && strncmp(&zLine[i], "hidden", 6)==0 ){
      aEntry[nUsed].eType |= CMDFLAG_HIDDEN;
    }else{
      fprintf(stderr, "%s:%d: unknown option: '%.*s'\n",
              zFile, nLine, j, &zLine[i]);
      nErr++;
    }
  }

Changes to src/name.c.
222
223
224
225
226
227
228








229
230
231
232
233
234
235
        " AND event.type GLOB '%q'"
      " ORDER BY event.mtime DESC LIMIT 1"
    ") LIMIT 1;",
    zType, zTag, zTag, zType
  );
}










/*
** Convert a symbolic name into a RID.  Acceptable forms:
**
**   *  artifact hash (optionally enclosed in [...])
**   *  4-character or larger prefix of a artifact
**   *  Symbolic Name







>
>
>
>
>
>
>
>







222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
        " AND event.type GLOB '%q'"
      " ORDER BY event.mtime DESC LIMIT 1"
    ") LIMIT 1;",
    zType, zTag, zTag, zType
  );
}

/*
** Return true if character "c" is a character that might have been
** accidentally appended to the end of a URL.
*/
static int is_trailing_punct(char c){
  return c=='.' || c=='_' || c==')' || c=='>' || c=='!' || c=='?' || c==',';
}


/*
** Convert a symbolic name into a RID.  Acceptable forms:
**
**   *  artifact hash (optionally enclosed in [...])
**   *  4-character or larger prefix of a artifact
**   *  Symbolic Name
483
484
485
486
487
488
489
























490
491
492
493
494
495
496
        rid = db_int(0,
          "SELECT event.objid"
          "  FROM event"
          " WHERE event.objid=%s"
          "   AND event.type GLOB '%q'", zTag /*safe-for-%s*/, zType);
      }
    }
























  }
  return rid;
}

/*
** This routine takes a user-entered string and tries to convert it to
** an artifact hash.







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







491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
        rid = db_int(0,
          "SELECT event.objid"
          "  FROM event"
          " WHERE event.objid=%s"
          "   AND event.type GLOB '%q'", zTag /*safe-for-%s*/, zType);
      }
    }
    return rid;
  }

  /* If nothing matches and the name ends with punctuation,
  ** then the name might have originated from a URL in plain text
  ** that was incorrectly extracted from the text.  Try to remove
  ** the extra punctuation and rerun the match.
  */
  if( nTag>4
   && is_trailing_punct(zTag[nTag-1])
   && !is_trailing_punct(zTag[nTag-2])
  ){
    char *zNew = fossil_strndup(zTag, nTag-1);
    rid = symbolic_name_to_rid(zNew,zType);
    fossil_free(zNew);
  }else 
  if( nTag>5
   && is_trailing_punct(zTag[nTag-1])
   && is_trailing_punct(zTag[nTag-2])
   && !is_trailing_punct(zTag[nTag-3])
  ){
    char *zNew = fossil_strndup(zTag, nTag-2);
    rid = symbolic_name_to_rid(zNew,zType);
    fossil_free(zNew);
  }
  return rid;
}

/*
** This routine takes a user-entered string and tries to convert it to
** an artifact hash.
Changes to src/patch.c.
370
371
372
373
374
375
376


377
378









379

380


381
382
383
384
385
386
387
** First update the check-out to be at "baseline".  Then loop through
** and update all files.
*/
void patch_apply(unsigned mFlags){
  Stmt q;
  Blob cmd;



  if( (mFlags & PATCH_FORCE)==0 && unsaved_changes(0) ){
    fossil_fatal("there are unsaved changes in the current checkout");









  }

  blob_init(&cmd, 0, 0);


  file_chdir(g.zLocalRoot, 0);
  db_prepare(&q,
    "SELECT patch.cfg.value"
    "  FROM patch.cfg, localdb.vvar"
    " WHERE patch.cfg.key='baseline'"
    "   AND localdb.vvar.name='checkout-hash'"
    "   AND patch.cfg.key<>localdb.vvar.name"







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







370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
** First update the check-out to be at "baseline".  Then loop through
** and update all files.
*/
void patch_apply(unsigned mFlags){
  Stmt q;
  Blob cmd;

  blob_init(&cmd, 0, 0);
  if( unsaved_changes(0) ){
    if( (mFlags & PATCH_FORCE)==0 ){
      fossil_fatal("there are unsaved changes in the current checkout");
    }else{
      blob_appendf(&cmd, "%$ revert", g.nameOfExe);
      if( mFlags & PATCH_DRYRUN ){
        fossil_print("%s\n", blob_str(&cmd));
      }else{
        int rc = fossil_system(blob_str(&cmd));
        if( rc ){
          fossil_fatal("unable to revert preexisting changes: %s",
                       blob_str(&cmd));
        }
      }
      blob_reset(&cmd);
    }
  }
  file_chdir(g.zLocalRoot, 0);
  db_prepare(&q,
    "SELECT patch.cfg.value"
    "  FROM patch.cfg, localdb.vvar"
    " WHERE patch.cfg.key='baseline'"
    "   AND localdb.vvar.name='checkout-hash'"
    "   AND patch.cfg.key<>localdb.vvar.name"
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
    }
  }
  db_finalize(&q);
  if( blob_size(&cmd)>0 ){
    if( mFlags & PATCH_DRYRUN ){
      fossil_print("%s", blob_str(&cmd));
    }else{
      int rc = fossil_system(blob_str(&cmd));
      if( rc ){
        fossil_fatal("unable to add new files:\n%s",
                     blob_str(&cmd));
      }
    }
    blob_reset(&cmd);
  }







|







574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
    }
  }
  db_finalize(&q);
  if( blob_size(&cmd)>0 ){
    if( mFlags & PATCH_DRYRUN ){
      fossil_print("%s", blob_str(&cmd));
    }else{
      int rc = fossil_unsafe_system(blob_str(&cmd));
      if( rc ){
        fossil_fatal("unable to add new files:\n%s",
                     blob_str(&cmd));
      }
    }
    blob_reset(&cmd);
  }
645
646
647
648
649
650
651

652
653
654
655
656
657




658



659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675

676
677
678
679
680
681
682
683
684
685
686
687
688
689

690
691
692
693
694
695
696
697
698
699
700
701
702
703
704

705
706
707
708
709
710
711
** a FILE* obtained from popen() into which we write the patch, or from
** which we read the patch, depending on whether this is a push or pull.
*/
static FILE *patch_remote_command(
  unsigned mFlags,             /* flags */
  const char *zThisCmd,        /* "push" or "pull" */
  const char *zRemoteCmd,      /* "apply" or "create" */

  const char *zRW              /* "w" or "r" */
){
  char *zRemote;
  char *zDir;
  Blob cmd;
  FILE *f;




  const char *zForce = (mFlags & PATCH_FORCE)!=0 ? " -f" : "";



  if( g.argc!=4 ){
    usage(mprintf("%s [USER@]HOST:DIRECTORY", zThisCmd));
  }
  zRemote = fossil_strdup(g.argv[3]);
  zDir = (char*)file_skip_userhost(zRemote);
  if( zDir==0 ){
    zDir = zRemote;
    blob_init(&cmd, 0, 0);
    blob_append_escaped_arg(&cmd, g.nameOfExe, 1);
    blob_appendf(&cmd, " patch %s%s %$ -", zRemoteCmd, zForce, zDir);
  }else{
    Blob remote;
    *(char*)(zDir-1) = 0;
    transport_ssh_command(&cmd);
    blob_appendf(&cmd, " -T");
    blob_append_escaped_arg(&cmd, zRemote, 0);
    blob_init(&remote, 0, 0);

    blob_appendf(&remote, "fossil patch %s%s --dir64 %z -", 
                 zRemoteCmd, zForce, encode64(zDir, -1));
    blob_append_escaped_arg(&cmd, blob_str(&remote), 0);
    blob_reset(&remote);
  }
  if( mFlags & PATCH_VERBOSE ){
    fossil_print("# %s\n", blob_str(&cmd));
    fflush(stdout);
  }
  f = popen(blob_str(&cmd), zRW);
  if( f==0 ){
    fossil_fatal("cannot run command: %s", blob_str(&cmd));
  }
  blob_reset(&cmd);

  return f;
}

/*
** Show a diff for the patch currently loaded into database "patch".
*/
static void patch_diff(
  unsigned mFlags,         /* Patch flags.  only -f is allowed */
  const char *zDiffCmd,    /* Command used for diffing */
  const char *zBinGlob,    /* GLOB pattern to determine binary files */
  int fIncludeBinary,      /* Do diffs against binary files */
  u64 diffFlags            /* Other diff flags */
){
  int nErr = 0;
  Stmt q;

  Blob empty;
  blob_zero(&empty);

  if( (mFlags & PATCH_FORCE)==0 ){
    /* Check to ensure that the patch is against the repository that
    ** we have opened.
    **







>






>
>
>
>
|
>
>
>

















>
|
|












>








<
<
|
<



>







659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721


722

723
724
725
726
727
728
729
730
731
732
733
** a FILE* obtained from popen() into which we write the patch, or from
** which we read the patch, depending on whether this is a push or pull.
*/
static FILE *patch_remote_command(
  unsigned mFlags,             /* flags */
  const char *zThisCmd,        /* "push" or "pull" */
  const char *zRemoteCmd,      /* "apply" or "create" */
  const char *zFossilCmd,      /* Name of "fossil" on remote system */
  const char *zRW              /* "w" or "r" */
){
  char *zRemote;
  char *zDir;
  Blob cmd;
  FILE *f;
  Blob flgs;
  char *zForce;

  blob_init(&flgs, 0, 0);
  if( mFlags & PATCH_FORCE )  blob_appendf(&flgs, " -f");
  if( mFlags & PATCH_VERBOSE )  blob_appendf(&flgs, " -v");
  if( mFlags & PATCH_DRYRUN )  blob_appendf(&flgs, " -n");
  zForce = blob_size(&flgs)>0 ? blob_str(&flgs) : "";
  if( g.argc!=4 ){
    usage(mprintf("%s [USER@]HOST:DIRECTORY", zThisCmd));
  }
  zRemote = fossil_strdup(g.argv[3]);
  zDir = (char*)file_skip_userhost(zRemote);
  if( zDir==0 ){
    zDir = zRemote;
    blob_init(&cmd, 0, 0);
    blob_append_escaped_arg(&cmd, g.nameOfExe, 1);
    blob_appendf(&cmd, " patch %s%s %$ -", zRemoteCmd, zForce, zDir);
  }else{
    Blob remote;
    *(char*)(zDir-1) = 0;
    transport_ssh_command(&cmd);
    blob_appendf(&cmd, " -T");
    blob_append_escaped_arg(&cmd, zRemote, 0);
    blob_init(&remote, 0, 0);
    if( zFossilCmd==0 ) zFossilCmd = "fossil";
    blob_appendf(&remote, "%$ patch %s%s --dir64 %z -", 
                 zFossilCmd, zRemoteCmd, zForce, encode64(zDir, -1));
    blob_append_escaped_arg(&cmd, blob_str(&remote), 0);
    blob_reset(&remote);
  }
  if( mFlags & PATCH_VERBOSE ){
    fossil_print("# %s\n", blob_str(&cmd));
    fflush(stdout);
  }
  f = popen(blob_str(&cmd), zRW);
  if( f==0 ){
    fossil_fatal("cannot run command: %s", blob_str(&cmd));
  }
  blob_reset(&cmd);
  blob_reset(&flgs);
  return f;
}

/*
** Show a diff for the patch currently loaded into database "patch".
*/
static void patch_diff(
  unsigned mFlags,         /* Patch flags.  only -f is allowed */


  DiffConfig *pCfg         /* Diff options */

){
  int nErr = 0;
  Stmt q;
  int bWebpage = (pCfg->diffFlags & DIFF_WEBPAGE)!=0;
  Blob empty;
  blob_zero(&empty);

  if( (mFlags & PATCH_FORCE)==0 ){
    /* Check to ensure that the patch is against the repository that
    ** we have opened.
    **
736
737
738
739
740
741
742
743

744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
                             " WHERE key='baseline'");
      if( zBaseline ){
        fossil_fatal("the baseline of the patch (check-in %S) is not found "
                     "in the %s repository", zBaseline, g.zRepositoryName);
      }
    }
  }
  

  db_prepare(&q,
     "SELECT"
       " (SELECT blob.rid FROM blob WHERE blob.uuid=chng.hash),"
       " pathname,"    /* 1: new pathname */
       " origname,"    /* 2: original pathname.  Null if not renamed */
       " delta,"       /* 3: delta.  NULL if deleted.  empty is no change */
       " hash"         /* 4: baseline hash */
     " FROM patch.chng"
     " ORDER BY pathname"
  );
  while( db_step(&q)==SQLITE_ROW ){
    int rid;
    const char *zName;
    int isBin1, isBin2;
    Blob a, b;
 
    if( db_column_type(&q,0)!=SQLITE_INTEGER
     && db_column_type(&q,4)==SQLITE_TEXT
    ){
      char *zUuid = fossil_strdup(db_column_text(&q,4));
      char *zName = fossil_strdup(db_column_text(&q,1));







|
>













<







758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779

780
781
782
783
784
785
786
                             " WHERE key='baseline'");
      if( zBaseline ){
        fossil_fatal("the baseline of the patch (check-in %S) is not found "
                     "in the %s repository", zBaseline, g.zRepositoryName);
      }
    }
  }

  diff_begin(pCfg);
  db_prepare(&q,
     "SELECT"
       " (SELECT blob.rid FROM blob WHERE blob.uuid=chng.hash),"
       " pathname,"    /* 1: new pathname */
       " origname,"    /* 2: original pathname.  Null if not renamed */
       " delta,"       /* 3: delta.  NULL if deleted.  empty is no change */
       " hash"         /* 4: baseline hash */
     " FROM patch.chng"
     " ORDER BY pathname"
  );
  while( db_step(&q)==SQLITE_ROW ){
    int rid;
    const char *zName;

    Blob a, b;
 
    if( db_column_type(&q,0)!=SQLITE_INTEGER
     && db_column_type(&q,4)==SQLITE_TEXT
    ){
      char *zUuid = fossil_strdup(db_column_text(&q,4));
      char *zName = fossil_strdup(db_column_text(&q,1));
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814

815
816
817
818
819
820
821
                     zUuid, zName);
      }
    }
    zName = db_column_text(&q, 1);
    rid = db_column_int(&q, 0);

    if( db_column_type(&q,3)==SQLITE_NULL ){
      fossil_print("DELETE %s\n", zName);
      diff_print_index(zName, diffFlags, 0);
      isBin2 = 0;
      content_get(rid, &a);
      isBin1 = fIncludeBinary ? 0 : looks_like_binary(&a);
      diff_file_mem(&a, &empty, isBin1, isBin2, zName, zDiffCmd,
                    zBinGlob, fIncludeBinary, diffFlags);
    }else if( rid==0 ){
      db_ephemeral_blob(&q, 3, &a);
      blob_uncompress(&a, &a);
      fossil_print("ADDED %s\n", zName);
      diff_print_index(zName, diffFlags, 0);
      isBin1 = 0;
      isBin2 = fIncludeBinary ? 0 : looks_like_binary(&a);
      diff_file_mem(&empty, &a, isBin1, isBin2, zName, zDiffCmd,
                    zBinGlob, fIncludeBinary, diffFlags);
      blob_reset(&a);
    }else if( db_column_bytes(&q, 3)>0 ){
      Blob delta;
      db_ephemeral_blob(&q, 3, &delta);
      blob_uncompress(&delta, &delta);
      content_get(rid, &a);
      blob_delta_apply(&a, &delta, &b);
      isBin1 = fIncludeBinary ? 0 : looks_like_binary(&a);
      isBin2 = fIncludeBinary ? 0 : looks_like_binary(&b);
      diff_file_mem(&a, &b, isBin1, isBin2, zName,
                    zDiffCmd, zBinGlob, fIncludeBinary, diffFlags);
      blob_reset(&a);
      blob_reset(&b);
      blob_reset(&delta);
    }
  }
  db_finalize(&q);

  if( nErr ) fossil_fatal("abort due to prior errors");
}


/*
** COMMAND: patch
**







|
|
<

<
|
<



|
|
<
<
|
<







<
<
|
<






>







797
798
799
800
801
802
803
804
805

806

807

808
809
810
811
812


813

814
815
816
817
818
819
820


821

822
823
824
825
826
827
828
829
830
831
832
833
834
835
                     zUuid, zName);
      }
    }
    zName = db_column_text(&q, 1);
    rid = db_column_int(&q, 0);

    if( db_column_type(&q,3)==SQLITE_NULL ){
      if( !bWebpage ) fossil_print("DELETE %s\n", zName);
      diff_print_index(zName, pCfg, 0);

      content_get(rid, &a);

      diff_file_mem(&a, &empty, zName, pCfg);

    }else if( rid==0 ){
      db_ephemeral_blob(&q, 3, &a);
      blob_uncompress(&a, &a);
      if( !bWebpage ) fossil_print("ADDED %s\n", zName);
      diff_print_index(zName, pCfg, 0);


      diff_file_mem(&empty, &a, zName, pCfg);

      blob_reset(&a);
    }else if( db_column_bytes(&q, 3)>0 ){
      Blob delta;
      db_ephemeral_blob(&q, 3, &delta);
      blob_uncompress(&delta, &delta);
      content_get(rid, &a);
      blob_delta_apply(&a, &delta, &b);


      diff_file_mem(&a, &b, zName, pCfg);

      blob_reset(&a);
      blob_reset(&b);
      blob_reset(&delta);
    }
  }
  db_finalize(&q);
  diff_end(pCfg, nErr);
  if( nErr ) fossil_fatal("abort due to prior errors");
}


/*
** COMMAND: patch
**
837
838
839
840
841
842
843
844

845
846
847
848
849
850
851
**
** > fossil patch apply [DIRECTORY] FILENAME
**
**       Apply the changes in FILENAME to the check-out at DIRECTORY, or
**       in the current directory if DIRECTORY is omitted. Options:
**
**           -f|--force     Apply the patch even though there are unsaved
**                          changes in the current check-out.

**           -n|--dryrun    Do nothing, but print what would have happened.
**           -v|--verbose   Extra output explaining what happens.
**
** > fossil patch diff [DIRECTORY] FILENAME
**
**       Show a human-readable diff for the patch.  All the usual
**       diff flags described at "fossil help diff" apply.  In addition:







|
>







851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
**
** > fossil patch apply [DIRECTORY] FILENAME
**
**       Apply the changes in FILENAME to the check-out at DIRECTORY, or
**       in the current directory if DIRECTORY is omitted. Options:
**
**           -f|--force     Apply the patch even though there are unsaved
**                          changes in the current check-out.  Unsaved changes
**                          are reverted and permanently lost.
**           -n|--dryrun    Do nothing, but print what would have happened.
**           -v|--verbose   Extra output explaining what happens.
**
** > fossil patch diff [DIRECTORY] FILENAME
**
**       Show a human-readable diff for the patch.  All the usual
**       diff flags described at "fossil help diff" apply.  In addition:
860
861
862
863
864
865
866
867




868




869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
**       a remote machine (using ssh) and apply the patch there.  The
**       REMOTE-CHECKOUT is in one of the following formats:
**
**           *   DIRECTORY
**           *   HOST:DIRECTORY
**           *   USER@HOST:DIRECTORY
**
**       This command will only work if "fossil" is on the default PATH




**       of the remote machine.




**
** > fossil patch pull REMOTE-CHECKOUT
**
**       Create a patch on a remote check-out, transfer that patch to the
**       local machine (using ssh) and apply the patch in the local checkout.
**
**           -f|--force     Apply the patch even though there are unsaved
**                          changes in the current check-out.
**           -n|--dryrun    Do nothing, but print what would have happened.
**           -v|--verbose   Extra output explaining what happens.
**
** > fossil patch view FILENAME
**
**       View a summary of the changes in the binary patch FILENAME.
**       Use "fossil patch diff" for detailed patch content.
**
**           -v|--verbose   Show extra detail about the patch.
**
*/
void patch_cmd(void){
  const char *zCmd;
  size_t n;
  if( g.argc<3 ){
    patch_usage:







|
>
>
>
>
|
>
>
>
>



|
<
<
<
|
<
<






|







875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895



896


897
898
899
900
901
902
903
904
905
906
907
908
909
910
**       a remote machine (using ssh) and apply the patch there.  The
**       REMOTE-CHECKOUT is in one of the following formats:
**
**           *   DIRECTORY
**           *   HOST:DIRECTORY
**           *   USER@HOST:DIRECTORY
**
**       Command-line options:
**
**           -f|--force         Apply the patch even though there are unsaved
**                              changes in the current check-out.  Unsaved
**                              changes will be reverted and then the patch is
**                              applied.
**           --fossilcmd EXE    Name of the "fossil" executable on the remote  
**           -n|--dryrun        Do nothing, but print what would have happened.
**           -v|--verbose       Extra output explaining what happens.
**
**
** > fossil patch pull REMOTE-CHECKOUT
**
**       Like "fossil patch push" except that the transfer is from remote



**       to local.  All the same command-line options apply.


**
** > fossil patch view FILENAME
**
**       View a summary of the changes in the binary patch FILENAME.
**       Use "fossil patch diff" for detailed patch content.
**
**           -v|--verbose       Show extra detail about the patch.
**
*/
void patch_cmd(void){
  const char *zCmd;
  size_t n;
  if( g.argc<3 ){
    patch_usage:
913
914
915
916
917
918
919
920
921
922
923
924
925

926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951

952
953
954
955
956
957

958
959
960
961
962
963
964
965
966

967
968
969
970
971
972
973
974
975
976
977
978
979
    zOut = patch_find_patch_filename("create");
    verify_all_options();
    db_must_be_within_tree();
    patch_create(flags, zOut, stdout);
    fossil_free(zOut);
  }else
  if( strncmp(zCmd, "diff", n)==0 ){
    const char *zDiffCmd = 0;
    const char *zBinGlob = 0;
    int fIncludeBinary = 0;
    u64 diffFlags;
    char *zIn;
    unsigned flags = 0;


    if( find_option("tk",0,0)!=0 ){
      db_close(0);
      diff_tk("patch diff", 3);
      return;
    }
    if( find_option("internal","i",0)==0 ){
      zDiffCmd = diff_command_external(zCmd[0]=='g');
    }
    diffFlags = diff_options();
    if( find_option("verbose","v",0)!=0 ) diffFlags |= DIFF_VERBOSE;
    if( zDiffCmd ){
      zBinGlob = diff_get_binary_glob();
      fIncludeBinary = diff_include_binary_files();
    }
    db_find_and_open_repository(0, 0);
    if( find_option("force","f",0) )    flags |= PATCH_FORCE;
    verify_all_options();
    zIn = patch_find_patch_filename("apply");
    patch_attach(zIn, stdin);
    patch_diff(flags, zDiffCmd, zBinGlob, fIncludeBinary, diffFlags);
    fossil_free(zIn);
  }else
  if( strncmp(zCmd, "pull", n)==0 ){
    FILE *pIn = 0;
    unsigned flags = 0;

    if( find_option("dryrun","n",0) )   flags |= PATCH_DRYRUN;
    if( find_option("verbose","v",0) )  flags |= PATCH_VERBOSE;
    if( find_option("force","f",0) )    flags |= PATCH_FORCE;
    db_must_be_within_tree();
    verify_all_options();
    pIn = patch_remote_command(flags & (~PATCH_FORCE), "pull", "create", "r");

    if( pIn ){
      patch_attach(0, pIn);
      pclose(pIn);
      patch_apply(flags);
    }
  }else
  if( strncmp(zCmd, "push", n)==0 ){
    FILE *pOut = 0;
    unsigned flags = 0;

    if( find_option("dryrun","n",0) )   flags |= PATCH_DRYRUN;
    if( find_option("verbose","v",0) )  flags |= PATCH_VERBOSE;
    if( find_option("force","f",0) )    flags |= PATCH_FORCE;
    db_must_be_within_tree();
    verify_all_options();
    pOut = patch_remote_command(flags, "push", "apply", "w");
    if( pOut ){
      patch_create(0, 0, pOut);
      pclose(pOut);
    }
  }else
  if( strncmp(zCmd, "view", n)==0 ){
    const char *zIn;







<
<
<
<


>






<
<
<
|
<
<
<
<
<





|





>





|
>









>





|







931
932
933
934
935
936
937




938
939
940
941
942
943
944
945
946



947





948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
    zOut = patch_find_patch_filename("create");
    verify_all_options();
    db_must_be_within_tree();
    patch_create(flags, zOut, stdout);
    fossil_free(zOut);
  }else
  if( strncmp(zCmd, "diff", n)==0 ){




    char *zIn;
    unsigned flags = 0;
    DiffConfig DCfg;

    if( find_option("tk",0,0)!=0 ){
      db_close(0);
      diff_tk("patch diff", 3);
      return;
    }



    diff_options(&DCfg, zCmd[0]=='g', 0);





    db_find_and_open_repository(0, 0);
    if( find_option("force","f",0) )    flags |= PATCH_FORCE;
    verify_all_options();
    zIn = patch_find_patch_filename("apply");
    patch_attach(zIn, stdin);
    patch_diff(flags, &DCfg);
    fossil_free(zIn);
  }else
  if( strncmp(zCmd, "pull", n)==0 ){
    FILE *pIn = 0;
    unsigned flags = 0;
    const char *zFossilCmd = find_option("fossilcmd",0,1);
    if( find_option("dryrun","n",0) )   flags |= PATCH_DRYRUN;
    if( find_option("verbose","v",0) )  flags |= PATCH_VERBOSE;
    if( find_option("force","f",0) )    flags |= PATCH_FORCE;
    db_must_be_within_tree();
    verify_all_options();
    pIn = patch_remote_command(flags & (~PATCH_FORCE), 
                 "pull", "create", zFossilCmd, "r");
    if( pIn ){
      patch_attach(0, pIn);
      pclose(pIn);
      patch_apply(flags);
    }
  }else
  if( strncmp(zCmd, "push", n)==0 ){
    FILE *pOut = 0;
    unsigned flags = 0;
    const char *zFossilCmd = find_option("fossilcmd",0,1);
    if( find_option("dryrun","n",0) )   flags |= PATCH_DRYRUN;
    if( find_option("verbose","v",0) )  flags |= PATCH_VERBOSE;
    if( find_option("force","f",0) )    flags |= PATCH_FORCE;
    db_must_be_within_tree();
    verify_all_options();
    pOut = patch_remote_command(flags, "push", "apply", zFossilCmd, "w");
    if( pOut ){
      patch_create(0, 0, pOut);
      pclose(pOut);
    }
  }else
  if( strncmp(zCmd, "view", n)==0 ){
    const char *zIn;
Changes to src/pikchrshow.c.
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
          blob_append(pOut, "</div>\n", 7);
        }
      }else{
        isErr = 2;
        if(PIKCHR_PROCESS_ERR_PRE & pikFlags){
          blob_append(pOut, "<pre class='error'>\n", 20);
        }
        blob_append(pOut, zOut, -1);
        if(PIKCHR_PROCESS_ERR_PRE & pikFlags){
          blob_append(pOut, "\n</pre>\n", 8);
        }
      }
      fossil_free(zOut);
    }
  }







|







212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
          blob_append(pOut, "</div>\n", 7);
        }
      }else{
        isErr = 2;
        if(PIKCHR_PROCESS_ERR_PRE & pikFlags){
          blob_append(pOut, "<pre class='error'>\n", 20);
        }
        blob_appendf(pOut, "%h", zOut);
        if(PIKCHR_PROCESS_ERR_PRE & pikFlags){
          blob_append(pOut, "\n</pre>\n", 8);
        }
      }
      fossil_free(zOut);
    }
  }
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
  int pikFlags =
    PIKCHR_PROCESS_DIV
    | PIKCHR_PROCESS_SRC
    | PIKCHR_PROCESS_ERR_PRE;

  login_check_credentials();
  if( !g.perm.RdWiki && !g.perm.Read && !g.perm.RdForum ){
    cgi_redirectf("%R/login?g=%R/pikchrshow");
  }
  zContent = PD("content",P("p"));
  if(P("ajax")!=0){
    /* Called from the JS-side preview updater.
       TODO: respond with JSON instead.*/
    cgi_set_content_type("text/html");
    if(zContent && *zContent){







|







247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
  int pikFlags =
    PIKCHR_PROCESS_DIV
    | PIKCHR_PROCESS_SRC
    | PIKCHR_PROCESS_ERR_PRE;

  login_check_credentials();
  if( !g.perm.RdWiki && !g.perm.Read && !g.perm.RdForum ){
    cgi_redirectf("%R/login?g=pikchrshow");
  }
  zContent = PD("content",P("p"));
  if(P("ajax")!=0){
    /* Called from the JS-side preview updater.
       TODO: respond with JSON instead.*/
    cgi_set_content_type("text/html");
    if(zContent && *zContent){
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
       "margin-right: 0.5em; vertical-align: middle;"
       "}\n");
    CX("body.pikchrshow .v-align-middle{"
       "vertical-align: middle"
       "}\n");
    CX(".dragover {border: 3px dotted rgba(0,255,0,0.6)}\n");
  } CX("</style>");
  CX("<div>Input pikchr code and tap Preview (or Ctrl-Enter) to render "
     "it:</div>");
  CX("<div id='sbs-wrapper'>"); {
    CX("<div id='pikchrshow-form'>"); {
      CX("<textarea id='content' name='content' rows='15'>"
         "%s</textarea>",zContent/*safe-for-%s*/);
      CX("<div id='pikchrshow-controls'>"); {
        CX("<button id='pikchr-submit-preview'>Preview</button>");







|







333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
       "margin-right: 0.5em; vertical-align: middle;"
       "}\n");
    CX("body.pikchrshow .v-align-middle{"
       "vertical-align: middle"
       "}\n");
    CX(".dragover {border: 3px dotted rgba(0,255,0,0.6)}\n");
  } CX("</style>");
  CX("<div>Input pikchr code and tap Preview (or Shift-Enter) to render "
     "it:</div>");
  CX("<div id='sbs-wrapper'>"); {
    CX("<div id='pikchrshow-form'>"); {
      CX("<textarea id='content' name='content' rows='15'>"
         "%s</textarea>",zContent/*safe-for-%s*/);
      CX("<div id='pikchrshow-controls'>"); {
        CX("<button id='pikchr-submit-preview'>Preview</button>");
Changes to src/printf.c.
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
** On windows, transform the output into the current terminal encoding
** if the output is going to the screen.  If output is redirected into
** a file, no translation occurs. Switch output mode to binary to
** properly process line-endings, make sure to switch the mode back to
** text when done.
** No translation ever occurs on unix.
*/
void fossil_puts(const char *z, int toStdErr){
  FILE* out = (toStdErr ? stderr : stdout);
  int n = (int)strlen(z);
  if( n==0 ) return;
  assert( toStdErr==0 || toStdErr==1 );
  if( toStdErr==0 ) stdoutAtBOL = (z[n-1]=='\n');
#if defined(_WIN32)
  if( fossil_utf8_to_console(z, n, toStdErr) >= 0 ){
    return;
  }







|

<







956
957
958
959
960
961
962
963
964

965
966
967
968
969
970
971
** On windows, transform the output into the current terminal encoding
** if the output is going to the screen.  If output is redirected into
** a file, no translation occurs. Switch output mode to binary to
** properly process line-endings, make sure to switch the mode back to
** text when done.
** No translation ever occurs on unix.
*/
void fossil_puts(const char *z, int toStdErr, int n){
  FILE* out = (toStdErr ? stderr : stdout);

  if( n==0 ) return;
  assert( toStdErr==0 || toStdErr==1 );
  if( toStdErr==0 ) stdoutAtBOL = (z[n-1]=='\n');
#if defined(_WIN32)
  if( fossil_utf8_to_console(z, n, toStdErr) >= 0 ){
    return;
  }
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996

/*
** Force the standard output cursor to move to the beginning
** of a line, if it is not there already.
*/
int fossil_force_newline(void){
  if( g.cgiOutput==0 && stdoutAtBOL==0 ){
    fossil_puts("\n", 0);
    return 1;
  }
  return 0;
}

/*
** Indicate that the cursor has moved to the start of a line by means







|







981
982
983
984
985
986
987
988
989
990
991
992
993
994
995

/*
** Force the standard output cursor to move to the beginning
** of a line, if it is not there already.
*/
int fossil_force_newline(void){
  if( g.cgiOutput==0 && stdoutAtBOL==0 ){
    fossil_puts("\n", 0, 1);
    return 1;
  }
  return 0;
}

/*
** Indicate that the cursor has moved to the start of a line by means
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
*/
void fossil_print(const char *zFormat, ...){
  va_list ap;
  va_start(ap, zFormat);
  if( g.cgiOutput ){
    cgi_vprintf(zFormat, ap);
  }else{
    Blob b = empty_blob;
    vxprintf(&b, zFormat, ap);
    fossil_puts(blob_str(&b), 0);
    blob_reset(&b);
  }
  va_end(ap);
}
void fossil_vprint(const char *zFormat, va_list ap){
  if( g.cgiOutput ){
    cgi_vprintf(zFormat, ap);
  }else{
    Blob b = empty_blob;
    vxprintf(&b, zFormat, ap);
    fossil_puts(blob_str(&b), 0);
    blob_reset(&b);
  }
}

/*
** Print a trace message on standard error.
*/
void fossil_trace(const char *zFormat, ...){
  va_list ap;
  Blob b;
  va_start(ap, zFormat);
  b = empty_blob;
  vxprintf(&b, zFormat, ap);
  fossil_puts(blob_str(&b), 1);
  blob_reset(&b);
  va_end(ap);
}

/*
** Write a message to the error log, if the error log filename is
** defined.







<
|
<
<







<
|
<
<












|







1006
1007
1008
1009
1010
1011
1012

1013


1014
1015
1016
1017
1018
1019
1020

1021


1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
*/
void fossil_print(const char *zFormat, ...){
  va_list ap;
  va_start(ap, zFormat);
  if( g.cgiOutput ){
    cgi_vprintf(zFormat, ap);
  }else{

    vxprintf(0, zFormat, ap);


  }
  va_end(ap);
}
void fossil_vprint(const char *zFormat, va_list ap){
  if( g.cgiOutput ){
    cgi_vprintf(zFormat, ap);
  }else{

    vxprintf(0, zFormat, ap);


  }
}

/*
** Print a trace message on standard error.
*/
void fossil_trace(const char *zFormat, ...){
  va_list ap;
  Blob b;
  va_start(ap, zFormat);
  b = empty_blob;
  vxprintf(&b, zFormat, ap);
  fossil_puts(blob_buffer(&b), 1, blob_size(&b));
  blob_reset(&b);
  va_end(ap);
}

/*
** Write a message to the error log, if the error log filename is
** defined.
Changes to src/rebuild.c.
923
924
925
926
927
928
929
930


931
932
933
934
935
936






937
938
939
940
941
942
943
944
    bNeedRebuild = db_exists("SELECT 1 FROM private");
    delete_private_content();
  }
  if( !privateOnly ){
    db_unprotect(PROTECT_ALL);
    db_multi_exec(
      "UPDATE user SET pw='';"
      "DELETE FROM config WHERE name GLOB 'last-sync-*';"


      "DELETE FROM config WHERE name GLOB 'sync-*:*';"
      "DELETE FROM config WHERE name GLOB 'peer-*';"
      "DELETE FROM config WHERE name GLOB 'login-group-*';"
      "DELETE FROM config WHERE name GLOB 'skin:*';"
      "DELETE FROM config WHERE name GLOB 'subrepo:*';"
      "DELETE FROM config WHERE name GLOB 'http-auth:*';"






      "DELETE FROM config WHERE name GLOB 'cert:*';"
    );
    if( bVerily ){
      db_multi_exec(
        "DELETE FROM concealed;\n"
        "UPDATE rcvfrom SET ipaddr='unknown';\n"
        "DROP TABLE IF EXISTS accesslog;\n"
        "UPDATE user SET photo=NULL, info='';\n"







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







923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
    bNeedRebuild = db_exists("SELECT 1 FROM private");
    delete_private_content();
  }
  if( !privateOnly ){
    db_unprotect(PROTECT_ALL);
    db_multi_exec(
      "UPDATE user SET pw='';"
      "DELETE FROM config WHERE name IN"
      "(WITH pattern(x) AS (VALUES"
      "  ('last-sync-*'),"
      "  ('sync-*'),"
      "  ('peer-*'),"
      "  ('login-group-*'),"
      "  ('skin:*'),"
      "  ('subrepo:*'),"
      "  ('http-auth:*'),"
      "  ('cert:*'),"
      "  ('syncwith:*'),"
      "  ('gitpush:*'),"
      "  ('ckout:*'),"
      "  ('draft[1-9]-*'),"
      "  ('baseurl:*')"
      ") SELECT name FROM config, pattern WHERE name GLOB x);"
    );
    if( bVerily ){
      db_multi_exec(
        "DELETE FROM concealed;\n"
        "UPDATE rcvfrom SET ipaddr='unknown';\n"
        "DROP TABLE IF EXISTS accesslog;\n"
        "UPDATE user SET photo=NULL, info='';\n"
Deleted src/sbsdiff.js.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/* The javascript in this file was added by Joel Bruick on 2013-07-06,
** originally as in-line javascript.  It does some kind of setup for
** side-by-side diff display, but I'm not really sure what.
*/
(function(){
  var SCROLL_LEN = 25;
  function initSbsDiff(diff){
    var txtCols = diff.querySelectorAll('.difftxtcol');
    var txtPres = diff.querySelectorAll('.difftxtcol pre');
    var width = Math.max(txtPres[0].scrollWidth, txtPres[1].scrollWidth);
    var i;
    for(i=0; i<2; i++){
      txtPres[i].style.width = width + 'px';
      txtCols[i].onscroll = function(e){
        txtCols[0].scrollLeft = txtCols[1].scrollLeft = this.scrollLeft;
      };
    }
    diff.tabIndex = 0;
    diff.onkeydown = function(e){
      e = e || event;
      var len = {37: -SCROLL_LEN, 39: SCROLL_LEN}[e.keyCode];
      if( !len ) return;
      txtCols[0].scrollLeft += len;
      return false;
    };
  }
  var i, diffs = document.querySelectorAll('.sbsdiffcols')
  /* Maintenance reminder: using forEach() here breaks
     MSIE<=11, and we need to keep those browsers working on
     the /info page. */;
  for(i=0; i<diffs.length; i++){
    initSbsDiff(diffs[i]);
  }
  if(window.fossil && fossil.page){
    /* Here we can use forEach() because the pages which use
       fossil.pages only work in HTML5-compliant browsers. */
    fossil.page.tweakSbsDiffs = function(){
      document.querySelectorAll('.sbsdiffcols').forEach(initSbsDiff);
    };
  }
})();
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


















































































Changes to src/security_audit.c.
279
280
281
282
283
284
285











286
287
288
289
290
291
292
    @ Anonymous users can act as moderators for wiki, tickets, or 
    @ forum posts. This defeats the whole purpose of moderation.
    @ <p>Fix this by removing the "Mod-Wiki", "Mod-Tkt", and "Mod-Forum"
    @ privileges (<a href="%R/setup_ucap_list">capabilities</a> "fq5")
    @ from users "anonymous" and "nobody"
    @ on the <a href="setup_ulist">User Configuration</a> page.
  }












  /* The strict-manifest-syntax setting should be on. */
  if( db_get_boolean("strict-manifest-syntax",1)==0 ){
    @ <li><p><b>WARNING:</b>
    @ The "strict-manifest-syntax"  flag is off.  This is a security
    @ risk.  Turn this setting on (its default) to protect the users
    @ of this repository.







>
>
>
>
>
>
>
>
>
>
>







279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
    @ Anonymous users can act as moderators for wiki, tickets, or 
    @ forum posts. This defeats the whole purpose of moderation.
    @ <p>Fix this by removing the "Mod-Wiki", "Mod-Tkt", and "Mod-Forum"
    @ privileges (<a href="%R/setup_ucap_list">capabilities</a> "fq5")
    @ from users "anonymous" and "nobody"
    @ on the <a href="setup_ulist">User Configuration</a> page.
  }

  /* Check to see if any TH1 scripts are configured to run on a sync
  */
  if( db_exists("SELECT 1 FROM config WHERE name GLOB 'xfer-*-script'"
                " AND length(value)>0") ){
    @ <li><p><b>WARNING:</b>
    @ TH1 scripts might be configured to run on any sync, push, pull, or
    @ clone operation.  See the the <a href="%R/xfersetup">/xfersetup</a>
    @ page for more information.  These TH1 scripts are a potential
    @ security concern and so should be carefully audited by a human.
  } 

  /* The strict-manifest-syntax setting should be on. */
  if( db_get_boolean("strict-manifest-syntax",1)==0 ){
    @ <li><p><b>WARNING:</b>
    @ The "strict-manifest-syntax"  flag is off.  This is a security
    @ risk.  Turn this setting on (its default) to protect the users
    @ of this repository.
Changes to src/setup.c.
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
  setup_menu_entry("Search","srchsetup",
    "Configure the built-in search engine");
  setup_menu_entry("URL Aliases", "waliassetup",
    "Configure URL aliases");
  if( setup_user ){
    setup_menu_entry("Notification", "setup_notification",
      "Automatic notifications of changes via outbound email");
    setup_menu_entry("Email-Server", "setup_smtp",
      "Activate and configure the built-in email server");
    setup_menu_entry("Transfers", "xfersetup",
      "Configure the transfer system for this repository");
  }
  setup_menu_entry("Skins", "setup_skin",
    "Select and/or modify the web interface \"skins\"");
  setup_menu_entry("Moderation", "setup_modreq",
    "Enable/Disable requiring moderator approval of Wiki and/or Ticket"







<
<







132
133
134
135
136
137
138


139
140
141
142
143
144
145
  setup_menu_entry("Search","srchsetup",
    "Configure the built-in search engine");
  setup_menu_entry("URL Aliases", "waliassetup",
    "Configure URL aliases");
  if( setup_user ){
    setup_menu_entry("Notification", "setup_notification",
      "Automatic notifications of changes via outbound email");


    setup_menu_entry("Transfers", "xfersetup",
      "Configure the transfer system for this repository");
  }
  setup_menu_entry("Skins", "setup_skin",
    "Select and/or modify the web interface \"skins\"");
  setup_menu_entry("Moderation", "setup_modreq",
    "Enable/Disable requiring moderator approval of Wiki and/or Ticket"
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
    @ </table>
    @
    @ <p><form action="%R/setup_login_group" method="post"><div>
    login_insert_csrf_secret();
    @ To leave this login group press
    @ <input type="submit" value="Leave Login Group" name="leave">
    @ </form></p>
    @ <br />For best results, use the same number of <a href="setup_access#ipt">
    @ IP octets</a> in the login cookie across all repositories in the
    @ same Login Group.
    @ <hr /><h2>Implementation Details</h2>
    @ <p>The following are fields from the CONFIG table related to login-groups,
    @ provided here for instructional and debugging purposes:</p>
    @ <table border='1' class='sortable' data-column-types='ttt' \
    @ data-init-sort='1'>
    @ <thead><tr>
    @ <th>Config.Name<th>Config.Value<th>Config.mtime</tr>







<
<
<







680
681
682
683
684
685
686



687
688
689
690
691
692
693
    @ </table>
    @
    @ <p><form action="%R/setup_login_group" method="post"><div>
    login_insert_csrf_secret();
    @ To leave this login group press
    @ <input type="submit" value="Leave Login Group" name="leave">
    @ </form></p>



    @ <hr /><h2>Implementation Details</h2>
    @ <p>The following are fields from the CONFIG table related to login-groups,
    @ provided here for instructional and debugging purposes:</p>
    @ <table border='1' class='sortable' data-column-types='ttt' \
    @ data-init-sort='1'>
    @ <thead><tr>
    @ <th>Config.Name<th>Config.Value<th>Config.mtime</tr>
Changes to src/shell.c.
649
650
651
652
653
654
655

656

657

658

659











660
661
662
663
664



665

666
667
668


669
670
671
672
673
674
675
  while( *z ){
    if( (0xc0&*(z++))!=0x80 ) n++;
  }
  return n;
}

/*

** Return true if zFile does not exist or if it is not an ordinary file.

*/

#ifdef _WIN32

# define notNormalFile(X) 0











#else
static int notNormalFile(const char *zFile){
  struct stat x;
  int rc;
  memset(&x, 0, sizeof(x));



  rc = stat(zFile, &x);

  return rc || !S_ISREG(x.st_mode);
}
#endif



/*
** This routine reads a line of text from FILE in, stores
** the text in memory obtained from malloc() and returns a pointer
** to the text.  NULL is returned at end of file, or if malloc()
** fails.
**







>
|
>

>

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

<
|
|
<
>
>
>
|
>
|
|

>
>







649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675

676
677

678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
  while( *z ){
    if( (0xc0&*(z++))!=0x80 ) n++;
  }
  return n;
}

/*
** Return open FILE * if zFile exists, can be opened for read
** and is an ordinary file or a character stream source.
** Otherwise return 0.
*/
static FILE * openChrSource(const char *zFile){
#ifdef _WIN32
  struct _stat x = {0};
# define STAT_CHR_SRC(mode) ((mode & (_S_IFCHR|_S_IFIFO|_S_IFREG))!=0)
  /* On Windows, open first, then check the stream nature. This order
  ** is necessary because _stat() and sibs, when checking a named pipe,
  ** effectively break the pipe as its supplier sees it. */
  FILE *rv = fopen(zFile, "rb");
  if( rv==0 ) return 0;
  if( _fstat(_fileno(rv), &x) != 0
      || !STAT_CHR_SRC(x.st_mode)){
    fclose(rv);
    rv = 0;
  }
  return rv;
#else

  struct stat x = {0};
  int rc = stat(zFile, &x);

# define STAT_CHR_SRC(mode) (S_ISREG(mode)||S_ISFIFO(mode)||S_ISCHR(mode))
  if( rc!=0 ) return 0;
  if( STAT_CHR_SRC(x.st_mode) ){
    return fopen(zFile, "rb");
  }else{
    return 0;
  }
#endif
#undef STAT_CHR_SRC
}

/*
** This routine reads a line of text from FILE in, stores
** the text in memory obtained from malloc() and returns a pointer
** to the text.  NULL is returned at end of file, or if malloc()
** fails.
**
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
  if( quote ){
    len += 2;
    for(i=0; i<nAppend; i++){
      if( zAppend[i]==quote ) len++;
    }
  }

  if( p->n+len>=p->nAlloc ){
    p->nAlloc = p->nAlloc*2 + len + 20;
    p->z = realloc(p->z, p->nAlloc);
    if( p->z==0 ) shell_out_of_memory();
  }

  if( quote ){
    char *zCsr = p->z+p->n;







|







870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
  if( quote ){
    len += 2;
    for(i=0; i<nAppend; i++){
      if( zAppend[i]==quote ) len++;
    }
  }

  if( p->z==0 || p->n+len>=p->nAlloc ){
    p->nAlloc = p->nAlloc*2 + len + 20;
    p->z = realloc(p->z, p->nAlloc);
    if( p->z==0 ) shell_out_of_memory();
  }

  if( quote ){
    char *zCsr = p->z+p->n;
2200
2201
2202
2203
2204
2205
2206





2207
2208
2209
2210
2211
2212
2213
**            symlink, a text value containing the text of the link. For a
**            directory, NULL.
**
**   If a non-NULL value is specified for the optional $dir parameter and
**   $path is a relative path, then $path is interpreted relative to $dir. 
**   And the paths returned in the "name" column of the table are also 
**   relative to directory $dir.





*/
/* #include "sqlite3ext.h" */
SQLITE_EXTENSION_INIT1
#include <stdio.h>
#include <string.h>
#include <assert.h>








>
>
>
>
>







2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
**            symlink, a text value containing the text of the link. For a
**            directory, NULL.
**
**   If a non-NULL value is specified for the optional $dir parameter and
**   $path is a relative path, then $path is interpreted relative to $dir. 
**   And the paths returned in the "name" column of the table are also 
**   relative to directory $dir.
**
** Notes on building this extension for Windows:
**   Unless linked statically with the SQLite library, a preprocessor
**   symbol, FILEIO_WIN32_DLL, must be #define'd to create a stand-alone
**   DLL form of this extension for WIN32. See its use below for details.
*/
/* #include "sqlite3ext.h" */
SQLITE_EXTENSION_INIT1
#include <stdio.h>
#include <string.h>
#include <assert.h>

2353
2354
2355
2356
2357
2358
2359
















2360
2361
2362
2363
2364
2365
2366

  fileIntervals.LowPart = pFileTime->dwLowDateTime;
  fileIntervals.HighPart = pFileTime->dwHighDateTime;

  return (fileIntervals.QuadPart - epochIntervals.QuadPart) / 10000000;
}

















/*
** This function attempts to normalize the time values found in the stat()
** buffer to UTC.  This is necessary on Win32, where the runtime library
** appears to return these values as local times.
*/
static void statTimesToUtc(
  const char *zPath,







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







2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406

  fileIntervals.LowPart = pFileTime->dwLowDateTime;
  fileIntervals.HighPart = pFileTime->dwHighDateTime;

  return (fileIntervals.QuadPart - epochIntervals.QuadPart) / 10000000;
}


#if defined(FILEIO_WIN32_DLL) && (defined(_WIN32) || defined(WIN32))
#  /* To allow a standalone DLL, use this next replacement function: */
#  undef sqlite3_win32_utf8_to_unicode
#  define sqlite3_win32_utf8_to_unicode utf8_to_utf16
#
LPWSTR utf8_to_utf16(const char *z){
  int nAllot = MultiByteToWideChar(CP_UTF8, 0, z, -1, NULL, 0);
  LPWSTR rv = sqlite3_malloc(nAllot * sizeof(WCHAR));
  if( rv!=0 && 0 < MultiByteToWideChar(CP_UTF8, 0, z, -1, rv, nAllot) )
    return rv;
  sqlite3_free(rv);
  return 0;
}
#endif

/*
** This function attempts to normalize the time values found in the stat()
** buffer to UTC.  This is necessary on Win32, where the runtime library
** appears to return these values as local times.
*/
static void statTimesToUtc(
  const char *zPath,
3126
3127
3128
3129
3130
3131
3132








3133
3134
3135
3136
3137
3138
3139
                                 lsModeFunc, 0, 0);
  }
  if( rc==SQLITE_OK ){
    rc = fsdirRegister(db);
  }
  return rc;
}









/************************* End ../ext/misc/fileio.c ********************/
/************************* Begin ../ext/misc/completion.c ******************/
/*
** 2017-07-10
**
** The author disclaims copyright to this source code.  In place of







>
>
>
>
>
>
>
>







3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
                                 lsModeFunc, 0, 0);
  }
  if( rc==SQLITE_OK ){
    rc = fsdirRegister(db);
  }
  return rc;
}

#if defined(FILEIO_WIN32_DLL) && (defined(_WIN32) || defined(WIN32))
/* To allow a standalone DLL, make test_windirent.c use the same
 * redefined SQLite API calls as the above extension code does.
 * Just pull in this .c to accomplish this. As a beneficial side
 * effect, this extension becomes a single translation unit. */
#  include "test_windirent.c"
#endif

/************************* End ../ext/misc/fileio.c ********************/
/************************* Begin ../ext/misc/completion.c ******************/
/*
** 2017-07-10
**
** The author disclaims copyright to this source code.  In place of
5348
5349
5350
5351
5352
5353
5354



5355

5356
5357
5358
5359
5360
5361
5362
    while( m!=0 && ((m>>32)&0xfff00000)==0 ){
      m <<= 1;
      e--;
    }
    e += 1075;
    if( e<=0 ){
      /* Subnormal */



      m >>= 1-e;

      e = 0;
    }else if( e>0x7ff ){
      e = 0x7ff;
    }
    a = m & ((((sqlite3_int64)1)<<52)-1);
    a |= e<<52;
    if( isNeg ) a |= ((sqlite3_uint64)1)<<63;







>
>
>
|
>







5396
5397
5398
5399
5400
5401
5402
5403
5404
5405
5406
5407
5408
5409
5410
5411
5412
5413
5414
    while( m!=0 && ((m>>32)&0xfff00000)==0 ){
      m <<= 1;
      e--;
    }
    e += 1075;
    if( e<=0 ){
      /* Subnormal */
      if( 1-e >= 64 ){
        m = 0;
      }else{
        m >>= 1-e;
      }
      e = 0;
    }else if( e>0x7ff ){
      e = 0x7ff;
    }
    a = m & ((((sqlite3_int64)1)<<52)-1);
    a |= e<<52;
    if( isNeg ) a |= ((sqlite3_uint64)1)<<63;
5894
5895
5896
5897
5898
5899
5900
5901
5902
5903
5904
5905
5906
5907
5908
  sqlite3 *db, 
  char **pzErrMsg, 
  const sqlite3_api_routines *pApi
){
  int rc = SQLITE_OK;
  SQLITE_EXTENSION_INIT2(pApi);
#ifndef SQLITE_OMIT_VIRTUALTABLE
  if( sqlite3_libversion_number()<3008012 ){
    *pzErrMsg = sqlite3_mprintf(
        "generate_series() requires SQLite 3.8.12 or later");
    return SQLITE_ERROR;
  }
  rc = sqlite3_create_module(db, "generate_series", &seriesModule, 0);
#endif
  return rc;







|







5946
5947
5948
5949
5950
5951
5952
5953
5954
5955
5956
5957
5958
5959
5960
  sqlite3 *db, 
  char **pzErrMsg, 
  const sqlite3_api_routines *pApi
){
  int rc = SQLITE_OK;
  SQLITE_EXTENSION_INIT2(pApi);
#ifndef SQLITE_OMIT_VIRTUALTABLE
  if( sqlite3_libversion_number()<3008012 && pzErrMsg!=0 ){
    *pzErrMsg = sqlite3_mprintf(
        "generate_series() requires SQLite 3.8.12 or later");
    return SQLITE_ERROR;
  }
  rc = sqlite3_create_module(db, "generate_series", &seriesModule, 0);
#endif
  return rc;
6207
6208
6209
6210
6211
6212
6213
6214
6215
6216
6217
6218
6219
6220
6221
6222
6223
        }
        case RE_OP_ACCEPT: {
          rc = 1;
          goto re_match_end;
        }
        case RE_OP_CC_EXC: {
          if( c==0 ) break;
          /* fall-through */
        }
        case RE_OP_CC_INC: {
          int j = 1;
          int n = pRe->aArg[x];
          int hit = 0;
          for(j=1; j>0 && j<n; j++){
            if( pRe->aOp[x+j]==RE_OP_CC_VALUE ){
              if( pRe->aArg[x+j]==c ){
                hit = 1;







|

|







6259
6260
6261
6262
6263
6264
6265
6266
6267
6268
6269
6270
6271
6272
6273
6274
6275
        }
        case RE_OP_ACCEPT: {
          rc = 1;
          goto re_match_end;
        }
        case RE_OP_CC_EXC: {
          if( c==0 ) break;
          /* fall-through */ goto re_op_cc_inc;
        }
        case RE_OP_CC_INC: re_op_cc_inc: {
          int j = 1;
          int n = pRe->aArg[x];
          int hit = 0;
          for(j=1; j>0 && j<n; j++){
            if( pRe->aOp[x+j]==RE_OP_CC_VALUE ){
              if( pRe->aArg[x+j]==c ){
                hit = 1;
6740
6741
6742
6743
6744
6745
6746



6747
6748
6749
6750
6751
6752
6753
/* typedef sqlite3_int64 i64; */
/* typedef unsigned char u8; */
typedef UINT32_TYPE u32;           /* 4-byte unsigned integer */
typedef UINT16_TYPE u16;           /* 2-byte unsigned integer */
#define MIN(a,b) ((a)<(b) ? (a) : (b))

#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST)



# define ALWAYS(X)      (1)
# define NEVER(X)       (0)
#elif !defined(NDEBUG)
# define ALWAYS(X)      ((X)?1:(assert(0),0))
# define NEVER(X)       ((X)?(assert(0),1):0)
#else
# define ALWAYS(X)      (X)







>
>
>







6792
6793
6794
6795
6796
6797
6798
6799
6800
6801
6802
6803
6804
6805
6806
6807
6808
/* typedef sqlite3_int64 i64; */
/* typedef unsigned char u8; */
typedef UINT32_TYPE u32;           /* 4-byte unsigned integer */
typedef UINT16_TYPE u16;           /* 2-byte unsigned integer */
#define MIN(a,b) ((a)<(b) ? (a) : (b))

#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST)
# define SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS 1
#endif
#if defined(SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS)
# define ALWAYS(X)      (1)
# define NEVER(X)       (0)
#elif !defined(NDEBUG)
# define ALWAYS(X)      ((X)?1:(assert(0),0))
# define NEVER(X)       ((X)?(assert(0),1):0)
#else
# define ALWAYS(X)      (X)
7244
7245
7246
7247
7248
7249
7250

7251
7252
7253
7254
7255
7256
7257
  return (aBuf[1] << 8) + aBuf[0];
}

/*
** Read and return a 32-bit little-endian unsigned integer from buffer aBuf.
*/
static u32 zipfileGetU32(const u8 *aBuf){

  return ((u32)(aBuf[3]) << 24)
       + ((u32)(aBuf[2]) << 16)
       + ((u32)(aBuf[1]) <<  8)
       + ((u32)(aBuf[0]) <<  0);
}

/*







>







7299
7300
7301
7302
7303
7304
7305
7306
7307
7308
7309
7310
7311
7312
7313
  return (aBuf[1] << 8) + aBuf[0];
}

/*
** Read and return a 32-bit little-endian unsigned integer from buffer aBuf.
*/
static u32 zipfileGetU32(const u8 *aBuf){
  if( aBuf==0 ) return 0;
  return ((u32)(aBuf[3]) << 24)
       + ((u32)(aBuf[2]) << 16)
       + ((u32)(aBuf[1]) <<  8)
       + ((u32)(aBuf[0]) <<  0);
}

/*
7546
7547
7548
7549
7550
7551
7552
7553
7554
7555
7556
7557
7558
7559
7560
      ZipfileLFH lfh;
      if( pFile ){
        rc = zipfileReadData(pFile, aRead, szFix, pNew->cds.iOffset, pzErr);
      }else{
        aRead = (u8*)&aBlob[pNew->cds.iOffset];
      }

      rc = zipfileReadLFH(aRead, &lfh);
      if( rc==SQLITE_OK ){
        pNew->iDataOff =  pNew->cds.iOffset + ZIPFILE_LFH_FIXED_SZ;
        pNew->iDataOff += lfh.nFile + lfh.nExtra;
        if( aBlob && pNew->cds.szCompressed ){
          pNew->aData = &pNew->aExtra[nExtra];
          memcpy(pNew->aData, &aBlob[pNew->iDataOff], pNew->cds.szCompressed);
        }







|







7602
7603
7604
7605
7606
7607
7608
7609
7610
7611
7612
7613
7614
7615
7616
      ZipfileLFH lfh;
      if( pFile ){
        rc = zipfileReadData(pFile, aRead, szFix, pNew->cds.iOffset, pzErr);
      }else{
        aRead = (u8*)&aBlob[pNew->cds.iOffset];
      }

      if( rc==SQLITE_OK ) rc = zipfileReadLFH(aRead, &lfh);
      if( rc==SQLITE_OK ){
        pNew->iDataOff =  pNew->cds.iOffset + ZIPFILE_LFH_FIXED_SZ;
        pNew->iDataOff += lfh.nFile + lfh.nExtra;
        if( aBlob && pNew->cds.szCompressed ){
          pNew->aData = &pNew->aExtra[nExtra];
          memcpy(pNew->aData, &aBlob[pNew->iDataOff], pNew->cds.szCompressed);
        }
7822
7823
7824
7825
7826
7827
7828

7829
7830
7831
7832
7833
7834
7835
7836
7837
7838
7839
7840
7841
7842
  FILE *pFile,                    /* Read from this file if aBlob==0 */
  ZipfileEOCD *pEOCD              /* Object to populate */
){
  u8 *aRead = pTab->aBuffer;      /* Temporary buffer */
  int nRead;                      /* Bytes to read from file */
  int rc = SQLITE_OK;


  if( aBlob==0 ){
    i64 iOff;                     /* Offset to read from */
    i64 szFile;                   /* Total size of file in bytes */
    fseek(pFile, 0, SEEK_END);
    szFile = (i64)ftell(pFile);
    if( szFile==0 ){
      memset(pEOCD, 0, sizeof(ZipfileEOCD));
      return SQLITE_OK;
    }
    nRead = (int)(MIN(szFile, ZIPFILE_BUFFER_SIZE));
    iOff = szFile - nRead;
    rc = zipfileReadData(pFile, aRead, nRead, iOff, &pTab->base.zErrMsg);
  }else{
    nRead = (int)(MIN(nBlob, ZIPFILE_BUFFER_SIZE));







>






<







7878
7879
7880
7881
7882
7883
7884
7885
7886
7887
7888
7889
7890
7891

7892
7893
7894
7895
7896
7897
7898
  FILE *pFile,                    /* Read from this file if aBlob==0 */
  ZipfileEOCD *pEOCD              /* Object to populate */
){
  u8 *aRead = pTab->aBuffer;      /* Temporary buffer */
  int nRead;                      /* Bytes to read from file */
  int rc = SQLITE_OK;

  memset(pEOCD, 0, sizeof(ZipfileEOCD));
  if( aBlob==0 ){
    i64 iOff;                     /* Offset to read from */
    i64 szFile;                   /* Total size of file in bytes */
    fseek(pFile, 0, SEEK_END);
    szFile = (i64)ftell(pFile);
    if( szFile==0 ){

      return SQLITE_OK;
    }
    nRead = (int)(MIN(szFile, ZIPFILE_BUFFER_SIZE));
    iOff = szFile - nRead;
    rc = zipfileReadData(pFile, aRead, nRead, iOff, &pTab->base.zErrMsg);
  }else{
    nRead = (int)(MIN(nBlob, ZIPFILE_BUFFER_SIZE));
9198
9199
9200
9201
9202
9203
9204

















9205
9206
9207
9208
9209
9210
9211
**
*************************************************************************
*/
/* #include "sqlite3expert.h" */
#include <assert.h>
#include <string.h>
#include <stdio.h>


















#ifndef SQLITE_OMIT_VIRTUALTABLE 

/* typedef sqlite3_int64 i64; */
/* typedef sqlite3_uint64 u64; */

typedef struct IdxColumn IdxColumn;







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







9254
9255
9256
9257
9258
9259
9260
9261
9262
9263
9264
9265
9266
9267
9268
9269
9270
9271
9272
9273
9274
9275
9276
9277
9278
9279
9280
9281
9282
9283
9284
**
*************************************************************************
*/
/* #include "sqlite3expert.h" */
#include <assert.h>
#include <string.h>
#include <stdio.h>

#if !defined(SQLITE_AMALGAMATION)
#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST)
# define SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS 1
#endif
#if defined(SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS)
# define ALWAYS(X)      (1)
# define NEVER(X)       (0)
#elif !defined(NDEBUG)
# define ALWAYS(X)      ((X)?1:(assert(0),0))
# define NEVER(X)       ((X)?(assert(0),1):0)
#else
# define ALWAYS(X)      (X)
# define NEVER(X)       (X)
#endif
#endif /* !defined(SQLITE_AMALGAMATION) */


#ifndef SQLITE_OMIT_VIRTUALTABLE 

/* typedef sqlite3_int64 i64; */
/* typedef sqlite3_uint64 u64; */

typedef struct IdxColumn IdxColumn;
9925
9926
9927
9928
9929
9930
9931
9932
9933
9934
9935
9936
9937
9938
9939
9940
9941
    nCol++;
  }
  idxFinalize(&rc, p1);

  if( rc!=SQLITE_OK ){
    sqlite3_free(pNew);
    pNew = 0;
  }else{
    pNew->zName = pCsr;
    memcpy(pNew->zName, zTab, nTab+1);
  }

  *ppOut = pNew;
  return rc;
}

/*







|

|







9998
9999
10000
10001
10002
10003
10004
10005
10006
10007
10008
10009
10010
10011
10012
10013
10014
    nCol++;
  }
  idxFinalize(&rc, p1);

  if( rc!=SQLITE_OK ){
    sqlite3_free(pNew);
    pNew = 0;
  }else if( ALWAYS(pNew!=0) ){
    pNew->zName = pCsr;
    if( ALWAYS(pNew->zName!=0) ) memcpy(pNew->zName, zTab, nTab+1);
  }

  *ppOut = pNew;
  return rc;
}

/*
10097
10098
10099
10100
10101
10102
10103













10104
10105
10106
10107
10108
10109
10110
    }
  }
  idxFinalize(&rc, pIdxList);

  *pRc = rc;
  return 0;
}














static int idxCreateFromCons(
  sqlite3expert *p,
  IdxScan *pScan,
  IdxConstraint *pEq, 
  IdxConstraint *pTail
){







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







10170
10171
10172
10173
10174
10175
10176
10177
10178
10179
10180
10181
10182
10183
10184
10185
10186
10187
10188
10189
10190
10191
10192
10193
10194
10195
10196
    }
  }
  idxFinalize(&rc, pIdxList);

  *pRc = rc;
  return 0;
}

/* Callback for sqlite3_exec() with query with leading count(*) column.
 * The first argument is expected to be an int*, referent to be incremented
 * if that leading column is not exactly '0'.
 */
static int countNonzeros(void* pCount, int nc,
                         char* azResults[], char* azColumns[]){
  (void)azColumns;  /* Suppress unused parameter warning */
  if( nc>0 && (azResults[0][0]!='0' || azResults[0][1]!=0) ){
    *((int *)pCount) += 1;
  }
  return 0;
}

static int idxCreateFromCons(
  sqlite3expert *p,
  IdxScan *pScan,
  IdxConstraint *pEq, 
  IdxConstraint *pTail
){
10124
10125
10126
10127
10128
10129
10130

10131


10132

10133
10134
10135

10136
10137


















10138
10139
10140
10141
10142
10143
10144
10145
10146
10147
10148
10149



10150

10151
10152
10153
10154
10155
10156
10157
    for(pCons=pTail; pCons; pCons=pCons->pLink){
      zCols = idxAppendColDefn(&rc, zCols, pTab, pCons);
    }

    if( rc==SQLITE_OK ){
      /* Hash the list of columns to come up with a name for the index */
      const char *zTable = pScan->pTab->zName;

      char *zName;                /* Index name */


      int i;

      for(i=0; zCols[i]; i++){
        h += ((h<<3) + zCols[i]);
      }

      zName = sqlite3_mprintf("%s_idx_%08x", zTable, h);
      if( zName==0 ){ 


















        rc = SQLITE_NOMEM;
      }else{
        if( idxIdentifierRequiresQuotes(zTable) ){
          zFmt = "CREATE INDEX '%q' ON %Q(%s)";
        }else{
          zFmt = "CREATE INDEX %s ON %s(%s)";
        }
        zIdx = sqlite3_mprintf(zFmt, zName, zTable, zCols);
        if( !zIdx ){
          rc = SQLITE_NOMEM;
        }else{
          rc = sqlite3_exec(dbm, zIdx, 0, 0, p->pzErrmsg);



          idxHashAdd(&rc, &p->hIdx, zName, zIdx);

        }
        sqlite3_free(zName);
        sqlite3_free(zIdx);
      }
    }

    sqlite3_free(zCols);







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


|
|








>
>
>
|
>







10210
10211
10212
10213
10214
10215
10216
10217
10218
10219
10220
10221
10222
10223
10224
10225
10226
10227
10228
10229
10230
10231
10232
10233
10234
10235
10236
10237
10238
10239
10240
10241
10242
10243
10244
10245
10246
10247
10248
10249
10250
10251
10252
10253
10254
10255
10256
10257
10258
10259
10260
10261
10262
10263
10264
10265
10266
10267
10268
10269
10270
    for(pCons=pTail; pCons; pCons=pCons->pLink){
      zCols = idxAppendColDefn(&rc, zCols, pTab, pCons);
    }

    if( rc==SQLITE_OK ){
      /* Hash the list of columns to come up with a name for the index */
      const char *zTable = pScan->pTab->zName;
      int quoteTable = idxIdentifierRequiresQuotes(zTable);
      char *zName = 0;          /* Index name */
      int collisions = 0;
      do{
        int i;
        char *zFind;
        for(i=0; zCols[i]; i++){
          h += ((h<<3) + zCols[i]);
        }
        sqlite3_free(zName);
        zName = sqlite3_mprintf("%s_idx_%08x", zTable, h);
        if( zName==0 ) break;
        /* Is is unique among table, view and index names? */
        zFmt = "SELECT count(*) FROM sqlite_schema WHERE name=%Q"
          " AND type in ('index','table','view')";
        zFind = sqlite3_mprintf(zFmt, zName);
        i = 0;
        rc = sqlite3_exec(dbm, zFind, countNonzeros, &i, 0);
        assert(rc==SQLITE_OK);
        sqlite3_free(zFind);
        if( i==0 ){
          collisions = 0;
          break;
        }
        ++collisions;
      }while( collisions<50 && zName!=0 );
      if( collisions ){
        /* This return means "Gave up trying to find a unique index name." */
        rc = SQLITE_BUSY_TIMEOUT;
      }else if( zName==0 ){
        rc = SQLITE_NOMEM;
      }else{
        if( quoteTable ){
          zFmt = "CREATE INDEX \"%w\" ON \"%w\"(%s)";
        }else{
          zFmt = "CREATE INDEX %s ON %s(%s)";
        }
        zIdx = sqlite3_mprintf(zFmt, zName, zTable, zCols);
        if( !zIdx ){
          rc = SQLITE_NOMEM;
        }else{
          rc = sqlite3_exec(dbm, zIdx, 0, 0, p->pzErrmsg);
          if( rc!=SQLITE_OK ){
            rc = SQLITE_BUSY_TIMEOUT;
          }else{
            idxHashAdd(&rc, &p->hIdx, zName, zIdx);
          }
        }
        sqlite3_free(zName);
        sqlite3_free(zIdx);
      }
    }

    sqlite3_free(zCols);
11067
11068
11069
11070
11071
11072
11073




11074
11075
11076
11077
11078
11079
11080

  /* Do trigger processing to collect any extra IdxScan structures */
  rc = idxProcessTriggers(p, pzErr);

  /* Create candidate indexes within the in-memory database file */
  if( rc==SQLITE_OK ){
    rc = idxCreateCandidates(p);




  }

  /* Generate the stat1 data */
  if( rc==SQLITE_OK ){
    rc = idxPopulateStat1(p, pzErr);
  }








>
>
>
>







11180
11181
11182
11183
11184
11185
11186
11187
11188
11189
11190
11191
11192
11193
11194
11195
11196
11197

  /* Do trigger processing to collect any extra IdxScan structures */
  rc = idxProcessTriggers(p, pzErr);

  /* Create candidate indexes within the in-memory database file */
  if( rc==SQLITE_OK ){
    rc = idxCreateCandidates(p);
  }else if ( rc==SQLITE_BUSY_TIMEOUT ){
    if( pzErr )
      *pzErr = sqlite3_mprintf("Cannot find a unique index name to propose.");
    return rc;
  }

  /* Generate the stat1 data */
  if( rc==SQLITE_OK ){
    rc = idxPopulateStat1(p, pzErr);
  }

12060
12061
12062
12063
12064
12065
12066


12067
12068
12069
12070
12071
12072
12073
  u8 autoEQPtest;        /* autoEQP is in test mode */
  u8 autoEQPtrace;       /* autoEQP is in trace mode */
  u8 scanstatsOn;        /* True to display scan stats before each finalize */
  u8 openMode;           /* SHELL_OPEN_NORMAL, _APPENDVFS, or _ZIPFILE */
  u8 doXdgOpen;          /* Invoke start/open/xdg-open in output_reset() */
  u8 nEqpLevel;          /* Depth of the EQP output graph */
  u8 eTraceType;         /* SHELL_TRACE_* value for type of trace */


  unsigned statsOn;      /* True to display memory stats before each finalize */
  unsigned mEqpLines;    /* Mask of veritical lines in the EQP output graph */
  int outCount;          /* Revert to stdout when reaching zero */
  int cnt;               /* Number of records displayed so far */
  int lineno;            /* Line number of last line read from in */
  int openFlags;         /* Additional flags to open.  (SQLITE_OPEN_NOFOLLOW) */
  FILE *in;              /* Read commands from this stream */







>
>







12177
12178
12179
12180
12181
12182
12183
12184
12185
12186
12187
12188
12189
12190
12191
12192
  u8 autoEQPtest;        /* autoEQP is in test mode */
  u8 autoEQPtrace;       /* autoEQP is in trace mode */
  u8 scanstatsOn;        /* True to display scan stats before each finalize */
  u8 openMode;           /* SHELL_OPEN_NORMAL, _APPENDVFS, or _ZIPFILE */
  u8 doXdgOpen;          /* Invoke start/open/xdg-open in output_reset() */
  u8 nEqpLevel;          /* Depth of the EQP output graph */
  u8 eTraceType;         /* SHELL_TRACE_* value for type of trace */
  u8 bSafeMode;          /* True to prohibit unsafe operations */
  u8 bSafeModePersist;   /* The long-term value of bSafeMode */
  unsigned statsOn;      /* True to display memory stats before each finalize */
  unsigned mEqpLines;    /* Mask of veritical lines in the EQP output graph */
  int outCount;          /* Revert to stdout when reaching zero */
  int cnt;               /* Number of records displayed so far */
  int lineno;            /* Line number of last line read from in */
  int openFlags;         /* Additional flags to open.  (SQLITE_OPEN_NOFOLLOW) */
  FILE *in;              /* Read commands from this stream */
12111
12112
12113
12114
12115
12116
12117

12118
12119
12120
12121
12122
12123
12124
12125
12126
    OpenSession aSession[4];   /* Array of sessions.  [0] is in focus. */
#endif
  } aAuxDb[5],           /* Array of all database connections */
    *pAuxDb;             /* Currently active database connection */
  int *aiIndent;         /* Array of indents used in MODE_Explain */
  int nIndent;           /* Size of array aiIndent[] */
  int iIndent;           /* Index of current op in aiIndent[] */

  EQPGraph sGraph;       /* Information for the graphical EXPLAIN QUERY PLAN */
  ExpertInfo expert;        /* Valid if previous command was ".expert OPT..." */
};


/* Allowed values for ShellState.autoEQP
*/
#define AUTOEQP_off      0           /* Automatic EXPLAIN QUERY PLAN is off */
#define AUTOEQP_on       1           /* Automatic EQP is on */







>

|







12230
12231
12232
12233
12234
12235
12236
12237
12238
12239
12240
12241
12242
12243
12244
12245
12246
    OpenSession aSession[4];   /* Array of sessions.  [0] is in focus. */
#endif
  } aAuxDb[5],           /* Array of all database connections */
    *pAuxDb;             /* Currently active database connection */
  int *aiIndent;         /* Array of indents used in MODE_Explain */
  int nIndent;           /* Size of array aiIndent[] */
  int iIndent;           /* Index of current op in aiIndent[] */
  char *zNonce;          /* Nonce for temporary safe-mode excapes */
  EQPGraph sGraph;       /* Information for the graphical EXPLAIN QUERY PLAN */
  ExpertInfo expert;     /* Valid if previous command was ".expert OPT..." */
};


/* Allowed values for ShellState.autoEQP
*/
#define AUTOEQP_off      0           /* Automatic EXPLAIN QUERY PLAN is off */
#define AUTOEQP_on       1           /* Automatic EQP is on */
12156
12157
12158
12159
12160
12161
12162
12163
12164
12165
12166
12167
12168
12169
12170
#define SHFLG_Pagecache      0x00000001 /* The --pagecache option is used */
#define SHFLG_Lookaside      0x00000002 /* Lookaside memory is used */
#define SHFLG_Backslash      0x00000004 /* The --backslash option is used */
#define SHFLG_PreserveRowid  0x00000008 /* .dump preserves rowid values */
#define SHFLG_Newlines       0x00000010 /* .dump --newline flag */
#define SHFLG_CountChanges   0x00000020 /* .changes setting */
#define SHFLG_Echo           0x00000040 /* .echo or --echo setting */
#define SHFLG_HeaderSet      0x00000080 /* .header has been used */
#define SHFLG_DumpDataOnly   0x00000100 /* .dump show data only */
#define SHFLG_DumpNoSys      0x00000200 /* .dump omits system tables */

/*
** Macros for testing and setting shellFlgs
*/
#define ShellHasFlag(P,X)    (((P)->shellFlgs & (X))!=0)







|







12276
12277
12278
12279
12280
12281
12282
12283
12284
12285
12286
12287
12288
12289
12290
#define SHFLG_Pagecache      0x00000001 /* The --pagecache option is used */
#define SHFLG_Lookaside      0x00000002 /* Lookaside memory is used */
#define SHFLG_Backslash      0x00000004 /* The --backslash option is used */
#define SHFLG_PreserveRowid  0x00000008 /* .dump preserves rowid values */
#define SHFLG_Newlines       0x00000010 /* .dump --newline flag */
#define SHFLG_CountChanges   0x00000020 /* .changes setting */
#define SHFLG_Echo           0x00000040 /* .echo or --echo setting */
#define SHFLG_HeaderSet      0x00000080 /* showHeader has been specified */
#define SHFLG_DumpDataOnly   0x00000100 /* .dump show data only */
#define SHFLG_DumpNoSys      0x00000200 /* .dump omits system tables */

/*
** Macros for testing and setting shellFlgs
*/
#define ShellHasFlag(P,X)    (((P)->shellFlgs & (X))!=0)
12247
12248
12249
12250
12251
12252
12253





















12254
12255
12256
12257
12258
12259
12260
  sqlite3_value **apVal
){
  ShellState *p = (ShellState*)sqlite3_user_data(pCtx);
  (void)nVal;
  utf8_printf(p->out, "%s\n", sqlite3_value_text(apVal[0]));
  sqlite3_result_value(pCtx, apVal[0]);
}






















/*
** SQL function:   edit(VALUE)
**                 edit(VALUE,EDITOR)
**
** These steps:
**







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







12367
12368
12369
12370
12371
12372
12373
12374
12375
12376
12377
12378
12379
12380
12381
12382
12383
12384
12385
12386
12387
12388
12389
12390
12391
12392
12393
12394
12395
12396
12397
12398
12399
12400
12401
  sqlite3_value **apVal
){
  ShellState *p = (ShellState*)sqlite3_user_data(pCtx);
  (void)nVal;
  utf8_printf(p->out, "%s\n", sqlite3_value_text(apVal[0]));
  sqlite3_result_value(pCtx, apVal[0]);
}

/*
** If in safe mode, print an error message described by the arguments
** and exit immediately.
*/
static void failIfSafeMode(
  ShellState *p,
  const char *zErrMsg,
  ...
){
  if( p->bSafeMode ){
    va_list ap;
    char *zMsg;
    va_start(ap, zErrMsg);
    zMsg = sqlite3_vmprintf(zErrMsg, ap);
    va_end(ap);
    raw_printf(stderr, "line %d: ", p->lineno);
    utf8_printf(stderr, "%s\n", zMsg);
    exit(1);
  }
}

/*
** SQL function:   edit(VALUE)
**                 edit(VALUE,EDITOR)
**
** These steps:
**
12368
12369
12370
12371
12372
12373
12374
12375
12376
12377
12378
12379
12380
12381
12382
  }
  if( bBin ){
    sqlite3_result_blob64(context, p, sz, sqlite3_free);
  }else{
    sqlite3_int64 i, j;
    if( hasCRNL ){
      /* If the original contains \r\n then do no conversions back to \n */
      j = sz;
    }else{
      /* If the file did not originally contain \r\n then convert any new
      ** \r\n back into \n */
      for(i=j=0; i<sz; i++){
        if( p[i]=='\r' && p[i+1]=='\n' ) i++;
        p[j++] = p[i];
      }







<







12509
12510
12511
12512
12513
12514
12515

12516
12517
12518
12519
12520
12521
12522
  }
  if( bBin ){
    sqlite3_result_blob64(context, p, sz, sqlite3_free);
  }else{
    sqlite3_int64 i, j;
    if( hasCRNL ){
      /* If the original contains \r\n then do no conversions back to \n */

    }else{
      /* If the file did not originally contain \r\n then convert any new
      ** \r\n back into \n */
      for(i=j=0; i<sz; i++){
        if( p[i]=='\r' && p[i+1]=='\n' ) i++;
        p[j++] = p[i];
      }
12725
12726
12727
12728
12729
12730
12731











































12732
12733
12734
12735
12736
12737
12738
    return TRUE;
  }
  return FALSE;
}
#endif

#ifndef SQLITE_OMIT_AUTHORIZATION











































/*
** When the ".auth ON" is set, the following authorizer callback is
** invoked.  It always returns SQLITE_OK.
*/
static int shellAuth(
  void *pClientData,
  int op,







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







12865
12866
12867
12868
12869
12870
12871
12872
12873
12874
12875
12876
12877
12878
12879
12880
12881
12882
12883
12884
12885
12886
12887
12888
12889
12890
12891
12892
12893
12894
12895
12896
12897
12898
12899
12900
12901
12902
12903
12904
12905
12906
12907
12908
12909
12910
12911
12912
12913
12914
12915
12916
12917
12918
12919
12920
12921
    return TRUE;
  }
  return FALSE;
}
#endif

#ifndef SQLITE_OMIT_AUTHORIZATION
/*
** This authorizer runs in safe mode.
*/
static int safeModeAuth(
  void *pClientData,
  int op,
  const char *zA1,
  const char *zA2,
  const char *zA3,
  const char *zA4
){
  ShellState *p = (ShellState*)pClientData;
  static const char *azProhibitedFunctions[] = {
    "edit",
    "fts3_tokenizer",
    "load_extension",
    "readfile",
    "writefile",
    "zipfile",
    "zipfile_cds",
  };
  UNUSED_PARAMETER(zA2);
  UNUSED_PARAMETER(zA3);
  UNUSED_PARAMETER(zA4);
  switch( op ){
    case SQLITE_ATTACH: {
      failIfSafeMode(p, "cannot run ATTACH in safe mode");
      break;
    }
    case SQLITE_FUNCTION: {
      int i;
      for(i=0; i<ArraySize(azProhibitedFunctions); i++){
        if( sqlite3_stricmp(zA1, azProhibitedFunctions[i])==0 ){
          failIfSafeMode(p, "cannot use the %s() function in safe mode",
                         azProhibitedFunctions[i]);
        }
      }
      break;
    }
  }
  return SQLITE_OK;
}

/*
** When the ".auth ON" is set, the following authorizer callback is
** invoked.  It always returns SQLITE_OK.
*/
static int shellAuth(
  void *pClientData,
  int op,
12767
12768
12769
12770
12771
12772
12773

12774
12775
12776
12777
12778
12779
12780
    if( az[i] ){
      output_c_string(p->out, az[i]);
    }else{
      raw_printf(p->out, "NULL");
    }
  }
  raw_printf(p->out, "\n");

  return SQLITE_OK;
}
#endif

/*
** Print a schema statement.  Part of MODE_Semi and MODE_Pretty output.
**







>







12950
12951
12952
12953
12954
12955
12956
12957
12958
12959
12960
12961
12962
12963
12964
    if( az[i] ){
      output_c_string(p->out, az[i]);
    }else{
      raw_printf(p->out, "NULL");
    }
  }
  raw_printf(p->out, "\n");
  if( p->bSafeMode ) (void)safeModeAuth(pClientData, op, zA1, zA2, zA3, zA4);
  return SQLITE_OK;
}
#endif

/*
** Print a schema statement.  Part of MODE_Semi and MODE_Pretty output.
**
14053
14054
14055
14056
14057
14058
14059
14060
14061
14062
14063
14064
14065
14066
14067
14068
14069
      if( azData==0 ) shell_out_of_memory();
    }
    nRow++;
    for(i=0; i<nColumn; i++){
      z = (const char*)sqlite3_column_text(pStmt,i);
      azData[nRow*nColumn + i] = z ? strdup(z) : 0;
    }
  }while( (rc = sqlite3_step(pStmt))==SQLITE_ROW );
  if( nColumn>p->nWidth ){
    p->colWidth = realloc(p->colWidth, nColumn*2*sizeof(int));
    if( p->colWidth==0 ) shell_out_of_memory();
    for(i=p->nWidth; i<nColumn; i++) p->colWidth[i] = 0;
    p->nWidth = nColumn;
    p->actualWidth = &p->colWidth[nColumn];
  }
  memset(p->actualWidth, 0, nColumn*sizeof(int));
  for(i=0; i<nColumn; i++){







|

|







14237
14238
14239
14240
14241
14242
14243
14244
14245
14246
14247
14248
14249
14250
14251
14252
14253
      if( azData==0 ) shell_out_of_memory();
    }
    nRow++;
    for(i=0; i<nColumn; i++){
      z = (const char*)sqlite3_column_text(pStmt,i);
      azData[nRow*nColumn + i] = z ? strdup(z) : 0;
    }
  }while( sqlite3_step(pStmt)==SQLITE_ROW );
  if( nColumn>p->nWidth ){
    p->colWidth = realloc(p->colWidth, (nColumn+1)*2*sizeof(int));
    if( p->colWidth==0 ) shell_out_of_memory();
    for(i=p->nWidth; i<nColumn; i++) p->colWidth[i] = 0;
    p->nWidth = nColumn;
    p->actualWidth = &p->colWidth[nColumn];
  }
  memset(p->actualWidth, 0, nColumn*sizeof(int));
  for(i=0; i<nColumn; i++){
14197
14198
14199
14200
14201
14202
14203
14204
14205
14206
14207
14208
14209
14210
14211
  rc = sqlite3_step(pStmt);
  /* if we have a result set... */
  if( SQLITE_ROW == rc ){
    /* allocate space for col name ptr, value ptr, and type */
    int nCol = sqlite3_column_count(pStmt);
    void *pData = sqlite3_malloc64(3*nCol*sizeof(const char*) + 1);
    if( !pData ){
      rc = SQLITE_NOMEM;
    }else{
      char **azCols = (char **)pData;      /* Names of result columns */
      char **azVals = &azCols[nCol];       /* Results */
      int *aiTypes = (int *)&azVals[nCol]; /* Result types */
      int i, x;
      assert(sizeof(int) <= sizeof(char *));
      /* save off ptrs to column names */







|







14381
14382
14383
14384
14385
14386
14387
14388
14389
14390
14391
14392
14393
14394
14395
  rc = sqlite3_step(pStmt);
  /* if we have a result set... */
  if( SQLITE_ROW == rc ){
    /* allocate space for col name ptr, value ptr, and type */
    int nCol = sqlite3_column_count(pStmt);
    void *pData = sqlite3_malloc64(3*nCol*sizeof(const char*) + 1);
    if( !pData ){
      shell_out_of_memory();
    }else{
      char **azCols = (char **)pData;      /* Names of result columns */
      char **azVals = &azCols[nCol];       /* Results */
      int *aiTypes = (int *)&azVals[nCol]; /* Result types */
      int i, x;
      assert(sizeof(int) <= sizeof(char *));
      /* save off ptrs to column names */
14940
14941
14942
14943
14944
14945
14946

14947
14948
14949
14950
14951
14952
14953
  "     line      One value per line",
  "     list      Values delimited by \"|\"",
  "     markdown  Markdown table format",
  "     quote     Escape answers as for SQL",
  "     table     ASCII-art table",
  "     tabs      Tab-separated values",
  "     tcl       TCL list elements",

  ".nullvalue STRING        Use STRING in place of NULL values",
  ".once ?OPTIONS? ?FILE?   Output for the next SQL command only to FILE",
  "     If FILE begins with '|' then open as a pipe",
  "       --bom  Put a UTF8 byte-order mark at the beginning",
  "       -e     Send output to the system text editor",
  "       -x     Send output as CSV to a spreadsheet (same as \".excel\")",
#ifdef SQLITE_DEBUG







>







15124
15125
15126
15127
15128
15129
15130
15131
15132
15133
15134
15135
15136
15137
15138
  "     line      One value per line",
  "     list      Values delimited by \"|\"",
  "     markdown  Markdown table format",
  "     quote     Escape answers as for SQL",
  "     table     ASCII-art table",
  "     tabs      Tab-separated values",
  "     tcl       TCL list elements",
  ".nonce STRING            Disable safe mode for one command if the nonce matches",
  ".nullvalue STRING        Use STRING in place of NULL values",
  ".once ?OPTIONS? ?FILE?   Output for the next SQL command only to FILE",
  "     If FILE begins with '|' then open as a pipe",
  "       --bom  Put a UTF8 byte-order mark at the beginning",
  "       -e     Send output to the system text editor",
  "       -x     Send output as CSV to a spreadsheet (same as \".excel\")",
#ifdef SQLITE_DEBUG
15337
15338
15339
15340
15341
15342
15343
15344
15345
15346
15347
15348
15349
15350
15351
      break;
    }
    rc = sscanf(zLine,"| %d: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x",
                &j, &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7],
                &x[8], &x[9], &x[10], &x[11], &x[12], &x[13], &x[14], &x[15]);
    if( rc==17 ){
      k = iOffset+j;
      if( k+16<=n ){
        int ii;
        for(ii=0; ii<16; ii++) a[k+ii] = x[ii]&0xff;
      }
    }
  }
  *pnData = n;
  if( in!=p->in ){







|







15522
15523
15524
15525
15526
15527
15528
15529
15530
15531
15532
15533
15534
15535
15536
      break;
    }
    rc = sscanf(zLine,"| %d: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x",
                &j, &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7],
                &x[8], &x[9], &x[10], &x[11], &x[12], &x[13], &x[14], &x[15]);
    if( rc==17 ){
      k = iOffset+j;
      if( k+16<=n && k>=0 ){
        int ii;
        for(ii=0; ii<16; ii++) a[k+ii] = x[ii]&0xff;
      }
    }
  }
  *pnData = n;
  if( in!=p->in ){
15654
15655
15656
15657
15658
15659
15660



15661
15662
15663
15664
15665
15666
15667
      }
      if( p->szMax>0 ){
        sqlite3_file_control(p->db, "main", SQLITE_FCNTL_SIZE_LIMIT, &p->szMax);
      }
    }
#endif
  }



}

/*
** Attempt to close the databaes connection.  Report errors.
*/
void close_db(sqlite3 *db){
  int rc = sqlite3_close(db);







>
>
>







15839
15840
15841
15842
15843
15844
15845
15846
15847
15848
15849
15850
15851
15852
15853
15854
15855
      }
      if( p->szMax>0 ){
        sqlite3_file_control(p->db, "main", SQLITE_FCNTL_SIZE_LIMIT, &p->szMax);
      }
    }
#endif
  }
  if( p->bSafeModePersist && p->db!=0 ){
    sqlite3_set_authorizer(p->db, safeModeAuth, p);
  }
}

/*
** Attempt to close the databaes connection.  Report errors.
*/
void close_db(sqlite3 *db){
  int rc = sqlite3_close(db);
16251
16252
16253
16254
16255
16256
16257
16258
16259
16260
16261
16262
16263
16264
16265
    rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
    if( rc ){
      utf8_printf(stderr, "Error: (%d) %s on [%s]\n",
                      sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
                      zQuery);
      goto end_schema_xfer;
    }
    while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
      zName = sqlite3_column_text(pQuery, 0);
      zSql = sqlite3_column_text(pQuery, 1);
      printf("%s... ", zName); fflush(stdout);
      sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg);
      if( zErrMsg ){
        utf8_printf(stderr, "Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
        sqlite3_free(zErrMsg);







|







16439
16440
16441
16442
16443
16444
16445
16446
16447
16448
16449
16450
16451
16452
16453
    rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
    if( rc ){
      utf8_printf(stderr, "Error: (%d) %s on [%s]\n",
                      sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
                      zQuery);
      goto end_schema_xfer;
    }
    while( sqlite3_step(pQuery)==SQLITE_ROW ){
      zName = sqlite3_column_text(pQuery, 0);
      zSql = sqlite3_column_text(pQuery, 1);
      printf("%s... ", zName); fflush(stdout);
      sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg);
      if( zErrMsg ){
        utf8_printf(stderr, "Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
        sqlite3_free(zErrMsg);
16639
16640
16641
16642
16643
16644
16645
16646
16647
16648
16649
16650
16651
16652
16653
16654
#endif
    }
    p->zTempFile = sqlite3_mprintf("%s/temp%llx.%s", zTemp, r, zSuffix);
  }else{
    p->zTempFile = sqlite3_mprintf("%z.%s", p->zTempFile, zSuffix);
  }
  if( p->zTempFile==0 ){
    raw_printf(stderr, "out of memory\n");
    exit(1);
  }
}


/*
** The implementation of SQL scalar function fkey_collate_clause(), used
** by the ".lint fkey-indexes" command. This scalar function is always







|
<







16827
16828
16829
16830
16831
16832
16833
16834

16835
16836
16837
16838
16839
16840
16841
#endif
    }
    p->zTempFile = sqlite3_mprintf("%s/temp%llx.%s", zTemp, r, zSuffix);
  }else{
    p->zTempFile = sqlite3_mprintf("%z.%s", p->zTempFile, zSuffix);
  }
  if( p->zTempFile==0 ){
    shell_out_of_memory();

  }
}


/*
** The implementation of SQL scalar function fkey_collate_clause(), used
** by the ".lint fkey-indexes" command. This scalar function is always
18417
18418
18419
18420
18421
18422
18423


18424
18425
18426
18427
18428
18429
18430
18431
18432

18433
18434
18435
18436
18437
18438
18439
18440
18441
18442
18443
18444
18445
18446

18447
18448
18449
18450
18451
18452
18453
      raw_printf(stderr, "Usage: .auth ON|OFF\n");
      rc = 1;
      goto meta_command_exit;
    }
    open_db(p, 0);
    if( booleanValue(azArg[1]) ){
      sqlite3_set_authorizer(p->db, shellAuth, p);


    }else{
      sqlite3_set_authorizer(p->db, 0, 0);
    }
  }else
#endif

#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB)
  if( c=='a' && strncmp(azArg[0], "archive", n)==0 ){
    open_db(p, 0);

    rc = arDotCommand(p, 0, azArg, nArg);
  }else
#endif

  if( (c=='b' && n>=3 && strncmp(azArg[0], "backup", n)==0)
   || (c=='s' && n>=3 && strncmp(azArg[0], "save", n)==0)
  ){
    const char *zDestFile = 0;
    const char *zDb = 0;
    sqlite3 *pDest;
    sqlite3_backup *pBackup;
    int j;
    int bAsync = 0;
    const char *zVfs = 0;

    for(j=1; j<nArg; j++){
      const char *z = azArg[j];
      if( z[0]=='-' ){
        if( z[1]=='-' ) z++;
        if( strcmp(z, "-append")==0 ){
          zVfs = "apndvfs";
        }else







>
>









>














>







18604
18605
18606
18607
18608
18609
18610
18611
18612
18613
18614
18615
18616
18617
18618
18619
18620
18621
18622
18623
18624
18625
18626
18627
18628
18629
18630
18631
18632
18633
18634
18635
18636
18637
18638
18639
18640
18641
18642
18643
18644
      raw_printf(stderr, "Usage: .auth ON|OFF\n");
      rc = 1;
      goto meta_command_exit;
    }
    open_db(p, 0);
    if( booleanValue(azArg[1]) ){
      sqlite3_set_authorizer(p->db, shellAuth, p);
    }else if( p->bSafeModePersist ){
      sqlite3_set_authorizer(p->db, safeModeAuth, p);
    }else{
      sqlite3_set_authorizer(p->db, 0, 0);
    }
  }else
#endif

#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB)
  if( c=='a' && strncmp(azArg[0], "archive", n)==0 ){
    open_db(p, 0);
    failIfSafeMode(p, "cannot run .archive in safe mode");
    rc = arDotCommand(p, 0, azArg, nArg);
  }else
#endif

  if( (c=='b' && n>=3 && strncmp(azArg[0], "backup", n)==0)
   || (c=='s' && n>=3 && strncmp(azArg[0], "save", n)==0)
  ){
    const char *zDestFile = 0;
    const char *zDb = 0;
    sqlite3 *pDest;
    sqlite3_backup *pBackup;
    int j;
    int bAsync = 0;
    const char *zVfs = 0;
    failIfSafeMode(p, "cannot run .%s in safe mode", azArg[0]);
    for(j=1; j<nArg; j++){
      const char *z = azArg[j];
      if( z[0]=='-' ){
        if( z[1]=='-' ) z++;
        if( strcmp(z, "-append")==0 ){
          zVfs = "apndvfs";
        }else
18528
18529
18530
18531
18532
18533
18534

18535
18536
18537
18538
18539
18540
18541
  ** routine named test_breakpoint().
  */
  if( c=='b' && n>=3 && strncmp(azArg[0], "breakpoint", n)==0 ){
    test_breakpoint();
  }else

  if( c=='c' && strcmp(azArg[0],"cd")==0 ){

    if( nArg==2 ){
#if defined(_WIN32) || defined(WIN32)
      wchar_t *z = sqlite3_win32_utf8_to_unicode(azArg[1]);
      rc = !SetCurrentDirectoryW(z);
      sqlite3_free(z);
#else
      rc = chdir(azArg[1]);







>







18719
18720
18721
18722
18723
18724
18725
18726
18727
18728
18729
18730
18731
18732
18733
  ** routine named test_breakpoint().
  */
  if( c=='b' && n>=3 && strncmp(azArg[0], "breakpoint", n)==0 ){
    test_breakpoint();
  }else

  if( c=='c' && strcmp(azArg[0],"cd")==0 ){
    failIfSafeMode(p, "cannot run .cd in safe mode");
    if( nArg==2 ){
#if defined(_WIN32) || defined(WIN32)
      wchar_t *z = sqlite3_win32_utf8_to_unicode(azArg[1]);
      rc = !SetCurrentDirectoryW(z);
      sqlite3_free(z);
#else
      rc = chdir(azArg[1]);
18581
18582
18583
18584
18585
18586
18587

18588
18589
18590
18591
18592
18593
18594
      utf8_printf(stdout, "testcase-%s ok\n", p->zTestcase);
      p->nCheck++;
    }
    sqlite3_free(zRes);
  }else

  if( c=='c' && strncmp(azArg[0], "clone", n)==0 ){

    if( nArg==2 ){
      tryToClone(p, azArg[1]);
    }else{
      raw_printf(stderr, "Usage: .clone FILENAME\n");
      rc = 1;
    }
  }else







>







18773
18774
18775
18776
18777
18778
18779
18780
18781
18782
18783
18784
18785
18786
18787
      utf8_printf(stdout, "testcase-%s ok\n", p->zTestcase);
      p->nCheck++;
    }
    sqlite3_free(zRes);
  }else

  if( c=='c' && strncmp(azArg[0], "clone", n)==0 ){
    failIfSafeMode(p, "cannot run .clone in safe mode");
    if( nArg==2 ){
      tryToClone(p, azArg[1]);
    }else{
      raw_printf(stderr, "Usage: .clone FILENAME\n");
      rc = 1;
    }
  }else
19142
19143
19144
19145
19146
19147
19148

19149
19150
19151
19152
19153
19154
19155
    char *zSql;                 /* An SQL statement */
    ImportCtx sCtx;             /* Reader context */
    char *(SQLITE_CDECL *xRead)(ImportCtx*); /* Func to read one value */
    int eVerbose = 0;           /* Larger for more console output */
    int nSkip = 0;              /* Initial lines to skip */
    int useOutputMode = 1;      /* Use output mode to determine separators */


    memset(&sCtx, 0, sizeof(sCtx));
    if( p->mode==MODE_Ascii ){
      xRead = ascii_read_one_field;
    }else{
      xRead = csv_read_one_field;
    }
    for(i=1; i<nArg; i++){







>







19335
19336
19337
19338
19339
19340
19341
19342
19343
19344
19345
19346
19347
19348
19349
    char *zSql;                 /* An SQL statement */
    ImportCtx sCtx;             /* Reader context */
    char *(SQLITE_CDECL *xRead)(ImportCtx*); /* Func to read one value */
    int eVerbose = 0;           /* Larger for more console output */
    int nSkip = 0;              /* Initial lines to skip */
    int useOutputMode = 1;      /* Use output mode to determine separators */

    failIfSafeMode(p, "cannot run .import in safe mode");
    memset(&sCtx, 0, sizeof(sCtx));
    if( p->mode==MODE_Ascii ){
      xRead = ascii_read_one_field;
    }else{
      xRead = csv_read_one_field;
    }
    for(i=1; i<nArg; i++){
19448
19449
19450
19451
19452
19453
19454
19455
19456
19457
19458
19459
19460
19461
19462
      isWO = sqlite3_column_int(pStmt, 1);
    }
    sqlite3_finalize(pStmt);
    zSql = sqlite3_mprintf("PRAGMA index_xinfo='%q'", azArg[1]);
    rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
    sqlite3_free(zSql);
    i = 0;
    while( sqlite3_step(pStmt)==SQLITE_ROW ){
      char zLabel[20];
      const char *zCol = (const char*)sqlite3_column_text(pStmt,2);
      i++;
      if( zCol==0 ){
        if( sqlite3_column_int(pStmt,1)==-1 ){
          zCol = "_ROWID_";
        }else{







|







19642
19643
19644
19645
19646
19647
19648
19649
19650
19651
19652
19653
19654
19655
19656
      isWO = sqlite3_column_int(pStmt, 1);
    }
    sqlite3_finalize(pStmt);
    zSql = sqlite3_mprintf("PRAGMA index_xinfo='%q'", azArg[1]);
    rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
    sqlite3_free(zSql);
    i = 0;
    while( rc==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){
      char zLabel[20];
      const char *zCol = (const char*)sqlite3_column_text(pStmt,2);
      i++;
      if( zCol==0 ){
        if( sqlite3_column_int(pStmt,1)==-1 ){
          zCol = "_ROWID_";
        }else{
19593
19594
19595
19596
19597
19598
19599

19600
19601
19602
19603
19604
19605
19606
19607
19608
19609
19610
19611
19612
19613
19614
19615
19616
19617

19618
19619
19620
19621
19622
19623
19624
    lintDotCommand(p, azArg, nArg);
  }else

#ifndef SQLITE_OMIT_LOAD_EXTENSION
  if( c=='l' && strncmp(azArg[0], "load", n)==0 ){
    const char *zFile, *zProc;
    char *zErrMsg = 0;

    if( nArg<2 ){
      raw_printf(stderr, "Usage: .load FILE ?ENTRYPOINT?\n");
      rc = 1;
      goto meta_command_exit;
    }
    zFile = azArg[1];
    zProc = nArg>=3 ? azArg[2] : 0;
    open_db(p, 0);
    rc = sqlite3_load_extension(p->db, zFile, zProc, &zErrMsg);
    if( rc!=SQLITE_OK ){
      utf8_printf(stderr, "Error: %s\n", zErrMsg);
      sqlite3_free(zErrMsg);
      rc = 1;
    }
  }else
#endif

  if( c=='l' && strncmp(azArg[0], "log", n)==0 ){

    if( nArg!=2 ){
      raw_printf(stderr, "Usage: .log FILENAME\n");
      rc = 1;
    }else{
      const char *zFile = azArg[1];
      output_file_close(p->pLog);
      p->pLog = output_file_open(zFile, 0);







>


















>







19787
19788
19789
19790
19791
19792
19793
19794
19795
19796
19797
19798
19799
19800
19801
19802
19803
19804
19805
19806
19807
19808
19809
19810
19811
19812
19813
19814
19815
19816
19817
19818
19819
19820
    lintDotCommand(p, azArg, nArg);
  }else

#ifndef SQLITE_OMIT_LOAD_EXTENSION
  if( c=='l' && strncmp(azArg[0], "load", n)==0 ){
    const char *zFile, *zProc;
    char *zErrMsg = 0;
    failIfSafeMode(p, "cannot run .load in safe mode");
    if( nArg<2 ){
      raw_printf(stderr, "Usage: .load FILE ?ENTRYPOINT?\n");
      rc = 1;
      goto meta_command_exit;
    }
    zFile = azArg[1];
    zProc = nArg>=3 ? azArg[2] : 0;
    open_db(p, 0);
    rc = sqlite3_load_extension(p->db, zFile, zProc, &zErrMsg);
    if( rc!=SQLITE_OK ){
      utf8_printf(stderr, "Error: %s\n", zErrMsg);
      sqlite3_free(zErrMsg);
      rc = 1;
    }
  }else
#endif

  if( c=='l' && strncmp(azArg[0], "log", n)==0 ){
    failIfSafeMode(p, "cannot run .log in safe mode");
    if( nArg!=2 ){
      raw_printf(stderr, "Usage: .log FILENAME\n");
      rc = 1;
    }else{
      const char *zFile = azArg[1];
      output_file_close(p->pLog);
      p->pLog = output_file_open(zFile, 0);
19680
19681
19682
19683
19684
19685
19686














19687
19688
19689
19690
19691
19692
19693
      raw_printf(stderr, "Error: mode should be one of: "
         "ascii box column csv html insert json line list markdown "
         "quote table tabs tcl\n");
      rc = 1;
    }
    p->cMode = p->mode;
  }else















  if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 ){
    if( nArg==2 ){
      sqlite3_snprintf(sizeof(p->nullValue), p->nullValue,
                       "%.*s", (int)ArraySize(p->nullValue)-1, azArg[1]);
    }else{
      raw_printf(stderr, "Usage: .nullvalue STRING\n");







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







19876
19877
19878
19879
19880
19881
19882
19883
19884
19885
19886
19887
19888
19889
19890
19891
19892
19893
19894
19895
19896
19897
19898
19899
19900
19901
19902
19903
      raw_printf(stderr, "Error: mode should be one of: "
         "ascii box column csv html insert json line list markdown "
         "quote table tabs tcl\n");
      rc = 1;
    }
    p->cMode = p->mode;
  }else

  if( c=='n' && strcmp(azArg[0], "nonce")==0 ){
    if( nArg!=2 ){
      raw_printf(stderr, "Usage: .nonce NONCE\n");
      rc = 1;
    }else if( p->zNonce==0 || strcmp(azArg[1],p->zNonce)!=0 ){
      raw_printf(stderr, "line %d: incorrect nonce: \"%s\"\n", p->lineno, azArg[1]);
      exit(1);
    }else{
      p->bSafeMode = 0;
      return 0;  /* Return immediately to bypass the safe mode reset
                 ** at the end of this procedure */
    }
  }else

  if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 ){
    if( nArg==2 ){
      sqlite3_snprintf(sizeof(p->nullValue), p->nullValue,
                       "%.*s", (int)ArraySize(p->nullValue)-1, azArg[1]);
    }else{
      raw_printf(stderr, "Usage: .nullvalue STRING\n");
19772
19773
19774
19775
19776
19777
19778
19779







19780
19781
19782
19783
19784
19785
19786
        goto meta_command_exit;
      }else{
        zNewFilename = sqlite3_mprintf("%s", z);
      }
    }
    /* If a filename is specified, try to open it first */
    if( zNewFilename || p->openMode==SHELL_OPEN_HEXDB ){
      if( newFlag ) shellDeleteFile(zNewFilename);







      p->pAuxDb->zDbFilename = zNewFilename;
      open_db(p, OPEN_DB_KEEPALIVE);
      if( p->db==0 ){
        utf8_printf(stderr, "Error: cannot open '%s'\n", zNewFilename);
        sqlite3_free(zNewFilename);
      }else{
        p->pAuxDb->zFreeOnClose = zNewFilename;







|
>
>
>
>
>
>
>







19982
19983
19984
19985
19986
19987
19988
19989
19990
19991
19992
19993
19994
19995
19996
19997
19998
19999
20000
20001
20002
20003
        goto meta_command_exit;
      }else{
        zNewFilename = sqlite3_mprintf("%s", z);
      }
    }
    /* If a filename is specified, try to open it first */
    if( zNewFilename || p->openMode==SHELL_OPEN_HEXDB ){
      if( newFlag && !p->bSafeMode ) shellDeleteFile(zNewFilename);
      if( p->bSafeMode
       && p->openMode!=SHELL_OPEN_HEXDB
       && zNewFilename
       && strcmp(zNewFilename,":memory:")!=0
      ){
        failIfSafeMode(p, "cannot open disk-based database files in safe mode");
      }
      p->pAuxDb->zDbFilename = zNewFilename;
      open_db(p, OPEN_DB_KEEPALIVE);
      if( p->db==0 ){
        utf8_printf(stderr, "Error: cannot open '%s'\n", zNewFilename);
        sqlite3_free(zNewFilename);
      }else{
        p->pAuxDb->zFreeOnClose = zNewFilename;
19800
19801
19802
19803
19804
19805
19806

19807
19808
19809
19810
19811
19812
19813
    char *zFile = 0;
    int bTxtMode = 0;
    int i;
    int eMode = 0;
    int bBOM = 0;
    int bOnce = 0;  /* 0: .output, 1: .once, 2: .excel */


    if( c=='e' ){
      eMode = 'x';
      bOnce = 2;
    }else if( strncmp(azArg[0],"once",n)==0 ){
      bOnce = 1;
    }
    for(i=1; i<nArg; i++){







>







20017
20018
20019
20020
20021
20022
20023
20024
20025
20026
20027
20028
20029
20030
20031
    char *zFile = 0;
    int bTxtMode = 0;
    int i;
    int eMode = 0;
    int bBOM = 0;
    int bOnce = 0;  /* 0: .output, 1: .once, 2: .excel */

    failIfSafeMode(p, "cannot run .%s in safe mode", azArg[0]);
    if( c=='e' ){
      eMode = 'x';
      bOnce = 2;
    }else if( strncmp(azArg[0],"once",n)==0 ){
      bOnce = 1;
    }
    for(i=1; i<nArg; i++){
19929
19930
19931
19932
19933
19934
19935
19936
19937
19938
19939
19940
19941
19942
19943
      }
      sqlite3_finalize(pStmt);
      pStmt = 0;
      if( len ){
        rx = sqlite3_prepare_v2(p->db,
             "SELECT key, quote(value) "
             "FROM temp.sqlite_parameters;", -1, &pStmt, 0);
        while( sqlite3_step(pStmt)==SQLITE_ROW ){
          utf8_printf(p->out, "%-*s %s\n", len, sqlite3_column_text(pStmt,0),
                      sqlite3_column_text(pStmt,1));
        }
        sqlite3_finalize(pStmt);
      }
    }else








|







20147
20148
20149
20150
20151
20152
20153
20154
20155
20156
20157
20158
20159
20160
20161
      }
      sqlite3_finalize(pStmt);
      pStmt = 0;
      if( len ){
        rx = sqlite3_prepare_v2(p->db,
             "SELECT key, quote(value) "
             "FROM temp.sqlite_parameters;", -1, &pStmt, 0);
        while( rx==SQLITE_OK && sqlite3_step(pStmt)==SQLITE_ROW ){
          utf8_printf(p->out, "%-*s %s\n", len, sqlite3_column_text(pStmt,0),
                      sqlite3_column_text(pStmt,1));
        }
        sqlite3_finalize(pStmt);
      }
    }else

20072
20073
20074
20075
20076
20077
20078

20079
20080
20081
20082
20083
20084
20085
20086
20087
20088
20089
20090
20091
20092
20093
20094
20095
20096
20097
20098
20099
20100
20101
20102
20103
20104
20105
20106
20107
20108
20109
20110
20111
20112
20113
20114
20115
20116

20117
20118
20119
20120
20121
20122
20123
  if( c=='q' && strncmp(azArg[0], "quit", n)==0 ){
    rc = 2;
  }else

  if( c=='r' && n>=3 && strncmp(azArg[0], "read", n)==0 ){
    FILE *inSaved = p->in;
    int savedLineno = p->lineno;

    if( nArg!=2 ){
      raw_printf(stderr, "Usage: .read FILE\n");
      rc = 1;
      goto meta_command_exit;
    }
    if( azArg[1][0]=='|' ){
#ifdef SQLITE_OMIT_POPEN
      raw_printf(stderr, "Error: pipes are not supported in this OS\n");
      rc = 1;
      p->out = stdout;
#else
      p->in = popen(azArg[1]+1, "r");
      if( p->in==0 ){
        utf8_printf(stderr, "Error: cannot open \"%s\"\n", azArg[1]);
        rc = 1;
      }else{
        rc = process_input(p);
        pclose(p->in);
      }
#endif
    }else if( notNormalFile(azArg[1]) || (p->in = fopen(azArg[1], "rb"))==0 ){
      utf8_printf(stderr,"Error: cannot open \"%s\"\n", azArg[1]);
      rc = 1;
    }else{
      rc = process_input(p);
      fclose(p->in);
    }
    p->in = inSaved;
    p->lineno = savedLineno;
  }else

  if( c=='r' && n>=3 && strncmp(azArg[0], "restore", n)==0 ){
    const char *zSrcFile;
    const char *zDb;
    sqlite3 *pSrc;
    sqlite3_backup *pBackup;
    int nTimeout = 0;


    if( nArg==2 ){
      zSrcFile = azArg[1];
      zDb = "main";
    }else if( nArg==3 ){
      zSrcFile = azArg[2];
      zDb = azArg[1];
    }else{







>




















|

















>







20290
20291
20292
20293
20294
20295
20296
20297
20298
20299
20300
20301
20302
20303
20304
20305
20306
20307
20308
20309
20310
20311
20312
20313
20314
20315
20316
20317
20318
20319
20320
20321
20322
20323
20324
20325
20326
20327
20328
20329
20330
20331
20332
20333
20334
20335
20336
20337
20338
20339
20340
20341
20342
20343
  if( c=='q' && strncmp(azArg[0], "quit", n)==0 ){
    rc = 2;
  }else

  if( c=='r' && n>=3 && strncmp(azArg[0], "read", n)==0 ){
    FILE *inSaved = p->in;
    int savedLineno = p->lineno;
    failIfSafeMode(p, "cannot run .read in safe mode");
    if( nArg!=2 ){
      raw_printf(stderr, "Usage: .read FILE\n");
      rc = 1;
      goto meta_command_exit;
    }
    if( azArg[1][0]=='|' ){
#ifdef SQLITE_OMIT_POPEN
      raw_printf(stderr, "Error: pipes are not supported in this OS\n");
      rc = 1;
      p->out = stdout;
#else
      p->in = popen(azArg[1]+1, "r");
      if( p->in==0 ){
        utf8_printf(stderr, "Error: cannot open \"%s\"\n", azArg[1]);
        rc = 1;
      }else{
        rc = process_input(p);
        pclose(p->in);
      }
#endif
    }else if( (p->in = openChrSource(azArg[1]))==0 ){
      utf8_printf(stderr,"Error: cannot open \"%s\"\n", azArg[1]);
      rc = 1;
    }else{
      rc = process_input(p);
      fclose(p->in);
    }
    p->in = inSaved;
    p->lineno = savedLineno;
  }else

  if( c=='r' && n>=3 && strncmp(azArg[0], "restore", n)==0 ){
    const char *zSrcFile;
    const char *zDb;
    sqlite3 *pSrc;
    sqlite3_backup *pBackup;
    int nTimeout = 0;

    failIfSafeMode(p, "cannot run .restore in safe mode");
    if( nArg==2 ){
      zSrcFile = azArg[1];
      zDb = "main";
    }else if( nArg==3 ){
      zSrcFile = azArg[2];
      zDb = azArg[1];
    }else{
20359
20360
20361
20362
20363
20364
20365

20366
20367
20368
20369
20370
20371
20372

    /* .session changeset FILE
    ** .session patchset FILE
    ** Write a changeset or patchset into a file.  The file is overwritten.
    */
    if( strcmp(azCmd[0],"changeset")==0 || strcmp(azCmd[0],"patchset")==0 ){
      FILE *out = 0;

      if( nCmd!=2 ) goto session_syntax_error;
      if( pSession->p==0 ) goto session_not_open;
      out = fopen(azCmd[1], "wb");
      if( out==0 ){
        utf8_printf(stderr, "ERROR: cannot open \"%s\" for writing\n",
                    azCmd[1]);
      }else{







>







20579
20580
20581
20582
20583
20584
20585
20586
20587
20588
20589
20590
20591
20592
20593

    /* .session changeset FILE
    ** .session patchset FILE
    ** Write a changeset or patchset into a file.  The file is overwritten.
    */
    if( strcmp(azCmd[0],"changeset")==0 || strcmp(azCmd[0],"patchset")==0 ){
      FILE *out = 0;
      failIfSafeMode(p, "cannot run \".session %s\" in safe mode", azCmd[0]);
      if( nCmd!=2 ) goto session_syntax_error;
      if( pSession->p==0 ) goto session_not_open;
      out = fopen(azCmd[1], "wb");
      if( out==0 ){
        utf8_printf(stderr, "ERROR: cannot open \"%s\" for writing\n",
                    azCmd[1]);
      }else{
20773
20774
20775
20776
20777
20778
20779

20780
20781
20782
20783
20784
20785
20786

#ifndef SQLITE_NOHAVE_SYSTEM
  if( c=='s'
   && (strncmp(azArg[0], "shell", n)==0 || strncmp(azArg[0],"system",n)==0)
  ){
    char *zCmd;
    int i, x;

    if( nArg<2 ){
      raw_printf(stderr, "Usage: .system COMMAND\n");
      rc = 1;
      goto meta_command_exit;
    }
    zCmd = sqlite3_mprintf(strchr(azArg[1],' ')==0?"%s":"\"%s\"", azArg[1]);
    for(i=2; i<nArg; i++){







>







20994
20995
20996
20997
20998
20999
21000
21001
21002
21003
21004
21005
21006
21007
21008

#ifndef SQLITE_NOHAVE_SYSTEM
  if( c=='s'
   && (strncmp(azArg[0], "shell", n)==0 || strncmp(azArg[0],"system",n)==0)
  ){
    char *zCmd;
    int i, x;
    failIfSafeMode(p, "cannot run .%s in safe mode", azArg[0]);
    if( nArg<2 ){
      raw_printf(stderr, "Usage: .system COMMAND\n");
      rc = 1;
      goto meta_command_exit;
    }
    zCmd = sqlite3_mprintf(strchr(azArg[1],' ')==0?"%s":"\"%s\"", azArg[1]);
    for(i=2; i<nArg; i++){
20898
20899
20900
20901
20902
20903
20904

20905
20906

20907
20908
20909
20910
20911
20912
20913
                      "   AND name LIKE ?1", 0);
      }else{
        appendText(&s," WHERE type='index'"
                      "   AND tbl_name LIKE ?1", 0);
      }
    }
    rc = sqlite3_finalize(pStmt);

    appendText(&s, " ORDER BY 1", 0);
    rc = sqlite3_prepare_v2(p->db, s.z, -1, &pStmt, 0);

    freeText(&s);
    if( rc ) return shellDatabaseError(p->db);

    /* Run the SQL statement prepared by the above block. Store the results
    ** as an array of nul-terminated strings in azResult[].  */
    nRow = nAlloc = 0;
    azResult = 0;







>
|
|
>







21120
21121
21122
21123
21124
21125
21126
21127
21128
21129
21130
21131
21132
21133
21134
21135
21136
21137
                      "   AND name LIKE ?1", 0);
      }else{
        appendText(&s," WHERE type='index'"
                      "   AND tbl_name LIKE ?1", 0);
      }
    }
    rc = sqlite3_finalize(pStmt);
    if( rc==SQLITE_OK ){
      appendText(&s, " ORDER BY 1", 0);
      rc = sqlite3_prepare_v2(p->db, s.z, -1, &pStmt, 0);
    }
    freeText(&s);
    if( rc ) return shellDatabaseError(p->db);

    /* Run the SQL statement prepared by the above block. Store the results
    ** as an array of nul-terminated strings in azResult[].  */
    nRow = nAlloc = 0;
    azResult = 0;
21425
21426
21427
21428
21429
21430
21431
21432
21433
21434
21435
21436
21437
21438
21439
21440
21441
21442
21443
21444
21445
21446
21447
21448
21449
21450

21451
21452
21453
21454
21455
21456
21457
21458

21459
21460
21461




21462





21463
21464
21465



21466

21467




21468
21469













21470

21471
21472


21473
21474

21475







21476








21477


21478
21479



21480

21481
21482


21483



21484



21485
21486
21487
21488
21489
21490
21491
21492
21493
21494
21495
21496
21497
21498
21499
21500
21501

21502

21503
21504
21505
21506
21507
21508
21509
    sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 3, &x);
  }else

  if( c=='w' && strncmp(azArg[0], "width", n)==0 ){
    int j;
    assert( nArg<=ArraySize(azArg) );
    p->nWidth = nArg-1;
    p->colWidth = realloc(p->colWidth, p->nWidth*sizeof(int)*2);
    if( p->colWidth==0 && p->nWidth>0 ) shell_out_of_memory();
    if( p->nWidth ) p->actualWidth = &p->colWidth[p->nWidth];
    for(j=1; j<nArg; j++){
      p->colWidth[j-1] = (int)integerValue(azArg[j]);
    }
  }else

  {
    utf8_printf(stderr, "Error: unknown command or invalid arguments: "
      " \"%s\". Enter \".help\" for help\n", azArg[0]);
    rc = 1;
  }

meta_command_exit:
  if( p->outCount ){
    p->outCount--;
    if( p->outCount==0 ) output_reset(p);
  }

  return rc;
}

/*
** Return TRUE if a semicolon occurs anywhere in the first N characters
** of string z[].
*/
static int line_contains_semicolon(const char *z, int N){

  int i;
  for(i=0; i<N; i++){  if( z[i]==';' ) return 1; }
  return 0;




}






/*
** Test to see if a line consists entirely of whitespace.



*/

static int _all_whitespace(const char *z){




  for(; *z; z++){
    if( IsSpace(z[0]) ) continue;













    if( *z=='/' && z[1]=='*' ){

      z += 2;
      while( *z && (*z!='*' || z[1]!='/') ){ z++; }


      if( *z==0 ) return 0;
      z++;

      continue;







    }








    if( *z=='-' && z[1]=='-' ){


      z += 2;
      while( *z && *z!='\n' ){ z++; }



      if( *z==0 ) return 1;

      continue;
    }


    return 0;



  }



  return 1;
}

/*
** Return TRUE if the line typed in is an SQL command terminator other
** than a semi-colon.  The SQL Server style "go" command is understood
** as is the Oracle "/".
*/
static int line_is_command_terminator(const char *zLine){
  while( IsSpace(zLine[0]) ){ zLine++; };
  if( zLine[0]=='/' && _all_whitespace(&zLine[1]) ){
    return 1;  /* Oracle */
  }
  if( ToLower(zLine[0])=='g' && ToLower(zLine[1])=='o'
         && _all_whitespace(&zLine[2]) ){
    return 1;  /* SQL Server */
  }

  return 0;

}

/*
** We need a default sqlite3_complete() implementation to use in case
** the shell is compiled with SQLITE_OMIT_COMPLETE.  The default assumes
** any arbitrary text is a complete SQL statement.  This is not very
** user-friendly, but it does seem to work.







|


















>



|
<
<

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


<
>
>
>

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







|

|
|
<
|
<
|
<
>
|
>







21649
21650
21651
21652
21653
21654
21655
21656
21657
21658
21659
21660
21661
21662
21663
21664
21665
21666
21667
21668
21669
21670
21671
21672
21673
21674
21675
21676
21677
21678
21679


21680

21681
21682

21683
21684
21685
21686
21687
21688
21689
21690
21691
21692
21693
21694
21695

21696
21697
21698
21699
21700
21701
21702
21703
21704
21705
21706
21707
21708
21709
21710
21711
21712
21713
21714
21715
21716
21717
21718
21719
21720
21721
21722
21723
21724
21725
21726
21727

21728
21729
21730
21731
21732
21733
21734
21735
21736
21737
21738
21739
21740
21741
21742
21743
21744
21745
21746
21747
21748
21749

21750
21751
21752
21753
21754
21755
21756
21757
21758
21759
21760
21761
21762
21763
21764
21765
21766
21767
21768
21769
21770
21771
21772
21773
21774
21775
21776
21777
21778

21779

21780

21781
21782
21783
21784
21785
21786
21787
21788
21789
21790
    sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, 3, &x);
  }else

  if( c=='w' && strncmp(azArg[0], "width", n)==0 ){
    int j;
    assert( nArg<=ArraySize(azArg) );
    p->nWidth = nArg-1;
    p->colWidth = realloc(p->colWidth, (p->nWidth+1)*sizeof(int)*2);
    if( p->colWidth==0 && p->nWidth>0 ) shell_out_of_memory();
    if( p->nWidth ) p->actualWidth = &p->colWidth[p->nWidth];
    for(j=1; j<nArg; j++){
      p->colWidth[j-1] = (int)integerValue(azArg[j]);
    }
  }else

  {
    utf8_printf(stderr, "Error: unknown command or invalid arguments: "
      " \"%s\". Enter \".help\" for help\n", azArg[0]);
    rc = 1;
  }

meta_command_exit:
  if( p->outCount ){
    p->outCount--;
    if( p->outCount==0 ) output_reset(p);
  }
  p->bSafeMode = p->bSafeModePersist;
  return rc;
}

/* Line scan result and intermediate states (supporting scan resumption)


*/

#ifndef CHAR_BIT
# define CHAR_BIT 8

#endif
typedef enum {
  QSS_HasDark = 1<<CHAR_BIT, QSS_EndingSemi = 2<<CHAR_BIT,
  QSS_CharMask = (1<<CHAR_BIT)-1, QSS_ScanMask = 3<<CHAR_BIT,
  QSS_Start = 0
} QuickScanState;
#define QSS_SETV(qss, newst) ((newst) | ((qss) & QSS_ScanMask))
#define QSS_INPLAIN(qss) (((qss)&QSS_CharMask)==QSS_Start)
#define QSS_PLAINWHITE(qss) (((qss)&~QSS_EndingSemi)==QSS_Start)
#define QSS_PLAINDARK(qss) (((qss)&~QSS_EndingSemi)==QSS_HasDark)
#define QSS_SEMITERM(qss) (((qss)&~QSS_HasDark)==QSS_EndingSemi)

/*

** Scan line for classification to guide shell's handling.
** The scan is resumable for subsequent lines when prior
** return values are passed as the 2nd argument.
*/
static QuickScanState quickscan(char *zLine, QuickScanState qss){
  char cin;
  char cWait = (char)qss; /* intentional narrowing loss */
  if( cWait==0 ){
  PlainScan:
    assert( cWait==0 );
    while( (cin = *zLine++)!=0 ){
      if( IsSpace(cin) )
        continue;
      switch (cin){
      case '-':
        if( *zLine!='-' )
          break;
        while((cin = *++zLine)!=0 )
          if( cin=='\n')
            goto PlainScan;
        return qss;
      case ';':
        qss |= QSS_EndingSemi;
        continue;
      case '/':
        if( *zLine=='*' ){
          ++zLine;
          cWait = '*';
          qss = QSS_SETV(qss, cWait);
          goto TermScan;
        }
        break;

      case '[':
        cin = ']';
        /* fall thru */
      case '`': case '\'': case '"':
        cWait = cin;
        qss = QSS_HasDark | cWait;
        goto TermScan;
      default:
        break;
      }
      qss = (qss & ~QSS_EndingSemi) | QSS_HasDark;
    }
  }else{
  TermScan:
    while( (cin = *zLine++)!=0 ){
      if( cin==cWait ){
        switch( cWait ){
        case '*':
          if( *zLine != '/' )
            continue;
          ++zLine;
          cWait = 0;

          qss = QSS_SETV(qss, 0);
          goto PlainScan;
        case '`': case '\'': case '"':
          if(*zLine==cWait){
            ++zLine;
            continue;
          }
          /* fall thru */
        case ']':
          cWait = 0;
          qss = QSS_SETV(qss, 0);
          goto PlainScan;
        default: assert(0); 
        }
      }
    }
  }
  return qss;
}

/*
** Return TRUE if the line typed in is an SQL command terminator other
** than a semi-colon.  The SQL Server style "go" command is understood
** as is the Oracle "/".
*/
static int line_is_command_terminator(char *zLine){
  while( IsSpace(zLine[0]) ){ zLine++; };
  if( zLine[0]=='/' )
    zLine += 1; /* Oracle */

  else if ( ToLower(zLine[0])=='g' && ToLower(zLine[1])=='o' )

    zLine += 2; /* SQL Server */

  else
    return 0;
  return quickscan(zLine,QSS_Start)==QSS_Start;
}

/*
** We need a default sqlite3_complete() implementation to use in case
** the shell is compiled with SQLITE_OMIT_COMPLETE.  The default assumes
** any arbitrary text is a complete SQL statement.  This is not very
** user-friendly, but it does seem to work.
21552
21553
21554
21555
21556
21557
21558


21559
21560

21561
21562
21563
21564
21565
21566
21567
21568
21569
21570
21571
21572
21573
21574
21575
21576
21577
21578
21579
21580
21581
21582
21583
21584

21585
21586
21587
21588
21589
21590
21591
21592
21593
21594
21595
21596
21597
21598
21599






21600
21601



21602
21603
21604
21605
21606
21607
21608
21609
21610
21611
21612
21613

21614
21615
21616
21617
21618
21619
21620

21621
21622
21623
21624
21625
21626
21627
21628
21629
21630
21631
21632
21633
21634
21635
21636
21637
21638
21639
21640
21641
21642
21643
21644
21645
21646
21647


21648
21649
21650

21651
21652
21653
21654
21655
21656
21657
21658
21659
21660
      sqlite3_free(zErrMsg);
      zErrMsg = 0;
    }else{
      utf8_printf(stderr, "%s %s\n", zPrefix, sqlite3_errmsg(p->db));
    }
    return 1;
  }else if( ShellHasFlag(p, SHFLG_CountChanges) ){


    raw_printf(p->out, "changes: %3lld   total_changes: %lld\n",
            sqlite3_changes64(p->db), sqlite3_total_changes64(p->db));

  }
  return 0;
}


/*
** Read input from *in and process it.  If *in==0 then input
** is interactive - the user is typing it it.  Otherwise, input
** is coming from a file or device.  A prompt is issued and history
** is saved only if input is interactive.  An interrupt signal will
** cause this routine to exit immediately, unless input is interactive.
**
** Return the number of errors.
*/
static int process_input(ShellState *p){
  char *zLine = 0;          /* A single input line */
  char *zSql = 0;           /* Accumulated SQL text */
  int nLine;                /* Length of current line */
  int nSql = 0;             /* Bytes of zSql[] used */
  int nAlloc = 0;           /* Allocated zSql[] space */
  int nSqlPrior = 0;        /* Bytes of zSql[] used by prior line */
  int rc;                   /* Error code */
  int errCnt = 0;           /* Number of errors seen */
  int startline = 0;        /* Line number for start of current input */


  p->lineno = 0;
  while( errCnt==0 || !bail_on_error || (p->in==0 && stdin_is_interactive) ){
    fflush(p->out);
    zLine = one_input_line(p->in, zLine, nSql>0);
    if( zLine==0 ){
      /* End of input */
      if( p->in==0 && stdin_is_interactive ) printf("\n");
      break;
    }
    if( seenInterrupt ){
      if( p->in!=0 ) break;
      seenInterrupt = 0;
    }
    p->lineno++;






    if( nSql==0 && _all_whitespace(zLine) ){
      if( ShellHasFlag(p, SHFLG_Echo) ) printf("%s\n", zLine);



      continue;
    }
    if( zLine && (zLine[0]=='.' || zLine[0]=='#') && nSql==0 ){
      if( ShellHasFlag(p, SHFLG_Echo) ) printf("%s\n", zLine);
      if( zLine[0]=='.' ){
        rc = do_meta_command(zLine, p);
        if( rc==2 ){ /* exit requested */
          break;
        }else if( rc ){
          errCnt++;
        }
      }

      continue;
    }
    if( line_is_command_terminator(zLine) && line_is_complete(zSql, nSql) ){
      memcpy(zLine,";",2);
    }
    nLine = strlen30(zLine);
    if( nSql+nLine+2>=nAlloc ){

      nAlloc = nSql+nLine+100;
      zSql = realloc(zSql, nAlloc);
      if( zSql==0 ) shell_out_of_memory();
    }
    nSqlPrior = nSql;
    if( nSql==0 ){
      int i;
      for(i=0; zLine[i] && IsSpace(zLine[i]); i++){}
      assert( nAlloc>0 && zSql!=0 );
      memcpy(zSql, zLine+i, nLine+1-i);
      startline = p->lineno;
      nSql = nLine-i;
    }else{
      zSql[nSql++] = '\n';
      memcpy(zSql+nSql, zLine, nLine+1);
      nSql += nLine;
    }
    if( nSql && line_contains_semicolon(&zSql[nSqlPrior], nSql-nSqlPrior)
                && sqlite3_complete(zSql) ){
      errCnt += runOneSqlLine(p, zSql, p->in, startline);
      nSql = 0;
      if( p->outCount ){
        output_reset(p);
        p->outCount = 0;
      }else{
        clearTempFile(p);
      }


    }else if( nSql && _all_whitespace(zSql) ){
      if( ShellHasFlag(p, SHFLG_Echo) ) printf("%s\n", zSql);
      nSql = 0;

    }
  }
  if( nSql && !_all_whitespace(zSql) ){
    errCnt += runOneSqlLine(p, zSql, p->in, startline);
  }
  free(zSql);
  free(zLine);
  return errCnt>0;
}








>
>
|

>




















<



>















>
>
>
>
>
>
|
|
>
>
>












>


<
|
<


>
|



<












<
|








>
>
|


>


|







21833
21834
21835
21836
21837
21838
21839
21840
21841
21842
21843
21844
21845
21846
21847
21848
21849
21850
21851
21852
21853
21854
21855
21856
21857
21858
21859
21860
21861
21862
21863
21864

21865
21866
21867
21868
21869
21870
21871
21872
21873
21874
21875
21876
21877
21878
21879
21880
21881
21882
21883
21884
21885
21886
21887
21888
21889
21890
21891
21892
21893
21894
21895
21896
21897
21898
21899
21900
21901
21902
21903
21904
21905
21906
21907
21908
21909

21910

21911
21912
21913
21914
21915
21916
21917

21918
21919
21920
21921
21922
21923
21924
21925
21926
21927
21928
21929

21930
21931
21932
21933
21934
21935
21936
21937
21938
21939
21940
21941
21942
21943
21944
21945
21946
21947
21948
21949
21950
21951
21952
21953
21954
      sqlite3_free(zErrMsg);
      zErrMsg = 0;
    }else{
      utf8_printf(stderr, "%s %s\n", zPrefix, sqlite3_errmsg(p->db));
    }
    return 1;
  }else if( ShellHasFlag(p, SHFLG_CountChanges) ){
    char zLineBuf[2000];
    sqlite3_snprintf(sizeof(zLineBuf), zLineBuf,
            "changes: %lld   total_changes: %lld",
            sqlite3_changes64(p->db), sqlite3_total_changes64(p->db));
    raw_printf(p->out, "%s\n", zLineBuf);
  }
  return 0;
}


/*
** Read input from *in and process it.  If *in==0 then input
** is interactive - the user is typing it it.  Otherwise, input
** is coming from a file or device.  A prompt is issued and history
** is saved only if input is interactive.  An interrupt signal will
** cause this routine to exit immediately, unless input is interactive.
**
** Return the number of errors.
*/
static int process_input(ShellState *p){
  char *zLine = 0;          /* A single input line */
  char *zSql = 0;           /* Accumulated SQL text */
  int nLine;                /* Length of current line */
  int nSql = 0;             /* Bytes of zSql[] used */
  int nAlloc = 0;           /* Allocated zSql[] space */

  int rc;                   /* Error code */
  int errCnt = 0;           /* Number of errors seen */
  int startline = 0;        /* Line number for start of current input */
  QuickScanState qss = QSS_Start; /* Accumulated line status (so far) */

  p->lineno = 0;
  while( errCnt==0 || !bail_on_error || (p->in==0 && stdin_is_interactive) ){
    fflush(p->out);
    zLine = one_input_line(p->in, zLine, nSql>0);
    if( zLine==0 ){
      /* End of input */
      if( p->in==0 && stdin_is_interactive ) printf("\n");
      break;
    }
    if( seenInterrupt ){
      if( p->in!=0 ) break;
      seenInterrupt = 0;
    }
    p->lineno++;
    if( QSS_INPLAIN(qss)
        && line_is_command_terminator(zLine)
        && line_is_complete(zSql, nSql) ){
      memcpy(zLine,";",2);
    }
    qss = quickscan(zLine, qss);
    if( QSS_PLAINWHITE(qss) && nSql==0 ){
      if( ShellHasFlag(p, SHFLG_Echo) )
        printf("%s\n", zLine);
      /* Just swallow single-line whitespace */
      qss = QSS_Start;
      continue;
    }
    if( zLine && (zLine[0]=='.' || zLine[0]=='#') && nSql==0 ){
      if( ShellHasFlag(p, SHFLG_Echo) ) printf("%s\n", zLine);
      if( zLine[0]=='.' ){
        rc = do_meta_command(zLine, p);
        if( rc==2 ){ /* exit requested */
          break;
        }else if( rc ){
          errCnt++;
        }
      }
      qss = QSS_Start;
      continue;
    }

    /* No single-line dispositions remain; accumulate line(s). */

    nLine = strlen30(zLine);
    if( nSql+nLine+2>=nAlloc ){
      /* Grow buffer by half-again increments when big. */
      nAlloc = nSql+(nSql>>1)+nLine+100;
      zSql = realloc(zSql, nAlloc);
      if( zSql==0 ) shell_out_of_memory();
    }

    if( nSql==0 ){
      int i;
      for(i=0; zLine[i] && IsSpace(zLine[i]); i++){}
      assert( nAlloc>0 && zSql!=0 );
      memcpy(zSql, zLine+i, nLine+1-i);
      startline = p->lineno;
      nSql = nLine-i;
    }else{
      zSql[nSql++] = '\n';
      memcpy(zSql+nSql, zLine, nLine+1);
      nSql += nLine;
    }

    if( nSql && QSS_SEMITERM(qss) && sqlite3_complete(zSql) ){
      errCnt += runOneSqlLine(p, zSql, p->in, startline);
      nSql = 0;
      if( p->outCount ){
        output_reset(p);
        p->outCount = 0;
      }else{
        clearTempFile(p);
      }
      p->bSafeMode = p->bSafeModePersist;
      qss = QSS_Start;
    }else if( nSql && QSS_PLAINWHITE(qss) ){
      if( ShellHasFlag(p, SHFLG_Echo) ) printf("%s\n", zSql);
      nSql = 0;
      qss = QSS_Start;
    }
  }
  if( nSql && QSS_PLAINDARK(qss) ){
    errCnt += runOneSqlLine(p, zSql, p->in, startline);
  }
  free(zSql);
  free(zLine);
  return errCnt>0;
}

21807
21808
21809
21810
21811
21812
21813

21814
21815
21816
21817

21818
21819
21820
21821
21822
21823
21824
  "   -memtrace            trace all memory allocations and deallocations\n"
  "   -mmap N              default mmap size set to N\n"
#ifdef SQLITE_ENABLE_MULTIPLEX
  "   -multiplex           enable the multiplexor VFS\n"
#endif
  "   -newline SEP         set output row separator. Default: '\\n'\n"
  "   -nofollow            refuse to open symbolic links to database files\n"

  "   -nullvalue TEXT      set text string for NULL values. Default ''\n"
  "   -pagecache SIZE N    use N slots of SZ bytes each for page cache memory\n"
  "   -quote               set output mode to 'quote'\n"
  "   -readonly            open the database read-only\n"

  "   -separator SEP       set output column separator. Default: '|'\n"
#ifdef SQLITE_ENABLE_SORTER_REFERENCES
  "   -sorterref SIZE      sorter references threshold size\n"
#endif
  "   -stats               print memory stats before each finalize\n"
  "   -table               set output mode to 'table'\n"
  "   -tabs                set output mode to 'tabs'\n"







>




>







22101
22102
22103
22104
22105
22106
22107
22108
22109
22110
22111
22112
22113
22114
22115
22116
22117
22118
22119
22120
  "   -memtrace            trace all memory allocations and deallocations\n"
  "   -mmap N              default mmap size set to N\n"
#ifdef SQLITE_ENABLE_MULTIPLEX
  "   -multiplex           enable the multiplexor VFS\n"
#endif
  "   -newline SEP         set output row separator. Default: '\\n'\n"
  "   -nofollow            refuse to open symbolic links to database files\n"
  "   -nonce STRING        set the safe-mode escape nonce\n"
  "   -nullvalue TEXT      set text string for NULL values. Default ''\n"
  "   -pagecache SIZE N    use N slots of SZ bytes each for page cache memory\n"
  "   -quote               set output mode to 'quote'\n"
  "   -readonly            open the database read-only\n"
  "   -safe                enable safe-mode\n"
  "   -separator SEP       set output column separator. Default: '|'\n"
#ifdef SQLITE_ENABLE_SORTER_REFERENCES
  "   -sorterref SIZE      sorter references threshold size\n"
#endif
  "   -stats               print memory stats before each finalize\n"
  "   -table               set output mode to 'table'\n"
  "   -tabs                set output mode to 'tabs'\n"
22096
22097
22098
22099
22100
22101
22102








22103
22104
22105
22106
22107
22108
22109
      int n, sz;
      sz = (int)integerValue(cmdline_option_value(argc,argv,++i));
      if( sz<0 ) sz = 0;
      n = (int)integerValue(cmdline_option_value(argc,argv,++i));
      if( n<0 ) n = 0;
      sqlite3_config(SQLITE_CONFIG_LOOKASIDE, sz, n);
      if( sz*n==0 ) data.shellFlgs &= ~SHFLG_Lookaside;








#ifdef SQLITE_ENABLE_VFSTRACE
    }else if( strcmp(z,"-vfstrace")==0 ){
      extern int vfstrace_register(
         const char *zTraceName,
         const char *zOldVfsName,
         int (*xOut)(const char*,void*),
         void *pOutArg,







>
>
>
>
>
>
>
>







22392
22393
22394
22395
22396
22397
22398
22399
22400
22401
22402
22403
22404
22405
22406
22407
22408
22409
22410
22411
22412
22413
      int n, sz;
      sz = (int)integerValue(cmdline_option_value(argc,argv,++i));
      if( sz<0 ) sz = 0;
      n = (int)integerValue(cmdline_option_value(argc,argv,++i));
      if( n<0 ) n = 0;
      sqlite3_config(SQLITE_CONFIG_LOOKASIDE, sz, n);
      if( sz*n==0 ) data.shellFlgs &= ~SHFLG_Lookaside;
    }else if( strcmp(z,"-threadsafe")==0 ){
      int n;
      n = (int)integerValue(cmdline_option_value(argc,argv,++i));
      switch( n ){
         case 0:  sqlite3_config(SQLITE_CONFIG_SINGLETHREAD);  break;
         case 2:  sqlite3_config(SQLITE_CONFIG_MULTITHREAD);   break;
         default: sqlite3_config(SQLITE_CONFIG_SERIALIZED);    break;
      }
#ifdef SQLITE_ENABLE_VFSTRACE
    }else if( strcmp(z,"-vfstrace")==0 ){
      extern int vfstrace_register(
         const char *zTraceName,
         const char *zOldVfsName,
         int (*xOut)(const char*,void*),
         void *pOutArg,
22148
22149
22150
22151
22152
22153
22154





22155
22156
22157
22158
22159
22160
22161
      ** command, so ignore them */
      break;
#endif
    }else if( strcmp(z, "-memtrace")==0 ){
      sqlite3MemTraceActivate(stderr);
    }else if( strcmp(z,"-bail")==0 ){
      bail_on_error = 1;





    }
  }
  verify_uninitialized();


#ifdef SQLITE_SHELL_INIT_PROC
  {







>
>
>
>
>







22452
22453
22454
22455
22456
22457
22458
22459
22460
22461
22462
22463
22464
22465
22466
22467
22468
22469
22470
      ** command, so ignore them */
      break;
#endif
    }else if( strcmp(z, "-memtrace")==0 ){
      sqlite3MemTraceActivate(stderr);
    }else if( strcmp(z,"-bail")==0 ){
      bail_on_error = 1;
    }else if( strcmp(z,"-nonce")==0 ){
      free(data.zNonce);
      data.zNonce = strdup(argv[++i]);
    }else if( strcmp(z,"-safe")==0 ){
      /* no-op - catch this on the second pass */
    }
  }
  verify_uninitialized();


#ifdef SQLITE_SHELL_INIT_PROC
  {
22274
22275
22276
22277
22278
22279
22280

22281
22282

22283
22284
22285
22286
22287
22288
22289
      sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator,
                       "%s",cmdline_option_value(argc,argv,++i));
    }else if( strcmp(z,"-nullvalue")==0 ){
      sqlite3_snprintf(sizeof(data.nullValue), data.nullValue,
                       "%s",cmdline_option_value(argc,argv,++i));
    }else if( strcmp(z,"-header")==0 ){
      data.showHeader = 1;

    }else if( strcmp(z,"-noheader")==0 ){
      data.showHeader = 0;

    }else if( strcmp(z,"-echo")==0 ){
      ShellSetFlag(&data, SHFLG_Echo);
    }else if( strcmp(z,"-eqp")==0 ){
      data.autoEQP = AUTOEQP_on;
    }else if( strcmp(z,"-eqpfull")==0 ){
      data.autoEQP = AUTOEQP_full;
    }else if( strcmp(z,"-stats")==0 ){







>
|

>







22583
22584
22585
22586
22587
22588
22589
22590
22591
22592
22593
22594
22595
22596
22597
22598
22599
22600
      sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator,
                       "%s",cmdline_option_value(argc,argv,++i));
    }else if( strcmp(z,"-nullvalue")==0 ){
      sqlite3_snprintf(sizeof(data.nullValue), data.nullValue,
                       "%s",cmdline_option_value(argc,argv,++i));
    }else if( strcmp(z,"-header")==0 ){
      data.showHeader = 1;
      ShellSetFlag(&data, SHFLG_HeaderSet);
     }else if( strcmp(z,"-noheader")==0 ){
      data.showHeader = 0;
      ShellSetFlag(&data, SHFLG_HeaderSet);
    }else if( strcmp(z,"-echo")==0 ){
      ShellSetFlag(&data, SHFLG_Echo);
    }else if( strcmp(z,"-eqp")==0 ){
      data.autoEQP = AUTOEQP_on;
    }else if( strcmp(z,"-eqpfull")==0 ){
      data.autoEQP = AUTOEQP_full;
    }else if( strcmp(z,"-stats")==0 ){
22308
22309
22310
22311
22312
22313
22314




22315
22316
22317
22318
22319
22320
22321
      stdin_is_interactive = 0;
    }else if( strcmp(z,"-heap")==0 ){
      i++;
    }else if( strcmp(z,"-pagecache")==0 ){
      i+=2;
    }else if( strcmp(z,"-lookaside")==0 ){
      i+=2;




    }else if( strcmp(z,"-mmap")==0 ){
      i++;
    }else if( strcmp(z,"-memtrace")==0 ){
      i++;
#ifdef SQLITE_ENABLE_SORTER_REFERENCES
    }else if( strcmp(z,"-sorterref")==0 ){
      i++;







>
>
>
>







22619
22620
22621
22622
22623
22624
22625
22626
22627
22628
22629
22630
22631
22632
22633
22634
22635
22636
      stdin_is_interactive = 0;
    }else if( strcmp(z,"-heap")==0 ){
      i++;
    }else if( strcmp(z,"-pagecache")==0 ){
      i+=2;
    }else if( strcmp(z,"-lookaside")==0 ){
      i+=2;
    }else if( strcmp(z,"-threadsafe")==0 ){
      i+=2;
    }else if( strcmp(z,"-nonce")==0 ){
      i += 2;
    }else if( strcmp(z,"-mmap")==0 ){
      i++;
    }else if( strcmp(z,"-memtrace")==0 ){
      i++;
#ifdef SQLITE_ENABLE_SORTER_REFERENCES
    }else if( strcmp(z,"-sorterref")==0 ){
      i++;
22366
22367
22368
22369
22370
22371
22372


22373
22374
22375
22376
22377
22378
22379
        arDotCommand(&data, 1, argv+(i-1), argc-(i-1));
      }else{
        arDotCommand(&data, 1, argv+i, argc-i);
      }
      readStdin = 0;
      break;
#endif


    }else{
      utf8_printf(stderr,"%s: Error: unknown option: %s\n", Argv0, z);
      raw_printf(stderr,"Use -help for a list of options.\n");
      return 1;
    }
    data.cMode = data.mode;
  }







>
>







22681
22682
22683
22684
22685
22686
22687
22688
22689
22690
22691
22692
22693
22694
22695
22696
        arDotCommand(&data, 1, argv+(i-1), argc-(i-1));
      }else{
        arDotCommand(&data, 1, argv+i, argc-i);
      }
      readStdin = 0;
      break;
#endif
    }else if( strcmp(z,"-safe")==0 ){
      data.bSafeMode = data.bSafeModePersist = 1;
    }else{
      utf8_printf(stderr,"%s: Error: unknown option: %s\n", Argv0, z);
      raw_printf(stderr,"Use -help for a list of options.\n");
      return 1;
    }
    data.cMode = data.mode;
  }
22468
22469
22470
22471
22472
22473
22474

22475
22476
22477
22478
22479
  data.doXdgOpen = 0;
  clearTempFile(&data);
#if !SQLITE_SHELL_IS_UTF8
  for(i=0; i<argcToFree; i++) free(argvToFree[i]);
  free(argvToFree);
#endif
  free(data.colWidth);

  /* Clear the global data structure so that valgrind will detect memory
  ** leaks */
  memset(&data, 0, sizeof(data));
  return rc;
}







>





22785
22786
22787
22788
22789
22790
22791
22792
22793
22794
22795
22796
22797
  data.doXdgOpen = 0;
  clearTempFile(&data);
#if !SQLITE_SHELL_IS_UTF8
  for(i=0; i<argcToFree; i++) free(argvToFree[i]);
  free(argvToFree);
#endif
  free(data.colWidth);
  free(data.zNonce);
  /* Clear the global data structure so that valgrind will detect memory
  ** leaks */
  memset(&data, 0, sizeof(data));
  return rc;
}
Changes to src/skins.c.
141
142
143
144
145
146
147

148
149
150
151
152
153
154
** be used (rank 3, above), then returns 0.
*/
char *skin_use_alternative(const char *zName, int rank){
  static int currentRank = 5;
  int i;
  Blob err = BLOB_INITIALIZER;
  if(rank > currentRank) return 0;

  if( zName && 1==rank && strchr(zName, '/')!=0 ){
    zAltSkinDir = fossil_strdup(zName);
    return 0;
  }
  if( zName && sqlite3_strglob("draft[1-9]", zName)==0 ){
    skin_use_draft(zName[5] - '0');
    return 0;







>







141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
** be used (rank 3, above), then returns 0.
*/
char *skin_use_alternative(const char *zName, int rank){
  static int currentRank = 5;
  int i;
  Blob err = BLOB_INITIALIZER;
  if(rank > currentRank) return 0;
  currentRank = rank;
  if( zName && 1==rank && strchr(zName, '/')!=0 ){
    zAltSkinDir = fossil_strdup(zName);
    return 0;
  }
  if( zName && sqlite3_strglob("draft[1-9]", zName)==0 ){
    skin_use_draft(zName[5] - '0');
    return 0;
864
865
866
867
868
869
870
871
872



873
874
875
876

877
878
879
880

881
882
883
884
885
886
887
888
889
  }
  @ <hr />
  @ Baseline: \
  skin_emit_skin_selector("basis", zBasis, zDraft);
  @ <input type="submit" name="diff" value="Unified Diff" />
  @ <input type="submit" name="sbsdiff" value="Side-by-Side Diff" />
  if( P("diff")!=0 || P("sbsdiff")!=0 ){
    u64 diffFlags = construct_diff_flags(1) | DIFF_STRIP_EOLCR;
    Blob from, to, out;



    if( P("sbsdiff")!=0 ) diffFlags |= DIFF_SIDEBYSIDE;
    blob_init(&to, zContent, -1);
    blob_init(&from, skin_file_content(zBasis, zFile), -1);
    blob_zero(&out);

    if( diffFlags & DIFF_SIDEBYSIDE ){
      text_diff(&from, &to, &out, 0, diffFlags | DIFF_HTML | DIFF_NOTTOOBIG);
      @ %s(blob_str(&out))
    }else{

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







<

>
>
>
|



>
|
|


>
|
<







865
866
867
868
869
870
871

872
873
874
875
876
877
878
879
880
881
882
883
884
885
886

887
888
889
890
891
892
893
  }
  @ <hr />
  @ Baseline: \
  skin_emit_skin_selector("basis", zBasis, zDraft);
  @ <input type="submit" name="diff" value="Unified Diff" />
  @ <input type="submit" name="sbsdiff" value="Side-by-Side Diff" />
  if( P("diff")!=0 || P("sbsdiff")!=0 ){

    Blob from, to, out;
    DiffConfig DCfg;
    construct_diff_flags(1, &DCfg);
    DCfg.diffFlags |= DIFF_STRIP_EOLCR;
    if( P("sbsdiff")!=0 ) DCfg.diffFlags |= DIFF_SIDEBYSIDE;
    blob_init(&to, zContent, -1);
    blob_init(&from, skin_file_content(zBasis, zFile), -1);
    blob_zero(&out);
    DCfg.diffFlags |= DIFF_HTML | DIFF_NOTTOOBIG; 
    if( DCfg.diffFlags & DIFF_SIDEBYSIDE ){
      text_diff(&from, &to, &out, &DCfg);
      @ %s(blob_str(&out))
    }else{
      DCfg.diffFlags |= DIFF_LINENO;
      text_diff(&from, &to, &out, &DCfg);

      @ <pre class="udiff">
      @ %s(blob_str(&out))
      @ </pre>
    }
    blob_reset(&from);
    blob_reset(&to);
    blob_reset(&out);
Changes to src/sqlite3.c.
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
**
** See also: [sqlite3_libversion()],
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
#define SQLITE_VERSION        "3.37.0"
#define SQLITE_VERSION_NUMBER 3037000
#define SQLITE_SOURCE_ID      "2021-08-06 20:17:39 087b8b41c6ed76b55c11315e7e95679d67590be20ae21108b593d00bb7d1c57a"

/*
** CAPI3REF: Run-Time Library Version Numbers
** KEYWORDS: sqlite3_version sqlite3_sourceid
**
** These interfaces provide the same information as the [SQLITE_VERSION],
** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros







|







450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
**
** See also: [sqlite3_libversion()],
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
#define SQLITE_VERSION        "3.37.0"
#define SQLITE_VERSION_NUMBER 3037000
#define SQLITE_SOURCE_ID      "2021-10-06 10:36:56 566e6974892ebd3d3de8d77b24655257a5efe14434c553e1a25fc680b201b336"

/*
** CAPI3REF: Run-Time Library Version Numbers
** KEYWORDS: sqlite3_version sqlite3_sourceid
**
** These interfaces provide the same information as the [SQLITE_VERSION],
** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros
863
864
865
866
867
868
869

870
871
872
873
874
875
876
#define SQLITE_CONSTRAINT_NOTNULL      (SQLITE_CONSTRAINT | (5<<8))
#define SQLITE_CONSTRAINT_PRIMARYKEY   (SQLITE_CONSTRAINT | (6<<8))
#define SQLITE_CONSTRAINT_TRIGGER      (SQLITE_CONSTRAINT | (7<<8))
#define SQLITE_CONSTRAINT_UNIQUE       (SQLITE_CONSTRAINT | (8<<8))
#define SQLITE_CONSTRAINT_VTAB         (SQLITE_CONSTRAINT | (9<<8))
#define SQLITE_CONSTRAINT_ROWID        (SQLITE_CONSTRAINT |(10<<8))
#define SQLITE_CONSTRAINT_PINNED       (SQLITE_CONSTRAINT |(11<<8))

#define SQLITE_NOTICE_RECOVER_WAL      (SQLITE_NOTICE | (1<<8))
#define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8))
#define SQLITE_WARNING_AUTOINDEX       (SQLITE_WARNING | (1<<8))
#define SQLITE_AUTH_USER               (SQLITE_AUTH | (1<<8))
#define SQLITE_OK_LOAD_PERMANENTLY     (SQLITE_OK | (1<<8))
#define SQLITE_OK_SYMLINK              (SQLITE_OK | (2<<8))








>







863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
#define SQLITE_CONSTRAINT_NOTNULL      (SQLITE_CONSTRAINT | (5<<8))
#define SQLITE_CONSTRAINT_PRIMARYKEY   (SQLITE_CONSTRAINT | (6<<8))
#define SQLITE_CONSTRAINT_TRIGGER      (SQLITE_CONSTRAINT | (7<<8))
#define SQLITE_CONSTRAINT_UNIQUE       (SQLITE_CONSTRAINT | (8<<8))
#define SQLITE_CONSTRAINT_VTAB         (SQLITE_CONSTRAINT | (9<<8))
#define SQLITE_CONSTRAINT_ROWID        (SQLITE_CONSTRAINT |(10<<8))
#define SQLITE_CONSTRAINT_PINNED       (SQLITE_CONSTRAINT |(11<<8))
#define SQLITE_CONSTRAINT_DATATYPE     (SQLITE_CONSTRAINT |(12<<8))
#define SQLITE_NOTICE_RECOVER_WAL      (SQLITE_NOTICE | (1<<8))
#define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8))
#define SQLITE_WARNING_AUTOINDEX       (SQLITE_WARNING | (1<<8))
#define SQLITE_AUTH_USER               (SQLITE_AUTH | (1<<8))
#define SQLITE_OK_LOAD_PERMANENTLY     (SQLITE_OK | (1<<8))
#define SQLITE_OK_SYMLINK              (SQLITE_OK | (2<<8))

13191
13192
13193
13194
13195
13196
13197








13198
13199
13200
13201
13202
13203
13204
13205
13206
13207
13208
13209
13210
13211
13212
13213
13214
13215
13216
13217
13218
13219
13220
*/
#ifndef NDEBUG
# define VVA_ONLY(X)  X
#else
# define VVA_ONLY(X)
#endif









/*
** The ALWAYS and NEVER macros surround boolean expressions which
** are intended to always be true or false, respectively.  Such
** expressions could be omitted from the code completely.  But they
** are included in a few cases in order to enhance the resilience
** of SQLite to unexpected behavior - to make the code "self-healing"
** or "ductile" rather than being "brittle" and crashing at the first
** hint of unplanned behavior.
**
** In other words, ALWAYS and NEVER are added for defensive code.
**
** When doing coverage testing ALWAYS and NEVER are hard-coded to
** be true and false so that the unreachable code they specify will
** not be counted as untested code.
*/
#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST)
# define ALWAYS(X)      (1)
# define NEVER(X)       (0)
#elif !defined(NDEBUG)
# define ALWAYS(X)      ((X)?1:(assert(0),0))
# define NEVER(X)       ((X)?(assert(0),1):0)
#else
# define ALWAYS(X)      (X)







>
>
>
>
>
>
>
>















|







13192
13193
13194
13195
13196
13197
13198
13199
13200
13201
13202
13203
13204
13205
13206
13207
13208
13209
13210
13211
13212
13213
13214
13215
13216
13217
13218
13219
13220
13221
13222
13223
13224
13225
13226
13227
13228
13229
*/
#ifndef NDEBUG
# define VVA_ONLY(X)  X
#else
# define VVA_ONLY(X)
#endif

/*
** Disable ALWAYS() and NEVER() (make them pass-throughs) for coverage
** and mutation testing
*/
#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST)
# define SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS  1
#endif

/*
** The ALWAYS and NEVER macros surround boolean expressions which
** are intended to always be true or false, respectively.  Such
** expressions could be omitted from the code completely.  But they
** are included in a few cases in order to enhance the resilience
** of SQLite to unexpected behavior - to make the code "self-healing"
** or "ductile" rather than being "brittle" and crashing at the first
** hint of unplanned behavior.
**
** In other words, ALWAYS and NEVER are added for defensive code.
**
** When doing coverage testing ALWAYS and NEVER are hard-coded to
** be true and false so that the unreachable code they specify will
** not be counted as untested code.
*/
#if defined(SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS)
# define ALWAYS(X)      (1)
# define NEVER(X)       (0)
#elif !defined(NDEBUG)
# define ALWAYS(X)      ((X)?1:(assert(0),0))
# define NEVER(X)       ((X)?(assert(0),1):0)
#else
# define ALWAYS(X)      (X)
13300
13301
13302
13303
13304
13305
13306







13307
13308
13309
13310
13311
13312
13313
/*
** SQLITE_ENABLE_EXPLAIN_COMMENTS is incompatible with SQLITE_OMIT_EXPLAIN
*/
#ifdef SQLITE_OMIT_EXPLAIN
# undef SQLITE_ENABLE_EXPLAIN_COMMENTS
#endif








/*
** Return true (non-zero) if the input is an integer that is too large
** to fit in 32-bits.  This macro is used inside of various testcase()
** macros to verify that we have tested SQLite for large-file support.
*/
#define IS_BIG_INT(X)  (((X)&~(i64)0xffffffff)!=0)








>
>
>
>
>
>
>







13309
13310
13311
13312
13313
13314
13315
13316
13317
13318
13319
13320
13321
13322
13323
13324
13325
13326
13327
13328
13329
/*
** SQLITE_ENABLE_EXPLAIN_COMMENTS is incompatible with SQLITE_OMIT_EXPLAIN
*/
#ifdef SQLITE_OMIT_EXPLAIN
# undef SQLITE_ENABLE_EXPLAIN_COMMENTS
#endif

/*
** SQLITE_OMIT_VIRTUALTABLE implies SQLITE_OMIT_ALTERTABLE
*/
#if defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_ALTERTABLE)
# define SQLITE_OMIT_ALTERTABLE
#endif

/*
** Return true (non-zero) if the input is an integer that is too large
** to fit in 32-bits.  This macro is used inside of various testcase()
** macros to verify that we have tested SQLite for large-file support.
*/
#define IS_BIG_INT(X)  (((X)&~(i64)0xffffffff)!=0)

13444
13445
13446
13447
13448
13449
13450
13451
13452

13453
13454
13455
13456
13457
13458
13459
#define TK_IF                              18
#define TK_NOT                             19
#define TK_EXISTS                          20
#define TK_TEMP                            21
#define TK_LP                              22
#define TK_RP                              23
#define TK_AS                              24
#define TK_WITHOUT                         25
#define TK_COMMA                           26

#define TK_ABORT                           27
#define TK_ACTION                          28
#define TK_AFTER                           29
#define TK_ANALYZE                         30
#define TK_ASC                             31
#define TK_ATTACH                          32
#define TK_BEFORE                          33







<
|
>







13460
13461
13462
13463
13464
13465
13466

13467
13468
13469
13470
13471
13472
13473
13474
13475
#define TK_IF                              18
#define TK_NOT                             19
#define TK_EXISTS                          20
#define TK_TEMP                            21
#define TK_LP                              22
#define TK_RP                              23
#define TK_AS                              24

#define TK_COMMA                           25
#define TK_WITHOUT                         26
#define TK_ABORT                           27
#define TK_ACTION                          28
#define TK_AFTER                           29
#define TK_ANALYZE                         30
#define TK_ASC                             31
#define TK_ATTACH                          32
#define TK_BEFORE                          33
15107
15108
15109
15110
15111
15112
15113

15114
15115
15116
15117
15118
15119
15120
15121
15122
15123
15124
15125
15126
15127
15128
15129
15130
15131
15132
15133
15134
15135
15136
15137

15138
15139
15140
15141
15142
15143
15144
15145
15146
15147
15148
15149
15150
15151

15152
15153
15154
15155
15156
15157
15158
15159
15160
15161
15162
15163
15164
15165
15166
15167
15168
15169
15170
15171
15172
15173
15174
15175
15176
15177
15178
15179
15180
15181
15182
15183
15184

15185
15186
15187
15188
15189
15190
15191
15192
15193
15194
15195
15196
15197
15198
15199
15200
15201
15202
15203
15204
15205
15206
15207
15208
15209


15210
15211
15212
15213
15214
15215
15216
15217
15218
15219
15220
15221
15222
15223
15224
15225
15226
15227
15228
15229
15230
15231
15232
15233
15234
15235
15236
15237
15238
15239
15240
15241
15242
15243
15244
15245


15246
15247
15248
15249
15250
15251
15252
15253
15254
15255
15256
15257
15258
15259
15260
15261
15262
15263
15264
15265
15266
15267
15268
15269
15270
15271
15272
15273
15274
15275
15276
15277
15278
15279
15280
15281
15282
15283
15284
15285
15286
15287
15288
15289
15290
15291
15292
15293
15294
15295
15296
15297
15298
15299
15300
15301
15302
15303
15304
15305
15306
15307
15308
15309
15310
15311
15312
15313
15314
15315
15316
15317
15318
15319
15320
15321
15322
#define OP_Yield          14 /* jump                                       */
#define OP_MustBeInt      15 /* jump                                       */
#define OP_Jump           16 /* jump                                       */
#define OP_Once           17 /* jump                                       */
#define OP_If             18 /* jump                                       */
#define OP_Not            19 /* same as TK_NOT, synopsis: r[P2]= !r[P1]    */
#define OP_IfNot          20 /* jump                                       */

#define OP_IfNullRow      21 /* jump, synopsis: if P1.nullRow then r[P3]=NULL, goto P2 */
#define OP_SeekLT         22 /* jump, synopsis: key=r[P3@P4]               */
#define OP_SeekLE         23 /* jump, synopsis: key=r[P3@P4]               */
#define OP_SeekGE         24 /* jump, synopsis: key=r[P3@P4]               */
#define OP_SeekGT         25 /* jump, synopsis: key=r[P3@P4]               */
#define OP_IfNotOpen      26 /* jump, synopsis: if( !csr[P1] ) goto P2     */
#define OP_IfNoHope       27 /* jump, synopsis: key=r[P3@P4]               */
#define OP_NoConflict     28 /* jump, synopsis: key=r[P3@P4]               */
#define OP_NotFound       29 /* jump, synopsis: key=r[P3@P4]               */
#define OP_Found          30 /* jump, synopsis: key=r[P3@P4]               */
#define OP_SeekRowid      31 /* jump, synopsis: intkey=r[P3]               */
#define OP_NotExists      32 /* jump, synopsis: intkey=r[P3]               */
#define OP_Last           33 /* jump                                       */
#define OP_IfSmaller      34 /* jump                                       */
#define OP_SorterSort     35 /* jump                                       */
#define OP_Sort           36 /* jump                                       */
#define OP_Rewind         37 /* jump                                       */
#define OP_IdxLE          38 /* jump, synopsis: key=r[P3@P4]               */
#define OP_IdxGT          39 /* jump, synopsis: key=r[P3@P4]               */
#define OP_IdxLT          40 /* jump, synopsis: key=r[P3@P4]               */
#define OP_IdxGE          41 /* jump, synopsis: key=r[P3@P4]               */
#define OP_RowSetRead     42 /* jump, synopsis: r[P3]=rowset(P1)           */
#define OP_Or             43 /* same as TK_OR, synopsis: r[P3]=(r[P1] || r[P2]) */
#define OP_And            44 /* same as TK_AND, synopsis: r[P3]=(r[P1] && r[P2]) */

#define OP_RowSetTest     45 /* jump, synopsis: if r[P3] in rowset(P1) goto P2 */
#define OP_Program        46 /* jump                                       */
#define OP_FkIfZero       47 /* jump, synopsis: if fkctr[P1]==0 goto P2    */
#define OP_IfPos          48 /* jump, synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */
#define OP_IfNotZero      49 /* jump, synopsis: if r[P1]!=0 then r[P1]--, goto P2 */
#define OP_IsNull         50 /* jump, same as TK_ISNULL, synopsis: if r[P1]==NULL goto P2 */
#define OP_NotNull        51 /* jump, same as TK_NOTNULL, synopsis: if r[P1]!=NULL goto P2 */
#define OP_Ne             52 /* jump, same as TK_NE, synopsis: IF r[P3]!=r[P1] */
#define OP_Eq             53 /* jump, same as TK_EQ, synopsis: IF r[P3]==r[P1] */
#define OP_Gt             54 /* jump, same as TK_GT, synopsis: IF r[P3]>r[P1] */
#define OP_Le             55 /* jump, same as TK_LE, synopsis: IF r[P3]<=r[P1] */
#define OP_Lt             56 /* jump, same as TK_LT, synopsis: IF r[P3]<r[P1] */
#define OP_Ge             57 /* jump, same as TK_GE, synopsis: IF r[P3]>=r[P1] */
#define OP_ElseEq         58 /* jump, same as TK_ESCAPE                    */

#define OP_DecrJumpZero   59 /* jump, synopsis: if (--r[P1])==0 goto P2    */
#define OP_IncrVacuum     60 /* jump                                       */
#define OP_VNext          61 /* jump                                       */
#define OP_Init           62 /* jump, synopsis: Start at P2                */
#define OP_PureFunc       63 /* synopsis: r[P3]=func(r[P2@NP])             */
#define OP_Function       64 /* synopsis: r[P3]=func(r[P2@NP])             */
#define OP_Return         65
#define OP_EndCoroutine   66
#define OP_HaltIfNull     67 /* synopsis: if r[P3]=null halt               */
#define OP_Halt           68
#define OP_Integer        69 /* synopsis: r[P2]=P1                         */
#define OP_Int64          70 /* synopsis: r[P2]=P4                         */
#define OP_String         71 /* synopsis: r[P2]='P4' (len=P1)              */
#define OP_Null           72 /* synopsis: r[P2..P3]=NULL                   */
#define OP_SoftNull       73 /* synopsis: r[P1]=NULL                       */
#define OP_Blob           74 /* synopsis: r[P2]=P4 (len=P1)                */
#define OP_Variable       75 /* synopsis: r[P2]=parameter(P1,P4)           */
#define OP_Move           76 /* synopsis: r[P2@P3]=r[P1@P3]                */
#define OP_Copy           77 /* synopsis: r[P2@P3+1]=r[P1@P3+1]            */
#define OP_SCopy          78 /* synopsis: r[P2]=r[P1]                      */
#define OP_IntCopy        79 /* synopsis: r[P2]=r[P1]                      */
#define OP_ChngCntRow     80 /* synopsis: output=r[P1]                     */
#define OP_ResultRow      81 /* synopsis: output=r[P1@P2]                  */
#define OP_CollSeq        82
#define OP_AddImm         83 /* synopsis: r[P1]=r[P1]+P2                   */
#define OP_RealAffinity   84
#define OP_Cast           85 /* synopsis: affinity(r[P1])                  */
#define OP_Permutation    86
#define OP_Compare        87 /* synopsis: r[P1@P3] <-> r[P2@P3]            */
#define OP_IsTrue         88 /* synopsis: r[P2] = coalesce(r[P1]==TRUE,P3) ^ P4 */
#define OP_ZeroOrNull     89 /* synopsis: r[P2] = 0 OR NULL                */
#define OP_Offset         90 /* synopsis: r[P3] = sqlite_offset(P1)        */
#define OP_Column         91 /* synopsis: r[P3]=PX                         */

#define OP_Affinity       92 /* synopsis: affinity(r[P1@P2])               */
#define OP_MakeRecord     93 /* synopsis: r[P3]=mkrec(r[P1@P2])            */
#define OP_Count          94 /* synopsis: r[P2]=count()                    */
#define OP_ReadCookie     95
#define OP_SetCookie      96
#define OP_ReopenIdx      97 /* synopsis: root=P2 iDb=P3                   */
#define OP_OpenRead       98 /* synopsis: root=P2 iDb=P3                   */
#define OP_OpenWrite      99 /* synopsis: root=P2 iDb=P3                   */
#define OP_OpenDup       100
#define OP_OpenAutoindex 101 /* synopsis: nColumn=P2                       */
#define OP_BitAnd        102 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */
#define OP_BitOr         103 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */
#define OP_ShiftLeft     104 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<<r[P1] */
#define OP_ShiftRight    105 /* same as TK_RSHIFT, synopsis: r[P3]=r[P2]>>r[P1] */
#define OP_Add           106 /* same as TK_PLUS, synopsis: r[P3]=r[P1]+r[P2] */
#define OP_Subtract      107 /* same as TK_MINUS, synopsis: r[P3]=r[P2]-r[P1] */
#define OP_Multiply      108 /* same as TK_STAR, synopsis: r[P3]=r[P1]*r[P2] */
#define OP_Divide        109 /* same as TK_SLASH, synopsis: r[P3]=r[P2]/r[P1] */
#define OP_Remainder     110 /* same as TK_REM, synopsis: r[P3]=r[P2]%r[P1] */
#define OP_Concat        111 /* same as TK_CONCAT, synopsis: r[P3]=r[P2]+r[P1] */
#define OP_OpenEphemeral 112 /* synopsis: nColumn=P2                       */
#define OP_BitNot        113 /* same as TK_BITNOT, synopsis: r[P2]= ~r[P1] */
#define OP_SorterOpen    114
#define OP_SequenceTest  115 /* synopsis: if( cursor[P1].ctr++ ) pc = P2   */
#define OP_String8       116 /* same as TK_STRING, synopsis: r[P2]='P4'    */


#define OP_OpenPseudo    117 /* synopsis: P3 columns in r[P2]              */
#define OP_Close         118
#define OP_ColumnsUsed   119
#define OP_SeekScan      120 /* synopsis: Scan-ahead up to P1 rows         */
#define OP_SeekHit       121 /* synopsis: set P2<=seekHit<=P3              */
#define OP_Sequence      122 /* synopsis: r[P2]=cursor[P1].ctr++           */
#define OP_NewRowid      123 /* synopsis: r[P2]=rowid                      */
#define OP_Insert        124 /* synopsis: intkey=r[P3] data=r[P2]          */
#define OP_RowCell       125
#define OP_Delete        126
#define OP_ResetCount    127
#define OP_SorterCompare 128 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 */
#define OP_SorterData    129 /* synopsis: r[P2]=data                       */
#define OP_RowData       130 /* synopsis: r[P2]=data                       */
#define OP_Rowid         131 /* synopsis: r[P2]=rowid                      */
#define OP_NullRow       132
#define OP_SeekEnd       133
#define OP_IdxInsert     134 /* synopsis: key=r[P2]                        */
#define OP_SorterInsert  135 /* synopsis: key=r[P2]                        */
#define OP_IdxDelete     136 /* synopsis: key=r[P2@P3]                     */
#define OP_DeferredSeek  137 /* synopsis: Move P3 to P1.rowid if needed    */
#define OP_IdxRowid      138 /* synopsis: r[P2]=rowid                      */
#define OP_FinishSeek    139
#define OP_Destroy       140
#define OP_Clear         141
#define OP_ResetSorter   142
#define OP_CreateBtree   143 /* synopsis: r[P2]=root iDb=P1 flags=P3       */
#define OP_SqlExec       144
#define OP_ParseSchema   145
#define OP_LoadAnalysis  146
#define OP_DropTable     147
#define OP_DropIndex     148
#define OP_DropTrigger   149
#define OP_IntegrityCk   150
#define OP_RowSetAdd     151 /* synopsis: rowset(P1)=r[P2]                 */
#define OP_Real          152 /* same as TK_FLOAT, synopsis: r[P2]=P4       */


#define OP_Param         153
#define OP_FkCounter     154 /* synopsis: fkctr[P1]+=P2                    */
#define OP_MemMax        155 /* synopsis: r[P1]=max(r[P1],r[P2])           */
#define OP_OffsetLimit   156 /* synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) */
#define OP_AggInverse    157 /* synopsis: accum=r[P3] inverse(r[P2@P5])    */
#define OP_AggStep       158 /* synopsis: accum=r[P3] step(r[P2@P5])       */
#define OP_AggStep1      159 /* synopsis: accum=r[P3] step(r[P2@P5])       */
#define OP_AggValue      160 /* synopsis: r[P3]=value N=P2                 */
#define OP_AggFinal      161 /* synopsis: accum=r[P1] N=P2                 */
#define OP_Expire        162
#define OP_CursorLock    163
#define OP_CursorUnlock  164
#define OP_TableLock     165 /* synopsis: iDb=P1 root=P2 write=P3          */
#define OP_VBegin        166
#define OP_VCreate       167
#define OP_VDestroy      168
#define OP_VOpen         169
#define OP_VColumn       170 /* synopsis: r[P3]=vcolumn(P2)                */
#define OP_VRename       171
#define OP_Pagecount     172
#define OP_MaxPgcnt      173
#define OP_Trace         174
#define OP_CursorHint    175
#define OP_ReleaseReg    176 /* synopsis: release r[P1@P2] mask P3         */
#define OP_Noop          177
#define OP_Explain       178
#define OP_Abortable     179

/* Properties such as "out2" or "jump" that are specified in
** comments following the "case" for each opcode in the vdbe.c
** are encoded into bitvectors as follows:
*/
#define OPFLG_JUMP        0x01  /* jump:  P2 holds jmp target */
#define OPFLG_IN1         0x02  /* in1:   P1 is an input */
#define OPFLG_IN2         0x04  /* in2:   P2 is an input */
#define OPFLG_IN3         0x08  /* in3:   P3 is an input */
#define OPFLG_OUT2        0x10  /* out2:  P2 is an output */
#define OPFLG_OUT3        0x20  /* out3:  P3 is an output */
#define OPFLG_INITIALIZER {\
/*   0 */ 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x10,\
/*   8 */ 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x03, 0x03,\
/*  16 */ 0x01, 0x01, 0x03, 0x12, 0x03, 0x01, 0x09, 0x09,\
/*  24 */ 0x09, 0x09, 0x01, 0x09, 0x09, 0x09, 0x09, 0x09,\
/*  32 */ 0x09, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,\
/*  40 */ 0x01, 0x01, 0x23, 0x26, 0x26, 0x0b, 0x01, 0x01,\
/*  48 */ 0x03, 0x03, 0x03, 0x03, 0x0b, 0x0b, 0x0b, 0x0b,\
/*  56 */ 0x0b, 0x0b, 0x01, 0x03, 0x01, 0x01, 0x01, 0x00,\
/*  64 */ 0x00, 0x02, 0x02, 0x08, 0x00, 0x10, 0x10, 0x10,\
/*  72 */ 0x10, 0x00, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10,\
/*  80 */ 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00,\
/*  88 */ 0x12, 0x1e, 0x20, 0x00, 0x00, 0x00, 0x10, 0x10,\
/*  96 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x26,\
/* 104 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26,\
/* 112 */ 0x00, 0x12, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,\
/* 120 */ 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,\
/* 128 */ 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x04, 0x04,\
/* 136 */ 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, 0x10,\
/* 144 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06,\
/* 152 */ 0x10, 0x10, 0x00, 0x04, 0x1a, 0x00, 0x00, 0x00,\
/* 160 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
/* 168 */ 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00,\
/* 176 */ 0x00, 0x00, 0x00, 0x00,}

/* The resolve3P2Values() routine is able to run faster if it knows
** the value of the largest JUMP opcode.  The smaller the maximum
** JUMP opcode the better, so the mkopcodeh.tcl script that
** generated this include file strives to group all JUMP opcodes
** together near the beginning of the list.
*/
#define SQLITE_MX_JUMP_OPCODE  62  /* Maximum JUMP opcode */

/************** End of opcodes.h *********************************************/
/************** Continuing where we left off in vdbe.h ***********************/

/*
** Additional non-public SQLITE_PREPARE_* flags
*/







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


>
|
|
|
|
<









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










|

|
|

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

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














|
|
|
|
|
|
|
|
|
|
|


|
|
|
|
|

|
|







|







15123
15124
15125
15126
15127
15128
15129
15130
15131
15132
15133
15134
15135
15136
15137
15138
15139
15140
15141
15142
15143
15144
15145
15146
15147
15148
15149
15150
15151

15152
15153
15154
15155
15156
15157
15158

15159
15160
15161
15162
15163
15164
15165
15166
15167
15168
15169
15170
15171
15172
15173
15174
15175
15176
15177
15178
15179
15180
15181
15182
15183
15184
15185
15186
15187
15188
15189
15190
15191
15192
15193
15194
15195
15196
15197
15198
15199
15200
15201
15202
15203
15204
15205
15206
15207
15208
15209
15210


15211
15212
15213
15214
15215
15216
15217
15218
15219
15220
15221
15222
15223
15224
15225
15226
15227
15228
15229
15230
15231
15232
15233
15234
15235
15236
15237
15238
15239
15240
15241
15242
15243
15244
15245
15246
15247
15248
15249
15250
15251
15252
15253
15254
15255
15256
15257
15258
15259
15260


15261
15262
15263
15264
15265
15266
15267
15268
15269
15270
15271
15272
15273
15274
15275
15276
15277
15278
15279
15280
15281
15282
15283
15284
15285
15286
15287
15288
15289
15290
15291
15292
15293
15294
15295
15296
15297
15298
15299
15300
15301
15302
15303
15304
15305
15306
15307
15308
15309
15310
15311
15312
15313
15314
15315
15316
15317
15318
15319
15320
15321
15322
15323
15324
15325
15326
15327
15328
15329
15330
15331
15332
15333
15334
15335
15336
15337
15338
15339
15340
#define OP_Yield          14 /* jump                                       */
#define OP_MustBeInt      15 /* jump                                       */
#define OP_Jump           16 /* jump                                       */
#define OP_Once           17 /* jump                                       */
#define OP_If             18 /* jump                                       */
#define OP_Not            19 /* same as TK_NOT, synopsis: r[P2]= !r[P1]    */
#define OP_IfNot          20 /* jump                                       */
#define OP_IsNullOrType   21 /* jump, synopsis: if typeof(r[P1]) IN (P3,5) goto P2 */
#define OP_IfNullRow      22 /* jump, synopsis: if P1.nullRow then r[P3]=NULL, goto P2 */
#define OP_SeekLT         23 /* jump, synopsis: key=r[P3@P4]               */
#define OP_SeekLE         24 /* jump, synopsis: key=r[P3@P4]               */
#define OP_SeekGE         25 /* jump, synopsis: key=r[P3@P4]               */
#define OP_SeekGT         26 /* jump, synopsis: key=r[P3@P4]               */
#define OP_IfNotOpen      27 /* jump, synopsis: if( !csr[P1] ) goto P2     */
#define OP_IfNoHope       28 /* jump, synopsis: key=r[P3@P4]               */
#define OP_NoConflict     29 /* jump, synopsis: key=r[P3@P4]               */
#define OP_NotFound       30 /* jump, synopsis: key=r[P3@P4]               */
#define OP_Found          31 /* jump, synopsis: key=r[P3@P4]               */
#define OP_SeekRowid      32 /* jump, synopsis: intkey=r[P3]               */
#define OP_NotExists      33 /* jump, synopsis: intkey=r[P3]               */
#define OP_Last           34 /* jump                                       */
#define OP_IfSmaller      35 /* jump                                       */
#define OP_SorterSort     36 /* jump                                       */
#define OP_Sort           37 /* jump                                       */
#define OP_Rewind         38 /* jump                                       */
#define OP_IdxLE          39 /* jump, synopsis: key=r[P3@P4]               */
#define OP_IdxGT          40 /* jump, synopsis: key=r[P3@P4]               */
#define OP_IdxLT          41 /* jump, synopsis: key=r[P3@P4]               */
#define OP_IdxGE          42 /* jump, synopsis: key=r[P3@P4]               */

#define OP_Or             43 /* same as TK_OR, synopsis: r[P3]=(r[P1] || r[P2]) */
#define OP_And            44 /* same as TK_AND, synopsis: r[P3]=(r[P1] && r[P2]) */
#define OP_RowSetRead     45 /* jump, synopsis: r[P3]=rowset(P1)           */
#define OP_RowSetTest     46 /* jump, synopsis: if r[P3] in rowset(P1) goto P2 */
#define OP_Program        47 /* jump                                       */
#define OP_FkIfZero       48 /* jump, synopsis: if fkctr[P1]==0 goto P2    */
#define OP_IfPos          49 /* jump, synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */

#define OP_IsNull         50 /* jump, same as TK_ISNULL, synopsis: if r[P1]==NULL goto P2 */
#define OP_NotNull        51 /* jump, same as TK_NOTNULL, synopsis: if r[P1]!=NULL goto P2 */
#define OP_Ne             52 /* jump, same as TK_NE, synopsis: IF r[P3]!=r[P1] */
#define OP_Eq             53 /* jump, same as TK_EQ, synopsis: IF r[P3]==r[P1] */
#define OP_Gt             54 /* jump, same as TK_GT, synopsis: IF r[P3]>r[P1] */
#define OP_Le             55 /* jump, same as TK_LE, synopsis: IF r[P3]<=r[P1] */
#define OP_Lt             56 /* jump, same as TK_LT, synopsis: IF r[P3]<r[P1] */
#define OP_Ge             57 /* jump, same as TK_GE, synopsis: IF r[P3]>=r[P1] */
#define OP_ElseEq         58 /* jump, same as TK_ESCAPE                    */
#define OP_IfNotZero      59 /* jump, synopsis: if r[P1]!=0 then r[P1]--, goto P2 */
#define OP_DecrJumpZero   60 /* jump, synopsis: if (--r[P1])==0 goto P2    */
#define OP_IncrVacuum     61 /* jump                                       */
#define OP_VNext          62 /* jump                                       */
#define OP_Init           63 /* jump, synopsis: Start at P2                */
#define OP_PureFunc       64 /* synopsis: r[P3]=func(r[P2@NP])             */
#define OP_Function       65 /* synopsis: r[P3]=func(r[P2@NP])             */
#define OP_Return         66
#define OP_EndCoroutine   67
#define OP_HaltIfNull     68 /* synopsis: if r[P3]=null halt               */
#define OP_Halt           69
#define OP_Integer        70 /* synopsis: r[P2]=P1                         */
#define OP_Int64          71 /* synopsis: r[P2]=P4                         */
#define OP_String         72 /* synopsis: r[P2]='P4' (len=P1)              */
#define OP_Null           73 /* synopsis: r[P2..P3]=NULL                   */
#define OP_SoftNull       74 /* synopsis: r[P1]=NULL                       */
#define OP_Blob           75 /* synopsis: r[P2]=P4 (len=P1)                */
#define OP_Variable       76 /* synopsis: r[P2]=parameter(P1,P4)           */
#define OP_Move           77 /* synopsis: r[P2@P3]=r[P1@P3]                */
#define OP_Copy           78 /* synopsis: r[P2@P3+1]=r[P1@P3+1]            */
#define OP_SCopy          79 /* synopsis: r[P2]=r[P1]                      */
#define OP_IntCopy        80 /* synopsis: r[P2]=r[P1]                      */
#define OP_ChngCntRow     81 /* synopsis: output=r[P1]                     */
#define OP_ResultRow      82 /* synopsis: output=r[P1@P2]                  */
#define OP_CollSeq        83
#define OP_AddImm         84 /* synopsis: r[P1]=r[P1]+P2                   */
#define OP_RealAffinity   85
#define OP_Cast           86 /* synopsis: affinity(r[P1])                  */
#define OP_Permutation    87
#define OP_Compare        88 /* synopsis: r[P1@P3] <-> r[P2@P3]            */
#define OP_IsTrue         89 /* synopsis: r[P2] = coalesce(r[P1]==TRUE,P3) ^ P4 */
#define OP_ZeroOrNull     90 /* synopsis: r[P2] = 0 OR NULL                */
#define OP_Offset         91 /* synopsis: r[P3] = sqlite_offset(P1)        */
#define OP_Column         92 /* synopsis: r[P3]=PX                         */
#define OP_TypeCheck      93 /* synopsis: typecheck(r[P1@P2])              */
#define OP_Affinity       94 /* synopsis: affinity(r[P1@P2])               */
#define OP_MakeRecord     95 /* synopsis: r[P3]=mkrec(r[P1@P2])            */
#define OP_Count          96 /* synopsis: r[P2]=count()                    */
#define OP_ReadCookie     97
#define OP_SetCookie      98
#define OP_ReopenIdx      99 /* synopsis: root=P2 iDb=P3                   */
#define OP_OpenRead      100 /* synopsis: root=P2 iDb=P3                   */
#define OP_OpenWrite     101 /* synopsis: root=P2 iDb=P3                   */


#define OP_BitAnd        102 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */
#define OP_BitOr         103 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */
#define OP_ShiftLeft     104 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<<r[P1] */
#define OP_ShiftRight    105 /* same as TK_RSHIFT, synopsis: r[P3]=r[P2]>>r[P1] */
#define OP_Add           106 /* same as TK_PLUS, synopsis: r[P3]=r[P1]+r[P2] */
#define OP_Subtract      107 /* same as TK_MINUS, synopsis: r[P3]=r[P2]-r[P1] */
#define OP_Multiply      108 /* same as TK_STAR, synopsis: r[P3]=r[P1]*r[P2] */
#define OP_Divide        109 /* same as TK_SLASH, synopsis: r[P3]=r[P2]/r[P1] */
#define OP_Remainder     110 /* same as TK_REM, synopsis: r[P3]=r[P2]%r[P1] */
#define OP_Concat        111 /* same as TK_CONCAT, synopsis: r[P3]=r[P2]+r[P1] */
#define OP_OpenDup       112
#define OP_BitNot        113 /* same as TK_BITNOT, synopsis: r[P2]= ~r[P1] */
#define OP_OpenAutoindex 114 /* synopsis: nColumn=P2                       */
#define OP_OpenEphemeral 115 /* synopsis: nColumn=P2                       */
#define OP_String8       116 /* same as TK_STRING, synopsis: r[P2]='P4'    */
#define OP_SorterOpen    117
#define OP_SequenceTest  118 /* synopsis: if( cursor[P1].ctr++ ) pc = P2   */
#define OP_OpenPseudo    119 /* synopsis: P3 columns in r[P2]              */
#define OP_Close         120
#define OP_ColumnsUsed   121
#define OP_SeekScan      122 /* synopsis: Scan-ahead up to P1 rows         */
#define OP_SeekHit       123 /* synopsis: set P2<=seekHit<=P3              */
#define OP_Sequence      124 /* synopsis: r[P2]=cursor[P1].ctr++           */
#define OP_NewRowid      125 /* synopsis: r[P2]=rowid                      */
#define OP_Insert        126 /* synopsis: intkey=r[P3] data=r[P2]          */
#define OP_RowCell       127
#define OP_Delete        128
#define OP_ResetCount    129
#define OP_SorterCompare 130 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 */
#define OP_SorterData    131 /* synopsis: r[P2]=data                       */
#define OP_RowData       132 /* synopsis: r[P2]=data                       */
#define OP_Rowid         133 /* synopsis: r[P2]=rowid                      */
#define OP_NullRow       134
#define OP_SeekEnd       135
#define OP_IdxInsert     136 /* synopsis: key=r[P2]                        */
#define OP_SorterInsert  137 /* synopsis: key=r[P2]                        */
#define OP_IdxDelete     138 /* synopsis: key=r[P2@P3]                     */
#define OP_DeferredSeek  139 /* synopsis: Move P3 to P1.rowid if needed    */
#define OP_IdxRowid      140 /* synopsis: r[P2]=rowid                      */
#define OP_FinishSeek    141
#define OP_Destroy       142
#define OP_Clear         143
#define OP_ResetSorter   144
#define OP_CreateBtree   145 /* synopsis: r[P2]=root iDb=P1 flags=P3       */
#define OP_SqlExec       146
#define OP_ParseSchema   147
#define OP_LoadAnalysis  148
#define OP_DropTable     149
#define OP_DropIndex     150
#define OP_DropTrigger   151


#define OP_Real          152 /* same as TK_FLOAT, synopsis: r[P2]=P4       */
#define OP_IntegrityCk   153
#define OP_RowSetAdd     154 /* synopsis: rowset(P1)=r[P2]                 */
#define OP_Param         155
#define OP_FkCounter     156 /* synopsis: fkctr[P1]+=P2                    */
#define OP_MemMax        157 /* synopsis: r[P1]=max(r[P1],r[P2])           */
#define OP_OffsetLimit   158 /* synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) */
#define OP_AggInverse    159 /* synopsis: accum=r[P3] inverse(r[P2@P5])    */
#define OP_AggStep       160 /* synopsis: accum=r[P3] step(r[P2@P5])       */
#define OP_AggStep1      161 /* synopsis: accum=r[P3] step(r[P2@P5])       */
#define OP_AggValue      162 /* synopsis: r[P3]=value N=P2                 */
#define OP_AggFinal      163 /* synopsis: accum=r[P1] N=P2                 */
#define OP_Expire        164
#define OP_CursorLock    165
#define OP_CursorUnlock  166
#define OP_TableLock     167 /* synopsis: iDb=P1 root=P2 write=P3          */
#define OP_VBegin        168
#define OP_VCreate       169
#define OP_VDestroy      170
#define OP_VOpen         171
#define OP_VColumn       172 /* synopsis: r[P3]=vcolumn(P2)                */
#define OP_VRename       173
#define OP_Pagecount     174
#define OP_MaxPgcnt      175
#define OP_Trace         176
#define OP_CursorHint    177
#define OP_ReleaseReg    178 /* synopsis: release r[P1@P2] mask P3         */
#define OP_Noop          179
#define OP_Explain       180
#define OP_Abortable     181

/* Properties such as "out2" or "jump" that are specified in
** comments following the "case" for each opcode in the vdbe.c
** are encoded into bitvectors as follows:
*/
#define OPFLG_JUMP        0x01  /* jump:  P2 holds jmp target */
#define OPFLG_IN1         0x02  /* in1:   P1 is an input */
#define OPFLG_IN2         0x04  /* in2:   P2 is an input */
#define OPFLG_IN3         0x08  /* in3:   P3 is an input */
#define OPFLG_OUT2        0x10  /* out2:  P2 is an output */
#define OPFLG_OUT3        0x20  /* out3:  P3 is an output */
#define OPFLG_INITIALIZER {\
/*   0 */ 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x10,\
/*   8 */ 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x03, 0x03,\
/*  16 */ 0x01, 0x01, 0x03, 0x12, 0x03, 0x03, 0x01, 0x09,\
/*  24 */ 0x09, 0x09, 0x09, 0x01, 0x09, 0x09, 0x09, 0x09,\
/*  32 */ 0x09, 0x09, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,\
/*  40 */ 0x01, 0x01, 0x01, 0x26, 0x26, 0x23, 0x0b, 0x01,\
/*  48 */ 0x01, 0x03, 0x03, 0x03, 0x0b, 0x0b, 0x0b, 0x0b,\
/*  56 */ 0x0b, 0x0b, 0x01, 0x03, 0x03, 0x01, 0x01, 0x01,\
/*  64 */ 0x00, 0x00, 0x02, 0x02, 0x08, 0x00, 0x10, 0x10,\
/*  72 */ 0x10, 0x10, 0x00, 0x10, 0x10, 0x00, 0x00, 0x10,\
/*  80 */ 0x10, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00,\
/*  88 */ 0x00, 0x12, 0x1e, 0x20, 0x00, 0x00, 0x00, 0x00,\
/*  96 */ 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x26, 0x26,\
/* 104 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26,\
/* 112 */ 0x00, 0x12, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,\
/* 120 */ 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00,\
/* 128 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,\
/* 136 */ 0x04, 0x04, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00,\
/* 144 */ 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
/* 152 */ 0x10, 0x00, 0x06, 0x10, 0x00, 0x04, 0x1a, 0x00,\
/* 160 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
/* 168 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10,\
/* 176 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,}

/* The resolve3P2Values() routine is able to run faster if it knows
** the value of the largest JUMP opcode.  The smaller the maximum
** JUMP opcode the better, so the mkopcodeh.tcl script that
** generated this include file strives to group all JUMP opcodes
** together near the beginning of the list.
*/
#define SQLITE_MX_JUMP_OPCODE  63  /* Maximum JUMP opcode */

/************** End of opcodes.h *********************************************/
/************** Continuing where we left off in vdbe.h ***********************/

/*
** Additional non-public SQLITE_PREPARE_* flags
*/
16385
16386
16387
16388
16389
16390
16391

16392
16393
16394
16395
16396
16397
16398
16399
16400
16401
16402
16403
16404
16405
16406
16407
16408
16409
16410
16411
16412
  signed char nextAutovac;      /* Autovac setting after VACUUM if >=0 */
  u8 suppressErr;               /* Do not issue error messages if true */
  u8 vtabOnConflict;            /* Value to return for s3_vtab_on_conflict() */
  u8 isTransactionSavepoint;    /* True if the outermost savepoint is a TS */
  u8 mTrace;                    /* zero or more SQLITE_TRACE flags */
  u8 noSharedCache;             /* True if no shared-cache backends */
  u8 nSqlExec;                  /* Number of pending OP_SqlExec opcodes */

  int nextPagesize;             /* Pagesize after VACUUM if >0 */
  u32 magic;                    /* Magic number for detect library misuse */
  i64 nChange;                  /* Value returned by sqlite3_changes() */
  i64 nTotalChange;             /* Value returned by sqlite3_total_changes() */
  int aLimit[SQLITE_N_LIMIT];   /* Limits */
  int nMaxSorterMmap;           /* Maximum size of regions mapped by sorter */
  struct sqlite3InitInfo {      /* Information used during initialization */
    Pgno newTnum;               /* Rootpage of table being initialized */
    u8 iDb;                     /* Which db file is being initialized */
    u8 busy;                    /* TRUE if currently initializing */
    unsigned orphanTrigger : 1; /* Last statement is orphaned TEMP trigger */
    unsigned imposterTable : 1; /* Building an imposter table */
    unsigned reopenMemdb : 1;   /* ATTACH is really a reopen using MemDB */
    char **azInit;              /* "type", "name", and "tbl_name" columns */
  } init;
  int nVdbeActive;              /* Number of VDBEs currently running */
  int nVdbeRead;                /* Number of active VDBEs that read or write */
  int nVdbeWrite;               /* Number of active VDBEs that read and write */
  int nVdbeExec;                /* Number of nested calls to VdbeExec() */
  int nVDestroy;                /* Number of active OP_VDestroy operations */
  int nExtension;               /* Number of loaded extensions */







>

<











|







16403
16404
16405
16406
16407
16408
16409
16410
16411

16412
16413
16414
16415
16416
16417
16418
16419
16420
16421
16422
16423
16424
16425
16426
16427
16428
16429
16430
  signed char nextAutovac;      /* Autovac setting after VACUUM if >=0 */
  u8 suppressErr;               /* Do not issue error messages if true */
  u8 vtabOnConflict;            /* Value to return for s3_vtab_on_conflict() */
  u8 isTransactionSavepoint;    /* True if the outermost savepoint is a TS */
  u8 mTrace;                    /* zero or more SQLITE_TRACE flags */
  u8 noSharedCache;             /* True if no shared-cache backends */
  u8 nSqlExec;                  /* Number of pending OP_SqlExec opcodes */
  u8 eOpenState;                /* Current condition of the connection */
  int nextPagesize;             /* Pagesize after VACUUM if >0 */

  i64 nChange;                  /* Value returned by sqlite3_changes() */
  i64 nTotalChange;             /* Value returned by sqlite3_total_changes() */
  int aLimit[SQLITE_N_LIMIT];   /* Limits */
  int nMaxSorterMmap;           /* Maximum size of regions mapped by sorter */
  struct sqlite3InitInfo {      /* Information used during initialization */
    Pgno newTnum;               /* Rootpage of table being initialized */
    u8 iDb;                     /* Which db file is being initialized */
    u8 busy;                    /* TRUE if currently initializing */
    unsigned orphanTrigger : 1; /* Last statement is orphaned TEMP trigger */
    unsigned imposterTable : 1; /* Building an imposter table */
    unsigned reopenMemdb : 1;   /* ATTACH is really a reopen using MemDB */
    const char **azInit;        /* "type", "name", and "tbl_name" columns */
  } init;
  int nVdbeActive;              /* Number of VDBEs currently running */
  int nVdbeRead;                /* Number of active VDBEs that read or write */
  int nVdbeWrite;               /* Number of active VDBEs that read and write */
  int nVdbeExec;                /* Number of nested calls to VdbeExec() */
  int nVDestroy;                /* Number of active OP_VDestroy operations */
  int nExtension;               /* Number of loaded extensions */
16613
16614
16615
16616
16617
16618
16619
16620
16621
16622
16623

16624
16625
16626
16627
16628
16629
16630
16631
16632
16633
16634
16635
16636
16637

/*
** Return true if it OK to factor constant expressions into the initialization
** code. The argument is a Parse object for the code generator.
*/
#define ConstFactorOk(P) ((P)->okConstFactor)

/*
** Possible values for the sqlite.magic field.
** The numbers are obtained at random and have no special meaning, other
** than being distinct from one another.

*/
#define SQLITE_MAGIC_OPEN     0xa029a697  /* Database is open */
#define SQLITE_MAGIC_CLOSED   0x9f3c2d33  /* Database is closed */
#define SQLITE_MAGIC_SICK     0x4b771290  /* Error and awaiting close */
#define SQLITE_MAGIC_BUSY     0xf03b7906  /* Database currently in use */
#define SQLITE_MAGIC_ERROR    0xb5357930  /* An SQLITE_MISUSE error occurred */
#define SQLITE_MAGIC_ZOMBIE   0x64cffc7f  /* Close with last statement close */

/*
** Each SQL function is defined by an instance of the following
** structure.  For global built-in functions (ex: substr(), max(), count())
** a pointer to this structure is held in the sqlite3BuiltinFunctions object.
** For per-connection application-defined functions, a pointer to this
** structure is held in the db->aHash hash table.







<
|
|
<
>

|
|
|
|
|
|







16631
16632
16633
16634
16635
16636
16637

16638
16639

16640
16641
16642
16643
16644
16645
16646
16647
16648
16649
16650
16651
16652
16653
16654

/*
** Return true if it OK to factor constant expressions into the initialization
** code. The argument is a Parse object for the code generator.
*/
#define ConstFactorOk(P) ((P)->okConstFactor)


/* Possible values for the sqlite3.eOpenState field.
** The numbers are randomly selected such that a minimum of three bits must

** change to convert any number to another or to zero
*/
#define SQLITE_STATE_OPEN     0x76  /* Database is open */
#define SQLITE_STATE_CLOSED   0xce  /* Database is closed */
#define SQLITE_STATE_SICK     0xba  /* Error and awaiting close */
#define SQLITE_STATE_BUSY     0x6d  /* Database currently in use */
#define SQLITE_STATE_ERROR    0xd5  /* An SQLITE_MISUSE error occurred */
#define SQLITE_STATE_ZOMBIE   0xa7  /* Close with last statement close */

/*
** Each SQL function is defined by an instance of the following
** structure.  For global built-in functions (ex: substr(), max(), count())
** a pointer to this structure is held in the sqlite3BuiltinFunctions object.
** For per-connection application-defined functions, a pointer to this
** structure is held in the db->aHash hash table.
16892
16893
16894
16895
16896
16897
16898
16899
16900
16901
16902
16903
16904
16905
16906
16907
16908
16909
16910
16911
16912
16913
16914

16915
16916
16917
16918
16919
16920
16921
16922
16923
16924
16925
16926
16927
** is only included if the COLFLAG_HASTYPE bit of colFlags is set and the
** collating sequence name is only included if the COLFLAG_HASCOLL bit is
** set.
*/
struct Column {
  char *zCnName;        /* Name of this column */
  unsigned notNull :4;  /* An OE_ code for handling a NOT NULL constraint */
  unsigned eType :4;    /* One of the standard types */
  char affinity;        /* One of the SQLITE_AFF_... values */
  u8 szEst;             /* Est size of value in this column. sizeof(INT)==1 */
  u8 hName;             /* Column name hash for faster lookup */
  u16 iDflt;            /* 1-based index of DEFAULT.  0 means "none" */
  u16 colFlags;         /* Boolean properties.  See COLFLAG_ defines below */
};

/* Allowed values for Column.eType.
**
** Values must match entries in the global constant arrays
** sqlite3StdTypeLen[] and sqlite3StdType[].  Each value is one more
** than the offset into these arrays for the corresponding name.
** Adjust the SQLITE_N_STDTYPE value if adding or removing entries.
*/
#define COLTYPE_CUSTOM      0   /* Type appended to zName */

#define COLTYPE_BLOB        1
#define COLTYPE_INT         2
#define COLTYPE_INTEGER     3
#define COLTYPE_REAL        4
#define COLTYPE_TEXT        5
#define SQLITE_N_STDTYPE    5  /* Number of standard types */

/* Allowed values for Column.colFlags.
**
** Constraints:
**         TF_HasVirtual == COLFLAG_VIRTUAL
**         TF_HasStored  == COLFLAG_STORED
**         TF_HasHidden  == COLFLAG_HIDDEN







|







|







>
|
|
|
|
|
|







16909
16910
16911
16912
16913
16914
16915
16916
16917
16918
16919
16920
16921
16922
16923
16924
16925
16926
16927
16928
16929
16930
16931
16932
16933
16934
16935
16936
16937
16938
16939
16940
16941
16942
16943
16944
16945
** is only included if the COLFLAG_HASTYPE bit of colFlags is set and the
** collating sequence name is only included if the COLFLAG_HASCOLL bit is
** set.
*/
struct Column {
  char *zCnName;        /* Name of this column */
  unsigned notNull :4;  /* An OE_ code for handling a NOT NULL constraint */
  unsigned eCType :4;   /* One of the standard types */
  char affinity;        /* One of the SQLITE_AFF_... values */
  u8 szEst;             /* Est size of value in this column. sizeof(INT)==1 */
  u8 hName;             /* Column name hash for faster lookup */
  u16 iDflt;            /* 1-based index of DEFAULT.  0 means "none" */
  u16 colFlags;         /* Boolean properties.  See COLFLAG_ defines below */
};

/* Allowed values for Column.eCType.
**
** Values must match entries in the global constant arrays
** sqlite3StdTypeLen[] and sqlite3StdType[].  Each value is one more
** than the offset into these arrays for the corresponding name.
** Adjust the SQLITE_N_STDTYPE value if adding or removing entries.
*/
#define COLTYPE_CUSTOM      0   /* Type appended to zName */
#define COLTYPE_ANY         1
#define COLTYPE_BLOB        2
#define COLTYPE_INT         3
#define COLTYPE_INTEGER     4
#define COLTYPE_REAL        5
#define COLTYPE_TEXT        6
#define SQLITE_N_STDTYPE    6  /* Number of standard types */

/* Allowed values for Column.colFlags.
**
** Constraints:
**         TF_HasVirtual == COLFLAG_VIRTUAL
**         TF_HasStored  == COLFLAG_STORED
**         TF_HasHidden  == COLFLAG_HIDDEN
17137
17138
17139
17140
17141
17142
17143

17144
17145
17146
17147
17148
17149
17150
#define TF_NoVisibleRowid 0x00000200 /* No user-visible "rowid" column */
#define TF_OOOHidden      0x00000400 /* Out-of-Order hidden columns */
#define TF_HasNotNull     0x00000800 /* Contains NOT NULL constraints */
#define TF_Shadow         0x00001000 /* True for a shadow table */
#define TF_HasStat4       0x00002000 /* STAT4 info available for this table */
#define TF_Ephemeral      0x00004000 /* An ephemeral table */
#define TF_Eponymous      0x00008000 /* An eponymous virtual table */


/*
** Allowed values for Table.eTabType
*/
#define TABTYP_NORM      0     /* Ordinary table */
#define TABTYP_VTAB      1     /* Virtual table */
#define TABTYP_VIEW      2     /* A view */







>







17155
17156
17157
17158
17159
17160
17161
17162
17163
17164
17165
17166
17167
17168
17169
#define TF_NoVisibleRowid 0x00000200 /* No user-visible "rowid" column */
#define TF_OOOHidden      0x00000400 /* Out-of-Order hidden columns */
#define TF_HasNotNull     0x00000800 /* Contains NOT NULL constraints */
#define TF_Shadow         0x00001000 /* True for a shadow table */
#define TF_HasStat4       0x00002000 /* STAT4 info available for this table */
#define TF_Ephemeral      0x00004000 /* An ephemeral table */
#define TF_Eponymous      0x00008000 /* An eponymous virtual table */
#define TF_Strict         0x00010000 /* STRICT mode */

/*
** Allowed values for Table.eTabType
*/
#define TABTYP_NORM      0     /* Ordinary table */
#define TABTYP_VTAB      1     /* Virtual table */
#define TABTYP_VIEW      2     /* A view */
18961
18962
18963
18964
18965
18966
18967
18968
18969
18970
18971
18972
18973
18974
18975
#ifndef SQLITE_OMIT_WINDOWFUNC
SQLITE_PRIVATE void sqlite3WindowDelete(sqlite3*, Window*);
SQLITE_PRIVATE void sqlite3WindowUnlinkFromSelect(Window*);
SQLITE_PRIVATE void sqlite3WindowListDelete(sqlite3 *db, Window *p);
SQLITE_PRIVATE Window *sqlite3WindowAlloc(Parse*, int, int, Expr*, int , Expr*, u8);
SQLITE_PRIVATE void sqlite3WindowAttach(Parse*, Expr*, Window*);
SQLITE_PRIVATE void sqlite3WindowLink(Select *pSel, Window *pWin);
SQLITE_PRIVATE int sqlite3WindowCompare(Parse*, Window*, Window*, int);
SQLITE_PRIVATE void sqlite3WindowCodeInit(Parse*, Select*);
SQLITE_PRIVATE void sqlite3WindowCodeStep(Parse*, Select*, WhereInfo*, int, int);
SQLITE_PRIVATE int sqlite3WindowRewrite(Parse*, Select*);
SQLITE_PRIVATE void sqlite3WindowUpdate(Parse*, Window*, Window*, FuncDef*);
SQLITE_PRIVATE Window *sqlite3WindowDup(sqlite3 *db, Expr *pOwner, Window *p);
SQLITE_PRIVATE Window *sqlite3WindowListDup(sqlite3 *db, Window *p);
SQLITE_PRIVATE void sqlite3WindowFunctions(void);







|







18980
18981
18982
18983
18984
18985
18986
18987
18988
18989
18990
18991
18992
18993
18994
#ifndef SQLITE_OMIT_WINDOWFUNC
SQLITE_PRIVATE void sqlite3WindowDelete(sqlite3*, Window*);
SQLITE_PRIVATE void sqlite3WindowUnlinkFromSelect(Window*);
SQLITE_PRIVATE void sqlite3WindowListDelete(sqlite3 *db, Window *p);
SQLITE_PRIVATE Window *sqlite3WindowAlloc(Parse*, int, int, Expr*, int , Expr*, u8);
SQLITE_PRIVATE void sqlite3WindowAttach(Parse*, Expr*, Window*);
SQLITE_PRIVATE void sqlite3WindowLink(Select *pSel, Window *pWin);
SQLITE_PRIVATE int sqlite3WindowCompare(const Parse*, const Window*, const Window*, int);
SQLITE_PRIVATE void sqlite3WindowCodeInit(Parse*, Select*);
SQLITE_PRIVATE void sqlite3WindowCodeStep(Parse*, Select*, WhereInfo*, int, int);
SQLITE_PRIVATE int sqlite3WindowRewrite(Parse*, Select*);
SQLITE_PRIVATE void sqlite3WindowUpdate(Parse*, Window*, Window*, FuncDef*);
SQLITE_PRIVATE Window *sqlite3WindowDup(sqlite3 *db, Expr *pOwner, Window *p);
SQLITE_PRIVATE Window *sqlite3WindowListDup(sqlite3 *db, Window *p);
SQLITE_PRIVATE void sqlite3WindowFunctions(void);
19093
19094
19095
19096
19097
19098
19099
19100
19101
19102
19103
19104
19105
19106
19107
19108
SQLITE_PRIVATE char *sqlite3DbStrNDup(sqlite3*,const char*, u64);
SQLITE_PRIVATE char *sqlite3DbSpanDup(sqlite3*,const char*,const char*);
SQLITE_PRIVATE void *sqlite3Realloc(void*, u64);
SQLITE_PRIVATE void *sqlite3DbReallocOrFree(sqlite3 *, void *, u64);
SQLITE_PRIVATE void *sqlite3DbRealloc(sqlite3 *, void *, u64);
SQLITE_PRIVATE void sqlite3DbFree(sqlite3*, void*);
SQLITE_PRIVATE void sqlite3DbFreeNN(sqlite3*, void*);
SQLITE_PRIVATE int sqlite3MallocSize(void*);
SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3*, void*);
SQLITE_PRIVATE void *sqlite3PageMalloc(int);
SQLITE_PRIVATE void sqlite3PageFree(void*);
SQLITE_PRIVATE void sqlite3MemSetDefault(void);
#ifndef SQLITE_UNTESTABLE
SQLITE_PRIVATE void sqlite3BenignMallocHooks(void (*)(void), void (*)(void));
#endif
SQLITE_PRIVATE int sqlite3HeapNearlyFull(void);







|
|







19112
19113
19114
19115
19116
19117
19118
19119
19120
19121
19122
19123
19124
19125
19126
19127
SQLITE_PRIVATE char *sqlite3DbStrNDup(sqlite3*,const char*, u64);
SQLITE_PRIVATE char *sqlite3DbSpanDup(sqlite3*,const char*,const char*);
SQLITE_PRIVATE void *sqlite3Realloc(void*, u64);
SQLITE_PRIVATE void *sqlite3DbReallocOrFree(sqlite3 *, void *, u64);
SQLITE_PRIVATE void *sqlite3DbRealloc(sqlite3 *, void *, u64);
SQLITE_PRIVATE void sqlite3DbFree(sqlite3*, void*);
SQLITE_PRIVATE void sqlite3DbFreeNN(sqlite3*, void*);
SQLITE_PRIVATE int sqlite3MallocSize(const void*);
SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3*, const void*);
SQLITE_PRIVATE void *sqlite3PageMalloc(int);
SQLITE_PRIVATE void sqlite3PageFree(void*);
SQLITE_PRIVATE void sqlite3MemSetDefault(void);
#ifndef SQLITE_UNTESTABLE
SQLITE_PRIVATE void sqlite3BenignMallocHooks(void (*)(void), void (*)(void));
#endif
SQLITE_PRIVATE int sqlite3HeapNearlyFull(void);
19230
19231
19232
19233
19234
19235
19236
19237
19238
19239
19240
19241
19242
19243
19244
19245
19246
19247
19248
19249
19250
19251
19252
19253
19254
SQLITE_PRIVATE Expr *sqlite3ExprAlloc(sqlite3*,int,const Token*,int);
SQLITE_PRIVATE Expr *sqlite3Expr(sqlite3*,int,const char*);
SQLITE_PRIVATE void sqlite3ExprAttachSubtrees(sqlite3*,Expr*,Expr*,Expr*);
SQLITE_PRIVATE Expr *sqlite3PExpr(Parse*, int, Expr*, Expr*);
SQLITE_PRIVATE void sqlite3PExprAddSelect(Parse*, Expr*, Select*);
SQLITE_PRIVATE Expr *sqlite3ExprAnd(Parse*,Expr*, Expr*);
SQLITE_PRIVATE Expr *sqlite3ExprSimplifiedAndOr(Expr*);
SQLITE_PRIVATE Expr *sqlite3ExprFunction(Parse*,ExprList*, Token*, int);
SQLITE_PRIVATE void sqlite3ExprFunctionUsable(Parse*,Expr*,FuncDef*);
SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse*, Expr*, u32);
SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3*, Expr*);
SQLITE_PRIVATE void sqlite3ExprDeferredDelete(Parse*, Expr*);
SQLITE_PRIVATE void sqlite3ExprUnmapAndDelete(Parse*, Expr*);
SQLITE_PRIVATE ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*);
SQLITE_PRIVATE ExprList *sqlite3ExprListAppendVector(Parse*,ExprList*,IdList*,Expr*);
SQLITE_PRIVATE Select *sqlite3ExprListToValues(Parse*, int, ExprList*);
SQLITE_PRIVATE void sqlite3ExprListSetSortOrder(ExprList*,int,int);
SQLITE_PRIVATE void sqlite3ExprListSetName(Parse*,ExprList*,Token*,int);
SQLITE_PRIVATE void sqlite3ExprListSetSpan(Parse*,ExprList*,const char*,const char*);
SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3*, ExprList*);
SQLITE_PRIVATE u32 sqlite3ExprListFlags(const ExprList*);
SQLITE_PRIVATE int sqlite3IndexHasDuplicateRootPage(Index*);
SQLITE_PRIVATE int sqlite3Init(sqlite3*, char**);
SQLITE_PRIVATE int sqlite3InitCallback(void*, int, char**, char**);
SQLITE_PRIVATE int sqlite3InitOne(sqlite3*, int, char**, u32);







|
|








|







19249
19250
19251
19252
19253
19254
19255
19256
19257
19258
19259
19260
19261
19262
19263
19264
19265
19266
19267
19268
19269
19270
19271
19272
19273
SQLITE_PRIVATE Expr *sqlite3ExprAlloc(sqlite3*,int,const Token*,int);
SQLITE_PRIVATE Expr *sqlite3Expr(sqlite3*,int,const char*);
SQLITE_PRIVATE void sqlite3ExprAttachSubtrees(sqlite3*,Expr*,Expr*,Expr*);
SQLITE_PRIVATE Expr *sqlite3PExpr(Parse*, int, Expr*, Expr*);
SQLITE_PRIVATE void sqlite3PExprAddSelect(Parse*, Expr*, Select*);
SQLITE_PRIVATE Expr *sqlite3ExprAnd(Parse*,Expr*, Expr*);
SQLITE_PRIVATE Expr *sqlite3ExprSimplifiedAndOr(Expr*);
SQLITE_PRIVATE Expr *sqlite3ExprFunction(Parse*,ExprList*, const Token*, int);
SQLITE_PRIVATE void sqlite3ExprFunctionUsable(Parse*,const Expr*,const FuncDef*);
SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse*, Expr*, u32);
SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3*, Expr*);
SQLITE_PRIVATE void sqlite3ExprDeferredDelete(Parse*, Expr*);
SQLITE_PRIVATE void sqlite3ExprUnmapAndDelete(Parse*, Expr*);
SQLITE_PRIVATE ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*);
SQLITE_PRIVATE ExprList *sqlite3ExprListAppendVector(Parse*,ExprList*,IdList*,Expr*);
SQLITE_PRIVATE Select *sqlite3ExprListToValues(Parse*, int, ExprList*);
SQLITE_PRIVATE void sqlite3ExprListSetSortOrder(ExprList*,int,int);
SQLITE_PRIVATE void sqlite3ExprListSetName(Parse*,ExprList*,const Token*,int);
SQLITE_PRIVATE void sqlite3ExprListSetSpan(Parse*,ExprList*,const char*,const char*);
SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3*, ExprList*);
SQLITE_PRIVATE u32 sqlite3ExprListFlags(const ExprList*);
SQLITE_PRIVATE int sqlite3IndexHasDuplicateRootPage(Index*);
SQLITE_PRIVATE int sqlite3Init(sqlite3*, char**);
SQLITE_PRIVATE int sqlite3InitCallback(void*, int, char**, char**);
SQLITE_PRIVATE int sqlite3InitOne(sqlite3*, int, char**, u32);
19288
19289
19290
19291
19292
19293
19294
19295
19296
19297
19298
19299
19300
19301
19302
SQLITE_PRIVATE void sqlite3AddColumn(Parse*,Token,Token);
SQLITE_PRIVATE void sqlite3AddNotNull(Parse*, int);
SQLITE_PRIVATE void sqlite3AddPrimaryKey(Parse*, ExprList*, int, int, int);
SQLITE_PRIVATE void sqlite3AddCheckConstraint(Parse*, Expr*, const char*, const char*);
SQLITE_PRIVATE void sqlite3AddDefaultValue(Parse*,Expr*,const char*,const char*);
SQLITE_PRIVATE void sqlite3AddCollateType(Parse*, Token*);
SQLITE_PRIVATE void sqlite3AddGenerated(Parse*,Expr*,Token*);
SQLITE_PRIVATE void sqlite3EndTable(Parse*,Token*,Token*,u8,Select*);
SQLITE_PRIVATE void sqlite3AddReturning(Parse*,ExprList*);
SQLITE_PRIVATE int sqlite3ParseUri(const char*,const char*,unsigned int*,
                    sqlite3_vfs**,char**,char **);
#define sqlite3CodecQueryParameters(A,B,C) 0
SQLITE_PRIVATE Btree *sqlite3DbNameToBtree(sqlite3*,const char*);

#ifdef SQLITE_UNTESTABLE







|







19307
19308
19309
19310
19311
19312
19313
19314
19315
19316
19317
19318
19319
19320
19321
SQLITE_PRIVATE void sqlite3AddColumn(Parse*,Token,Token);
SQLITE_PRIVATE void sqlite3AddNotNull(Parse*, int);
SQLITE_PRIVATE void sqlite3AddPrimaryKey(Parse*, ExprList*, int, int, int);
SQLITE_PRIVATE void sqlite3AddCheckConstraint(Parse*, Expr*, const char*, const char*);
SQLITE_PRIVATE void sqlite3AddDefaultValue(Parse*,Expr*,const char*,const char*);
SQLITE_PRIVATE void sqlite3AddCollateType(Parse*, Token*);
SQLITE_PRIVATE void sqlite3AddGenerated(Parse*,Expr*,Token*);
SQLITE_PRIVATE void sqlite3EndTable(Parse*,Token*,Token*,u32,Select*);
SQLITE_PRIVATE void sqlite3AddReturning(Parse*,ExprList*);
SQLITE_PRIVATE int sqlite3ParseUri(const char*,const char*,unsigned int*,
                    sqlite3_vfs**,char**,char **);
#define sqlite3CodecQueryParameters(A,B,C) 0
SQLITE_PRIVATE Btree *sqlite3DbNameToBtree(sqlite3*,const char*);

#ifdef SQLITE_UNTESTABLE
19423
19424
19425
19426
19427
19428
19429
19430
19431
19432
19433
19434
19435
19436
19437
19438
19439
19440
19441
SQLITE_PRIVATE Table *sqlite3LocateTable(Parse*,u32 flags,const char*, const char*);
SQLITE_PRIVATE Table *sqlite3LocateTableItem(Parse*,u32 flags,SrcItem *);
SQLITE_PRIVATE Index *sqlite3FindIndex(sqlite3*,const char*, const char*);
SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTable(sqlite3*,int,const char*);
SQLITE_PRIVATE void sqlite3UnlinkAndDeleteIndex(sqlite3*,int,const char*);
SQLITE_PRIVATE void sqlite3Vacuum(Parse*,Token*,Expr*);
SQLITE_PRIVATE int sqlite3RunVacuum(char**, sqlite3*, int, sqlite3_value*);
SQLITE_PRIVATE char *sqlite3NameFromToken(sqlite3*, Token*);
SQLITE_PRIVATE int sqlite3ExprCompare(Parse*,Expr*, Expr*, int);
SQLITE_PRIVATE int sqlite3ExprCompareSkip(Expr*, Expr*, int);
SQLITE_PRIVATE int sqlite3ExprListCompare(ExprList*, ExprList*, int);
SQLITE_PRIVATE int sqlite3ExprImpliesExpr(Parse*,Expr*, Expr*, int);
SQLITE_PRIVATE int sqlite3ExprImpliesNonNullRow(Expr*,int);
SQLITE_PRIVATE void sqlite3AggInfoPersistWalkerInit(Walker*,Parse*);
SQLITE_PRIVATE void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*);
SQLITE_PRIVATE void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*);
SQLITE_PRIVATE int sqlite3ExprCoveredByIndex(Expr*, int iCur, Index *pIdx);
SQLITE_PRIVATE int sqlite3FunctionUsesThisSrc(Expr*, SrcList*);
SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse*);







|
|
|
|
|







19442
19443
19444
19445
19446
19447
19448
19449
19450
19451
19452
19453
19454
19455
19456
19457
19458
19459
19460
SQLITE_PRIVATE Table *sqlite3LocateTable(Parse*,u32 flags,const char*, const char*);
SQLITE_PRIVATE Table *sqlite3LocateTableItem(Parse*,u32 flags,SrcItem *);
SQLITE_PRIVATE Index *sqlite3FindIndex(sqlite3*,const char*, const char*);
SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTable(sqlite3*,int,const char*);
SQLITE_PRIVATE void sqlite3UnlinkAndDeleteIndex(sqlite3*,int,const char*);
SQLITE_PRIVATE void sqlite3Vacuum(Parse*,Token*,Expr*);
SQLITE_PRIVATE int sqlite3RunVacuum(char**, sqlite3*, int, sqlite3_value*);
SQLITE_PRIVATE char *sqlite3NameFromToken(sqlite3*, const Token*);
SQLITE_PRIVATE int sqlite3ExprCompare(const Parse*,const Expr*,const Expr*, int);
SQLITE_PRIVATE int sqlite3ExprCompareSkip(Expr*,Expr*,int);
SQLITE_PRIVATE int sqlite3ExprListCompare(const ExprList*,const ExprList*, int);
SQLITE_PRIVATE int sqlite3ExprImpliesExpr(const Parse*,const Expr*,const Expr*, int);
SQLITE_PRIVATE int sqlite3ExprImpliesNonNullRow(Expr*,int);
SQLITE_PRIVATE void sqlite3AggInfoPersistWalkerInit(Walker*,Parse*);
SQLITE_PRIVATE void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*);
SQLITE_PRIVATE void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*);
SQLITE_PRIVATE int sqlite3ExprCoveredByIndex(Expr*, int iCur, Index *pIdx);
SQLITE_PRIVATE int sqlite3FunctionUsesThisSrc(Expr*, SrcList*);
SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse*);
19458
19459
19460
19461
19462
19463
19464
19465
19466
19467
19468
19469
19470
19471
19472
SQLITE_PRIVATE int sqlite3ExprIsConstantNotJoin(Expr*);
SQLITE_PRIVATE int sqlite3ExprIsConstantOrFunction(Expr*, u8);
SQLITE_PRIVATE int sqlite3ExprIsConstantOrGroupBy(Parse*, Expr*, ExprList*);
SQLITE_PRIVATE int sqlite3ExprIsTableConstant(Expr*,int);
#ifdef SQLITE_ENABLE_CURSOR_HINTS
SQLITE_PRIVATE int sqlite3ExprContainsSubquery(Expr*);
#endif
SQLITE_PRIVATE int sqlite3ExprIsInteger(Expr*, int*);
SQLITE_PRIVATE int sqlite3ExprCanBeNull(const Expr*);
SQLITE_PRIVATE int sqlite3ExprNeedsNoAffinityChange(const Expr*, char);
SQLITE_PRIVATE int sqlite3IsRowid(const char*);
SQLITE_PRIVATE void sqlite3GenerateRowDelete(
    Parse*,Table*,Trigger*,int,int,int,i16,u8,u8,u8,int);
SQLITE_PRIVATE void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int, int*, int);
SQLITE_PRIVATE int sqlite3GenerateIndexKey(Parse*, Index*, int, int, int, int*,Index*,int);







|







19477
19478
19479
19480
19481
19482
19483
19484
19485
19486
19487
19488
19489
19490
19491
SQLITE_PRIVATE int sqlite3ExprIsConstantNotJoin(Expr*);
SQLITE_PRIVATE int sqlite3ExprIsConstantOrFunction(Expr*, u8);
SQLITE_PRIVATE int sqlite3ExprIsConstantOrGroupBy(Parse*, Expr*, ExprList*);
SQLITE_PRIVATE int sqlite3ExprIsTableConstant(Expr*,int);
#ifdef SQLITE_ENABLE_CURSOR_HINTS
SQLITE_PRIVATE int sqlite3ExprContainsSubquery(Expr*);
#endif
SQLITE_PRIVATE int sqlite3ExprIsInteger(const Expr*, int*);
SQLITE_PRIVATE int sqlite3ExprCanBeNull(const Expr*);
SQLITE_PRIVATE int sqlite3ExprNeedsNoAffinityChange(const Expr*, char);
SQLITE_PRIVATE int sqlite3IsRowid(const char*);
SQLITE_PRIVATE void sqlite3GenerateRowDelete(
    Parse*,Table*,Trigger*,int,int,int,i16,u8,u8,u8,int);
SQLITE_PRIVATE void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int, int*, int);
SQLITE_PRIVATE int sqlite3GenerateIndexKey(Parse*, Index*, int, int, int, int*,Index*,int);
19483
19484
19485
19486
19487
19488
19489
19490
19491
19492
19493
19494
19495
19496
19497
19498
19499
19500
19501
SQLITE_PRIVATE int sqlite3OpenTableAndIndices(Parse*, Table*, int, u8, int, u8*, int*, int*);
SQLITE_PRIVATE void sqlite3BeginWriteOperation(Parse*, int, int);
SQLITE_PRIVATE void sqlite3MultiWrite(Parse*);
SQLITE_PRIVATE void sqlite3MayAbort(Parse*);
SQLITE_PRIVATE void sqlite3HaltConstraint(Parse*, int, int, char*, i8, u8);
SQLITE_PRIVATE void sqlite3UniqueConstraint(Parse*, int, Index*);
SQLITE_PRIVATE void sqlite3RowidConstraint(Parse*, int, Table*);
SQLITE_PRIVATE Expr *sqlite3ExprDup(sqlite3*,Expr*,int);
SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3*,ExprList*,int);
SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3*,SrcList*,int);
SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3*,IdList*);
SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3*,Select*,int);
SQLITE_PRIVATE FuncDef *sqlite3FunctionSearch(int,const char*);
SQLITE_PRIVATE void sqlite3InsertBuiltinFuncs(FuncDef*,int);
SQLITE_PRIVATE FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,u8,u8);
SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void);
SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void);
SQLITE_PRIVATE void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3*);
SQLITE_PRIVATE int sqlite3SafetyCheckOk(sqlite3*);







|
|
|
|
|







19502
19503
19504
19505
19506
19507
19508
19509
19510
19511
19512
19513
19514
19515
19516
19517
19518
19519
19520
SQLITE_PRIVATE int sqlite3OpenTableAndIndices(Parse*, Table*, int, u8, int, u8*, int*, int*);
SQLITE_PRIVATE void sqlite3BeginWriteOperation(Parse*, int, int);
SQLITE_PRIVATE void sqlite3MultiWrite(Parse*);
SQLITE_PRIVATE void sqlite3MayAbort(Parse*);
SQLITE_PRIVATE void sqlite3HaltConstraint(Parse*, int, int, char*, i8, u8);
SQLITE_PRIVATE void sqlite3UniqueConstraint(Parse*, int, Index*);
SQLITE_PRIVATE void sqlite3RowidConstraint(Parse*, int, Table*);
SQLITE_PRIVATE Expr *sqlite3ExprDup(sqlite3*,const Expr*,int);
SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3*,const ExprList*,int);
SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3*,const SrcList*,int);
SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3*,const IdList*);
SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3*,const Select*,int);
SQLITE_PRIVATE FuncDef *sqlite3FunctionSearch(int,const char*);
SQLITE_PRIVATE void sqlite3InsertBuiltinFuncs(FuncDef*,int);
SQLITE_PRIVATE FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,u8,u8);
SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void);
SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void);
SQLITE_PRIVATE void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3*);
SQLITE_PRIVATE int sqlite3SafetyCheckOk(sqlite3*);
19625
19626
19627
19628
19629
19630
19631
19632
19633
19634
19635
19636
19637
19638
19639
#define putVarint    sqlite3PutVarint


SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(sqlite3*, Index*);
SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe*, Table*, int);
SQLITE_PRIVATE char sqlite3CompareAffinity(const Expr *pExpr, char aff2);
SQLITE_PRIVATE int sqlite3IndexAffinityOk(const Expr *pExpr, char idx_affinity);
SQLITE_PRIVATE char sqlite3TableColumnAffinity(Table*,int);
SQLITE_PRIVATE char sqlite3ExprAffinity(const Expr *pExpr);
SQLITE_PRIVATE int sqlite3Atoi64(const char*, i64*, int, u8);
SQLITE_PRIVATE int sqlite3DecOrHexToI64(const char*, i64*);
SQLITE_PRIVATE void sqlite3ErrorWithMsg(sqlite3*, int, const char*,...);
SQLITE_PRIVATE void sqlite3Error(sqlite3*,int);
SQLITE_PRIVATE void sqlite3ErrorClear(sqlite3*);
SQLITE_PRIVATE void sqlite3SystemError(sqlite3*,int);







|







19644
19645
19646
19647
19648
19649
19650
19651
19652
19653
19654
19655
19656
19657
19658
#define putVarint    sqlite3PutVarint


SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(sqlite3*, Index*);
SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe*, Table*, int);
SQLITE_PRIVATE char sqlite3CompareAffinity(const Expr *pExpr, char aff2);
SQLITE_PRIVATE int sqlite3IndexAffinityOk(const Expr *pExpr, char idx_affinity);
SQLITE_PRIVATE char sqlite3TableColumnAffinity(const Table*,int);
SQLITE_PRIVATE char sqlite3ExprAffinity(const Expr *pExpr);
SQLITE_PRIVATE int sqlite3Atoi64(const char*, i64*, int, u8);
SQLITE_PRIVATE int sqlite3DecOrHexToI64(const char*, i64*);
SQLITE_PRIVATE void sqlite3ErrorWithMsg(sqlite3*, int, const char*,...);
SQLITE_PRIVATE void sqlite3Error(sqlite3*,int);
SQLITE_PRIVATE void sqlite3ErrorClear(sqlite3*);
SQLITE_PRIVATE void sqlite3SystemError(sqlite3*,int);
19654
19655
19656
19657
19658
19659
19660
19661
19662
19663
19664
19665
19666
19667
19668
19669
SQLITE_PRIVATE CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int);
SQLITE_PRIVATE int sqlite3IsBinary(const CollSeq*);
SQLITE_PRIVATE CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName);
SQLITE_PRIVATE void sqlite3SetTextEncoding(sqlite3 *db, u8);
SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, const Expr *pExpr);
SQLITE_PRIVATE CollSeq *sqlite3ExprNNCollSeq(Parse *pParse, const Expr *pExpr);
SQLITE_PRIVATE int sqlite3ExprCollSeqMatch(Parse*,const Expr*,const Expr*);
SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, const Token*, int);
SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString(Parse*,Expr*,const char*);
SQLITE_PRIVATE Expr *sqlite3ExprSkipCollate(Expr*);
SQLITE_PRIVATE Expr *sqlite3ExprSkipCollateAndLikely(Expr*);
SQLITE_PRIVATE int sqlite3CheckCollSeq(Parse *, CollSeq *);
SQLITE_PRIVATE int sqlite3WritableSchema(sqlite3*);
SQLITE_PRIVATE int sqlite3CheckObjectName(Parse*, const char*,const char*,const char*);
SQLITE_PRIVATE void sqlite3VdbeSetChanges(sqlite3 *, i64);
SQLITE_PRIVATE int sqlite3AddInt64(i64*,i64);







|
|







19673
19674
19675
19676
19677
19678
19679
19680
19681
19682
19683
19684
19685
19686
19687
19688
SQLITE_PRIVATE CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int);
SQLITE_PRIVATE int sqlite3IsBinary(const CollSeq*);
SQLITE_PRIVATE CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName);
SQLITE_PRIVATE void sqlite3SetTextEncoding(sqlite3 *db, u8);
SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, const Expr *pExpr);
SQLITE_PRIVATE CollSeq *sqlite3ExprNNCollSeq(Parse *pParse, const Expr *pExpr);
SQLITE_PRIVATE int sqlite3ExprCollSeqMatch(Parse*,const Expr*,const Expr*);
SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken(const Parse *pParse, Expr*, const Token*, int);
SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString(const Parse*,Expr*,const char*);
SQLITE_PRIVATE Expr *sqlite3ExprSkipCollate(Expr*);
SQLITE_PRIVATE Expr *sqlite3ExprSkipCollateAndLikely(Expr*);
SQLITE_PRIVATE int sqlite3CheckCollSeq(Parse *, CollSeq *);
SQLITE_PRIVATE int sqlite3WritableSchema(sqlite3*);
SQLITE_PRIVATE int sqlite3CheckObjectName(Parse*, const char*,const char*,const char*);
SQLITE_PRIVATE void sqlite3VdbeSetChanges(sqlite3 *, i64);
SQLITE_PRIVATE int sqlite3AddInt64(i64*,i64);
19686
19687
19688
19689
19690
19691
19692
19693
19694
19695
19696
19697
19698
19699

19700
19701
19702
19703
19704
19705
19706
#ifndef SQLITE_UNTESTABLE
SQLITE_PRIVATE void sqlite3ResultIntReal(sqlite3_context*);
#endif
SQLITE_PRIVATE sqlite3_value *sqlite3ValueNew(sqlite3 *);
#ifndef SQLITE_OMIT_UTF16
SQLITE_PRIVATE char *sqlite3Utf16to8(sqlite3 *, const void*, int, u8);
#endif
SQLITE_PRIVATE int sqlite3ValueFromExpr(sqlite3 *, Expr *, u8, u8, sqlite3_value **);
SQLITE_PRIVATE void sqlite3ValueApplyAffinity(sqlite3_value *, u8, u8);
#ifndef SQLITE_AMALGAMATION
SQLITE_PRIVATE const unsigned char sqlite3OpcodeProperty[];
SQLITE_PRIVATE const char sqlite3StrBINARY[];
SQLITE_PRIVATE const unsigned char sqlite3StdTypeLen[];
SQLITE_PRIVATE const char sqlite3StdTypeAffinity[];

SQLITE_PRIVATE const char *sqlite3StdType[];
SQLITE_PRIVATE const unsigned char sqlite3UpperToLower[];
SQLITE_PRIVATE const unsigned char *sqlite3aLTb;
SQLITE_PRIVATE const unsigned char *sqlite3aEQb;
SQLITE_PRIVATE const unsigned char *sqlite3aGTb;
SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[];
SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config;







|






>







19705
19706
19707
19708
19709
19710
19711
19712
19713
19714
19715
19716
19717
19718
19719
19720
19721
19722
19723
19724
19725
19726
#ifndef SQLITE_UNTESTABLE
SQLITE_PRIVATE void sqlite3ResultIntReal(sqlite3_context*);
#endif
SQLITE_PRIVATE sqlite3_value *sqlite3ValueNew(sqlite3 *);
#ifndef SQLITE_OMIT_UTF16
SQLITE_PRIVATE char *sqlite3Utf16to8(sqlite3 *, const void*, int, u8);
#endif
SQLITE_PRIVATE int sqlite3ValueFromExpr(sqlite3 *, const Expr *, u8, u8, sqlite3_value **);
SQLITE_PRIVATE void sqlite3ValueApplyAffinity(sqlite3_value *, u8, u8);
#ifndef SQLITE_AMALGAMATION
SQLITE_PRIVATE const unsigned char sqlite3OpcodeProperty[];
SQLITE_PRIVATE const char sqlite3StrBINARY[];
SQLITE_PRIVATE const unsigned char sqlite3StdTypeLen[];
SQLITE_PRIVATE const char sqlite3StdTypeAffinity[];
SQLITE_PRIVATE const char sqlite3StdTypeMap[];
SQLITE_PRIVATE const char *sqlite3StdType[];
SQLITE_PRIVATE const unsigned char sqlite3UpperToLower[];
SQLITE_PRIVATE const unsigned char *sqlite3aLTb;
SQLITE_PRIVATE const unsigned char *sqlite3aEQb;
SQLITE_PRIVATE const unsigned char *sqlite3aGTb;
SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[];
SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config;
19737
19738
19739
19740
19741
19742
19743
19744
19745
19746
19747
19748
19749
19750
19751
19752
19753
SQLITE_PRIVATE int sqlite3ResolveExprListNames(NameContext*, ExprList*);
SQLITE_PRIVATE void sqlite3ResolveSelectNames(Parse*, Select*, NameContext*);
SQLITE_PRIVATE int sqlite3ResolveSelfReference(Parse*,Table*,int,Expr*,ExprList*);
SQLITE_PRIVATE int sqlite3ResolveOrderGroupBy(Parse*, Select*, ExprList*, const char*);
SQLITE_PRIVATE void sqlite3ColumnDefault(Vdbe *, Table *, int, int);
SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *, Token *);
SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *, SrcList *);
SQLITE_PRIVATE void sqlite3AlterDropColumn(Parse*, SrcList*, Token*);
SQLITE_PRIVATE void *sqlite3RenameTokenMap(Parse*, void*, Token*);
SQLITE_PRIVATE void sqlite3RenameTokenRemap(Parse*, void *pTo, void *pFrom);
SQLITE_PRIVATE void sqlite3RenameExprUnmap(Parse*, Expr*);
SQLITE_PRIVATE void sqlite3RenameExprlistUnmap(Parse*, ExprList*);
SQLITE_PRIVATE CollSeq *sqlite3GetCollSeq(Parse*, u8, CollSeq *, const char*);
SQLITE_PRIVATE char sqlite3AffinityType(const char*, Column*);
SQLITE_PRIVATE void sqlite3Analyze(Parse*, Token*, Token*);
SQLITE_PRIVATE int sqlite3InvokeBusyHandler(BusyHandler*);
SQLITE_PRIVATE int sqlite3FindDb(sqlite3*, Token*);







|
|
|







19757
19758
19759
19760
19761
19762
19763
19764
19765
19766
19767
19768
19769
19770
19771
19772
19773
SQLITE_PRIVATE int sqlite3ResolveExprListNames(NameContext*, ExprList*);
SQLITE_PRIVATE void sqlite3ResolveSelectNames(Parse*, Select*, NameContext*);
SQLITE_PRIVATE int sqlite3ResolveSelfReference(Parse*,Table*,int,Expr*,ExprList*);
SQLITE_PRIVATE int sqlite3ResolveOrderGroupBy(Parse*, Select*, ExprList*, const char*);
SQLITE_PRIVATE void sqlite3ColumnDefault(Vdbe *, Table *, int, int);
SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *, Token *);
SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *, SrcList *);
SQLITE_PRIVATE void sqlite3AlterDropColumn(Parse*, SrcList*, const Token*);
SQLITE_PRIVATE const void *sqlite3RenameTokenMap(Parse*, const void*, const Token*);
SQLITE_PRIVATE void sqlite3RenameTokenRemap(Parse*, const void *pTo, const void *pFrom);
SQLITE_PRIVATE void sqlite3RenameExprUnmap(Parse*, Expr*);
SQLITE_PRIVATE void sqlite3RenameExprlistUnmap(Parse*, ExprList*);
SQLITE_PRIVATE CollSeq *sqlite3GetCollSeq(Parse*, u8, CollSeq *, const char*);
SQLITE_PRIVATE char sqlite3AffinityType(const char*, Column*);
SQLITE_PRIVATE void sqlite3Analyze(Parse*, Token*, Token*);
SQLITE_PRIVATE int sqlite3InvokeBusyHandler(BusyHandler*);
SQLITE_PRIVATE int sqlite3FindDb(sqlite3*, Token*);
19783
19784
19785
19786
19787
19788
19789


19790
19791
19792
19793
19794
19795
19796
SQLITE_PRIVATE void sqlite3OomFault(sqlite3*);
SQLITE_PRIVATE void sqlite3OomClear(sqlite3*);
SQLITE_PRIVATE int sqlite3ApiExit(sqlite3 *db, int);
SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *);

SQLITE_PRIVATE void sqlite3StrAccumInit(StrAccum*, sqlite3*, char*, int, int);
SQLITE_PRIVATE char *sqlite3StrAccumFinish(StrAccum*);


SQLITE_PRIVATE void sqlite3SelectDestInit(SelectDest*,int,int);
SQLITE_PRIVATE Expr *sqlite3CreateColumnExpr(sqlite3 *, SrcList *, int, int);

SQLITE_PRIVATE void sqlite3BackupRestart(sqlite3_backup *);
SQLITE_PRIVATE void sqlite3BackupUpdate(sqlite3_backup *, Pgno, const u8 *);

#ifndef SQLITE_OMIT_SUBQUERY







>
>







19803
19804
19805
19806
19807
19808
19809
19810
19811
19812
19813
19814
19815
19816
19817
19818
SQLITE_PRIVATE void sqlite3OomFault(sqlite3*);
SQLITE_PRIVATE void sqlite3OomClear(sqlite3*);
SQLITE_PRIVATE int sqlite3ApiExit(sqlite3 *db, int);
SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *);

SQLITE_PRIVATE void sqlite3StrAccumInit(StrAccum*, sqlite3*, char*, int, int);
SQLITE_PRIVATE char *sqlite3StrAccumFinish(StrAccum*);
SQLITE_PRIVATE void sqlite3StrAccumSetError(StrAccum*, u8);
SQLITE_PRIVATE void sqlite3ResultStrAccum(sqlite3_context*,StrAccum*);
SQLITE_PRIVATE void sqlite3SelectDestInit(SelectDest*,int,int);
SQLITE_PRIVATE Expr *sqlite3CreateColumnExpr(sqlite3 *, SrcList *, int, int);

SQLITE_PRIVATE void sqlite3BackupRestart(sqlite3_backup *);
SQLITE_PRIVATE void sqlite3BackupUpdate(sqlite3_backup *, Pgno, const u8 *);

#ifndef SQLITE_OMIT_SUBQUERY
19835
19836
19837
19838
19839
19840
19841
19842
19843
19844
19845
19846
19847
19848
19849
#endif

#ifdef SQLITE_TEST
SQLITE_PRIVATE   int sqlite3Utf8To8(unsigned char*);
#endif

#ifdef SQLITE_OMIT_VIRTUALTABLE
#  define sqlite3VtabClear(Y)
#  define sqlite3VtabSync(X,Y) SQLITE_OK
#  define sqlite3VtabRollback(X)
#  define sqlite3VtabCommit(X)
#  define sqlite3VtabInSync(db) 0
#  define sqlite3VtabLock(X)
#  define sqlite3VtabUnlock(X)
#  define sqlite3VtabModuleUnref(D,X)







|







19857
19858
19859
19860
19861
19862
19863
19864
19865
19866
19867
19868
19869
19870
19871
#endif

#ifdef SQLITE_TEST
SQLITE_PRIVATE   int sqlite3Utf8To8(unsigned char*);
#endif

#ifdef SQLITE_OMIT_VIRTUALTABLE
#  define sqlite3VtabClear(D,T)
#  define sqlite3VtabSync(X,Y) SQLITE_OK
#  define sqlite3VtabRollback(X)
#  define sqlite3VtabCommit(X)
#  define sqlite3VtabInSync(db) 0
#  define sqlite3VtabLock(X)
#  define sqlite3VtabUnlock(X)
#  define sqlite3VtabModuleUnref(D,X)
20014
20015
20016
20017
20018
20019
20020
20021
20022
20023
20024
20025
20026
20027
20028
#endif

SQLITE_PRIVATE int sqlite3JournalIsInMemory(sqlite3_file *p);
SQLITE_PRIVATE void sqlite3MemJournalOpen(sqlite3_file *);

SQLITE_PRIVATE void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p);
#if SQLITE_MAX_EXPR_DEPTH>0
SQLITE_PRIVATE   int sqlite3SelectExprHeight(Select *);
SQLITE_PRIVATE   int sqlite3ExprCheckHeight(Parse*, int);
#else
  #define sqlite3SelectExprHeight(x) 0
  #define sqlite3ExprCheckHeight(x,y)
#endif

SQLITE_PRIVATE u32 sqlite3Get4byte(const u8*);







|







20036
20037
20038
20039
20040
20041
20042
20043
20044
20045
20046
20047
20048
20049
20050
#endif

SQLITE_PRIVATE int sqlite3JournalIsInMemory(sqlite3_file *p);
SQLITE_PRIVATE void sqlite3MemJournalOpen(sqlite3_file *);

SQLITE_PRIVATE void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p);
#if SQLITE_MAX_EXPR_DEPTH>0
SQLITE_PRIVATE   int sqlite3SelectExprHeight(const Select *);
SQLITE_PRIVATE   int sqlite3ExprCheckHeight(Parse*, int);
#else
  #define sqlite3SelectExprHeight(x) 0
  #define sqlite3ExprCheckHeight(x,y)
#endif

SQLITE_PRIVATE u32 sqlite3Get4byte(const u8*);
20111
20112
20113
20114
20115
20116
20117
20118
20119
20120
20121
20122
20123
20124
20125
20126
#if defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST)
SQLITE_PRIVATE int sqlite3DbpageRegister(sqlite3*);
#endif
#if defined(SQLITE_ENABLE_DBSTAT_VTAB) || defined(SQLITE_TEST)
SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3*);
#endif

SQLITE_PRIVATE int sqlite3ExprVectorSize(Expr *pExpr);
SQLITE_PRIVATE int sqlite3ExprIsVector(Expr *pExpr);
SQLITE_PRIVATE Expr *sqlite3VectorFieldSubexpr(Expr*, int);
SQLITE_PRIVATE Expr *sqlite3ExprForVectorField(Parse*,Expr*,int,int);
SQLITE_PRIVATE void sqlite3VectorErrorMsg(Parse*, Expr*);

#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
SQLITE_PRIVATE const char **sqlite3CompileOptions(int *pnOpt);
#endif







|
|







20133
20134
20135
20136
20137
20138
20139
20140
20141
20142
20143
20144
20145
20146
20147
20148
#if defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST)
SQLITE_PRIVATE int sqlite3DbpageRegister(sqlite3*);
#endif
#if defined(SQLITE_ENABLE_DBSTAT_VTAB) || defined(SQLITE_TEST)
SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3*);
#endif

SQLITE_PRIVATE int sqlite3ExprVectorSize(const Expr *pExpr);
SQLITE_PRIVATE int sqlite3ExprIsVector(const Expr *pExpr);
SQLITE_PRIVATE Expr *sqlite3VectorFieldSubexpr(Expr*, int);
SQLITE_PRIVATE Expr *sqlite3ExprForVectorField(Parse*,Expr*,int,int);
SQLITE_PRIVATE void sqlite3VectorErrorMsg(Parse*, Expr*);

#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
SQLITE_PRIVATE const char **sqlite3CompileOptions(int *pnOpt);
#endif
21462
21463
21464
21465
21466
21467
21468












21469
21470
21471

21472
21473
21474
21475
21476
21477








21478

21479
21480
21481
21482
21483
21484
21485
** Name of the default collating sequence
*/
SQLITE_PRIVATE const char sqlite3StrBINARY[] = "BINARY";

/*
** Standard typenames.  These names must match the COLTYPE_* definitions.
** Adjust the SQLITE_N_STDTYPE value if adding or removing entries.












*/
SQLITE_PRIVATE const unsigned char sqlite3StdTypeLen[] = { 4, 3, 7, 4, 4 };
SQLITE_PRIVATE const char sqlite3StdTypeAffinity[] = {

  SQLITE_AFF_BLOB,
  SQLITE_AFF_INTEGER,
  SQLITE_AFF_INTEGER,
  SQLITE_AFF_REAL,
  SQLITE_AFF_TEXT
};








SQLITE_PRIVATE const char *sqlite3StdType[] = {

  "BLOB",
  "INT",
  "INTEGER",
  "REAL",
  "TEXT"
};








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

|

>






>
>
>
>
>
>
>
>

>







21484
21485
21486
21487
21488
21489
21490
21491
21492
21493
21494
21495
21496
21497
21498
21499
21500
21501
21502
21503
21504
21505
21506
21507
21508
21509
21510
21511
21512
21513
21514
21515
21516
21517
21518
21519
21520
21521
21522
21523
21524
21525
21526
21527
21528
21529
** Name of the default collating sequence
*/
SQLITE_PRIVATE const char sqlite3StrBINARY[] = "BINARY";

/*
** Standard typenames.  These names must match the COLTYPE_* definitions.
** Adjust the SQLITE_N_STDTYPE value if adding or removing entries.
**
**    sqlite3StdType[]            The actual names of the datatypes.
**
**    sqlite3StdTypeLen[]         The length (in bytes) of each entry
**                                in sqlite3StdType[].
**
**    sqlite3StdTypeAffinity[]    The affinity associated with each entry
**                                in sqlite3StdType[].
**
**    sqlite3StdTypeMap[]         The type value (as returned from
**                                sqlite3_column_type() or sqlite3_value_type())
**                                for each entry in sqlite3StdType[].
*/
SQLITE_PRIVATE const unsigned char sqlite3StdTypeLen[] = { 3, 4, 3, 7, 4, 4 };
SQLITE_PRIVATE const char sqlite3StdTypeAffinity[] = {
  SQLITE_AFF_NUMERIC,
  SQLITE_AFF_BLOB,
  SQLITE_AFF_INTEGER,
  SQLITE_AFF_INTEGER,
  SQLITE_AFF_REAL,
  SQLITE_AFF_TEXT
};
SQLITE_PRIVATE const char sqlite3StdTypeMap[] = {
  0,
  SQLITE_BLOB,
  SQLITE_INTEGER,
  SQLITE_INTEGER,
  SQLITE_FLOAT,
  SQLITE_TEXT
};
SQLITE_PRIVATE const char *sqlite3StdType[] = {
  "ANY",
  "BLOB",
  "INT",
  "INTEGER",
  "REAL",
  "TEXT"
};

23519
23520
23521
23522
23523
23524
23525
23526
23527
23528
23529
23530

23531

23532
23533
23534
23535
23536
23537
23538
23539
23540
23541
23542
23543
23544
23545
23546
23547
23548
23549
23550
23551
23552
23553
23554
23555
23556
23557
23558
23559
23560
23561
23562
23563
23564
23565
23566
23567
23568
23569
23570
23571
23572
23573
23574
23575
23576
23577
23578
23579
23580
23581
23582
23583
23584
23585
23586
23587
23588
23589
23590
23591

23592
23593



23594
23595
23596
23597
23598
23599
23600
23601



23602
23603
23604
23605
23606
23607
23608
23609
23610
23611
23612
23613
23614
23615
23616
23617
23618
23619
23620
23621
23622
23623
23624
23625
23626
23627



23628



23629
23630
23631
23632
23633
23634

23635


23636

23637
23638
23639
23640
23641
23642
23643




23644


23645
23646
23647
23648

23649
23650
23651
23652
23653
23654
23655
23656
23657
*/
static void strftimeFunc(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  DateTime x;
  u64 n;
  size_t i,j;
  char *z;
  sqlite3 *db;
  const char *zFmt;

  char zBuf[100];

  if( argc==0 ) return;
  zFmt = (const char*)sqlite3_value_text(argv[0]);
  if( zFmt==0 || isDate(context, argc-1, argv+1, &x) ) return;
  db = sqlite3_context_db_handle(context);
  for(i=0, n=1; zFmt[i]; i++, n++){
    if( zFmt[i]=='%' ){
      switch( zFmt[i+1] ){
        case 'd':
        case 'H':
        case 'm':
        case 'M':
        case 'S':
        case 'W':
          n++;
          /* fall thru */
        case 'w':
        case '%':
          break;
        case 'f':
          n += 8;
          break;
        case 'j':
          n += 3;
          break;
        case 'Y':
          n += 8;
          break;
        case 's':
        case 'J':
          n += 50;
          break;
        default:
          return;  /* ERROR.  return a NULL */
      }
      i++;
    }
  }
  testcase( n==sizeof(zBuf)-1 );
  testcase( n==sizeof(zBuf) );
  testcase( n==(u64)db->aLimit[SQLITE_LIMIT_LENGTH]+1 );
  testcase( n==(u64)db->aLimit[SQLITE_LIMIT_LENGTH] );
  if( n<sizeof(zBuf) ){
    z = zBuf;
  }else if( n>(u64)db->aLimit[SQLITE_LIMIT_LENGTH] ){
    sqlite3_result_error_toobig(context);
    return;
  }else{
    z = sqlite3DbMallocRawNN(db, (int)n);
    if( z==0 ){
      sqlite3_result_error_nomem(context);
      return;
    }
  }
  computeJD(&x);
  computeYMD_HMS(&x);
  for(i=j=0; zFmt[i]; i++){
    if( zFmt[i]!='%' ){
      z[j++] = zFmt[i];
    }else{
      i++;

      switch( zFmt[i] ){
        case 'd':  sqlite3_snprintf(3, &z[j],"%02d",x.D); j+=2; break;



        case 'f': {
          double s = x.s;
          if( s>59.999 ) s = 59.999;
          sqlite3_snprintf(7, &z[j],"%06.3f", s);
          j += sqlite3Strlen30(&z[j]);
          break;
        }
        case 'H':  sqlite3_snprintf(3, &z[j],"%02d",x.h); j+=2; break;



        case 'W': /* Fall thru */
        case 'j': {
          int nDay;             /* Number of days since 1st day of year */
          DateTime y = x;
          y.validJD = 0;
          y.M = 1;
          y.D = 1;
          computeJD(&y);
          nDay = (int)((x.iJD-y.iJD+43200000)/86400000);
          if( zFmt[i]=='W' ){
            int wd;   /* 0=Monday, 1=Tuesday, ... 6=Sunday */
            wd = (int)(((x.iJD+43200000)/86400000)%7);
            sqlite3_snprintf(3, &z[j],"%02d",(nDay+7-wd)/7);
            j += 2;
          }else{
            sqlite3_snprintf(4, &z[j],"%03d",nDay+1);
            j += 3;
          }
          break;
        }
        case 'J': {
          sqlite3_snprintf(20, &z[j],"%.16g",x.iJD/86400000.0);
          j+=sqlite3Strlen30(&z[j]);
          break;
        }
        case 'm':  sqlite3_snprintf(3, &z[j],"%02d",x.M); j+=2; break;



        case 'M':  sqlite3_snprintf(3, &z[j],"%02d",x.m); j+=2; break;



        case 's': {
          i64 iS = (i64)(x.iJD/1000 - 21086676*(i64)10000);
          sqlite3Int64ToText(iS, &z[j]);
          j += sqlite3Strlen30(&z[j]);
          break;
        }

        case 'S':  sqlite3_snprintf(3,&z[j],"%02d",(int)x.s); j+=2; break;


        case 'w': {

          z[j++] = (char)(((x.iJD+129600000)/86400000) % 7) + '0';
          break;
        }
        case 'Y': {
          sqlite3_snprintf(5,&z[j],"%04d",x.Y); j+=sqlite3Strlen30(&z[j]);
          break;
        }




        default:   z[j++] = '%'; break;


      }
    }
  }
  z[j] = 0;

  sqlite3_result_text(context, z, -1,
                      z==zBuf ? SQLITE_TRANSIENT : SQLITE_DYNAMIC);
}

/*
** current_time()
**
** This function returns the same value as time('now').
*/







<

<


>
|
>




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



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



<
>
|
<







23563
23564
23565
23566
23567
23568
23569

23570

23571
23572
23573
23574
23575
23576
23577
23578
23579




































23580










23581

23582
23583
23584
23585
23586

23587
23588
23589
23590
23591
23592
23593
23594
23595
23596
23597

23598
23599
23600
23601
23602
23603
23604
23605
23606
23607
23608
23609
23610
23611
23612
23613
23614
23615
23616

23617
23618

23619
23620
23621
23622
23623

23624
23625
23626
23627
23628
23629
23630
23631
23632
23633
23634
23635
23636

23637
23638
23639
23640
23641
23642
23643
23644
23645
23646
23647
23648
23649
23650
23651
23652
23653
23654
23655
23656
23657
23658
23659
23660
23661

23662
23663

23664
23665
23666
23667
23668
23669
23670
*/
static void strftimeFunc(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  DateTime x;

  size_t i,j;

  sqlite3 *db;
  const char *zFmt;
  sqlite3_str sRes;


  if( argc==0 ) return;
  zFmt = (const char*)sqlite3_value_text(argv[0]);
  if( zFmt==0 || isDate(context, argc-1, argv+1, &x) ) return;
  db = sqlite3_context_db_handle(context);




































  sqlite3StrAccumInit(&sRes, 0, 0, 0, db->aLimit[SQLITE_LIMIT_LENGTH]);












  computeJD(&x);
  computeYMD_HMS(&x);
  for(i=j=0; zFmt[i]; i++){
    if( zFmt[i]!='%' ) continue;
    if( j<i ) sqlite3_str_append(&sRes, zFmt+j, (int)(i-j));

    i++;
    j = i + 1;
    switch( zFmt[i] ){
      case 'd': {
        sqlite3_str_appendf(&sRes, "%02d", x.D);
        break;
      }
      case 'f': {
        double s = x.s;
        if( s>59.999 ) s = 59.999;
        sqlite3_str_appendf(&sRes, "%06.3f", s);

        break;
      }
      case 'H': {
        sqlite3_str_appendf(&sRes, "%02d", x.h);
        break;
      }
      case 'W': /* Fall thru */
      case 'j': {
        int nDay;             /* Number of days since 1st day of year */
        DateTime y = x;
        y.validJD = 0;
        y.M = 1;
        y.D = 1;
        computeJD(&y);
        nDay = (int)((x.iJD-y.iJD+43200000)/86400000);
        if( zFmt[i]=='W' ){
          int wd;   /* 0=Monday, 1=Tuesday, ... 6=Sunday */
          wd = (int)(((x.iJD+43200000)/86400000)%7);
          sqlite3_str_appendf(&sRes,"%02d",(nDay+7-wd)/7);

        }else{
          sqlite3_str_appendf(&sRes,"%03d",nDay+1);

        }
        break;
      }
      case 'J': {
        sqlite3_str_appendf(&sRes,"%.16g",x.iJD/86400000.0);

        break;
      }
      case 'm': {
        sqlite3_str_appendf(&sRes,"%02d",x.M);
        break;
      }
      case 'M': {
        sqlite3_str_appendf(&sRes,"%02d",x.m);
        break;
      }
      case 's': {
        i64 iS = (i64)(x.iJD/1000 - 21086676*(i64)10000);
        sqlite3_str_appendf(&sRes,"%lld",iS);

        break;
      }
      case 'S': {
        sqlite3_str_appendf(&sRes,"%02d",(int)x.s);
        break;
      }
      case 'w': {
        sqlite3_str_appendchar(&sRes, 1,
                       (char)(((x.iJD+129600000)/86400000) % 7) + '0');
        break;
      }
      case 'Y': {
        sqlite3_str_appendf(&sRes,"%04d",x.Y);
        break;
      }
      case '%': {
        sqlite3_str_appendchar(&sRes, 1, '%');
        break;
      }
      default: {
        sqlite3_str_reset(&sRes);
        return;
      }
    }
  }

  if( j<i ) sqlite3_str_append(&sRes, zFmt+j, (int)(i-j));
  sqlite3ResultStrAccum(context, &sRes);

}

/*
** current_time()
**
** This function returns the same value as time('now').
*/
23924
23925
23926
23927
23928
23929
23930

23931
23932
23933
23934
23935
23936
23937
}

SQLITE_PRIVATE int sqlite3OsSectorSize(sqlite3_file *id){
  int (*xSectorSize)(sqlite3_file*) = id->pMethods->xSectorSize;
  return (xSectorSize ? xSectorSize(id) : SQLITE_DEFAULT_SECTOR_SIZE);
}
SQLITE_PRIVATE int sqlite3OsDeviceCharacteristics(sqlite3_file *id){

  return id->pMethods->xDeviceCharacteristics(id);
}
#ifndef SQLITE_OMIT_WAL
SQLITE_PRIVATE int sqlite3OsShmLock(sqlite3_file *id, int offset, int n, int flags){
  return id->pMethods->xShmLock(id, offset, n, flags);
}
SQLITE_PRIVATE void sqlite3OsShmBarrier(sqlite3_file *id){







>







23937
23938
23939
23940
23941
23942
23943
23944
23945
23946
23947
23948
23949
23950
23951
}

SQLITE_PRIVATE int sqlite3OsSectorSize(sqlite3_file *id){
  int (*xSectorSize)(sqlite3_file*) = id->pMethods->xSectorSize;
  return (xSectorSize ? xSectorSize(id) : SQLITE_DEFAULT_SECTOR_SIZE);
}
SQLITE_PRIVATE int sqlite3OsDeviceCharacteristics(sqlite3_file *id){
  if( NEVER(id->pMethods==0) ) return 0;
  return id->pMethods->xDeviceCharacteristics(id);
}
#ifndef SQLITE_OMIT_WAL
SQLITE_PRIVATE int sqlite3OsShmLock(sqlite3_file *id, int offset, int n, int flags){
  return id->pMethods->xShmLock(id, offset, n, flags);
}
SQLITE_PRIVATE void sqlite3OsShmBarrier(sqlite3_file *id){
28241
28242
28243
28244
28245
28246
28247
28248
28249
28250
28251
28252
28253
28254
28255
28256
28257
28258
28259
28260
28261
28262
28263
28264
28265
28266
28267
28268
28269
28270
28271
28272
28273
28274
28275
28276
28277
  return sqlite3Malloc(n);
}

/*
** TRUE if p is a lookaside memory allocation from db
*/
#ifndef SQLITE_OMIT_LOOKASIDE
static int isLookaside(sqlite3 *db, void *p){
  return SQLITE_WITHIN(p, db->lookaside.pStart, db->lookaside.pEnd);
}
#else
#define isLookaside(A,B) 0
#endif

/*
** Return the size of a memory allocation previously obtained from
** sqlite3Malloc() or sqlite3_malloc().
*/
SQLITE_PRIVATE int sqlite3MallocSize(void *p){
  assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
  return sqlite3GlobalConfig.m.xSize(p);
}
static int lookasideMallocSize(sqlite3 *db, void *p){
#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
  return p<db->lookaside.pMiddle ? db->lookaside.szTrue : LOOKASIDE_SMALL;
#else
  return db->lookaside.szTrue;
#endif
}
SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3 *db, void *p){
  assert( p!=0 );
#ifdef SQLITE_DEBUG
  if( db==0 || !isLookaside(db,p) ){
    if( db==0 ){
      assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) );
      assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
    }else{







|










|

|

|






|







28255
28256
28257
28258
28259
28260
28261
28262
28263
28264
28265
28266
28267
28268
28269
28270
28271
28272
28273
28274
28275
28276
28277
28278
28279
28280
28281
28282
28283
28284
28285
28286
28287
28288
28289
28290
28291
  return sqlite3Malloc(n);
}

/*
** TRUE if p is a lookaside memory allocation from db
*/
#ifndef SQLITE_OMIT_LOOKASIDE
static int isLookaside(sqlite3 *db, const void *p){
  return SQLITE_WITHIN(p, db->lookaside.pStart, db->lookaside.pEnd);
}
#else
#define isLookaside(A,B) 0
#endif

/*
** Return the size of a memory allocation previously obtained from
** sqlite3Malloc() or sqlite3_malloc().
*/
SQLITE_PRIVATE int sqlite3MallocSize(const void *p){
  assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
  return sqlite3GlobalConfig.m.xSize((void*)p);
}
static int lookasideMallocSize(sqlite3 *db, const void *p){
#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
  return p<db->lookaside.pMiddle ? db->lookaside.szTrue : LOOKASIDE_SMALL;
#else
  return db->lookaside.szTrue;
#endif
}
SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3 *db, const void *p){
  assert( p!=0 );
#ifdef SQLITE_DEBUG
  if( db==0 || !isLookaside(db,p) ){
    if( db==0 ){
      assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) );
      assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
    }else{
28290
28291
28292
28293
28294
28295
28296
28297
28298
28299
28300
28301
28302
28303
28304
#endif
      if( ((uptr)p)>=(uptr)(db->lookaside.pStart) ){
        assert( sqlite3_mutex_held(db->mutex) );
        return db->lookaside.szTrue;
      }
    }
  }
  return sqlite3GlobalConfig.m.xSize(p);
}
SQLITE_API sqlite3_uint64 sqlite3_msize(void *p){
  assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) );
  assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
  return p ? sqlite3GlobalConfig.m.xSize(p) : 0;
}








|







28304
28305
28306
28307
28308
28309
28310
28311
28312
28313
28314
28315
28316
28317
28318
#endif
      if( ((uptr)p)>=(uptr)(db->lookaside.pStart) ){
        assert( sqlite3_mutex_held(db->mutex) );
        return db->lookaside.szTrue;
      }
    }
  }
  return sqlite3GlobalConfig.m.xSize((void*)p);
}
SQLITE_API sqlite3_uint64 sqlite3_msize(void *p){
  assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) );
  assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
  return p ? sqlite3GlobalConfig.m.xSize(p) : 0;
}

28900
28901
28902
28903
28904
28905
28906
28907
28908
28909
28910
28911
28912
28913
28914
  return (char)digit;
}
#endif /* SQLITE_OMIT_FLOATING_POINT */

/*
** Set the StrAccum object to an error mode.
*/
static void setStrAccumError(StrAccum *p, u8 eError){
  assert( eError==SQLITE_NOMEM || eError==SQLITE_TOOBIG );
  p->accError = eError;
  if( p->mxAlloc ) sqlite3_str_reset(p);
  if( eError==SQLITE_TOOBIG ) sqlite3ErrorToParser(p->db, eError);
}

/*







|







28914
28915
28916
28917
28918
28919
28920
28921
28922
28923
28924
28925
28926
28927
28928
  return (char)digit;
}
#endif /* SQLITE_OMIT_FLOATING_POINT */

/*
** Set the StrAccum object to an error mode.
*/
SQLITE_PRIVATE void sqlite3StrAccumSetError(StrAccum *p, u8 eError){
  assert( eError==SQLITE_NOMEM || eError==SQLITE_TOOBIG );
  p->accError = eError;
  if( p->mxAlloc ) sqlite3_str_reset(p);
  if( eError==SQLITE_TOOBIG ) sqlite3ErrorToParser(p->db, eError);
}

/*
28936
28937
28938
28939
28940
28941
28942
28943
28944
28945
28946
28947
28948
28949
28950
28951
28952
28953
28954
28955
** SQL from requesting large allocations using the precision or width
** field of the printf() function.
*/
static char *printfTempBuf(sqlite3_str *pAccum, sqlite3_int64 n){
  char *z;
  if( pAccum->accError ) return 0;
  if( n>pAccum->nAlloc && n>pAccum->mxAlloc ){
    setStrAccumError(pAccum, SQLITE_TOOBIG);
    return 0;
  }
  z = sqlite3DbMallocRaw(pAccum->db, n);
  if( z==0 ){
    setStrAccumError(pAccum, SQLITE_NOMEM);
  }
  return z;
}

/*
** On machines with a small stack size, you can redefine the
** SQLITE_PRINT_BUF_SIZE to be something smaller, if desired.







|




|







28950
28951
28952
28953
28954
28955
28956
28957
28958
28959
28960
28961
28962
28963
28964
28965
28966
28967
28968
28969
** SQL from requesting large allocations using the precision or width
** field of the printf() function.
*/
static char *printfTempBuf(sqlite3_str *pAccum, sqlite3_int64 n){
  char *z;
  if( pAccum->accError ) return 0;
  if( n>pAccum->nAlloc && n>pAccum->mxAlloc ){
    sqlite3StrAccumSetError(pAccum, SQLITE_TOOBIG);
    return 0;
  }
  z = sqlite3DbMallocRaw(pAccum->db, n);
  if( z==0 ){
    sqlite3StrAccumSetError(pAccum, SQLITE_NOMEM);
  }
  return z;
}

/*
** On machines with a small stack size, you can redefine the
** SQLITE_PRINT_BUF_SIZE to be something smaller, if desired.
29680
29681
29682
29683
29684
29685
29686
29687
29688
29689
29690
29691
29692
29693
29694
29695
29696
29697
29698
29699
29700
29701
29702
29703
29704
29705
29706
29707
29708
29709
29710
29711
29712
29713
29714
29715
29716
29717
29718
29719
29720
29721
29722
29723
29724
29725
  assert( p->nChar+(i64)N >= p->nAlloc ); /* Only called if really needed */
  if( p->accError ){
    testcase(p->accError==SQLITE_TOOBIG);
    testcase(p->accError==SQLITE_NOMEM);
    return 0;
  }
  if( p->mxAlloc==0 ){
    setStrAccumError(p, SQLITE_TOOBIG);
    return p->nAlloc - p->nChar - 1;
  }else{
    char *zOld = isMalloced(p) ? p->zText : 0;
    i64 szNew = p->nChar;
    szNew += (sqlite3_int64)N + 1;
    if( szNew+p->nChar<=p->mxAlloc ){
      /* Force exponential buffer size growth as long as it does not overflow,
      ** to avoid having to call this routine too often */
      szNew += p->nChar;
    }
    if( szNew > p->mxAlloc ){
      sqlite3_str_reset(p);
      setStrAccumError(p, SQLITE_TOOBIG);
      return 0;
    }else{
      p->nAlloc = (int)szNew;
    }
    if( p->db ){
      zNew = sqlite3DbRealloc(p->db, zOld, p->nAlloc);
    }else{
      zNew = sqlite3Realloc(zOld, p->nAlloc);
    }
    if( zNew ){
      assert( p->zText!=0 || p->nChar==0 );
      if( !isMalloced(p) && p->nChar>0 ) memcpy(zNew, p->zText, p->nChar);
      p->zText = zNew;
      p->nAlloc = sqlite3DbMallocSize(p->db, zNew);
      p->printfFlags |= SQLITE_PRINTF_MALLOCED;
    }else{
      sqlite3_str_reset(p);
      setStrAccumError(p, SQLITE_NOMEM);
      return 0;
    }
  }
  return N;
}

/*







|












|

















|







29694
29695
29696
29697
29698
29699
29700
29701
29702
29703
29704
29705
29706
29707
29708
29709
29710
29711
29712
29713
29714
29715
29716
29717
29718
29719
29720
29721
29722
29723
29724
29725
29726
29727
29728
29729
29730
29731
29732
29733
29734
29735
29736
29737
29738
29739
  assert( p->nChar+(i64)N >= p->nAlloc ); /* Only called if really needed */
  if( p->accError ){
    testcase(p->accError==SQLITE_TOOBIG);
    testcase(p->accError==SQLITE_NOMEM);
    return 0;
  }
  if( p->mxAlloc==0 ){
    sqlite3StrAccumSetError(p, SQLITE_TOOBIG);
    return p->nAlloc - p->nChar - 1;
  }else{
    char *zOld = isMalloced(p) ? p->zText : 0;
    i64 szNew = p->nChar;
    szNew += (sqlite3_int64)N + 1;
    if( szNew+p->nChar<=p->mxAlloc ){
      /* Force exponential buffer size growth as long as it does not overflow,
      ** to avoid having to call this routine too often */
      szNew += p->nChar;
    }
    if( szNew > p->mxAlloc ){
      sqlite3_str_reset(p);
      sqlite3StrAccumSetError(p, SQLITE_TOOBIG);
      return 0;
    }else{
      p->nAlloc = (int)szNew;
    }
    if( p->db ){
      zNew = sqlite3DbRealloc(p->db, zOld, p->nAlloc);
    }else{
      zNew = sqlite3Realloc(zOld, p->nAlloc);
    }
    if( zNew ){
      assert( p->zText!=0 || p->nChar==0 );
      if( !isMalloced(p) && p->nChar>0 ) memcpy(zNew, p->zText, p->nChar);
      p->zText = zNew;
      p->nAlloc = sqlite3DbMallocSize(p->db, zNew);
      p->printfFlags |= SQLITE_PRINTF_MALLOCED;
    }else{
      sqlite3_str_reset(p);
      sqlite3StrAccumSetError(p, SQLITE_NOMEM);
      return 0;
    }
  }
  return N;
}

/*
29784
29785
29786
29787
29788
29789
29790
29791
29792
29793
29794
29795
29796
29797
29798
29799
29800
29801
29802
29803
29804
















29805
29806
29807
29808
29809
29810
29811
  char *zText;
  assert( p->mxAlloc>0 && !isMalloced(p) );
  zText = sqlite3DbMallocRaw(p->db, p->nChar+1 );
  if( zText ){
    memcpy(zText, p->zText, p->nChar+1);
    p->printfFlags |= SQLITE_PRINTF_MALLOCED;
  }else{
    setStrAccumError(p, SQLITE_NOMEM);
  }
  p->zText = zText;
  return zText;
}
SQLITE_PRIVATE char *sqlite3StrAccumFinish(StrAccum *p){
  if( p->zText ){
    p->zText[p->nChar] = 0;
    if( p->mxAlloc>0 && !isMalloced(p) ){
      return strAccumFinishRealloc(p);
    }
  }
  return p->zText;
}

















/*
** This singleton is an sqlite3_str object that is returned if
** sqlite3_malloc() fails to provide space for a real one.  This
** sqlite3_str object accepts no new text and always returns
** an SQLITE_NOMEM error.
*/







|













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







29798
29799
29800
29801
29802
29803
29804
29805
29806
29807
29808
29809
29810
29811
29812
29813
29814
29815
29816
29817
29818
29819
29820
29821
29822
29823
29824
29825
29826
29827
29828
29829
29830
29831
29832
29833
29834
29835
29836
29837
29838
29839
29840
29841
  char *zText;
  assert( p->mxAlloc>0 && !isMalloced(p) );
  zText = sqlite3DbMallocRaw(p->db, p->nChar+1 );
  if( zText ){
    memcpy(zText, p->zText, p->nChar+1);
    p->printfFlags |= SQLITE_PRINTF_MALLOCED;
  }else{
    sqlite3StrAccumSetError(p, SQLITE_NOMEM);
  }
  p->zText = zText;
  return zText;
}
SQLITE_PRIVATE char *sqlite3StrAccumFinish(StrAccum *p){
  if( p->zText ){
    p->zText[p->nChar] = 0;
    if( p->mxAlloc>0 && !isMalloced(p) ){
      return strAccumFinishRealloc(p);
    }
  }
  return p->zText;
}

/*
** Use the content of the StrAccum passed as the second argument
** as the result of an SQL function.
*/
SQLITE_PRIVATE void sqlite3ResultStrAccum(sqlite3_context *pCtx, StrAccum *p){
  if( p->accError ){
    sqlite3_result_error_code(pCtx, p->accError);
    sqlite3_str_reset(p);
  }else if( isMalloced(p) ){
    sqlite3_result_text(pCtx, p->zText, p->nChar, SQLITE_DYNAMIC);
  }else{
    sqlite3_result_text(pCtx, "", 0, SQLITE_STATIC);
    sqlite3_str_reset(p);
  }
}

/*
** This singleton is an sqlite3_str object that is returned if
** sqlite3_malloc() fails to provide space for a real one.  This
** sqlite3_str object accepts no new text and always returns
** an SQLITE_NOMEM error.
*/
31894
31895
31896
31897
31898
31899
31900



31901
31902


31903
31904





31905
31906
31907
31908
31909
31910
31911
31912
  return xCallback ? xCallback(iTest) : SQLITE_OK;
}
#endif

#ifndef SQLITE_OMIT_FLOATING_POINT
/*
** Return true if the floating point value is Not a Number (NaN).



*/
SQLITE_PRIVATE int sqlite3IsNaN(double x){


  u64 y;
  memcpy(&y,&x,sizeof(y));





  return IsNaN(y);
}
#endif /* SQLITE_OMIT_FLOATING_POINT */

/*
** Compute a string length that is limited to what can be stored in
** lower 30 bits of a 32-bit signed integer.
**







>
>
>


>
>


>
>
>
>
>
|







31924
31925
31926
31927
31928
31929
31930
31931
31932
31933
31934
31935
31936
31937
31938
31939
31940
31941
31942
31943
31944
31945
31946
31947
31948
31949
31950
31951
31952
  return xCallback ? xCallback(iTest) : SQLITE_OK;
}
#endif

#ifndef SQLITE_OMIT_FLOATING_POINT
/*
** Return true if the floating point value is Not a Number (NaN).
**
** Use the math library isnan() function if compiled with SQLITE_HAVE_ISNAN.
** Otherwise, we have our own implementation that works on most systems.
*/
SQLITE_PRIVATE int sqlite3IsNaN(double x){
  int rc;   /* The value return */
#if !SQLITE_HAVE_ISNAN && !HAVE_ISNAN
  u64 y;
  memcpy(&y,&x,sizeof(y));
  rc = IsNaN(y);
#else
  rc = isnan(x);
#endif /* HAVE_ISNAN */
  testcase( rc );
  return rc;
}
#endif /* SQLITE_OMIT_FLOATING_POINT */

/*
** Compute a string length that is limited to what can be stored in
** lower 30 bits of a 32-bit signed integer.
**
31925
31926
31927
31928
31929
31930
31931
31932
31933
31934
31935
31936
31937
31938
31939
31940
31941
**
** The column type is an extra string stored after the zero-terminator on
** the column name if and only if the COLFLAG_HASTYPE flag is set.
*/
SQLITE_PRIVATE char *sqlite3ColumnType(Column *pCol, char *zDflt){
  if( pCol->colFlags & COLFLAG_HASTYPE ){
    return pCol->zCnName + strlen(pCol->zCnName) + 1;
  }else if( pCol->eType ){
    assert( pCol->eType<=SQLITE_N_STDTYPE );
    return (char*)sqlite3StdType[pCol->eType-1];
  }else{
    return zDflt;
  }
}

/*
** Helper function for sqlite3Error() - called rarely.  Broken out into







|
|
|







31965
31966
31967
31968
31969
31970
31971
31972
31973
31974
31975
31976
31977
31978
31979
31980
31981
**
** The column type is an extra string stored after the zero-terminator on
** the column name if and only if the COLFLAG_HASTYPE flag is set.
*/
SQLITE_PRIVATE char *sqlite3ColumnType(Column *pCol, char *zDflt){
  if( pCol->colFlags & COLFLAG_HASTYPE ){
    return pCol->zCnName + strlen(pCol->zCnName) + 1;
  }else if( pCol->eCType ){
    assert( pCol->eCType<=SQLITE_N_STDTYPE );
    return (char*)sqlite3StdType[pCol->eCType-1];
  }else{
    return zDflt;
  }
}

/*
** Helper function for sqlite3Error() - called rarely.  Broken out into
33233
33234
33235
33236
33237
33238
33239
33240
33241
33242
33243
33244
33245
33246
33247
33248
33249
33250
33251
33252
33253
33254
33255
33256
33257
33258
33259
33260
33261
33262
33263
33264
33265
33266
33267
33268
**
** sqlite3SafetyCheckOk() requires that the db pointer be valid for
** use.  sqlite3SafetyCheckSickOrOk() allows a db pointer that failed to
** open properly and is not fit for general use but which can be
** used as an argument to sqlite3_errmsg() or sqlite3_close().
*/
SQLITE_PRIVATE int sqlite3SafetyCheckOk(sqlite3 *db){
  u32 magic;
  if( db==0 ){
    logBadConnection("NULL");
    return 0;
  }
  magic = db->magic;
  if( magic!=SQLITE_MAGIC_OPEN ){
    if( sqlite3SafetyCheckSickOrOk(db) ){
      testcase( sqlite3GlobalConfig.xLog!=0 );
      logBadConnection("unopened");
    }
    return 0;
  }else{
    return 1;
  }
}
SQLITE_PRIVATE int sqlite3SafetyCheckSickOrOk(sqlite3 *db){
  u32 magic;
  magic = db->magic;
  if( magic!=SQLITE_MAGIC_SICK &&
      magic!=SQLITE_MAGIC_OPEN &&
      magic!=SQLITE_MAGIC_BUSY ){
    testcase( sqlite3GlobalConfig.xLog!=0 );
    logBadConnection("invalid");
    return 0;
  }else{
    return 1;
  }
}







|




|
|










|
|
|
|
|







33273
33274
33275
33276
33277
33278
33279
33280
33281
33282
33283
33284
33285
33286
33287
33288
33289
33290
33291
33292
33293
33294
33295
33296
33297
33298
33299
33300
33301
33302
33303
33304
33305
33306
33307
33308
**
** sqlite3SafetyCheckOk() requires that the db pointer be valid for
** use.  sqlite3SafetyCheckSickOrOk() allows a db pointer that failed to
** open properly and is not fit for general use but which can be
** used as an argument to sqlite3_errmsg() or sqlite3_close().
*/
SQLITE_PRIVATE int sqlite3SafetyCheckOk(sqlite3 *db){
  u8 eOpenState;
  if( db==0 ){
    logBadConnection("NULL");
    return 0;
  }
  eOpenState = db->eOpenState;
  if( eOpenState!=SQLITE_STATE_OPEN ){
    if( sqlite3SafetyCheckSickOrOk(db) ){
      testcase( sqlite3GlobalConfig.xLog!=0 );
      logBadConnection("unopened");
    }
    return 0;
  }else{
    return 1;
  }
}
SQLITE_PRIVATE int sqlite3SafetyCheckSickOrOk(sqlite3 *db){
  u8 eOpenState;
  eOpenState = db->eOpenState;
  if( eOpenState!=SQLITE_STATE_SICK &&
      eOpenState!=SQLITE_STATE_OPEN &&
      eOpenState!=SQLITE_STATE_BUSY ){
    testcase( sqlite3GlobalConfig.xLog!=0 );
    logBadConnection("invalid");
    return 0;
  }else{
    return 1;
  }
}
33873
33874
33875
33876
33877
33878
33879

33880
33881
33882
33883
33884
33885
33886
33887
33888
33889
33890
33891
33892
33893
33894
33895
33896
33897
33898
33899
33900
33901
33902
33903

33904
33905
33906
33907
33908
33909
33910
33911
33912
33913
33914
33915
33916
33917

33918
33919
33920
33921
33922
33923
33924
33925
33926
33927
33928
33929
33930
33931
33932
33933
33934
33935
33936
33937
33938
33939
33940
33941
33942
33943
33944
33945
33946
33947
33948
33949
33950

33951
33952
33953
33954
33955
33956
33957
33958
33959
33960
33961
33962
33963
33964
33965
33966
33967
33968
33969
33970
33971
33972
33973
33974
33975


33976
33977
33978
33979
33980
33981
33982
33983
33984
33985
33986
33987
33988
33989
33990
33991
33992
33993
33994
33995
33996
33997
33998
33999
34000
34001
34002
34003
34004
34005
34006
34007
34008
34009
34010
34011


34012
34013
34014
34015
34016
34017
34018
34019
34020
34021
34022
34023
34024
34025
34026
34027
34028
34029
34030
34031
34032
34033
34034
34035
34036
34037
34038
34039
34040
34041
34042
34043
34044
34045
    /*  14 */ "Yield"            OpHelp(""),
    /*  15 */ "MustBeInt"        OpHelp(""),
    /*  16 */ "Jump"             OpHelp(""),
    /*  17 */ "Once"             OpHelp(""),
    /*  18 */ "If"               OpHelp(""),
    /*  19 */ "Not"              OpHelp("r[P2]= !r[P1]"),
    /*  20 */ "IfNot"            OpHelp(""),

    /*  21 */ "IfNullRow"        OpHelp("if P1.nullRow then r[P3]=NULL, goto P2"),
    /*  22 */ "SeekLT"           OpHelp("key=r[P3@P4]"),
    /*  23 */ "SeekLE"           OpHelp("key=r[P3@P4]"),
    /*  24 */ "SeekGE"           OpHelp("key=r[P3@P4]"),
    /*  25 */ "SeekGT"           OpHelp("key=r[P3@P4]"),
    /*  26 */ "IfNotOpen"        OpHelp("if( !csr[P1] ) goto P2"),
    /*  27 */ "IfNoHope"         OpHelp("key=r[P3@P4]"),
    /*  28 */ "NoConflict"       OpHelp("key=r[P3@P4]"),
    /*  29 */ "NotFound"         OpHelp("key=r[P3@P4]"),
    /*  30 */ "Found"            OpHelp("key=r[P3@P4]"),
    /*  31 */ "SeekRowid"        OpHelp("intkey=r[P3]"),
    /*  32 */ "NotExists"        OpHelp("intkey=r[P3]"),
    /*  33 */ "Last"             OpHelp(""),
    /*  34 */ "IfSmaller"        OpHelp(""),
    /*  35 */ "SorterSort"       OpHelp(""),
    /*  36 */ "Sort"             OpHelp(""),
    /*  37 */ "Rewind"           OpHelp(""),
    /*  38 */ "IdxLE"            OpHelp("key=r[P3@P4]"),
    /*  39 */ "IdxGT"            OpHelp("key=r[P3@P4]"),
    /*  40 */ "IdxLT"            OpHelp("key=r[P3@P4]"),
    /*  41 */ "IdxGE"            OpHelp("key=r[P3@P4]"),
    /*  42 */ "RowSetRead"       OpHelp("r[P3]=rowset(P1)"),
    /*  43 */ "Or"               OpHelp("r[P3]=(r[P1] || r[P2])"),
    /*  44 */ "And"              OpHelp("r[P3]=(r[P1] && r[P2])"),

    /*  45 */ "RowSetTest"       OpHelp("if r[P3] in rowset(P1) goto P2"),
    /*  46 */ "Program"          OpHelp(""),
    /*  47 */ "FkIfZero"         OpHelp("if fkctr[P1]==0 goto P2"),
    /*  48 */ "IfPos"            OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"),
    /*  49 */ "IfNotZero"        OpHelp("if r[P1]!=0 then r[P1]--, goto P2"),
    /*  50 */ "IsNull"           OpHelp("if r[P1]==NULL goto P2"),
    /*  51 */ "NotNull"          OpHelp("if r[P1]!=NULL goto P2"),
    /*  52 */ "Ne"               OpHelp("IF r[P3]!=r[P1]"),
    /*  53 */ "Eq"               OpHelp("IF r[P3]==r[P1]"),
    /*  54 */ "Gt"               OpHelp("IF r[P3]>r[P1]"),
    /*  55 */ "Le"               OpHelp("IF r[P3]<=r[P1]"),
    /*  56 */ "Lt"               OpHelp("IF r[P3]<r[P1]"),
    /*  57 */ "Ge"               OpHelp("IF r[P3]>=r[P1]"),
    /*  58 */ "ElseEq"           OpHelp(""),

    /*  59 */ "DecrJumpZero"     OpHelp("if (--r[P1])==0 goto P2"),
    /*  60 */ "IncrVacuum"       OpHelp(""),
    /*  61 */ "VNext"            OpHelp(""),
    /*  62 */ "Init"             OpHelp("Start at P2"),
    /*  63 */ "PureFunc"         OpHelp("r[P3]=func(r[P2@NP])"),
    /*  64 */ "Function"         OpHelp("r[P3]=func(r[P2@NP])"),
    /*  65 */ "Return"           OpHelp(""),
    /*  66 */ "EndCoroutine"     OpHelp(""),
    /*  67 */ "HaltIfNull"       OpHelp("if r[P3]=null halt"),
    /*  68 */ "Halt"             OpHelp(""),
    /*  69 */ "Integer"          OpHelp("r[P2]=P1"),
    /*  70 */ "Int64"            OpHelp("r[P2]=P4"),
    /*  71 */ "String"           OpHelp("r[P2]='P4' (len=P1)"),
    /*  72 */ "Null"             OpHelp("r[P2..P3]=NULL"),
    /*  73 */ "SoftNull"         OpHelp("r[P1]=NULL"),
    /*  74 */ "Blob"             OpHelp("r[P2]=P4 (len=P1)"),
    /*  75 */ "Variable"         OpHelp("r[P2]=parameter(P1,P4)"),
    /*  76 */ "Move"             OpHelp("r[P2@P3]=r[P1@P3]"),
    /*  77 */ "Copy"             OpHelp("r[P2@P3+1]=r[P1@P3+1]"),
    /*  78 */ "SCopy"            OpHelp("r[P2]=r[P1]"),
    /*  79 */ "IntCopy"          OpHelp("r[P2]=r[P1]"),
    /*  80 */ "ChngCntRow"       OpHelp("output=r[P1]"),
    /*  81 */ "ResultRow"        OpHelp("output=r[P1@P2]"),
    /*  82 */ "CollSeq"          OpHelp(""),
    /*  83 */ "AddImm"           OpHelp("r[P1]=r[P1]+P2"),
    /*  84 */ "RealAffinity"     OpHelp(""),
    /*  85 */ "Cast"             OpHelp("affinity(r[P1])"),
    /*  86 */ "Permutation"      OpHelp(""),
    /*  87 */ "Compare"          OpHelp("r[P1@P3] <-> r[P2@P3]"),
    /*  88 */ "IsTrue"           OpHelp("r[P2] = coalesce(r[P1]==TRUE,P3) ^ P4"),
    /*  89 */ "ZeroOrNull"       OpHelp("r[P2] = 0 OR NULL"),
    /*  90 */ "Offset"           OpHelp("r[P3] = sqlite_offset(P1)"),
    /*  91 */ "Column"           OpHelp("r[P3]=PX"),

    /*  92 */ "Affinity"         OpHelp("affinity(r[P1@P2])"),
    /*  93 */ "MakeRecord"       OpHelp("r[P3]=mkrec(r[P1@P2])"),
    /*  94 */ "Count"            OpHelp("r[P2]=count()"),
    /*  95 */ "ReadCookie"       OpHelp(""),
    /*  96 */ "SetCookie"        OpHelp(""),
    /*  97 */ "ReopenIdx"        OpHelp("root=P2 iDb=P3"),
    /*  98 */ "OpenRead"         OpHelp("root=P2 iDb=P3"),
    /*  99 */ "OpenWrite"        OpHelp("root=P2 iDb=P3"),
    /* 100 */ "OpenDup"          OpHelp(""),
    /* 101 */ "OpenAutoindex"    OpHelp("nColumn=P2"),
    /* 102 */ "BitAnd"           OpHelp("r[P3]=r[P1]&r[P2]"),
    /* 103 */ "BitOr"            OpHelp("r[P3]=r[P1]|r[P2]"),
    /* 104 */ "ShiftLeft"        OpHelp("r[P3]=r[P2]<<r[P1]"),
    /* 105 */ "ShiftRight"       OpHelp("r[P3]=r[P2]>>r[P1]"),
    /* 106 */ "Add"              OpHelp("r[P3]=r[P1]+r[P2]"),
    /* 107 */ "Subtract"         OpHelp("r[P3]=r[P2]-r[P1]"),
    /* 108 */ "Multiply"         OpHelp("r[P3]=r[P1]*r[P2]"),
    /* 109 */ "Divide"           OpHelp("r[P3]=r[P2]/r[P1]"),
    /* 110 */ "Remainder"        OpHelp("r[P3]=r[P2]%r[P1]"),
    /* 111 */ "Concat"           OpHelp("r[P3]=r[P2]+r[P1]"),
    /* 112 */ "OpenEphemeral"    OpHelp("nColumn=P2"),
    /* 113 */ "BitNot"           OpHelp("r[P2]= ~r[P1]"),
    /* 114 */ "SorterOpen"       OpHelp(""),
    /* 115 */ "SequenceTest"     OpHelp("if( cursor[P1].ctr++ ) pc = P2"),
    /* 116 */ "String8"          OpHelp("r[P2]='P4'"),


    /* 117 */ "OpenPseudo"       OpHelp("P3 columns in r[P2]"),
    /* 118 */ "Close"            OpHelp(""),
    /* 119 */ "ColumnsUsed"      OpHelp(""),
    /* 120 */ "SeekScan"         OpHelp("Scan-ahead up to P1 rows"),
    /* 121 */ "SeekHit"          OpHelp("set P2<=seekHit<=P3"),
    /* 122 */ "Sequence"         OpHelp("r[P2]=cursor[P1].ctr++"),
    /* 123 */ "NewRowid"         OpHelp("r[P2]=rowid"),
    /* 124 */ "Insert"           OpHelp("intkey=r[P3] data=r[P2]"),
    /* 125 */ "RowCell"          OpHelp(""),
    /* 126 */ "Delete"           OpHelp(""),
    /* 127 */ "ResetCount"       OpHelp(""),
    /* 128 */ "SorterCompare"    OpHelp("if key(P1)!=trim(r[P3],P4) goto P2"),
    /* 129 */ "SorterData"       OpHelp("r[P2]=data"),
    /* 130 */ "RowData"          OpHelp("r[P2]=data"),
    /* 131 */ "Rowid"            OpHelp("r[P2]=rowid"),
    /* 132 */ "NullRow"          OpHelp(""),
    /* 133 */ "SeekEnd"          OpHelp(""),
    /* 134 */ "IdxInsert"        OpHelp("key=r[P2]"),
    /* 135 */ "SorterInsert"     OpHelp("key=r[P2]"),
    /* 136 */ "IdxDelete"        OpHelp("key=r[P2@P3]"),
    /* 137 */ "DeferredSeek"     OpHelp("Move P3 to P1.rowid if needed"),
    /* 138 */ "IdxRowid"         OpHelp("r[P2]=rowid"),
    /* 139 */ "FinishSeek"       OpHelp(""),
    /* 140 */ "Destroy"          OpHelp(""),
    /* 141 */ "Clear"            OpHelp(""),
    /* 142 */ "ResetSorter"      OpHelp(""),
    /* 143 */ "CreateBtree"      OpHelp("r[P2]=root iDb=P1 flags=P3"),
    /* 144 */ "SqlExec"          OpHelp(""),
    /* 145 */ "ParseSchema"      OpHelp(""),
    /* 146 */ "LoadAnalysis"     OpHelp(""),
    /* 147 */ "DropTable"        OpHelp(""),
    /* 148 */ "DropIndex"        OpHelp(""),
    /* 149 */ "DropTrigger"      OpHelp(""),
    /* 150 */ "IntegrityCk"      OpHelp(""),
    /* 151 */ "RowSetAdd"        OpHelp("rowset(P1)=r[P2]"),
    /* 152 */ "Real"             OpHelp("r[P2]=P4"),


    /* 153 */ "Param"            OpHelp(""),
    /* 154 */ "FkCounter"        OpHelp("fkctr[P1]+=P2"),
    /* 155 */ "MemMax"           OpHelp("r[P1]=max(r[P1],r[P2])"),
    /* 156 */ "OffsetLimit"      OpHelp("if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)"),
    /* 157 */ "AggInverse"       OpHelp("accum=r[P3] inverse(r[P2@P5])"),
    /* 158 */ "AggStep"          OpHelp("accum=r[P3] step(r[P2@P5])"),
    /* 159 */ "AggStep1"         OpHelp("accum=r[P3] step(r[P2@P5])"),
    /* 160 */ "AggValue"         OpHelp("r[P3]=value N=P2"),
    /* 161 */ "AggFinal"         OpHelp("accum=r[P1] N=P2"),
    /* 162 */ "Expire"           OpHelp(""),
    /* 163 */ "CursorLock"       OpHelp(""),
    /* 164 */ "CursorUnlock"     OpHelp(""),
    /* 165 */ "TableLock"        OpHelp("iDb=P1 root=P2 write=P3"),
    /* 166 */ "VBegin"           OpHelp(""),
    /* 167 */ "VCreate"          OpHelp(""),
    /* 168 */ "VDestroy"         OpHelp(""),
    /* 169 */ "VOpen"            OpHelp(""),
    /* 170 */ "VColumn"          OpHelp("r[P3]=vcolumn(P2)"),
    /* 171 */ "VRename"          OpHelp(""),
    /* 172 */ "Pagecount"        OpHelp(""),
    /* 173 */ "MaxPgcnt"         OpHelp(""),
    /* 174 */ "Trace"            OpHelp(""),
    /* 175 */ "CursorHint"       OpHelp(""),
    /* 176 */ "ReleaseReg"       OpHelp("release r[P1@P2] mask P3"),
    /* 177 */ "Noop"             OpHelp(""),
    /* 178 */ "Explain"          OpHelp(""),
    /* 179 */ "Abortable"        OpHelp(""),
  };
  return azName[i];
}
#endif

/************** End of opcodes.c *********************************************/
/************** Begin file os_unix.c *****************************************/







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


>
|
|
|
|
<









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










|

|
|

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

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







33913
33914
33915
33916
33917
33918
33919
33920
33921
33922
33923
33924
33925
33926
33927
33928
33929
33930
33931
33932
33933
33934
33935
33936
33937
33938
33939
33940
33941

33942
33943
33944
33945
33946
33947
33948

33949
33950
33951
33952
33953
33954
33955
33956
33957
33958
33959
33960
33961
33962
33963
33964
33965
33966
33967
33968
33969
33970
33971
33972
33973
33974
33975
33976
33977
33978
33979
33980
33981
33982
33983
33984
33985
33986
33987
33988
33989
33990
33991
33992
33993
33994
33995
33996
33997
33998
33999
34000


34001
34002
34003
34004
34005
34006
34007
34008
34009
34010
34011
34012
34013
34014
34015
34016
34017
34018
34019
34020
34021
34022
34023
34024
34025
34026
34027
34028
34029
34030
34031
34032
34033
34034
34035
34036
34037
34038
34039
34040
34041
34042
34043
34044
34045
34046
34047
34048
34049
34050


34051
34052
34053
34054
34055
34056
34057
34058
34059
34060
34061
34062
34063
34064
34065
34066
34067
34068
34069
34070
34071
34072
34073
34074
34075
34076
34077
34078
34079
34080
34081
34082
34083
34084
34085
34086
34087
    /*  14 */ "Yield"            OpHelp(""),
    /*  15 */ "MustBeInt"        OpHelp(""),
    /*  16 */ "Jump"             OpHelp(""),
    /*  17 */ "Once"             OpHelp(""),
    /*  18 */ "If"               OpHelp(""),
    /*  19 */ "Not"              OpHelp("r[P2]= !r[P1]"),
    /*  20 */ "IfNot"            OpHelp(""),
    /*  21 */ "IsNullOrType"     OpHelp("if typeof(r[P1]) IN (P3,5) goto P2"),
    /*  22 */ "IfNullRow"        OpHelp("if P1.nullRow then r[P3]=NULL, goto P2"),
    /*  23 */ "SeekLT"           OpHelp("key=r[P3@P4]"),
    /*  24 */ "SeekLE"           OpHelp("key=r[P3@P4]"),
    /*  25 */ "SeekGE"           OpHelp("key=r[P3@P4]"),
    /*  26 */ "SeekGT"           OpHelp("key=r[P3@P4]"),
    /*  27 */ "IfNotOpen"        OpHelp("if( !csr[P1] ) goto P2"),
    /*  28 */ "IfNoHope"         OpHelp("key=r[P3@P4]"),
    /*  29 */ "NoConflict"       OpHelp("key=r[P3@P4]"),
    /*  30 */ "NotFound"         OpHelp("key=r[P3@P4]"),
    /*  31 */ "Found"            OpHelp("key=r[P3@P4]"),
    /*  32 */ "SeekRowid"        OpHelp("intkey=r[P3]"),
    /*  33 */ "NotExists"        OpHelp("intkey=r[P3]"),
    /*  34 */ "Last"             OpHelp(""),
    /*  35 */ "IfSmaller"        OpHelp(""),
    /*  36 */ "SorterSort"       OpHelp(""),
    /*  37 */ "Sort"             OpHelp(""),
    /*  38 */ "Rewind"           OpHelp(""),
    /*  39 */ "IdxLE"            OpHelp("key=r[P3@P4]"),
    /*  40 */ "IdxGT"            OpHelp("key=r[P3@P4]"),
    /*  41 */ "IdxLT"            OpHelp("key=r[P3@P4]"),
    /*  42 */ "IdxGE"            OpHelp("key=r[P3@P4]"),

    /*  43 */ "Or"               OpHelp("r[P3]=(r[P1] || r[P2])"),
    /*  44 */ "And"              OpHelp("r[P3]=(r[P1] && r[P2])"),
    /*  45 */ "RowSetRead"       OpHelp("r[P3]=rowset(P1)"),
    /*  46 */ "RowSetTest"       OpHelp("if r[P3] in rowset(P1) goto P2"),
    /*  47 */ "Program"          OpHelp(""),
    /*  48 */ "FkIfZero"         OpHelp("if fkctr[P1]==0 goto P2"),
    /*  49 */ "IfPos"            OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"),

    /*  50 */ "IsNull"           OpHelp("if r[P1]==NULL goto P2"),
    /*  51 */ "NotNull"          OpHelp("if r[P1]!=NULL goto P2"),
    /*  52 */ "Ne"               OpHelp("IF r[P3]!=r[P1]"),
    /*  53 */ "Eq"               OpHelp("IF r[P3]==r[P1]"),
    /*  54 */ "Gt"               OpHelp("IF r[P3]>r[P1]"),
    /*  55 */ "Le"               OpHelp("IF r[P3]<=r[P1]"),
    /*  56 */ "Lt"               OpHelp("IF r[P3]<r[P1]"),
    /*  57 */ "Ge"               OpHelp("IF r[P3]>=r[P1]"),
    /*  58 */ "ElseEq"           OpHelp(""),
    /*  59 */ "IfNotZero"        OpHelp("if r[P1]!=0 then r[P1]--, goto P2"),
    /*  60 */ "DecrJumpZero"     OpHelp("if (--r[P1])==0 goto P2"),
    /*  61 */ "IncrVacuum"       OpHelp(""),
    /*  62 */ "VNext"            OpHelp(""),
    /*  63 */ "Init"             OpHelp("Start at P2"),
    /*  64 */ "PureFunc"         OpHelp("r[P3]=func(r[P2@NP])"),
    /*  65 */ "Function"         OpHelp("r[P3]=func(r[P2@NP])"),
    /*  66 */ "Return"           OpHelp(""),
    /*  67 */ "EndCoroutine"     OpHelp(""),
    /*  68 */ "HaltIfNull"       OpHelp("if r[P3]=null halt"),
    /*  69 */ "Halt"             OpHelp(""),
    /*  70 */ "Integer"          OpHelp("r[P2]=P1"),
    /*  71 */ "Int64"            OpHelp("r[P2]=P4"),
    /*  72 */ "String"           OpHelp("r[P2]='P4' (len=P1)"),
    /*  73 */ "Null"             OpHelp("r[P2..P3]=NULL"),
    /*  74 */ "SoftNull"         OpHelp("r[P1]=NULL"),
    /*  75 */ "Blob"             OpHelp("r[P2]=P4 (len=P1)"),
    /*  76 */ "Variable"         OpHelp("r[P2]=parameter(P1,P4)"),
    /*  77 */ "Move"             OpHelp("r[P2@P3]=r[P1@P3]"),
    /*  78 */ "Copy"             OpHelp("r[P2@P3+1]=r[P1@P3+1]"),
    /*  79 */ "SCopy"            OpHelp("r[P2]=r[P1]"),
    /*  80 */ "IntCopy"          OpHelp("r[P2]=r[P1]"),
    /*  81 */ "ChngCntRow"       OpHelp("output=r[P1]"),
    /*  82 */ "ResultRow"        OpHelp("output=r[P1@P2]"),
    /*  83 */ "CollSeq"          OpHelp(""),
    /*  84 */ "AddImm"           OpHelp("r[P1]=r[P1]+P2"),
    /*  85 */ "RealAffinity"     OpHelp(""),
    /*  86 */ "Cast"             OpHelp("affinity(r[P1])"),
    /*  87 */ "Permutation"      OpHelp(""),
    /*  88 */ "Compare"          OpHelp("r[P1@P3] <-> r[P2@P3]"),
    /*  89 */ "IsTrue"           OpHelp("r[P2] = coalesce(r[P1]==TRUE,P3) ^ P4"),
    /*  90 */ "ZeroOrNull"       OpHelp("r[P2] = 0 OR NULL"),
    /*  91 */ "Offset"           OpHelp("r[P3] = sqlite_offset(P1)"),
    /*  92 */ "Column"           OpHelp("r[P3]=PX"),
    /*  93 */ "TypeCheck"        OpHelp("typecheck(r[P1@P2])"),
    /*  94 */ "Affinity"         OpHelp("affinity(r[P1@P2])"),
    /*  95 */ "MakeRecord"       OpHelp("r[P3]=mkrec(r[P1@P2])"),
    /*  96 */ "Count"            OpHelp("r[P2]=count()"),
    /*  97 */ "ReadCookie"       OpHelp(""),
    /*  98 */ "SetCookie"        OpHelp(""),
    /*  99 */ "ReopenIdx"        OpHelp("root=P2 iDb=P3"),
    /* 100 */ "OpenRead"         OpHelp("root=P2 iDb=P3"),
    /* 101 */ "OpenWrite"        OpHelp("root=P2 iDb=P3"),


    /* 102 */ "BitAnd"           OpHelp("r[P3]=r[P1]&r[P2]"),
    /* 103 */ "BitOr"            OpHelp("r[P3]=r[P1]|r[P2]"),
    /* 104 */ "ShiftLeft"        OpHelp("r[P3]=r[P2]<<r[P1]"),
    /* 105 */ "ShiftRight"       OpHelp("r[P3]=r[P2]>>r[P1]"),
    /* 106 */ "Add"              OpHelp("r[P3]=r[P1]+r[P2]"),
    /* 107 */ "Subtract"         OpHelp("r[P3]=r[P2]-r[P1]"),
    /* 108 */ "Multiply"         OpHelp("r[P3]=r[P1]*r[P2]"),
    /* 109 */ "Divide"           OpHelp("r[P3]=r[P2]/r[P1]"),
    /* 110 */ "Remainder"        OpHelp("r[P3]=r[P2]%r[P1]"),
    /* 111 */ "Concat"           OpHelp("r[P3]=r[P2]+r[P1]"),
    /* 112 */ "OpenDup"          OpHelp(""),
    /* 113 */ "BitNot"           OpHelp("r[P2]= ~r[P1]"),
    /* 114 */ "OpenAutoindex"    OpHelp("nColumn=P2"),
    /* 115 */ "OpenEphemeral"    OpHelp("nColumn=P2"),
    /* 116 */ "String8"          OpHelp("r[P2]='P4'"),
    /* 117 */ "SorterOpen"       OpHelp(""),
    /* 118 */ "SequenceTest"     OpHelp("if( cursor[P1].ctr++ ) pc = P2"),
    /* 119 */ "OpenPseudo"       OpHelp("P3 columns in r[P2]"),
    /* 120 */ "Close"            OpHelp(""),
    /* 121 */ "ColumnsUsed"      OpHelp(""),
    /* 122 */ "SeekScan"         OpHelp("Scan-ahead up to P1 rows"),
    /* 123 */ "SeekHit"          OpHelp("set P2<=seekHit<=P3"),
    /* 124 */ "Sequence"         OpHelp("r[P2]=cursor[P1].ctr++"),
    /* 125 */ "NewRowid"         OpHelp("r[P2]=rowid"),
    /* 126 */ "Insert"           OpHelp("intkey=r[P3] data=r[P2]"),
    /* 127 */ "RowCell"          OpHelp(""),
    /* 128 */ "Delete"           OpHelp(""),
    /* 129 */ "ResetCount"       OpHelp(""),
    /* 130 */ "SorterCompare"    OpHelp("if key(P1)!=trim(r[P3],P4) goto P2"),
    /* 131 */ "SorterData"       OpHelp("r[P2]=data"),
    /* 132 */ "RowData"          OpHelp("r[P2]=data"),
    /* 133 */ "Rowid"            OpHelp("r[P2]=rowid"),
    /* 134 */ "NullRow"          OpHelp(""),
    /* 135 */ "SeekEnd"          OpHelp(""),
    /* 136 */ "IdxInsert"        OpHelp("key=r[P2]"),
    /* 137 */ "SorterInsert"     OpHelp("key=r[P2]"),
    /* 138 */ "IdxDelete"        OpHelp("key=r[P2@P3]"),
    /* 139 */ "DeferredSeek"     OpHelp("Move P3 to P1.rowid if needed"),
    /* 140 */ "IdxRowid"         OpHelp("r[P2]=rowid"),
    /* 141 */ "FinishSeek"       OpHelp(""),
    /* 142 */ "Destroy"          OpHelp(""),
    /* 143 */ "Clear"            OpHelp(""),
    /* 144 */ "ResetSorter"      OpHelp(""),
    /* 145 */ "CreateBtree"      OpHelp("r[P2]=root iDb=P1 flags=P3"),
    /* 146 */ "SqlExec"          OpHelp(""),
    /* 147 */ "ParseSchema"      OpHelp(""),
    /* 148 */ "LoadAnalysis"     OpHelp(""),
    /* 149 */ "DropTable"        OpHelp(""),
    /* 150 */ "DropIndex"        OpHelp(""),
    /* 151 */ "DropTrigger"      OpHelp(""),


    /* 152 */ "Real"             OpHelp("r[P2]=P4"),
    /* 153 */ "IntegrityCk"      OpHelp(""),
    /* 154 */ "RowSetAdd"        OpHelp("rowset(P1)=r[P2]"),
    /* 155 */ "Param"            OpHelp(""),
    /* 156 */ "FkCounter"        OpHelp("fkctr[P1]+=P2"),
    /* 157 */ "MemMax"           OpHelp("r[P1]=max(r[P1],r[P2])"),
    /* 158 */ "OffsetLimit"      OpHelp("if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)"),
    /* 159 */ "AggInverse"       OpHelp("accum=r[P3] inverse(r[P2@P5])"),
    /* 160 */ "AggStep"          OpHelp("accum=r[P3] step(r[P2@P5])"),
    /* 161 */ "AggStep1"         OpHelp("accum=r[P3] step(r[P2@P5])"),
    /* 162 */ "AggValue"         OpHelp("r[P3]=value N=P2"),
    /* 163 */ "AggFinal"         OpHelp("accum=r[P1] N=P2"),
    /* 164 */ "Expire"           OpHelp(""),
    /* 165 */ "CursorLock"       OpHelp(""),
    /* 166 */ "CursorUnlock"     OpHelp(""),
    /* 167 */ "TableLock"        OpHelp("iDb=P1 root=P2 write=P3"),
    /* 168 */ "VBegin"           OpHelp(""),
    /* 169 */ "VCreate"          OpHelp(""),
    /* 170 */ "VDestroy"         OpHelp(""),
    /* 171 */ "VOpen"            OpHelp(""),
    /* 172 */ "VColumn"          OpHelp("r[P3]=vcolumn(P2)"),
    /* 173 */ "VRename"          OpHelp(""),
    /* 174 */ "Pagecount"        OpHelp(""),
    /* 175 */ "MaxPgcnt"         OpHelp(""),
    /* 176 */ "Trace"            OpHelp(""),
    /* 177 */ "CursorHint"       OpHelp(""),
    /* 178 */ "ReleaseReg"       OpHelp("release r[P1@P2] mask P3"),
    /* 179 */ "Noop"             OpHelp(""),
    /* 180 */ "Explain"          OpHelp(""),
    /* 181 */ "Abortable"        OpHelp(""),
  };
  return azName[i];
}
#endif

/************** End of opcodes.c *********************************************/
/************** Begin file os_unix.c *****************************************/
48815
48816
48817
48818
48819
48820
48821
48822
48823
48824
48825
48826
48827
48828
48829
){
  MemFile *pFile = (MemFile*)pFd;
  MemStore *p = 0;
  int szName;
  if( (flags & SQLITE_OPEN_MAIN_DB)==0 ){
    return ORIGVFS(pVfs)->xOpen(ORIGVFS(pVfs), zName, pFd, flags, pOutFlags);
  }
  memset(pFile, 0, sizeof(*p));
  szName = sqlite3Strlen30(zName);
  if( szName>1 && zName[0]=='/' ){
    int i;
#ifndef SQLITE_MUTEX_OMIT
    sqlite3_mutex *pVfsMutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1);
#endif
    sqlite3_mutex_enter(pVfsMutex);







|







48857
48858
48859
48860
48861
48862
48863
48864
48865
48866
48867
48868
48869
48870
48871
){
  MemFile *pFile = (MemFile*)pFd;
  MemStore *p = 0;
  int szName;
  if( (flags & SQLITE_OPEN_MAIN_DB)==0 ){
    return ORIGVFS(pVfs)->xOpen(ORIGVFS(pVfs), zName, pFd, flags, pOutFlags);
  }
  memset(pFile, 0, sizeof(*pFile));
  szName = sqlite3Strlen30(zName);
  if( szName>1 && zName[0]=='/' ){
    int i;
#ifndef SQLITE_MUTEX_OMIT
    sqlite3_mutex *pVfsMutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1);
#endif
    sqlite3_mutex_enter(pVfsMutex);
49540
49541
49542
49543
49544
49545
49546
49547
49548
49549
49550
49551
49552
49553
49554
  if( pBitvec==0 || pV==0 || pTmpSpace==0  ) goto bitvec_end;

  /* NULL pBitvec tests */
  sqlite3BitvecSet(0, 1);
  sqlite3BitvecClear(0, 1, pTmpSpace);

  /* Run the program */
  pc = 0;
  while( (op = aOp[pc])!=0 ){
    switch( op ){
      case 1:
      case 2:
      case 5: {
        nx = 4;
        i = aOp[pc+2] - 1;







|







49582
49583
49584
49585
49586
49587
49588
49589
49590
49591
49592
49593
49594
49595
49596
  if( pBitvec==0 || pV==0 || pTmpSpace==0  ) goto bitvec_end;

  /* NULL pBitvec tests */
  sqlite3BitvecSet(0, 1);
  sqlite3BitvecClear(0, 1, pTmpSpace);

  /* Run the program */
  pc = i = 0;
  while( (op = aOp[pc])!=0 ){
    switch( op ){
      case 1:
      case 2:
      case 5: {
        nx = 4;
        i = aOp[pc+2] - 1;
49844
49845
49846
49847
49848
49849
49850

49851
49852
49853
49854
49855


49856
49857
49858
49859
49860
49861
49862
*/
static int numberOfCachePages(PCache *p){
  if( p->szCache>=0 ){
    /* IMPLEMENTATION-OF: R-42059-47211 If the argument N is positive then the
    ** suggested cache size is set to N. */
    return p->szCache;
  }else{

    /* IMPLEMANTATION-OF: R-59858-46238 If the argument N is negative, then the
    ** number of cache pages is adjusted to be a number of pages that would
    ** use approximately abs(N*1024) bytes of memory based on the current
    ** page size. */
    return (int)((-1024*(i64)p->szCache)/(p->szPage+p->szExtra));


  }
}

/*************************************************** General Interfaces ******
**
** Initialize and shutdown the page cache subsystem. Neither of these
** functions are threadsafe.







>




|
>
>







49886
49887
49888
49889
49890
49891
49892
49893
49894
49895
49896
49897
49898
49899
49900
49901
49902
49903
49904
49905
49906
49907
*/
static int numberOfCachePages(PCache *p){
  if( p->szCache>=0 ){
    /* IMPLEMENTATION-OF: R-42059-47211 If the argument N is positive then the
    ** suggested cache size is set to N. */
    return p->szCache;
  }else{
    i64 n;
    /* IMPLEMANTATION-OF: R-59858-46238 If the argument N is negative, then the
    ** number of cache pages is adjusted to be a number of pages that would
    ** use approximately abs(N*1024) bytes of memory based on the current
    ** page size. */
    n = ((-1024*(i64)p->szCache)/(p->szPage+p->szExtra));
    if( n>1000000000 ) n = 1000000000;
    return (int)n;
  }
}

/*************************************************** General Interfaces ******
**
** Initialize and shutdown the page cache subsystem. Neither of these
** functions are threadsafe.
51303
51304
51305
51306
51307
51308
51309


51310
51311
51312




51313
51314
51315
51316
51317
51318
51319
51320
51321
51322
51323
51324
51325
51326
51327
51328
51329
51330
51331
51332
51333
51334
51335
51336
51337
51338
/*
** Implementation of the sqlite3_pcache.xCachesize method.
**
** Configure the cache_size limit for a cache.
*/
static void pcache1Cachesize(sqlite3_pcache *p, int nMax){
  PCache1 *pCache = (PCache1 *)p;


  if( pCache->bPurgeable ){
    PGroup *pGroup = pCache->pGroup;
    pcache1EnterMutex(pGroup);




    pGroup->nMaxPage += (nMax - pCache->nMax);
    pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage;
    pCache->nMax = nMax;
    pCache->n90pct = pCache->nMax*9/10;
    pcache1EnforceMaxPage(pCache);
    pcache1LeaveMutex(pGroup);
  }
}

/*
** Implementation of the sqlite3_pcache.xShrink method.
**
** Free up as much memory as possible.
*/
static void pcache1Shrink(sqlite3_pcache *p){
  PCache1 *pCache = (PCache1*)p;
  if( pCache->bPurgeable ){
    PGroup *pGroup = pCache->pGroup;
    int savedMaxPage;
    pcache1EnterMutex(pGroup);
    savedMaxPage = pGroup->nMaxPage;
    pGroup->nMaxPage = 0;
    pcache1EnforceMaxPage(pCache);
    pGroup->nMaxPage = savedMaxPage;
    pcache1LeaveMutex(pGroup);
  }







>
>



>
>
>
>
|

|















|







51348
51349
51350
51351
51352
51353
51354
51355
51356
51357
51358
51359
51360
51361
51362
51363
51364
51365
51366
51367
51368
51369
51370
51371
51372
51373
51374
51375
51376
51377
51378
51379
51380
51381
51382
51383
51384
51385
51386
51387
51388
51389
/*
** Implementation of the sqlite3_pcache.xCachesize method.
**
** Configure the cache_size limit for a cache.
*/
static void pcache1Cachesize(sqlite3_pcache *p, int nMax){
  PCache1 *pCache = (PCache1 *)p;
  u32 n;
  assert( nMax>=0 );
  if( pCache->bPurgeable ){
    PGroup *pGroup = pCache->pGroup;
    pcache1EnterMutex(pGroup);
    n = (u32)nMax;
    if( n > 0x7fff0000 - pGroup->nMaxPage + pCache->nMax ){
      n = 0x7fff0000 - pGroup->nMaxPage + pCache->nMax;
    }
    pGroup->nMaxPage += (n - pCache->nMax);
    pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage;
    pCache->nMax = n;
    pCache->n90pct = pCache->nMax*9/10;
    pcache1EnforceMaxPage(pCache);
    pcache1LeaveMutex(pGroup);
  }
}

/*
** Implementation of the sqlite3_pcache.xShrink method.
**
** Free up as much memory as possible.
*/
static void pcache1Shrink(sqlite3_pcache *p){
  PCache1 *pCache = (PCache1*)p;
  if( pCache->bPurgeable ){
    PGroup *pGroup = pCache->pGroup;
    unsigned int savedMaxPage;
    pcache1EnterMutex(pGroup);
    savedMaxPage = pGroup->nMaxPage;
    pGroup->nMaxPage = 0;
    pcache1EnforceMaxPage(pCache);
    pGroup->nMaxPage = savedMaxPage;
    pcache1LeaveMutex(pGroup);
  }
53110
53111
53112
53113
53114
53115
53116
53117
53118

53119
53120
53121
53122
53123
53124
53125
  ** End of the routinely-changing class members
  ***************************************************************************/

  u16 nExtra;                 /* Add this many bytes to each in-memory page */
  i16 nReserve;               /* Number of unused bytes at end of each page */
  u32 vfsFlags;               /* Flags for sqlite3_vfs.xOpen() */
  u32 sectorSize;             /* Assumed sector size during rollback */
  int pageSize;               /* Number of bytes in a page */
  Pgno mxPgno;                /* Maximum allowed size of the database */

  i64 journalSizeLimit;       /* Size limit for persistent journal files */
  char *zFilename;            /* Name of the database file */
  char *zJournal;             /* Name of the journal file */
  int (*xBusyHandler)(void*); /* Function to call when busy */
  void *pBusyHandlerArg;      /* Context argument for xBusyHandler */
  int aStat[4];               /* Total cache hits, misses, writes, spills */
#ifdef SQLITE_TEST







<

>







53161
53162
53163
53164
53165
53166
53167

53168
53169
53170
53171
53172
53173
53174
53175
53176
  ** End of the routinely-changing class members
  ***************************************************************************/

  u16 nExtra;                 /* Add this many bytes to each in-memory page */
  i16 nReserve;               /* Number of unused bytes at end of each page */
  u32 vfsFlags;               /* Flags for sqlite3_vfs.xOpen() */
  u32 sectorSize;             /* Assumed sector size during rollback */

  Pgno mxPgno;                /* Maximum allowed size of the database */
  i64 pageSize;               /* Number of bytes in a page */
  i64 journalSizeLimit;       /* Size limit for persistent journal files */
  char *zFilename;            /* Name of the database file */
  char *zJournal;             /* Name of the journal file */
  int (*xBusyHandler)(void*); /* Function to call when busy */
  void *pBusyHandlerArg;      /* Context argument for xBusyHandler */
  int aStat[4];               /* Total cache hits, misses, writes, spills */
#ifdef SQLITE_TEST
55455
55456
55457
55458
55459
55460
55461

55462
55463
55464
55465
55466
55467
55468
**
** This is an unconditional update.  See also the pager_incr_changecounter()
** routine which only updates the change-counter if the update is actually
** needed, as determined by the pPager->changeCountDone state variable.
*/
static void pager_write_changecounter(PgHdr *pPg){
  u32 change_counter;


  /* Increment the value just read and write it back to byte 24. */
  change_counter = sqlite3Get4byte((u8*)pPg->pPager->dbFileVers)+1;
  put32bits(((char*)pPg->pData)+24, change_counter);

  /* Also store the SQLite version number in bytes 96..99 and in
  ** bytes 92..95 store the change counter for which the version number







>







55506
55507
55508
55509
55510
55511
55512
55513
55514
55515
55516
55517
55518
55519
55520
**
** This is an unconditional update.  See also the pager_incr_changecounter()
** routine which only updates the change-counter if the update is actually
** needed, as determined by the pPager->changeCountDone state variable.
*/
static void pager_write_changecounter(PgHdr *pPg){
  u32 change_counter;
  if( NEVER(pPg==0) ) return;

  /* Increment the value just read and write it back to byte 24. */
  change_counter = sqlite3Get4byte((u8*)pPg->pPager->dbFileVers)+1;
  put32bits(((char*)pPg->pData)+24, change_counter);

  /* Also store the SQLite version number in bytes 96..99 and in
  ** bytes 92..95 store the change counter for which the version number
57289
57290
57291
57292
57293
57294
57295

57296
57297
57298
57299
57300
57301
57302
    sqlite3FileSuffix3(zFilename, pPager->zWal);
    pPtr = (u8*)(pPager->zWal + sqlite3Strlen30(pPager->zWal)+1);
#endif
  }else{
    pPager->zWal = 0;
  }
#endif


  if( nPathname ) sqlite3DbFree(0, zPathname);
  pPager->pVfs = pVfs;
  pPager->vfsFlags = vfsFlags;

  /* Open the pager file.
  */







>







57341
57342
57343
57344
57345
57346
57347
57348
57349
57350
57351
57352
57353
57354
57355
    sqlite3FileSuffix3(zFilename, pPager->zWal);
    pPtr = (u8*)(pPager->zWal + sqlite3Strlen30(pPager->zWal)+1);
#endif
  }else{
    pPager->zWal = 0;
  }
#endif
  (void)pPtr;  /* Suppress warning about unused pPtr value */

  if( nPathname ) sqlite3DbFree(0, zPathname);
  pPager->pVfs = pVfs;
  pPager->vfsFlags = vfsFlags;

  /* Open the pager file.
  */
59168
59169
59170
59171
59172
59173
59174
59175
59176
59177
59178
59179
59180
59181
59182
59183
#endif

/*
** Return the approximate number of bytes of memory currently
** used by the pager and its associated cache.
*/
SQLITE_PRIVATE int sqlite3PagerMemUsed(Pager *pPager){
  int perPageSize = pPager->pageSize + pPager->nExtra + sizeof(PgHdr)
                                     + 5*sizeof(void*);
  return perPageSize*sqlite3PcachePagecount(pPager->pPCache)
           + sqlite3MallocSize(pPager)
           + pPager->pageSize;
}

/*
** Return the number of references to the specified page.







|
|







59221
59222
59223
59224
59225
59226
59227
59228
59229
59230
59231
59232
59233
59234
59235
59236
#endif

/*
** Return the approximate number of bytes of memory currently
** used by the pager and its associated cache.
*/
SQLITE_PRIVATE int sqlite3PagerMemUsed(Pager *pPager){
  int perPageSize = pPager->pageSize + pPager->nExtra
    + (int)(sizeof(PgHdr) + 5*sizeof(void*));
  return perPageSize*sqlite3PcachePagecount(pPager->pPCache)
           + sqlite3MallocSize(pPager)
           + pPager->pageSize;
}

/*
** Return the number of references to the specified page.
59363
59364
59365
59366
59367
59368
59369
59370
59371

59372
59373
59374
59375
59376
59377
59378
59379
59380
59381
59382
59383
59384
    */
    nNew = iSavepoint + (( op==SAVEPOINT_RELEASE ) ? 0 : 1);
    for(ii=nNew; ii<pPager->nSavepoint; ii++){
      sqlite3BitvecDestroy(pPager->aSavepoint[ii].pInSavepoint);
    }
    pPager->nSavepoint = nNew;

    /* If this is a release of the outermost savepoint, truncate
    ** the sub-journal to zero bytes in size. */

    if( op==SAVEPOINT_RELEASE ){
      PagerSavepoint *pRel = &pPager->aSavepoint[nNew];
      if( pRel->bTruncateOnRelease && isOpen(pPager->sjfd) ){
        /* Only truncate if it is an in-memory sub-journal. */
        if( sqlite3JournalIsInMemory(pPager->sjfd) ){
          i64 sz = (pPager->pageSize+4)*pRel->iSubRec;
          rc = sqlite3OsTruncate(pPager->sjfd, sz);
          assert( rc==SQLITE_OK );
        }
        pPager->nSubRec = pRel->iSubRec;
      }
    }
    /* Else this is a rollback operation, playback the specified savepoint.







<
|
>





|







59416
59417
59418
59419
59420
59421
59422

59423
59424
59425
59426
59427
59428
59429
59430
59431
59432
59433
59434
59435
59436
59437
    */
    nNew = iSavepoint + (( op==SAVEPOINT_RELEASE ) ? 0 : 1);
    for(ii=nNew; ii<pPager->nSavepoint; ii++){
      sqlite3BitvecDestroy(pPager->aSavepoint[ii].pInSavepoint);
    }
    pPager->nSavepoint = nNew;


    /* Truncate the sub-journal so that it only includes the parts
    ** that are still in use. */
    if( op==SAVEPOINT_RELEASE ){
      PagerSavepoint *pRel = &pPager->aSavepoint[nNew];
      if( pRel->bTruncateOnRelease && isOpen(pPager->sjfd) ){
        /* Only truncate if it is an in-memory sub-journal. */
        if( sqlite3JournalIsInMemory(pPager->sjfd) ){
          i64 sz = (pPager->pageSize+4)*(i64)pRel->iSubRec;
          rc = sqlite3OsTruncate(pPager->sjfd, sz);
          assert( rc==SQLITE_OK );
        }
        pPager->nSubRec = pRel->iSubRec;
      }
    }
    /* Else this is a rollback operation, playback the specified savepoint.
68431
68432
68433
68434
68435
68436
68437
68438
68439
68440
68441
68442
68443
68444
68445
68446
68447
68448
68449
68450
68451
68452
68453
68454
68455
68456
68457
** is returned if we run out of memory.
*/
static int lockBtree(BtShared *pBt){
  int rc;              /* Result code from subfunctions */
  MemPage *pPage1;     /* Page 1 of the database file */
  u32 nPage;           /* Number of pages in the database */
  u32 nPageFile = 0;   /* Number of pages in the database file */
  u32 nPageHeader;     /* Number of pages in the database according to hdr */

  assert( sqlite3_mutex_held(pBt->mutex) );
  assert( pBt->pPage1==0 );
  rc = sqlite3PagerSharedLock(pBt->pPager);
  if( rc!=SQLITE_OK ) return rc;
  rc = btreeGetPage(pBt, 1, &pPage1, 0);
  if( rc!=SQLITE_OK ) return rc;

  /* Do some checking to help insure the file we opened really is
  ** a valid database file.
  */
  nPage = nPageHeader = get4byte(28+(u8*)pPage1->aData);
  sqlite3PagerPagecount(pBt->pPager, (int*)&nPageFile);
  if( nPage==0 || memcmp(24+(u8*)pPage1->aData, 92+(u8*)pPage1->aData,4)!=0 ){
    nPage = nPageFile;
  }
  if( (pBt->db->flags & SQLITE_ResetDatabase)!=0 ){
    nPage = 0;
  }







<











|







68484
68485
68486
68487
68488
68489
68490

68491
68492
68493
68494
68495
68496
68497
68498
68499
68500
68501
68502
68503
68504
68505
68506
68507
68508
68509
** is returned if we run out of memory.
*/
static int lockBtree(BtShared *pBt){
  int rc;              /* Result code from subfunctions */
  MemPage *pPage1;     /* Page 1 of the database file */
  u32 nPage;           /* Number of pages in the database */
  u32 nPageFile = 0;   /* Number of pages in the database file */


  assert( sqlite3_mutex_held(pBt->mutex) );
  assert( pBt->pPage1==0 );
  rc = sqlite3PagerSharedLock(pBt->pPager);
  if( rc!=SQLITE_OK ) return rc;
  rc = btreeGetPage(pBt, 1, &pPage1, 0);
  if( rc!=SQLITE_OK ) return rc;

  /* Do some checking to help insure the file we opened really is
  ** a valid database file.
  */
  nPage = get4byte(28+(u8*)pPage1->aData);
  sqlite3PagerPagecount(pBt->pPager, (int*)&nPageFile);
  if( nPage==0 || memcmp(24+(u8*)pPage1->aData, 92+(u8*)pPage1->aData,4)!=0 ){
    nPage = nPageFile;
  }
  if( (pBt->db->flags & SQLITE_ResetDatabase)!=0 ){
    nPage = 0;
  }
68478
68479
68480
68481
68482
68483
68484
68485
68486
68487
68488
68489
68490
68491
68492
    if( page1[18]>2 ){
      pBt->btsFlags |= BTS_READ_ONLY;
    }
    if( page1[19]>2 ){
      goto page1_init_failed;
    }

    /* If the write version is set to 2, this database should be accessed
    ** in WAL mode. If the log is not already open, open it now. Then
    ** return SQLITE_OK and return without populating BtShared.pPage1.
    ** The caller detects this and calls this function again. This is
    ** required as the version of page 1 currently in the page1 buffer
    ** may not be the latest version - there may be a newer one in the log
    ** file.
    */







|







68530
68531
68532
68533
68534
68535
68536
68537
68538
68539
68540
68541
68542
68543
68544
    if( page1[18]>2 ){
      pBt->btsFlags |= BTS_READ_ONLY;
    }
    if( page1[19]>2 ){
      goto page1_init_failed;
    }

    /* If the read version is set to 2, this database should be accessed
    ** in WAL mode. If the log is not already open, open it now. Then
    ** return SQLITE_OK and return without populating BtShared.pPage1.
    ** The caller detects this and calls this function again. This is
    ** required as the version of page 1 currently in the page1 buffer
    ** may not be the latest version - there may be a newer one in the log
    ** file.
    */
70816
70817
70818
70819
70820
70821
70822
70823
70824
70825
70826
70827
70828
70829
70830
70831
70832
        *pRes = 0;
        rc = sqlite3BtreeNext(pCur, 0);
        if( rc==SQLITE_OK ){
          getCellInfo(pCur);
          if( pCur->info.nKey==intKey ){
            return SQLITE_OK;
          }
        }else if( rc==SQLITE_DONE ){
          rc = SQLITE_OK;
        }else{
          return rc;
        }
      }
    }
  }

#ifdef SQLITE_DEBUG







|
<
<







70868
70869
70870
70871
70872
70873
70874
70875


70876
70877
70878
70879
70880
70881
70882
        *pRes = 0;
        rc = sqlite3BtreeNext(pCur, 0);
        if( rc==SQLITE_OK ){
          getCellInfo(pCur);
          if( pCur->info.nKey==intKey ){
            return SQLITE_OK;
          }
        }else if( rc!=SQLITE_DONE ){


          return rc;
        }
      }
    }
  }

#ifdef SQLITE_DEBUG
72663
72664
72665
72666
72667
72668
72669

72670
72671
72672
72673
72674
72675
72676
    int nTail = pageFreeArray(pPg, iNewEnd, iOldEnd - iNewEnd, pCArray);
    assert( nCell>=nTail );
    nCell -= nTail;
  }

  pData = &aData[get2byteNotZero(&aData[hdr+5])];
  if( pData<pBegin ) goto editpage_fail;


  /* Add cells to the start of the page */
  if( iNew<iOld ){
    int nAdd = MIN(nNew,iOld-iNew);
    assert( (iOld-iNew)<nNew || nCell==0 || CORRUPT_DB );
    assert( nAdd>=0 );
    pCellptr = pPg->aCellIdx;







>







72713
72714
72715
72716
72717
72718
72719
72720
72721
72722
72723
72724
72725
72726
72727
    int nTail = pageFreeArray(pPg, iNewEnd, iOldEnd - iNewEnd, pCArray);
    assert( nCell>=nTail );
    nCell -= nTail;
  }

  pData = &aData[get2byteNotZero(&aData[hdr+5])];
  if( pData<pBegin ) goto editpage_fail;
  if( NEVER(pData>pPg->aDataEnd) ) goto editpage_fail;

  /* Add cells to the start of the page */
  if( iNew<iOld ){
    int nAdd = MIN(nNew,iOld-iNew);
    assert( (iOld-iNew)<nNew || nCell==0 || CORRUPT_DB );
    assert( nAdd>=0 );
    pCellptr = pPg->aCellIdx;
73024
73025
73026
73027
73028
73029
73030
73031
73032
73033
73034
73035
73036
73037
73038
73039
73040
73041
73042
  int szNew[NB+2];             /* Combined size of cells placed on i-th page */
  u8 *aSpace1;                 /* Space for copies of dividers cells */
  Pgno pgno;                   /* Temp var to store a page number in */
  u8 abDone[NB+2];             /* True after i'th new page is populated */
  Pgno aPgno[NB+2];            /* Page numbers of new pages before shuffling */
  Pgno aPgOrder[NB+2];         /* Copy of aPgno[] used for sorting pages */
  u16 aPgFlags[NB+2];          /* flags field of new pages before shuffling */
  CellArray b;                  /* Parsed information on cells being balanced */

  memset(abDone, 0, sizeof(abDone));
  b.nCell = 0;
  b.apCell = 0;
  pBt = pParent->pBt;
  assert( sqlite3_mutex_held(pBt->mutex) );
  assert( sqlite3PagerIswriteable(pParent->pDbPage) );

  /* At this point pParent may have at most one overflow cell. And if
  ** this overflow cell is present, it must be the cell with
  ** index iParentIdx. This scenario comes about when this function







|


|
<







73075
73076
73077
73078
73079
73080
73081
73082
73083
73084
73085

73086
73087
73088
73089
73090
73091
73092
  int szNew[NB+2];             /* Combined size of cells placed on i-th page */
  u8 *aSpace1;                 /* Space for copies of dividers cells */
  Pgno pgno;                   /* Temp var to store a page number in */
  u8 abDone[NB+2];             /* True after i'th new page is populated */
  Pgno aPgno[NB+2];            /* Page numbers of new pages before shuffling */
  Pgno aPgOrder[NB+2];         /* Copy of aPgno[] used for sorting pages */
  u16 aPgFlags[NB+2];          /* flags field of new pages before shuffling */
  CellArray b;                 /* Parsed information on cells being balanced */

  memset(abDone, 0, sizeof(abDone));
  memset(&b, 0, sizeof(b));

  pBt = pParent->pBt;
  assert( sqlite3_mutex_held(pBt->mutex) );
  assert( sqlite3PagerIswriteable(pParent->pDbPage) );

  /* At this point pParent may have at most one overflow cell. And if
  ** this overflow cell is present, it must be the cell with
  ** index iParentIdx. This scenario comes about when this function
73839
73840
73841
73842
73843
73844
73845
73846
73847
73848
73849
73850
73851
73852
73853
  return SQLITE_OK;
}

/*
** Return SQLITE_CORRUPT if any cursor other than pCur is currently valid
** on the same B-tree as pCur.
**
** This can if a database is corrupt with two or more SQL tables
** pointing to the same b-tree.  If an insert occurs on one SQL table
** and causes a BEFORE TRIGGER to do a secondary insert on the other SQL
** table linked to the same b-tree.  If the secondary insert causes a
** rebalance, that can change content out from under the cursor on the
** first SQL table, violating invariants on the first insert.
*/
static int anotherValidCursor(BtCursor *pCur){







|







73889
73890
73891
73892
73893
73894
73895
73896
73897
73898
73899
73900
73901
73902
73903
  return SQLITE_OK;
}

/*
** Return SQLITE_CORRUPT if any cursor other than pCur is currently valid
** on the same B-tree as pCur.
**
** This can occur if a database is corrupt with two or more SQL tables
** pointing to the same b-tree.  If an insert occurs on one SQL table
** and causes a BEFORE TRIGGER to do a secondary insert on the other SQL
** table linked to the same b-tree.  If the secondary insert causes a
** rebalance, that can change content out from under the cursor on the
** first SQL table, violating invariants on the first insert.
*/
static int anotherValidCursor(BtCursor *pCur){
74068
74069
74070
74071
74072
74073
74074
74075
74076
74077
74078
74079
74080
74081
74082
  assert( iOffset>=0 );
  ovflPgno = get4byte(pCur->info.pPayload + iOffset);
  pBt = pPage->pBt;
  ovflPageSize = pBt->usableSize - 4;
  do{
    rc = btreeGetPage(pBt, ovflPgno, &pPage, 0);
    if( rc ) return rc;
    if( sqlite3PagerPageRefcount(pPage->pDbPage)!=1 ){
      rc = SQLITE_CORRUPT_BKPT;
    }else{
      if( iOffset+ovflPageSize<(u32)nTotal ){
        ovflPgno = get4byte(pPage->aData);
      }else{
        ovflPageSize = nTotal - iOffset;
      }







|







74118
74119
74120
74121
74122
74123
74124
74125
74126
74127
74128
74129
74130
74131
74132
  assert( iOffset>=0 );
  ovflPgno = get4byte(pCur->info.pPayload + iOffset);
  pBt = pPage->pBt;
  ovflPageSize = pBt->usableSize - 4;
  do{
    rc = btreeGetPage(pBt, ovflPgno, &pPage, 0);
    if( rc ) return rc;
    if( sqlite3PagerPageRefcount(pPage->pDbPage)!=1 || pPage->isInit ){
      rc = SQLITE_CORRUPT_BKPT;
    }else{
      if( iOffset+ovflPageSize<(u32)nTotal ){
        ovflPgno = get4byte(pPage->aData);
      }else{
        ovflPageSize = nTotal - iOffset;
      }
74490
74491
74492
74493
74494
74495
74496
74497
74498
74499
74500
74501
74502
74503
74504
            ovflIn = get4byte(aIn);
            aIn += 4;
            nIn = pSrc->pBt->usableSize - 4;
          }
        }
      }while( rc==SQLITE_OK && nOut>0 );

      if( rc==SQLITE_OK && nRem>0 ){
        Pgno pgnoNew;
        MemPage *pNew = 0;
        rc = allocateBtreePage(pBt, &pNew, &pgnoNew, 0, 0);
        put4byte(pPgnoOut, pgnoNew);
        if( ISAUTOVACUUM && pPageOut ){
          ptrmapPut(pBt, pgnoNew, PTRMAP_OVERFLOW2, pPageOut->pgno, &rc);
        }







|







74540
74541
74542
74543
74544
74545
74546
74547
74548
74549
74550
74551
74552
74553
74554
            ovflIn = get4byte(aIn);
            aIn += 4;
            nIn = pSrc->pBt->usableSize - 4;
          }
        }
      }while( rc==SQLITE_OK && nOut>0 );

      if( rc==SQLITE_OK && nRem>0 && ALWAYS(pPgnoOut) ){
        Pgno pgnoNew;
        MemPage *pNew = 0;
        rc = allocateBtreePage(pBt, &pNew, &pgnoNew, 0, 0);
        put4byte(pPgnoOut, pgnoNew);
        if( ISAUTOVACUUM && pPageOut ){
          ptrmapPut(pBt, pgnoNew, PTRMAP_OVERFLOW2, pPageOut->pgno, &rc);
        }
77164
77165
77166
77167
77168
77169
77170

77171
77172
77173
77174
77175
77176
77177
** SQLITE_NOMEM may be returned if a malloc() fails during conversion
** between formats.
*/
SQLITE_PRIVATE int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){
#ifndef SQLITE_OMIT_UTF16
  int rc;
#endif

  assert( !sqlite3VdbeMemIsRowSet(pMem) );
  assert( desiredEnc==SQLITE_UTF8 || desiredEnc==SQLITE_UTF16LE
           || desiredEnc==SQLITE_UTF16BE );
  if( !(pMem->flags&MEM_Str) || pMem->enc==desiredEnc ){
    return SQLITE_OK;
  }
  assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );







>







77214
77215
77216
77217
77218
77219
77220
77221
77222
77223
77224
77225
77226
77227
77228
** SQLITE_NOMEM may be returned if a malloc() fails during conversion
** between formats.
*/
SQLITE_PRIVATE int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){
#ifndef SQLITE_OMIT_UTF16
  int rc;
#endif
  assert( pMem!=0 );
  assert( !sqlite3VdbeMemIsRowSet(pMem) );
  assert( desiredEnc==SQLITE_UTF8 || desiredEnc==SQLITE_UTF16LE
           || desiredEnc==SQLITE_UTF16BE );
  if( !(pMem->flags&MEM_Str) || pMem->enc==desiredEnc ){
    return SQLITE_OK;
  }
  assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
77296
77297
77298
77299
77300
77301
77302

77303
77304
77305
77306
77307
77308
77309
/*
** Change pMem so that its MEM_Str or MEM_Blob value is stored in
** MEM.zMalloc, where it can be safely written.
**
** Return SQLITE_OK on success or SQLITE_NOMEM if malloc fails.
*/
SQLITE_PRIVATE int sqlite3VdbeMemMakeWriteable(Mem *pMem){

  assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
  assert( !sqlite3VdbeMemIsRowSet(pMem) );
  if( (pMem->flags & (MEM_Str|MEM_Blob))!=0 ){
    if( ExpandBlob(pMem) ) return SQLITE_NOMEM;
    if( pMem->szMalloc==0 || pMem->z!=pMem->zMalloc ){
      int rc = vdbeMemAddTerminator(pMem);
      if( rc ) return rc;







>







77347
77348
77349
77350
77351
77352
77353
77354
77355
77356
77357
77358
77359
77360
77361
/*
** Change pMem so that its MEM_Str or MEM_Blob value is stored in
** MEM.zMalloc, where it can be safely written.
**
** Return SQLITE_OK on success or SQLITE_NOMEM if malloc fails.
*/
SQLITE_PRIVATE int sqlite3VdbeMemMakeWriteable(Mem *pMem){
  assert( pMem!=0 );
  assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
  assert( !sqlite3VdbeMemIsRowSet(pMem) );
  if( (pMem->flags & (MEM_Str|MEM_Blob))!=0 ){
    if( ExpandBlob(pMem) ) return SQLITE_NOMEM;
    if( pMem->szMalloc==0 || pMem->z!=pMem->zMalloc ){
      int rc = vdbeMemAddTerminator(pMem);
      if( rc ) return rc;
77320
77321
77322
77323
77324
77325
77326

77327
77328
77329
77330
77331
77332
77333
/*
** If the given Mem* has a zero-filled tail, turn it into an ordinary
** blob stored in dynamically allocated space.
*/
#ifndef SQLITE_OMIT_INCRBLOB
SQLITE_PRIVATE int sqlite3VdbeMemExpandBlob(Mem *pMem){
  int nByte;

  assert( pMem->flags & MEM_Zero );
  assert( (pMem->flags&MEM_Blob)!=0 || MemNullNochng(pMem) );
  testcase( sqlite3_value_nochange(pMem) );
  assert( !sqlite3VdbeMemIsRowSet(pMem) );
  assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );

  /* Set nByte to the number of bytes required to store the expanded blob. */







>







77372
77373
77374
77375
77376
77377
77378
77379
77380
77381
77382
77383
77384
77385
77386
/*
** If the given Mem* has a zero-filled tail, turn it into an ordinary
** blob stored in dynamically allocated space.
*/
#ifndef SQLITE_OMIT_INCRBLOB
SQLITE_PRIVATE int sqlite3VdbeMemExpandBlob(Mem *pMem){
  int nByte;
  assert( pMem!=0 );
  assert( pMem->flags & MEM_Zero );
  assert( (pMem->flags&MEM_Blob)!=0 || MemNullNochng(pMem) );
  testcase( sqlite3_value_nochange(pMem) );
  assert( !sqlite3VdbeMemIsRowSet(pMem) );
  assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );

  /* Set nByte to the number of bytes required to store the expanded blob. */
77347
77348
77349
77350
77351
77352
77353

77354
77355
77356
77357
77358
77359
77360
}
#endif

/*
** Make sure the given Mem is \u0000 terminated.
*/
SQLITE_PRIVATE int sqlite3VdbeMemNulTerminate(Mem *pMem){

  assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
  testcase( (pMem->flags & (MEM_Term|MEM_Str))==(MEM_Term|MEM_Str) );
  testcase( (pMem->flags & (MEM_Term|MEM_Str))==0 );
  if( (pMem->flags & (MEM_Term|MEM_Str))!=MEM_Str ){
    return SQLITE_OK;   /* Nothing to do */
  }else{
    return vdbeMemAddTerminator(pMem);







>







77400
77401
77402
77403
77404
77405
77406
77407
77408
77409
77410
77411
77412
77413
77414
}
#endif

/*
** Make sure the given Mem is \u0000 terminated.
*/
SQLITE_PRIVATE int sqlite3VdbeMemNulTerminate(Mem *pMem){
  assert( pMem!=0 );
  assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
  testcase( (pMem->flags & (MEM_Term|MEM_Str))==(MEM_Term|MEM_Str) );
  testcase( (pMem->flags & (MEM_Term|MEM_Str))==0 );
  if( (pMem->flags & (MEM_Term|MEM_Str))!=MEM_Str ){
    return SQLITE_OK;   /* Nothing to do */
  }else{
    return vdbeMemAddTerminator(pMem);
77374
77375
77376
77377
77378
77379
77380

77381
77382
77383
77384
77385
77386
77387
** sqlite3_value_text()), or for ensuring that values to be used as btree
** keys are strings. In the former case a NULL pointer is returned the
** user and the latter is an internal programming error.
*/
SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){
  const int nByte = 32;


  assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
  assert( !(pMem->flags&MEM_Zero) );
  assert( !(pMem->flags&(MEM_Str|MEM_Blob)) );
  assert( pMem->flags&(MEM_Int|MEM_Real|MEM_IntReal) );
  assert( !sqlite3VdbeMemIsRowSet(pMem) );
  assert( EIGHT_BYTE_ALIGNMENT(pMem) );








>







77428
77429
77430
77431
77432
77433
77434
77435
77436
77437
77438
77439
77440
77441
77442
** sqlite3_value_text()), or for ensuring that values to be used as btree
** keys are strings. In the former case a NULL pointer is returned the
** user and the latter is an internal programming error.
*/
SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){
  const int nByte = 32;

  assert( pMem!=0 );
  assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
  assert( !(pMem->flags&MEM_Zero) );
  assert( !(pMem->flags&(MEM_Str|MEM_Blob)) );
  assert( pMem->flags&(MEM_Int|MEM_Real|MEM_IntReal) );
  assert( !sqlite3VdbeMemIsRowSet(pMem) );
  assert( EIGHT_BYTE_ALIGNMENT(pMem) );

77409
77410
77411
77412
77413
77414
77415

77416
77417
77418
77419
77420
77421
77422
** Return SQLITE_ERROR if the finalizer reports an error.  SQLITE_OK
** otherwise.
*/
SQLITE_PRIVATE int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){
  sqlite3_context ctx;
  Mem t;
  assert( pFunc!=0 );

  assert( pFunc->xFinalize!=0 );
  assert( (pMem->flags & MEM_Null)!=0 || pFunc==pMem->u.pDef );
  assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
  memset(&ctx, 0, sizeof(ctx));
  memset(&t, 0, sizeof(t));
  t.flags = MEM_Null;
  t.db = pMem->db;







>







77464
77465
77466
77467
77468
77469
77470
77471
77472
77473
77474
77475
77476
77477
77478
** Return SQLITE_ERROR if the finalizer reports an error.  SQLITE_OK
** otherwise.
*/
SQLITE_PRIVATE int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){
  sqlite3_context ctx;
  Mem t;
  assert( pFunc!=0 );
  assert( pMem!=0 );
  assert( pFunc->xFinalize!=0 );
  assert( (pMem->flags & MEM_Null)!=0 || pFunc==pMem->u.pDef );
  assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
  memset(&ctx, 0, sizeof(ctx));
  memset(&t, 0, sizeof(t));
  t.flags = MEM_Null;
  t.db = pMem->db;
77559
77560
77561
77562
77563
77564
77565

77566
77567
77568
77569
77570
77571
77572
static SQLITE_NOINLINE i64 memIntValue(Mem *pMem){
  i64 value = 0;
  sqlite3Atoi64(pMem->z, &value, pMem->n, pMem->enc);
  return value;
}
SQLITE_PRIVATE i64 sqlite3VdbeIntValue(Mem *pMem){
  int flags;

  assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
  assert( EIGHT_BYTE_ALIGNMENT(pMem) );
  flags = pMem->flags;
  if( flags & (MEM_Int|MEM_IntReal) ){
    testcase( flags & MEM_IntReal );
    return pMem->u.i;
  }else if( flags & MEM_Real ){







>







77615
77616
77617
77618
77619
77620
77621
77622
77623
77624
77625
77626
77627
77628
77629
static SQLITE_NOINLINE i64 memIntValue(Mem *pMem){
  i64 value = 0;
  sqlite3Atoi64(pMem->z, &value, pMem->n, pMem->enc);
  return value;
}
SQLITE_PRIVATE i64 sqlite3VdbeIntValue(Mem *pMem){
  int flags;
  assert( pMem!=0 );
  assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
  assert( EIGHT_BYTE_ALIGNMENT(pMem) );
  flags = pMem->flags;
  if( flags & (MEM_Int|MEM_IntReal) ){
    testcase( flags & MEM_IntReal );
    return pMem->u.i;
  }else if( flags & MEM_Real ){
77587
77588
77589
77590
77591
77592
77593

77594
77595
77596
77597
77598
77599
77600
static SQLITE_NOINLINE double memRealValue(Mem *pMem){
  /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */
  double val = (double)0;
  sqlite3AtoF(pMem->z, &val, pMem->n, pMem->enc);
  return val;
}
SQLITE_PRIVATE double sqlite3VdbeRealValue(Mem *pMem){

  assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
  assert( EIGHT_BYTE_ALIGNMENT(pMem) );
  if( pMem->flags & MEM_Real ){
    return pMem->u.r;
  }else if( pMem->flags & (MEM_Int|MEM_IntReal) ){
    testcase( pMem->flags & MEM_IntReal );
    return (double)pMem->u.i;







>







77644
77645
77646
77647
77648
77649
77650
77651
77652
77653
77654
77655
77656
77657
77658
static SQLITE_NOINLINE double memRealValue(Mem *pMem){
  /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */
  double val = (double)0;
  sqlite3AtoF(pMem->z, &val, pMem->n, pMem->enc);
  return val;
}
SQLITE_PRIVATE double sqlite3VdbeRealValue(Mem *pMem){
  assert( pMem!=0 );
  assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
  assert( EIGHT_BYTE_ALIGNMENT(pMem) );
  if( pMem->flags & MEM_Real ){
    return pMem->u.r;
  }else if( pMem->flags & (MEM_Int|MEM_IntReal) ){
    testcase( pMem->flags & MEM_IntReal );
    return (double)pMem->u.i;
77619
77620
77621
77622
77623
77624
77625

77626
77627
77628
77629
77630
77631
77632

/*
** The MEM structure is already a MEM_Real.  Try to also make it a
** MEM_Int if we can.
*/
SQLITE_PRIVATE void sqlite3VdbeIntegerAffinity(Mem *pMem){
  i64 ix;

  assert( pMem->flags & MEM_Real );
  assert( !sqlite3VdbeMemIsRowSet(pMem) );
  assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
  assert( EIGHT_BYTE_ALIGNMENT(pMem) );

  ix = doubleToInt64(pMem->u.r);








>







77677
77678
77679
77680
77681
77682
77683
77684
77685
77686
77687
77688
77689
77690
77691

/*
** The MEM structure is already a MEM_Real.  Try to also make it a
** MEM_Int if we can.
*/
SQLITE_PRIVATE void sqlite3VdbeIntegerAffinity(Mem *pMem){
  i64 ix;
  assert( pMem!=0 );
  assert( pMem->flags & MEM_Real );
  assert( !sqlite3VdbeMemIsRowSet(pMem) );
  assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
  assert( EIGHT_BYTE_ALIGNMENT(pMem) );

  ix = doubleToInt64(pMem->u.r);

77646
77647
77648
77649
77650
77651
77652

77653
77654
77655
77656
77657
77658
77659
77660
77661
77662
77663
77664
77665
77666

77667
77668
77669
77670
77671
77672
77673
  }
}

/*
** Convert pMem to type integer.  Invalidate any prior representations.
*/
SQLITE_PRIVATE int sqlite3VdbeMemIntegerify(Mem *pMem){

  assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
  assert( !sqlite3VdbeMemIsRowSet(pMem) );
  assert( EIGHT_BYTE_ALIGNMENT(pMem) );

  pMem->u.i = sqlite3VdbeIntValue(pMem);
  MemSetTypeFlag(pMem, MEM_Int);
  return SQLITE_OK;
}

/*
** Convert pMem so that it is of type MEM_Real.
** Invalidate any prior representations.
*/
SQLITE_PRIVATE int sqlite3VdbeMemRealify(Mem *pMem){

  assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
  assert( EIGHT_BYTE_ALIGNMENT(pMem) );

  pMem->u.r = sqlite3VdbeRealValue(pMem);
  MemSetTypeFlag(pMem, MEM_Real);
  return SQLITE_OK;
}







>














>







77705
77706
77707
77708
77709
77710
77711
77712
77713
77714
77715
77716
77717
77718
77719
77720
77721
77722
77723
77724
77725
77726
77727
77728
77729
77730
77731
77732
77733
77734
  }
}

/*
** Convert pMem to type integer.  Invalidate any prior representations.
*/
SQLITE_PRIVATE int sqlite3VdbeMemIntegerify(Mem *pMem){
  assert( pMem!=0 );
  assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
  assert( !sqlite3VdbeMemIsRowSet(pMem) );
  assert( EIGHT_BYTE_ALIGNMENT(pMem) );

  pMem->u.i = sqlite3VdbeIntValue(pMem);
  MemSetTypeFlag(pMem, MEM_Int);
  return SQLITE_OK;
}

/*
** Convert pMem so that it is of type MEM_Real.
** Invalidate any prior representations.
*/
SQLITE_PRIVATE int sqlite3VdbeMemRealify(Mem *pMem){
  assert( pMem!=0 );
  assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
  assert( EIGHT_BYTE_ALIGNMENT(pMem) );

  pMem->u.r = sqlite3VdbeRealValue(pMem);
  MemSetTypeFlag(pMem, MEM_Real);
  return SQLITE_OK;
}
77693
77694
77695
77696
77697
77698
77699

77700
77701
77702
77703
77704
77705
77706
** Invalidate any prior representations.
**
** Every effort is made to force the conversion, even if the input
** is a string that does not look completely like a number.  Convert
** as much of the string as we can and ignore the rest.
*/
SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem *pMem){

  testcase( pMem->flags & MEM_Int );
  testcase( pMem->flags & MEM_Real );
  testcase( pMem->flags & MEM_IntReal );
  testcase( pMem->flags & MEM_Null );
  if( (pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal|MEM_Null))==0 ){
    int rc;
    sqlite3_int64 ix;







>







77754
77755
77756
77757
77758
77759
77760
77761
77762
77763
77764
77765
77766
77767
77768
** Invalidate any prior representations.
**
** Every effort is made to force the conversion, even if the input
** is a string that does not look completely like a number.  Convert
** as much of the string as we can and ignore the rest.
*/
SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem *pMem){
  assert( pMem!=0 );
  testcase( pMem->flags & MEM_Int );
  testcase( pMem->flags & MEM_Real );
  testcase( pMem->flags & MEM_IntReal );
  testcase( pMem->flags & MEM_Null );
  if( (pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal|MEM_Null))==0 ){
    int rc;
    sqlite3_int64 ix;
78044
78045
78046
78047
78048
78049
78050

78051
78052
78053
78054
78055
78056
78057
  u8 enc,             /* Encoding of z.  0 for BLOBs */
  void (*xDel)(void*) /* Destructor function */
){
  i64 nByte = n;      /* New value for pMem->n */
  int iLimit;         /* Maximum allowed string or blob size */
  u16 flags = 0;      /* New value for pMem->flags */


  assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
  assert( !sqlite3VdbeMemIsRowSet(pMem) );

  /* If z is a NULL pointer, set pMem to contain an SQL NULL. */
  if( !z ){
    sqlite3VdbeMemSetNull(pMem);
    return SQLITE_OK;







>







78106
78107
78108
78109
78110
78111
78112
78113
78114
78115
78116
78117
78118
78119
78120
  u8 enc,             /* Encoding of z.  0 for BLOBs */
  void (*xDel)(void*) /* Destructor function */
){
  i64 nByte = n;      /* New value for pMem->n */
  int iLimit;         /* Maximum allowed string or blob size */
  u16 flags = 0;      /* New value for pMem->flags */

  assert( pMem!=0 );
  assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
  assert( !sqlite3VdbeMemIsRowSet(pMem) );

  /* If z is a NULL pointer, set pMem to contain an SQL NULL. */
  if( !z ){
    sqlite3VdbeMemSetNull(pMem);
    return SQLITE_OK;
78352
78353
78354
78355
78356
78357
78358
78359
78360
78361
78362
78363
78364
78365
78366
** If the conditions above are not met, this function returns SQLITE_OK
** and sets (*ppVal) to NULL. Or, if an error occurs, (*ppVal) is set to
** NULL and an SQLite error code returned.
*/
#ifdef SQLITE_ENABLE_STAT4
static int valueFromFunction(
  sqlite3 *db,                    /* The database connection */
  Expr *p,                        /* The expression to evaluate */
  u8 enc,                         /* Encoding to use */
  u8 aff,                         /* Affinity to use */
  sqlite3_value **ppVal,          /* Write the new value here */
  struct ValueNewStat4Ctx *pCtx   /* Second argument for valueNew() */
){
  sqlite3_context ctx;            /* Context object for function invocation */
  sqlite3_value **apVal = 0;      /* Function arguments */







|







78415
78416
78417
78418
78419
78420
78421
78422
78423
78424
78425
78426
78427
78428
78429
** If the conditions above are not met, this function returns SQLITE_OK
** and sets (*ppVal) to NULL. Or, if an error occurs, (*ppVal) is set to
** NULL and an SQLite error code returned.
*/
#ifdef SQLITE_ENABLE_STAT4
static int valueFromFunction(
  sqlite3 *db,                    /* The database connection */
  const Expr *p,                  /* The expression to evaluate */
  u8 enc,                         /* Encoding to use */
  u8 aff,                         /* Affinity to use */
  sqlite3_value **ppVal,          /* Write the new value here */
  struct ValueNewStat4Ctx *pCtx   /* Second argument for valueNew() */
){
  sqlite3_context ctx;            /* Context object for function invocation */
  sqlite3_value **apVal = 0;      /* Function arguments */
78446
78447
78448
78449
78450
78451
78452
78453
78454
78455
78456
78457
78458
78459
78460
** If pCtx is NULL and an error occurs after the sqlite3_value object
** has been allocated, it is freed before returning. Or, if pCtx is not
** NULL, it is assumed that the caller will free any allocated object
** in all cases.
*/
static int valueFromExpr(
  sqlite3 *db,                    /* The database connection */
  Expr *pExpr,                    /* The expression to evaluate */
  u8 enc,                         /* Encoding to use */
  u8 affinity,                    /* Affinity to use */
  sqlite3_value **ppVal,          /* Write the new value here */
  struct ValueNewStat4Ctx *pCtx   /* Second argument for valueNew() */
){
  int op;
  char *zVal = 0;







|







78509
78510
78511
78512
78513
78514
78515
78516
78517
78518
78519
78520
78521
78522
78523
** If pCtx is NULL and an error occurs after the sqlite3_value object
** has been allocated, it is freed before returning. Or, if pCtx is not
** NULL, it is assumed that the caller will free any allocated object
** in all cases.
*/
static int valueFromExpr(
  sqlite3 *db,                    /* The database connection */
  const Expr *pExpr,              /* The expression to evaluate */
  u8 enc,                         /* Encoding to use */
  u8 affinity,                    /* Affinity to use */
  sqlite3_value **ppVal,          /* Write the new value here */
  struct ValueNewStat4Ctx *pCtx   /* Second argument for valueNew() */
){
  int op;
  char *zVal = 0;
78601
78602
78603
78604
78605
78606
78607
78608
78609
78610
78611
78612
78613
78614
78615
** be converted directly into a value, then the value is allocated and
** a pointer written to *ppVal. The caller is responsible for deallocating
** the value by passing it to sqlite3ValueFree() later on. If the expression
** cannot be converted to a value, then *ppVal is set to NULL.
*/
SQLITE_PRIVATE int sqlite3ValueFromExpr(
  sqlite3 *db,              /* The database connection */
  Expr *pExpr,              /* The expression to evaluate */
  u8 enc,                   /* Encoding to use */
  u8 affinity,              /* Affinity to use */
  sqlite3_value **ppVal     /* Write the new value here */
){
  return pExpr ? valueFromExpr(db, pExpr, enc, affinity, ppVal, 0) : 0;
}








|







78664
78665
78666
78667
78668
78669
78670
78671
78672
78673
78674
78675
78676
78677
78678
** be converted directly into a value, then the value is allocated and
** a pointer written to *ppVal. The caller is responsible for deallocating
** the value by passing it to sqlite3ValueFree() later on. If the expression
** cannot be converted to a value, then *ppVal is set to NULL.
*/
SQLITE_PRIVATE int sqlite3ValueFromExpr(
  sqlite3 *db,              /* The database connection */
  const Expr *pExpr,        /* The expression to evaluate */
  u8 enc,                   /* Encoding to use */
  u8 affinity,              /* Affinity to use */
  sqlite3_value **ppVal     /* Write the new value here */
){
  return pExpr ? valueFromExpr(db, pExpr, enc, affinity, ppVal, 0) : 0;
}

79117
79118
79119
79120
79121
79122
79123

79124
79125

79126
79127
79128
79129
79130
79131
79132

  i = p->nOp;
  assert( p->iVdbeMagic==VDBE_MAGIC_INIT );
  assert( op>=0 && op<0xff );
  if( p->nOpAlloc<=i ){
    return growOp3(p, op, p1, p2, p3);
  }

  p->nOp++;
  pOp = &p->aOp[i];

  pOp->opcode = (u8)op;
  pOp->p5 = 0;
  pOp->p1 = p1;
  pOp->p2 = p2;
  pOp->p3 = p3;
  pOp->p4.p = 0;
  pOp->p4type = P4_NOTUSED;







>


>







79180
79181
79182
79183
79184
79185
79186
79187
79188
79189
79190
79191
79192
79193
79194
79195
79196
79197

  i = p->nOp;
  assert( p->iVdbeMagic==VDBE_MAGIC_INIT );
  assert( op>=0 && op<0xff );
  if( p->nOpAlloc<=i ){
    return growOp3(p, op, p1, p2, p3);
  }
  assert( p->aOp!=0 );
  p->nOp++;
  pOp = &p->aOp[i];
  assert( pOp!=0 );
  pOp->opcode = (u8)op;
  pOp->p5 = 0;
  pOp->p1 = p1;
  pOp->p2 = p2;
  pOp->p3 = p3;
  pOp->p4.p = 0;
  pOp->p4type = P4_NOTUSED;
80361
80362
80363
80364
80365
80366
80367
80368
80369
80370
80371
80372
80373
80374
80375

  sqlite3StrAccumInit(&x, 0, 0, 0, SQLITE_MAX_LENGTH);
  zOpName = sqlite3OpcodeName(pOp->opcode);
  nOpName = sqlite3Strlen30(zOpName);
  if( zOpName[nOpName+1] ){
    int seenCom = 0;
    char c;
    zSynopsis = zOpName += nOpName + 1;
    if( strncmp(zSynopsis,"IF ",3)==0 ){
      sqlite3_snprintf(sizeof(zAlt), zAlt, "if %s goto P2", zSynopsis+3);
      zSynopsis = zAlt;
    }
    for(ii=0; (c = zSynopsis[ii])!=0; ii++){
      if( c=='P' ){
        c = zSynopsis[++ii];







|







80426
80427
80428
80429
80430
80431
80432
80433
80434
80435
80436
80437
80438
80439
80440

  sqlite3StrAccumInit(&x, 0, 0, 0, SQLITE_MAX_LENGTH);
  zOpName = sqlite3OpcodeName(pOp->opcode);
  nOpName = sqlite3Strlen30(zOpName);
  if( zOpName[nOpName+1] ){
    int seenCom = 0;
    char c;
    zSynopsis = zOpName + nOpName + 1;
    if( strncmp(zSynopsis,"IF ",3)==0 ){
      sqlite3_snprintf(sizeof(zAlt), zAlt, "if %s goto P2", zSynopsis+3);
      zSynopsis = zAlt;
    }
    for(ii=0; (c = zSynopsis[ii])!=0; ii++){
      if( c=='P' ){
        c = zSynopsis[++ii];
81881
81882
81883
81884
81885
81886
81887
81888
81889
81890
81891
81892
81893
81894
81895
81896
81897
#endif

/*
** This routine is called the when a VDBE tries to halt.  If the VDBE
** has made changes and is in autocommit mode, then commit those
** changes.  If a rollback is needed, then do the rollback.
**
** This routine is the only way to move the state of a VM from
** SQLITE_MAGIC_RUN to SQLITE_MAGIC_HALT.  It is harmless to
** call this on a VM that is in the SQLITE_MAGIC_HALT state.
**
** Return an error code.  If the commit could not complete because of
** lock contention, return SQLITE_BUSY.  If SQLITE_BUSY is returned, it
** means the close did not happen and needs to be repeated.
*/
SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
  int rc;                         /* Used to store transient return codes */







|
|
|







81946
81947
81948
81949
81950
81951
81952
81953
81954
81955
81956
81957
81958
81959
81960
81961
81962
#endif

/*
** This routine is called the when a VDBE tries to halt.  If the VDBE
** has made changes and is in autocommit mode, then commit those
** changes.  If a rollback is needed, then do the rollback.
**
** This routine is the only way to move the sqlite3eOpenState of a VM from
** SQLITE_STATE_RUN to SQLITE_STATE_HALT.  It is harmless to
** call this on a VM that is in the SQLITE_STATE_HALT state.
**
** Return an error code.  If the commit could not complete because of
** lock contention, return SQLITE_BUSY.  If SQLITE_BUSY is returned, it
** means the close did not happen and needs to be repeated.
*/
SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
  int rc;                         /* Used to store transient return codes */
86265
86266
86267
86268
86269
86270
86271
86272
86273
86274
86275
86276
86277
86278
86279
86280
86281
86282
86283
  int nToken;              /* Length of the parameter token */
  int i;                   /* Loop counter */
  Mem *pVar;               /* Value of a host parameter */
  StrAccum out;            /* Accumulate the output here */
#ifndef SQLITE_OMIT_UTF16
  Mem utf8;                /* Used to convert UTF16 into UTF8 for display */
#endif
  char zBase[100];         /* Initial working space */

  db = p->db;
  sqlite3StrAccumInit(&out, 0, zBase, sizeof(zBase),
                      db->aLimit[SQLITE_LIMIT_LENGTH]);
  if( db->nVdbeExec>1 ){
    while( *zRawSql ){
      const char *zStart = zRawSql;
      while( *(zRawSql++)!='\n' && *zRawSql );
      sqlite3_str_append(&out, "-- ", 3);
      assert( (zRawSql - zStart) > 0 );
      sqlite3_str_append(&out, zStart, (int)(zRawSql-zStart));







<


|
<







86330
86331
86332
86333
86334
86335
86336

86337
86338
86339

86340
86341
86342
86343
86344
86345
86346
  int nToken;              /* Length of the parameter token */
  int i;                   /* Loop counter */
  Mem *pVar;               /* Value of a host parameter */
  StrAccum out;            /* Accumulate the output here */
#ifndef SQLITE_OMIT_UTF16
  Mem utf8;                /* Used to convert UTF16 into UTF8 for display */
#endif


  db = p->db;
  sqlite3StrAccumInit(&out, 0, 0, 0, db->aLimit[SQLITE_LIMIT_LENGTH]);

  if( db->nVdbeExec>1 ){
    while( *zRawSql ){
      const char *zStart = zRawSql;
      while( *(zRawSql++)!='\n' && *zRawSql );
      sqlite3_str_append(&out, "-- ", 3);
      assert( (zRawSql - zStart) > 0 );
      sqlite3_str_append(&out, zStart, (int)(zRawSql-zStart));
87049
87050
87051
87052
87053
87054
87055













87056
87057
87058
87059
87060
87061
87062
    return out2PrereleaseWithClear(pOut);
  }else{
    pOut->flags = MEM_Int;
    return pOut;
  }
}















/*
** Execute as much of a VDBE program as we can.
** This is the core of sqlite3_step().
*/
SQLITE_PRIVATE int sqlite3VdbeExec(
  Vdbe *p                    /* The VDBE */







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







87112
87113
87114
87115
87116
87117
87118
87119
87120
87121
87122
87123
87124
87125
87126
87127
87128
87129
87130
87131
87132
87133
87134
87135
87136
87137
87138
    return out2PrereleaseWithClear(pOut);
  }else{
    pOut->flags = MEM_Int;
    return pOut;
  }
}

/*
** Return the symbolic name for the data type of a pMem
*/
static const char *vdbeMemTypeName(Mem *pMem){
  static const char *azTypes[] = {
      /* SQLITE_INTEGER */ "INT",
      /* SQLITE_FLOAT   */ "REAL",
      /* SQLITE_TEXT    */ "TEXT",
      /* SQLITE_BLOB    */ "BLOB",
      /* SQLITE_NULL    */ "NULL"
  };
  return azTypes[sqlite3_value_type(pMem)-1];
}

/*
** Execute as much of a VDBE program as we can.
** This is the core of sqlite3_step().
*/
SQLITE_PRIVATE int sqlite3VdbeExec(
  Vdbe *p                    /* The VDBE */
88879
88880
88881
88882
88883
88884
88885
















88886
88887
88888
88889
88890
88891
88892
  pIn1 = &aMem[pOp->p1];
  VdbeBranchTaken( (pIn1->flags & MEM_Null)!=0, 2);
  if( (pIn1->flags & MEM_Null)!=0 ){
    goto jump_to_p2;
  }
  break;
}

















/* Opcode: ZeroOrNull P1 P2 P3 * *
** Synopsis: r[P2] = 0 OR NULL
**
** If all both registers P1 and P3 are NOT NULL, then store a zero in
** register P2.  If either registers P1 or P3 are NULL then put
** a NULL in register P2.







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







88955
88956
88957
88958
88959
88960
88961
88962
88963
88964
88965
88966
88967
88968
88969
88970
88971
88972
88973
88974
88975
88976
88977
88978
88979
88980
88981
88982
88983
88984
  pIn1 = &aMem[pOp->p1];
  VdbeBranchTaken( (pIn1->flags & MEM_Null)!=0, 2);
  if( (pIn1->flags & MEM_Null)!=0 ){
    goto jump_to_p2;
  }
  break;
}

/* Opcode: IsNullOrType P1 P2 P3 * *
** Synopsis: if typeof(r[P1]) IN (P3,5) goto P2
**
** Jump to P2 if the value in register P1 is NULL or has a datatype P3.
** P3 is an integer which should be one of SQLITE_INTEGER, SQLITE_FLOAT,
** SQLITE_BLOB, SQLITE_NULL, or SQLITE_TEXT.
*/
case OP_IsNullOrType: {      /* jump, in1 */
  int doTheJump;
  pIn1 = &aMem[pOp->p1];
  doTheJump = (pIn1->flags & MEM_Null)!=0 || sqlite3_value_type(pIn1)==pOp->p3;
  VdbeBranchTaken( doTheJump, 2);
  if( doTheJump ) goto jump_to_p2;
  break;
}

/* Opcode: ZeroOrNull P1 P2 P3 * *
** Synopsis: r[P2] = 0 OR NULL
**
** If all both registers P1 and P3 are NOT NULL, then store a zero in
** register P2.  If either registers P1 or P3 are NULL then put
** a NULL in register P2.
89247
89248
89249
89250
89251
89252
89253






























































































89254
89255
89256
89257
89258
89259
89260
    pOp = &aOp[aOp[0].p3-1];
    break;
  }else{
    rc = SQLITE_CORRUPT_BKPT;
    goto abort_due_to_error;
  }
}































































































/* Opcode: Affinity P1 P2 * P4 *
** Synopsis: affinity(r[P1@P2])
**
** Apply affinities to a range of P2 registers starting with P1.
**
** P4 is a string that is P2 characters long. The N-th character of the







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







89339
89340
89341
89342
89343
89344
89345
89346
89347
89348
89349
89350
89351
89352
89353
89354
89355
89356
89357
89358
89359
89360
89361
89362
89363
89364
89365
89366
89367
89368
89369
89370
89371
89372
89373
89374
89375
89376
89377
89378
89379
89380
89381
89382
89383
89384
89385
89386
89387
89388
89389
89390
89391
89392
89393
89394
89395
89396
89397
89398
89399
89400
89401
89402
89403
89404
89405
89406
89407
89408
89409
89410
89411
89412
89413
89414
89415
89416
89417
89418
89419
89420
89421
89422
89423
89424
89425
89426
89427
89428
89429
89430
89431
89432
89433
89434
89435
89436
89437
89438
89439
89440
89441
89442
89443
89444
89445
89446
    pOp = &aOp[aOp[0].p3-1];
    break;
  }else{
    rc = SQLITE_CORRUPT_BKPT;
    goto abort_due_to_error;
  }
}

/* Opcode: TypeCheck P1 P2 * P4 *
** Synopsis: typecheck(r[P1@P2])
**
** Apply affinities to the range of P2 registers beginning with P1.
** Take the affinities from the Table object in P4.  If any value
** cannot be coerced into the correct type, then raise an error.
**
** This opcode is similar to OP_Affinity except that this opcode
** forces the register type to the Table column type.  This is used
** to implement "strict affinity".
**
** Preconditions:
**
** <ul>
** <li> P2 should be the number of non-virtual columns in the
**      table of P4.
** <li> Table P4 should be a STRICT table.
** </ul>
**
** If any precondition is false, an assertion fault occurs.
*/
case OP_TypeCheck: {
  Table *pTab;
  Column *aCol;
  int i;

  assert( pOp->p4type==P4_TABLE );
  pTab = pOp->p4.pTab;
  assert( pTab->tabFlags & TF_Strict );
  assert( pTab->nNVCol==pOp->p2 );
  aCol = pTab->aCol;
  pIn1 = &aMem[pOp->p1];
  for(i=0; i<pTab->nCol; i++){
    if( aCol[i].colFlags & COLFLAG_VIRTUAL ) continue;
    assert( pIn1 < &aMem[pOp->p1+pOp->p2] );
    applyAffinity(pIn1, aCol[i].affinity, encoding);
    if( (pIn1->flags & MEM_Null)==0 ){
      switch( aCol[i].eCType ){
        case COLTYPE_BLOB: {
          if( (pIn1->flags & MEM_Blob)==0 ) goto vdbe_type_error;
          break;
        }
        case COLTYPE_INTEGER:
        case COLTYPE_INT: {
          if( (pIn1->flags & MEM_Int)==0 ) goto vdbe_type_error;
          break;
        }
        case COLTYPE_TEXT: {
          if( (pIn1->flags & MEM_Str)==0 ) goto vdbe_type_error;
          break;
        }
        case COLTYPE_REAL: {
          if( pIn1->flags & MEM_Int ){
            /* When applying REAL affinity, if the result is still an MEM_Int
            ** that will fit in 6 bytes, then change the type to MEM_IntReal
            ** so that we keep the high-resolution integer value but know that
            ** the type really wants to be REAL. */
            testcase( pIn1->u.i==140737488355328LL );
            testcase( pIn1->u.i==140737488355327LL );
            testcase( pIn1->u.i==-140737488355328LL );
            testcase( pIn1->u.i==-140737488355329LL );
            if( pIn1->u.i<=140737488355327LL && pIn1->u.i>=-140737488355328LL){
              pIn1->flags |= MEM_IntReal;
              pIn1->flags &= ~MEM_Int;
            }else{
              pIn1->u.r = (double)pIn1->u.i;
              pIn1->flags |= MEM_Real;
              pIn1->flags &= ~MEM_Int;
            }
          }else if( (pIn1->flags & MEM_Real)==0 ){
            goto vdbe_type_error;
          }
          break;
        }
        default: {
          /* COLTYPE_ANY.  Accept anything. */
          break;
        }
      }
    }
    REGISTER_TRACE((int)(pIn1-aMem), pIn1);
    pIn1++;
  }
  assert( pIn1 == &aMem[pOp->p1+pOp->p2] );
  break;

vdbe_type_error:
  sqlite3VdbeError(p, "cannot store %s value in %s column %s.%s",
     vdbeMemTypeName(pIn1), sqlite3StdType[aCol[i].eCType-1],
     pTab->zName, aCol[i].zCnName);
  rc = SQLITE_CONSTRAINT_DATATYPE;
  goto abort_due_to_error;
}

/* Opcode: Affinity P1 P2 * P4 *
** Synopsis: affinity(r[P1@P2])
**
** Apply affinities to a range of P2 registers starting with P1.
**
** P4 is a string that is P2 characters long. The N-th character of the
91511
91512
91513
91514
91515
91516
91517
91518
91519
91520
91521
91522
91523
91524
91525
  if( pOp->p4type==P4_TABLE && HAS_UPDATE_HOOK(db) ){
    assert( pC->iDb>=0 );
    zDb = db->aDb[pC->iDb].zDbSName;
    pTab = pOp->p4.pTab;
    assert( (pOp->p5 & OPFLAG_ISNOOP) || HasRowid(pTab) );
  }else{
    pTab = 0;
    zDb = 0;  /* Not needed.  Silence a compiler warning. */
  }

#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
  /* Invoke the pre-update hook, if any */
  if( pTab ){
    if( db->xPreUpdateCallback && !(pOp->p5 & OPFLAG_ISUPDATE) ){
      sqlite3VdbePreUpdateHook(p,pC,SQLITE_INSERT,zDb,pTab,x.nKey,pOp->p2,-1);







|







91697
91698
91699
91700
91701
91702
91703
91704
91705
91706
91707
91708
91709
91710
91711
  if( pOp->p4type==P4_TABLE && HAS_UPDATE_HOOK(db) ){
    assert( pC->iDb>=0 );
    zDb = db->aDb[pC->iDb].zDbSName;
    pTab = pOp->p4.pTab;
    assert( (pOp->p5 & OPFLAG_ISNOOP) || HasRowid(pTab) );
  }else{
    pTab = 0;
    zDb = 0;
  }

#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
  /* Invoke the pre-update hook, if any */
  if( pTab ){
    if( db->xPreUpdateCallback && !(pOp->p5 & OPFLAG_ISUPDATE) ){
      sqlite3VdbePreUpdateHook(p,pC,SQLITE_INSERT,zDb,pTab,x.nKey,pOp->p2,-1);
91664
91665
91666
91667
91668
91669
91670
91671
91672
91673
91674
91675
91676

91677
91678
91679
91680
91681
91682
91683
91684
    assert( pOp->p4.pTab!=0 );
    zDb = db->aDb[pC->iDb].zDbSName;
    pTab = pOp->p4.pTab;
    if( (pOp->p5 & OPFLAG_SAVEPOSITION)!=0 && pC->isTable ){
      pC->movetoTarget = sqlite3BtreeIntegerKey(pC->uc.pCursor);
    }
  }else{
    zDb = 0;   /* Not needed.  Silence a compiler warning. */
    pTab = 0;  /* Not needed.  Silence a compiler warning. */
  }

#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
  /* Invoke the pre-update-hook if required. */

  if( db->xPreUpdateCallback && pOp->p4.pTab ){
    assert( !(opflags & OPFLAG_ISUPDATE)
         || HasRowid(pTab)==0
         || (aMem[pOp->p3].flags & MEM_Int)
    );
    sqlite3VdbePreUpdateHook(p, pC,
        (opflags & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_DELETE,
        zDb, pTab, pC->movetoTarget,







|
|




>
|







91850
91851
91852
91853
91854
91855
91856
91857
91858
91859
91860
91861
91862
91863
91864
91865
91866
91867
91868
91869
91870
91871
    assert( pOp->p4.pTab!=0 );
    zDb = db->aDb[pC->iDb].zDbSName;
    pTab = pOp->p4.pTab;
    if( (pOp->p5 & OPFLAG_SAVEPOSITION)!=0 && pC->isTable ){
      pC->movetoTarget = sqlite3BtreeIntegerKey(pC->uc.pCursor);
    }
  }else{
    zDb = 0;
    pTab = 0;
  }

#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
  /* Invoke the pre-update-hook if required. */
  assert( db->xPreUpdateCallback==0 || pTab==pOp->p4.pTab );
  if( db->xPreUpdateCallback && pTab ){
    assert( !(opflags & OPFLAG_ISUPDATE)
         || HasRowid(pTab)==0
         || (aMem[pOp->p3].flags & MEM_Int)
    );
    sqlite3VdbePreUpdateHook(p, pC,
        (opflags & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_DELETE,
        zDb, pTab, pC->movetoTarget,
91711
91712
91713
91714
91715
91716
91717
91718
91719
91720
91721
91722
91723
91724
91725
  pC->cacheStatus = CACHE_STALE;
  pC->seekResult = 0;
  if( rc ) goto abort_due_to_error;

  /* Invoke the update-hook if required. */
  if( opflags & OPFLAG_NCHANGE ){
    p->nChange++;
    if( db->xUpdateCallback && HasRowid(pTab) ){
      db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE, zDb, pTab->zName,
          pC->movetoTarget);
      assert( pC->iDb>=0 );
    }
  }

  break;







|







91898
91899
91900
91901
91902
91903
91904
91905
91906
91907
91908
91909
91910
91911
91912
  pC->cacheStatus = CACHE_STALE;
  pC->seekResult = 0;
  if( rc ) goto abort_due_to_error;

  /* Invoke the update-hook if required. */
  if( opflags & OPFLAG_NCHANGE ){
    p->nChange++;
    if( db->xUpdateCallback && ALWAYS(pTab!=0) && HasRowid(pTab) ){
      db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE, zDb, pTab->zName,
          pC->movetoTarget);
      assert( pC->iDb>=0 );
    }
  }

  break;
92298
92299
92300
92301
92302
92303
92304
92305

92306
92307
92308
92309
92310
92311
92312
** index opened by cursor P1.
**
** If P5 is not zero, then raise an SQLITE_CORRUPT_INDEX error
** if no matching index entry is found.  This happens when running
** an UPDATE or DELETE statement and the index entry to be updated
** or deleted is not found.  For some uses of IdxDelete
** (example:  the EXCEPT operator) it does not matter that no matching
** entry is found.  For those cases, P5 is zero.

*/
case OP_IdxDelete: {
  VdbeCursor *pC;
  BtCursor *pCrsr;
  int res;
  UnpackedRecord r;








|
>







92485
92486
92487
92488
92489
92490
92491
92492
92493
92494
92495
92496
92497
92498
92499
92500
** index opened by cursor P1.
**
** If P5 is not zero, then raise an SQLITE_CORRUPT_INDEX error
** if no matching index entry is found.  This happens when running
** an UPDATE or DELETE statement and the index entry to be updated
** or deleted is not found.  For some uses of IdxDelete
** (example:  the EXCEPT operator) it does not matter that no matching
** entry is found.  For those cases, P5 is zero.  Also, do not raise
** this (self-correcting and non-critical) error if in writable_schema mode.
*/
case OP_IdxDelete: {
  VdbeCursor *pC;
  BtCursor *pCrsr;
  int res;
  UnpackedRecord r;

92324
92325
92326
92327
92328
92329
92330
92331
92332
92333
92334
92335
92336
92337
92338
  r.default_rc = 0;
  r.aMem = &aMem[pOp->p2];
  rc = sqlite3BtreeIndexMoveto(pCrsr, &r, &res);
  if( rc ) goto abort_due_to_error;
  if( res==0 ){
    rc = sqlite3BtreeDelete(pCrsr, BTREE_AUXDELETE);
    if( rc ) goto abort_due_to_error;
  }else if( pOp->p5 ){
    rc = sqlite3ReportError(SQLITE_CORRUPT_INDEX, __LINE__, "index corruption");
    goto abort_due_to_error;
  }
  assert( pC->deferredMoveto==0 );
  pC->cacheStatus = CACHE_STALE;
  pC->seekResult = 0;
  break;







|







92512
92513
92514
92515
92516
92517
92518
92519
92520
92521
92522
92523
92524
92525
92526
  r.default_rc = 0;
  r.aMem = &aMem[pOp->p2];
  rc = sqlite3BtreeIndexMoveto(pCrsr, &r, &res);
  if( rc ) goto abort_due_to_error;
  if( res==0 ){
    rc = sqlite3BtreeDelete(pCrsr, BTREE_AUXDELETE);
    if( rc ) goto abort_due_to_error;
  }else if( pOp->p5 && !sqlite3WritableSchema(db) ){
    rc = sqlite3ReportError(SQLITE_CORRUPT_INDEX, __LINE__, "index corruption");
    goto abort_due_to_error;
  }
  assert( pC->deferredMoveto==0 );
  pC->cacheStatus = CACHE_STALE;
  pC->seekResult = 0;
  break;
93989
93990
93991
93992
93993
93994
93995
93996
93997
93998
93999
94000
94001
94002
94003

  /* Grab the index number and argc parameters */
  assert( (pQuery->flags&MEM_Int)!=0 && pArgc->flags==MEM_Int );
  nArg = (int)pArgc->u.i;
  iQuery = (int)pQuery->u.i;

  /* Invoke the xFilter method */
  res = 0;
  apArg = p->apArg;
  for(i = 0; i<nArg; i++){
    apArg[i] = &pArgc[i+1];
  }
  rc = pModule->xFilter(pVCur, iQuery, pOp->p4.z, nArg, apArg);
  sqlite3VtabImportErrmsg(p, pVtab);
  if( rc ) goto abort_due_to_error;







<







94177
94178
94179
94180
94181
94182
94183

94184
94185
94186
94187
94188
94189
94190

  /* Grab the index number and argc parameters */
  assert( (pQuery->flags&MEM_Int)!=0 && pArgc->flags==MEM_Int );
  nArg = (int)pArgc->u.i;
  iQuery = (int)pQuery->u.i;

  /* Invoke the xFilter method */

  apArg = p->apArg;
  for(i = 0; i<nArg; i++){
    apArg[i] = &pArgc[i+1];
  }
  rc = pModule->xFilter(pVCur, iQuery, pOp->p4.z, nArg, apArg);
  sqlite3VtabImportErrmsg(p, pVtab);
  if( rc ) goto abort_due_to_error;
94079
94080
94081
94082
94083
94084
94085
94086
94087
94088
94089
94090
94091
94092
94093
*/
case OP_VNext: {   /* jump */
  sqlite3_vtab *pVtab;
  const sqlite3_module *pModule;
  int res;
  VdbeCursor *pCur;

  res = 0;
  pCur = p->apCsr[pOp->p1];
  assert( pCur->eCurType==CURTYPE_VTAB );
  if( pCur->nullRow ){
    break;
  }
  pVtab = pCur->uc.pVCur->pVtab;
  pModule = pVtab->pModule;







<







94266
94267
94268
94269
94270
94271
94272

94273
94274
94275
94276
94277
94278
94279
*/
case OP_VNext: {   /* jump */
  sqlite3_vtab *pVtab;
  const sqlite3_module *pModule;
  int res;
  VdbeCursor *pCur;


  pCur = p->apCsr[pOp->p1];
  assert( pCur->eCurType==CURTYPE_VTAB );
  if( pCur->nullRow ){
    break;
  }
  pVtab = pCur->uc.pVCur->pVtab;
  pModule = pVtab->pModule;
94621
94622
94623
94624
94625
94626
94627





94628
94629
94630
94631
94632
94633
94634
abort_due_to_error:
  if( db->mallocFailed ){
    rc = SQLITE_NOMEM_BKPT;
  }else if( rc==SQLITE_IOERR_CORRUPTFS ){
    rc = SQLITE_CORRUPT_BKPT;
  }
  assert( rc );





  if( p->zErrMsg==0 && rc!=SQLITE_IOERR_NOMEM ){
    sqlite3VdbeError(p, "%s", sqlite3ErrStr(rc));
  }
  p->rc = rc;
  sqlite3SystemError(db, rc);
  testcase( sqlite3GlobalConfig.xLog!=0 );
  sqlite3_log(rc, "statement aborts at %d: [%s] %s",







>
>
>
>
>







94807
94808
94809
94810
94811
94812
94813
94814
94815
94816
94817
94818
94819
94820
94821
94822
94823
94824
94825
abort_due_to_error:
  if( db->mallocFailed ){
    rc = SQLITE_NOMEM_BKPT;
  }else if( rc==SQLITE_IOERR_CORRUPTFS ){
    rc = SQLITE_CORRUPT_BKPT;
  }
  assert( rc );
#ifdef SQLITE_DEBUG
  if( db->flags & SQLITE_VdbeTrace ){
     printf("ABORT-due-to-error.  rc=%d\n", rc);
  }
#endif
  if( p->zErrMsg==0 && rc!=SQLITE_IOERR_NOMEM ){
    sqlite3VdbeError(p, "%s", sqlite3ErrStr(rc));
  }
  p->rc = rc;
  sqlite3SystemError(db, rc);
  testcase( sqlite3GlobalConfig.xLog!=0 );
  sqlite3_log(rc, "statement aborts at %d: [%s] %s",
100212
100213
100214
100215
100216
100217
100218

100219
100220

100221

100222
100223
100224
100225
100226
100227
100228
      testcase( pExpr->op==TK_IN );
      if( ExprHasProperty(pExpr, EP_xIsSelect) ){
        int nRef = pNC->nRef;
        testcase( pNC->ncFlags & NC_IsCheck );
        testcase( pNC->ncFlags & NC_PartIdx );
        testcase( pNC->ncFlags & NC_IdxExpr );
        testcase( pNC->ncFlags & NC_GenCol );

        sqlite3ResolveNotValid(pParse, pNC, "subqueries",
                 NC_IsCheck|NC_PartIdx|NC_IdxExpr|NC_GenCol, pExpr);

        sqlite3WalkSelect(pWalker, pExpr->x.pSelect);

        assert( pNC->nRef>=nRef );
        if( nRef!=pNC->nRef ){
          ExprSetProperty(pExpr, EP_VarSelect);
          pNC->ncFlags |= NC_VarSelect;
        }
      }
      break;







>
|
<
>
|
>







100403
100404
100405
100406
100407
100408
100409
100410
100411

100412
100413
100414
100415
100416
100417
100418
100419
100420
100421
      testcase( pExpr->op==TK_IN );
      if( ExprHasProperty(pExpr, EP_xIsSelect) ){
        int nRef = pNC->nRef;
        testcase( pNC->ncFlags & NC_IsCheck );
        testcase( pNC->ncFlags & NC_PartIdx );
        testcase( pNC->ncFlags & NC_IdxExpr );
        testcase( pNC->ncFlags & NC_GenCol );
        if( pNC->ncFlags & NC_SelfRef ){
          notValidImpl(pParse, pNC, "subqueries", pExpr);

        }else{
          sqlite3WalkSelect(pWalker, pExpr->x.pSelect);
        }
        assert( pNC->nRef>=nRef );
        if( nRef!=pNC->nRef ){
          ExprSetProperty(pExpr, EP_VarSelect);
          pNC->ncFlags |= NC_VarSelect;
        }
      }
      break;
101142
101143
101144
101145
101146
101147
101148
101149
101150
101151
101152
101153
101154
101155
101156
/* Forward declarations */
static void exprCodeBetween(Parse*,Expr*,int,void(*)(Parse*,Expr*,int,int),int);
static int exprCodeVector(Parse *pParse, Expr *p, int *piToFree);

/*
** Return the affinity character for a single column of a table.
*/
SQLITE_PRIVATE char sqlite3TableColumnAffinity(Table *pTab, int iCol){
  assert( iCol<pTab->nCol );
  return iCol>=0 ? pTab->aCol[iCol].affinity : SQLITE_AFF_INTEGER;
}

/*
** Return the 'affinity' of the expression pExpr if any.
**







|







101335
101336
101337
101338
101339
101340
101341
101342
101343
101344
101345
101346
101347
101348
101349
/* Forward declarations */
static void exprCodeBetween(Parse*,Expr*,int,void(*)(Parse*,Expr*,int,int),int);
static int exprCodeVector(Parse *pParse, Expr *p, int *piToFree);

/*
** Return the affinity character for a single column of a table.
*/
SQLITE_PRIVATE char sqlite3TableColumnAffinity(const Table *pTab, int iCol){
  assert( iCol<pTab->nCol );
  return iCol>=0 ? pTab->aCol[iCol].affinity : SQLITE_AFF_INTEGER;
}

/*
** Return the 'affinity' of the expression pExpr if any.
**
101213
101214
101215
101216
101217
101218
101219
101220
101221
101222
101223
101224
101225
101226
101227
101228
101229
101230
101231
101232
101233
101234
101235




101236
101237
101238
101239
101240
101241
101242
** sequence named by pToken.   Return a pointer to a new Expr node that
** implements the COLLATE operator.
**
** If a memory allocation error occurs, that fact is recorded in pParse->db
** and the pExpr parameter is returned unchanged.
*/
SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken(
  Parse *pParse,           /* Parsing context */
  Expr *pExpr,             /* Add the "COLLATE" clause to this expression */
  const Token *pCollName,  /* Name of collating sequence */
  int dequote              /* True to dequote pCollName */
){
  if( pCollName->n>0 ){
    Expr *pNew = sqlite3ExprAlloc(pParse->db, TK_COLLATE, pCollName, dequote);
    if( pNew ){
      pNew->pLeft = pExpr;
      pNew->flags |= EP_Collate|EP_Skip;
      pExpr = pNew;
    }
  }
  return pExpr;
}
SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString(Parse *pParse, Expr *pExpr, const char *zC){




  Token s;
  assert( zC!=0 );
  sqlite3TokenInit(&s, (char*)zC);
  return sqlite3ExprAddCollateToken(pParse, pExpr, &s, 0);
}

/*







|














|
>
>
>
>







101406
101407
101408
101409
101410
101411
101412
101413
101414
101415
101416
101417
101418
101419
101420
101421
101422
101423
101424
101425
101426
101427
101428
101429
101430
101431
101432
101433
101434
101435
101436
101437
101438
101439
** sequence named by pToken.   Return a pointer to a new Expr node that
** implements the COLLATE operator.
**
** If a memory allocation error occurs, that fact is recorded in pParse->db
** and the pExpr parameter is returned unchanged.
*/
SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken(
  const Parse *pParse,     /* Parsing context */
  Expr *pExpr,             /* Add the "COLLATE" clause to this expression */
  const Token *pCollName,  /* Name of collating sequence */
  int dequote              /* True to dequote pCollName */
){
  if( pCollName->n>0 ){
    Expr *pNew = sqlite3ExprAlloc(pParse->db, TK_COLLATE, pCollName, dequote);
    if( pNew ){
      pNew->pLeft = pExpr;
      pNew->flags |= EP_Collate|EP_Skip;
      pExpr = pNew;
    }
  }
  return pExpr;
}
SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString(
  const Parse *pParse,  /* Parsing context */
  Expr *pExpr,          /* Add the "COLLATE" clause to this expression */
  const char *zC        /* The collating sequence name */
){
  Token s;
  assert( zC!=0 );
  sqlite3TokenInit(&s, (char*)zC);
  return sqlite3ExprAddCollateToken(pParse, pExpr, &s, 0);
}

/*
101530
101531
101532
101533
101534
101535
101536
101537
101538
101539
101540
101541
101542
101543
101544
101545
101546
101547
101548
101549
101550
101551
101552
101553
101554
**
** A vector is defined as any expression that results in two or more
** columns of result.  Every TK_VECTOR node is an vector because the
** parser will not generate a TK_VECTOR with fewer than two entries.
** But a TK_SELECT might be either a vector or a scalar. It is only
** considered a vector if it has two or more result columns.
*/
SQLITE_PRIVATE int sqlite3ExprIsVector(Expr *pExpr){
  return sqlite3ExprVectorSize(pExpr)>1;
}

/*
** If the expression passed as the only argument is of type TK_VECTOR
** return the number of expressions in the vector. Or, if the expression
** is a sub-select, return the number of columns in the sub-select. For
** any other type of expression, return 1.
*/
SQLITE_PRIVATE int sqlite3ExprVectorSize(Expr *pExpr){
  u8 op = pExpr->op;
  if( op==TK_REGISTER ) op = pExpr->op2;
  if( op==TK_VECTOR ){
    return pExpr->x.pList->nExpr;
  }else if( op==TK_SELECT ){
    return pExpr->x.pSelect->pEList->nExpr;
  }else{







|









|







101727
101728
101729
101730
101731
101732
101733
101734
101735
101736
101737
101738
101739
101740
101741
101742
101743
101744
101745
101746
101747
101748
101749
101750
101751
**
** A vector is defined as any expression that results in two or more
** columns of result.  Every TK_VECTOR node is an vector because the
** parser will not generate a TK_VECTOR with fewer than two entries.
** But a TK_SELECT might be either a vector or a scalar. It is only
** considered a vector if it has two or more result columns.
*/
SQLITE_PRIVATE int sqlite3ExprIsVector(const Expr *pExpr){
  return sqlite3ExprVectorSize(pExpr)>1;
}

/*
** If the expression passed as the only argument is of type TK_VECTOR
** return the number of expressions in the vector. Or, if the expression
** is a sub-select, return the number of columns in the sub-select. For
** any other type of expression, return 1.
*/
SQLITE_PRIVATE int sqlite3ExprVectorSize(const Expr *pExpr){
  u8 op = pExpr->op;
  if( op==TK_REGISTER ) op = pExpr->op2;
  if( op==TK_VECTOR ){
    return pExpr->x.pList->nExpr;
  }else if( op==TK_SELECT ){
    return pExpr->x.pSelect->pEList->nExpr;
  }else{
101633
101634
101635
101636
101637
101638
101639
101640








101641
101642
101643
101644
101645
101646
101647
101648
101649
    pRet = sqlite3PExpr(pParse, TK_SELECT_COLUMN, 0, 0);
    if( pRet ){
      pRet->iTable = nField;
      pRet->iColumn = iField;
      pRet->pLeft = pVector;
    }
  }else{
    if( pVector->op==TK_VECTOR ) pVector = pVector->x.pList->a[iField].pExpr;








    pRet = sqlite3ExprDup(pParse->db, pVector, 0);
    sqlite3RenameTokenRemap(pParse, pRet, pVector);
  }
  return pRet;
}

/*
** If expression pExpr is of type TK_SELECT, generate code to evaluate
** it. Return the register in which the result is stored (or, if the







|
>
>
>
>
>
>
>
>

<







101830
101831
101832
101833
101834
101835
101836
101837
101838
101839
101840
101841
101842
101843
101844
101845
101846

101847
101848
101849
101850
101851
101852
101853
    pRet = sqlite3PExpr(pParse, TK_SELECT_COLUMN, 0, 0);
    if( pRet ){
      pRet->iTable = nField;
      pRet->iColumn = iField;
      pRet->pLeft = pVector;
    }
  }else{
    if( pVector->op==TK_VECTOR ){
      Expr **ppVector = &pVector->x.pList->a[iField].pExpr;
      pVector = *ppVector;
      if( IN_RENAME_OBJECT ){
        /* This must be a vector UPDATE inside a trigger */
        *ppVector = 0;
        return pVector;
      }
    }
    pRet = sqlite3ExprDup(pParse->db, pVector, 0);

  }
  return pRet;
}

/*
** If expression pExpr is of type TK_SELECT, generate code to evaluate
** it. Return the register in which the result is stored (or, if the
101828
101829
101830
101831
101832
101833
101834
101835
101836
101837
101838
101839
101840
101841
101842
101843
101844
101845
101846
101847
101848
101849
101850
101851
101852
101853
101854
101855
101856
101857
101858
** of any expression tree referenced by the structure passed as the
** first argument.
**
** If this maximum height is greater than the current value pointed
** to by pnHeight, the second parameter, then set *pnHeight to that
** value.
*/
static void heightOfExpr(Expr *p, int *pnHeight){
  if( p ){
    if( p->nHeight>*pnHeight ){
      *pnHeight = p->nHeight;
    }
  }
}
static void heightOfExprList(ExprList *p, int *pnHeight){
  if( p ){
    int i;
    for(i=0; i<p->nExpr; i++){
      heightOfExpr(p->a[i].pExpr, pnHeight);
    }
  }
}
static void heightOfSelect(Select *pSelect, int *pnHeight){
  Select *p;
  for(p=pSelect; p; p=p->pPrior){
    heightOfExpr(p->pWhere, pnHeight);
    heightOfExpr(p->pHaving, pnHeight);
    heightOfExpr(p->pLimit, pnHeight);
    heightOfExprList(p->pEList, pnHeight);
    heightOfExprList(p->pGroupBy, pnHeight);
    heightOfExprList(p->pOrderBy, pnHeight);







|






|







|
|







102032
102033
102034
102035
102036
102037
102038
102039
102040
102041
102042
102043
102044
102045
102046
102047
102048
102049
102050
102051
102052
102053
102054
102055
102056
102057
102058
102059
102060
102061
102062
** of any expression tree referenced by the structure passed as the
** first argument.
**
** If this maximum height is greater than the current value pointed
** to by pnHeight, the second parameter, then set *pnHeight to that
** value.
*/
static void heightOfExpr(const Expr *p, int *pnHeight){
  if( p ){
    if( p->nHeight>*pnHeight ){
      *pnHeight = p->nHeight;
    }
  }
}
static void heightOfExprList(const ExprList *p, int *pnHeight){
  if( p ){
    int i;
    for(i=0; i<p->nExpr; i++){
      heightOfExpr(p->a[i].pExpr, pnHeight);
    }
  }
}
static void heightOfSelect(const Select *pSelect, int *pnHeight){
  const Select *p;
  for(p=pSelect; p; p=p->pPrior){
    heightOfExpr(p->pWhere, pnHeight);
    heightOfExpr(p->pHaving, pnHeight);
    heightOfExpr(p->pLimit, pnHeight);
    heightOfExprList(p->pEList, pnHeight);
    heightOfExprList(p->pGroupBy, pnHeight);
    heightOfExprList(p->pOrderBy, pnHeight);
101896
101897
101898
101899
101900
101901
101902
101903
101904
101905
101906
101907
101908
101909
101910
  sqlite3ExprCheckHeight(pParse, p->nHeight);
}

/*
** Return the maximum height of any expression tree referenced
** by the select statement passed as an argument.
*/
SQLITE_PRIVATE int sqlite3SelectExprHeight(Select *p){
  int nHeight = 0;
  heightOfSelect(p, &nHeight);
  return nHeight;
}
#else /* ABOVE:  Height enforcement enabled.  BELOW: Height enforcement off */
/*
** Propagate all EP_Propagate flags from the Expr.x.pList into







|







102100
102101
102102
102103
102104
102105
102106
102107
102108
102109
102110
102111
102112
102113
102114
  sqlite3ExprCheckHeight(pParse, p->nHeight);
}

/*
** Return the maximum height of any expression tree referenced
** by the select statement passed as an argument.
*/
SQLITE_PRIVATE int sqlite3SelectExprHeight(const Select *p){
  int nHeight = 0;
  heightOfSelect(p, &nHeight);
  return nHeight;
}
#else /* ABOVE:  Height enforcement enabled.  BELOW: Height enforcement off */
/*
** Propagate all EP_Propagate flags from the Expr.x.pList into
102149
102150
102151
102152
102153
102154
102155
102156
102157
102158
102159
102160
102161
102162
102163
/*
** Construct a new expression node for a function with multiple
** arguments.
*/
SQLITE_PRIVATE Expr *sqlite3ExprFunction(
  Parse *pParse,        /* Parsing context */
  ExprList *pList,      /* Argument list */
  Token *pToken,        /* Name of the function */
  int eDistinct         /* SF_Distinct or SF_ALL or 0 */
){
  Expr *pNew;
  sqlite3 *db = pParse->db;
  assert( pToken );
  pNew = sqlite3ExprAlloc(db, TK_FUNCTION, pToken, 1);
  if( pNew==0 ){







|







102353
102354
102355
102356
102357
102358
102359
102360
102361
102362
102363
102364
102365
102366
102367
/*
** Construct a new expression node for a function with multiple
** arguments.
*/
SQLITE_PRIVATE Expr *sqlite3ExprFunction(
  Parse *pParse,        /* Parsing context */
  ExprList *pList,      /* Argument list */
  const Token *pToken,  /* Name of the function */
  int eDistinct         /* SF_Distinct or SF_ALL or 0 */
){
  Expr *pNew;
  sqlite3 *db = pParse->db;
  assert( pToken );
  pNew = sqlite3ExprAlloc(db, TK_FUNCTION, pToken, 1);
  if( pNew==0 ){
102187
102188
102189
102190
102191
102192
102193
102194
102195
102196
102197
102198
102199
102200
102201
102202
**    SQLITE_FUNC_UNSAFE    -     Usable if TRUSTED_SCHEMA or from
**                                top-level SQL
**
** If the function is not usable, create an error.
*/
SQLITE_PRIVATE void sqlite3ExprFunctionUsable(
  Parse *pParse,         /* Parsing and code generating context */
  Expr *pExpr,           /* The function invocation */
  FuncDef *pDef          /* The function being invoked */
){
  assert( !IN_RENAME_OBJECT );
  assert( (pDef->funcFlags & (SQLITE_FUNC_DIRECT|SQLITE_FUNC_UNSAFE))!=0 );
  if( ExprHasProperty(pExpr, EP_FromDDL) ){
    if( (pDef->funcFlags & SQLITE_FUNC_DIRECT)!=0
     || (pParse->db->flags & SQLITE_TrustedSchema)==0
    ){







|
|







102391
102392
102393
102394
102395
102396
102397
102398
102399
102400
102401
102402
102403
102404
102405
102406
**    SQLITE_FUNC_UNSAFE    -     Usable if TRUSTED_SCHEMA or from
**                                top-level SQL
**
** If the function is not usable, create an error.
*/
SQLITE_PRIVATE void sqlite3ExprFunctionUsable(
  Parse *pParse,         /* Parsing and code generating context */
  const Expr *pExpr,     /* The function invocation */
  const FuncDef *pDef    /* The function being invoked */
){
  assert( !IN_RENAME_OBJECT );
  assert( (pDef->funcFlags & (SQLITE_FUNC_DIRECT|SQLITE_FUNC_UNSAFE))!=0 );
  if( ExprHasProperty(pExpr, EP_FromDDL) ){
    if( (pDef->funcFlags & SQLITE_FUNC_DIRECT)!=0
     || (pParse->db->flags & SQLITE_TrustedSchema)==0
    ){
102368
102369
102370
102371
102372
102373
102374
102375
102376
102377
102378
102379
102380
102381
102382
}

/*
** Return the number of bytes allocated for the expression structure
** passed as the first argument. This is always one of EXPR_FULLSIZE,
** EXPR_REDUCEDSIZE or EXPR_TOKENONLYSIZE.
*/
static int exprStructSize(Expr *p){
  if( ExprHasProperty(p, EP_TokenOnly) ) return EXPR_TOKENONLYSIZE;
  if( ExprHasProperty(p, EP_Reduced) ) return EXPR_REDUCEDSIZE;
  return EXPR_FULLSIZE;
}

/*
** The dupedExpr*Size() routines each return the number of bytes required







|







102572
102573
102574
102575
102576
102577
102578
102579
102580
102581
102582
102583
102584
102585
102586
}

/*
** Return the number of bytes allocated for the expression structure
** passed as the first argument. This is always one of EXPR_FULLSIZE,
** EXPR_REDUCEDSIZE or EXPR_TOKENONLYSIZE.
*/
static int exprStructSize(const Expr *p){
  if( ExprHasProperty(p, EP_TokenOnly) ) return EXPR_TOKENONLYSIZE;
  if( ExprHasProperty(p, EP_Reduced) ) return EXPR_REDUCEDSIZE;
  return EXPR_FULLSIZE;
}

/*
** The dupedExpr*Size() routines each return the number of bytes required
102408
102409
102410
102411
102412
102413
102414
102415
102416
102417
102418
102419
102420
102421
102422
** later parts of the Expr object and that extra information might get chopped
** off if the expression is reduced.  Note also that it does not work to
** make an EXPRDUP_REDUCE copy of a reduced expression.  It is only legal
** to reduce a pristine expression tree from the parser.  The implementation
** of dupedExprStructSize() contain multiple assert() statements that attempt
** to enforce this constraint.
*/
static int dupedExprStructSize(Expr *p, int flags){
  int nSize;
  assert( flags==EXPRDUP_REDUCE || flags==0 ); /* Only one flag value allowed */
  assert( EXPR_FULLSIZE<=0xfff );
  assert( (0xfff & (EP_Reduced|EP_TokenOnly))==0 );
  if( 0==flags || p->op==TK_SELECT_COLUMN
#ifndef SQLITE_OMIT_WINDOWFUNC
   || ExprHasProperty(p, EP_WinFunc)







|







102612
102613
102614
102615
102616
102617
102618
102619
102620
102621
102622
102623
102624
102625
102626
** later parts of the Expr object and that extra information might get chopped
** off if the expression is reduced.  Note also that it does not work to
** make an EXPRDUP_REDUCE copy of a reduced expression.  It is only legal
** to reduce a pristine expression tree from the parser.  The implementation
** of dupedExprStructSize() contain multiple assert() statements that attempt
** to enforce this constraint.
*/
static int dupedExprStructSize(const Expr *p, int flags){
  int nSize;
  assert( flags==EXPRDUP_REDUCE || flags==0 ); /* Only one flag value allowed */
  assert( EXPR_FULLSIZE<=0xfff );
  assert( (0xfff & (EP_Reduced|EP_TokenOnly))==0 );
  if( 0==flags || p->op==TK_SELECT_COLUMN
#ifndef SQLITE_OMIT_WINDOWFUNC
   || ExprHasProperty(p, EP_WinFunc)
102439
102440
102441
102442
102443
102444
102445
102446
102447
102448
102449
102450
102451
102452
102453
102454
102455
102456
102457
102458
102459
102460
102461
102462
102463
102464
102465
102466
102467
102468
102469
102470
102471
102472
102473
102474
102475
102476
102477
102478
102479
102480
102481
102482
102483
102484
102485
102486
102487
102488
102489
102490
102491
102492
102493
}

/*
** This function returns the space in bytes required to store the copy
** of the Expr structure and a copy of the Expr.u.zToken string (if that
** string is defined.)
*/
static int dupedExprNodeSize(Expr *p, int flags){
  int nByte = dupedExprStructSize(p, flags) & 0xfff;
  if( !ExprHasProperty(p, EP_IntValue) && p->u.zToken ){
    nByte += sqlite3Strlen30NN(p->u.zToken)+1;
  }
  return ROUND8(nByte);
}

/*
** Return the number of bytes required to create a duplicate of the
** expression passed as the first argument. The second argument is a
** mask containing EXPRDUP_XXX flags.
**
** The value returned includes space to create a copy of the Expr struct
** itself and the buffer referred to by Expr.u.zToken, if any.
**
** If the EXPRDUP_REDUCE flag is set, then the return value includes
** space to duplicate all Expr nodes in the tree formed by Expr.pLeft
** and Expr.pRight variables (but not for any structures pointed to or
** descended from the Expr.x.pList or Expr.x.pSelect variables).
*/
static int dupedExprSize(Expr *p, int flags){
  int nByte = 0;
  if( p ){
    nByte = dupedExprNodeSize(p, flags);
    if( flags&EXPRDUP_REDUCE ){
      nByte += dupedExprSize(p->pLeft, flags) + dupedExprSize(p->pRight, flags);
    }
  }
  return nByte;
}

/*
** This function is similar to sqlite3ExprDup(), except that if pzBuffer
** is not NULL then *pzBuffer is assumed to point to a buffer large enough
** to store the copy of expression p, the copies of p->u.zToken
** (if applicable), and the copies of the p->pLeft and p->pRight expressions,
** if any. Before returning, *pzBuffer is set to the first byte past the
** portion of the buffer copied into by this function.
*/
static Expr *exprDup(sqlite3 *db, Expr *p, int dupFlags, u8 **pzBuffer){
  Expr *pNew;           /* Value to return */
  u8 *zAlloc;           /* Memory space from which to build Expr object */
  u32 staticFlag;       /* EP_Static if space not obtained from malloc */

  assert( db!=0 );
  assert( p );
  assert( dupFlags==0 || dupFlags==EXPRDUP_REDUCE );







|




















|


















|







102643
102644
102645
102646
102647
102648
102649
102650
102651
102652
102653
102654
102655
102656
102657
102658
102659
102660
102661
102662
102663
102664
102665
102666
102667
102668
102669
102670
102671
102672
102673
102674
102675
102676
102677
102678
102679
102680
102681
102682
102683
102684
102685
102686
102687
102688
102689
102690
102691
102692
102693
102694
102695
102696
102697
}

/*
** This function returns the space in bytes required to store the copy
** of the Expr structure and a copy of the Expr.u.zToken string (if that
** string is defined.)
*/
static int dupedExprNodeSize(const Expr *p, int flags){
  int nByte = dupedExprStructSize(p, flags) & 0xfff;
  if( !ExprHasProperty(p, EP_IntValue) && p->u.zToken ){
    nByte += sqlite3Strlen30NN(p->u.zToken)+1;
  }
  return ROUND8(nByte);
}

/*
** Return the number of bytes required to create a duplicate of the
** expression passed as the first argument. The second argument is a
** mask containing EXPRDUP_XXX flags.
**
** The value returned includes space to create a copy of the Expr struct
** itself and the buffer referred to by Expr.u.zToken, if any.
**
** If the EXPRDUP_REDUCE flag is set, then the return value includes
** space to duplicate all Expr nodes in the tree formed by Expr.pLeft
** and Expr.pRight variables (but not for any structures pointed to or
** descended from the Expr.x.pList or Expr.x.pSelect variables).
*/
static int dupedExprSize(const Expr *p, int flags){
  int nByte = 0;
  if( p ){
    nByte = dupedExprNodeSize(p, flags);
    if( flags&EXPRDUP_REDUCE ){
      nByte += dupedExprSize(p->pLeft, flags) + dupedExprSize(p->pRight, flags);
    }
  }
  return nByte;
}

/*
** This function is similar to sqlite3ExprDup(), except that if pzBuffer
** is not NULL then *pzBuffer is assumed to point to a buffer large enough
** to store the copy of expression p, the copies of p->u.zToken
** (if applicable), and the copies of the p->pLeft and p->pRight expressions,
** if any. Before returning, *pzBuffer is set to the first byte past the
** portion of the buffer copied into by this function.
*/
static Expr *exprDup(sqlite3 *db, const Expr *p, int dupFlags, u8 **pzBuffer){
  Expr *pNew;           /* Value to return */
  u8 *zAlloc;           /* Memory space from which to build Expr object */
  u32 staticFlag;       /* EP_Static if space not obtained from malloc */

  assert( db!=0 );
  assert( p );
  assert( dupFlags==0 || dupFlags==EXPRDUP_REDUCE );
102660
102661
102662
102663
102664
102665
102666
102667
102668
102669
102670
102671
102672
102673

102674
102675
102676
102677
102678
102679
102680
** Any tables that the SrcList might point to are not duplicated.
**
** The flags parameter contains a combination of the EXPRDUP_XXX flags.
** If the EXPRDUP_REDUCE flag is set, then the structure returned is a
** truncated version of the usual Expr structure that will be stored as
** part of the in-memory representation of the database schema.
*/
SQLITE_PRIVATE Expr *sqlite3ExprDup(sqlite3 *db, Expr *p, int flags){
  assert( flags==0 || flags==EXPRDUP_REDUCE );
  return p ? exprDup(db, p, flags, 0) : 0;
}
SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags){
  ExprList *pNew;
  struct ExprList_item *pItem, *pOldItem;

  int i;
  Expr *pPriorSelectColOld = 0;
  Expr *pPriorSelectColNew = 0;
  assert( db!=0 );
  if( p==0 ) return 0;
  pNew = sqlite3DbMallocRawNN(db, sqlite3DbMallocSize(db, p));
  if( pNew==0 ) return 0;







|



|

|
>







102864
102865
102866
102867
102868
102869
102870
102871
102872
102873
102874
102875
102876
102877
102878
102879
102880
102881
102882
102883
102884
102885
** Any tables that the SrcList might point to are not duplicated.
**
** The flags parameter contains a combination of the EXPRDUP_XXX flags.
** If the EXPRDUP_REDUCE flag is set, then the structure returned is a
** truncated version of the usual Expr structure that will be stored as
** part of the in-memory representation of the database schema.
*/
SQLITE_PRIVATE Expr *sqlite3ExprDup(sqlite3 *db, const Expr *p, int flags){
  assert( flags==0 || flags==EXPRDUP_REDUCE );
  return p ? exprDup(db, p, flags, 0) : 0;
}
SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3 *db, const ExprList *p, int flags){
  ExprList *pNew;
  struct ExprList_item *pItem;
  const struct ExprList_item *pOldItem;
  int i;
  Expr *pPriorSelectColOld = 0;
  Expr *pPriorSelectColNew = 0;
  assert( db!=0 );
  if( p==0 ) return 0;
  pNew = sqlite3DbMallocRawNN(db, sqlite3DbMallocSize(db, p));
  if( pNew==0 ) return 0;
102718
102719
102720
102721
102722
102723
102724
102725
102726
102727
102728
102729
102730
102731
102732
102733
102734
102735
102736
102737
102738
102739
102740
102741
102742
102743
102744
** If cursors, triggers, views and subqueries are all omitted from
** the build, then none of the following routines, except for
** sqlite3SelectDup(), can be called. sqlite3SelectDup() is sometimes
** called with a NULL argument.
*/
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER) \
 || !defined(SQLITE_OMIT_SUBQUERY)
SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p, int flags){
  SrcList *pNew;
  int i;
  int nByte;
  assert( db!=0 );
  if( p==0 ) return 0;
  nByte = sizeof(*p) + (p->nSrc>0 ? sizeof(p->a[0]) * (p->nSrc-1) : 0);
  pNew = sqlite3DbMallocRawNN(db, nByte );
  if( pNew==0 ) return 0;
  pNew->nSrc = pNew->nAlloc = p->nSrc;
  for(i=0; i<p->nSrc; i++){
    SrcItem *pNewItem = &pNew->a[i];
    SrcItem *pOldItem = &p->a[i];
    Table *pTab;
    pNewItem->pSchema = pOldItem->pSchema;
    pNewItem->zDatabase = sqlite3DbStrDup(db, pOldItem->zDatabase);
    pNewItem->zName = sqlite3DbStrDup(db, pOldItem->zName);
    pNewItem->zAlias = sqlite3DbStrDup(db, pOldItem->zAlias);
    pNewItem->fg = pOldItem->fg;
    pNewItem->iCursor = pOldItem->iCursor;







|











|







102923
102924
102925
102926
102927
102928
102929
102930
102931
102932
102933
102934
102935
102936
102937
102938
102939
102940
102941
102942
102943
102944
102945
102946
102947
102948
102949
** If cursors, triggers, views and subqueries are all omitted from
** the build, then none of the following routines, except for
** sqlite3SelectDup(), can be called. sqlite3SelectDup() is sometimes
** called with a NULL argument.
*/
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER) \
 || !defined(SQLITE_OMIT_SUBQUERY)
SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3 *db, const SrcList *p, int flags){
  SrcList *pNew;
  int i;
  int nByte;
  assert( db!=0 );
  if( p==0 ) return 0;
  nByte = sizeof(*p) + (p->nSrc>0 ? sizeof(p->a[0]) * (p->nSrc-1) : 0);
  pNew = sqlite3DbMallocRawNN(db, nByte );
  if( pNew==0 ) return 0;
  pNew->nSrc = pNew->nAlloc = p->nSrc;
  for(i=0; i<p->nSrc; i++){
    SrcItem *pNewItem = &pNew->a[i];
    const SrcItem *pOldItem = &p->a[i];
    Table *pTab;
    pNewItem->pSchema = pOldItem->pSchema;
    pNewItem->zDatabase = sqlite3DbStrDup(db, pOldItem->zDatabase);
    pNewItem->zName = sqlite3DbStrDup(db, pOldItem->zName);
    pNewItem->zAlias = sqlite3DbStrDup(db, pOldItem->zAlias);
    pNewItem->fg = pOldItem->fg;
    pNewItem->iCursor = pOldItem->iCursor;
102762
102763
102764
102765
102766
102767
102768
102769
102770
102771
102772
102773
102774
102775
102776
    pNewItem->pSelect = sqlite3SelectDup(db, pOldItem->pSelect, flags);
    pNewItem->pOn = sqlite3ExprDup(db, pOldItem->pOn, flags);
    pNewItem->pUsing = sqlite3IdListDup(db, pOldItem->pUsing);
    pNewItem->colUsed = pOldItem->colUsed;
  }
  return pNew;
}
SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3 *db, IdList *p){
  IdList *pNew;
  int i;
  assert( db!=0 );
  if( p==0 ) return 0;
  pNew = sqlite3DbMallocRawNN(db, sizeof(*pNew) );
  if( pNew==0 ) return 0;
  pNew->nId = p->nId;







|







102967
102968
102969
102970
102971
102972
102973
102974
102975
102976
102977
102978
102979
102980
102981
    pNewItem->pSelect = sqlite3SelectDup(db, pOldItem->pSelect, flags);
    pNewItem->pOn = sqlite3ExprDup(db, pOldItem->pOn, flags);
    pNewItem->pUsing = sqlite3IdListDup(db, pOldItem->pUsing);
    pNewItem->colUsed = pOldItem->colUsed;
  }
  return pNew;
}
SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3 *db, const IdList *p){
  IdList *pNew;
  int i;
  assert( db!=0 );
  if( p==0 ) return 0;
  pNew = sqlite3DbMallocRawNN(db, sizeof(*pNew) );
  if( pNew==0 ) return 0;
  pNew->nId = p->nId;
102786
102787
102788
102789
102790
102791
102792
102793
102794
102795
102796
102797
102798
102799
102800
102801
102802
102803
102804
    struct IdList_item *pNewItem = &pNew->a[i];
    struct IdList_item *pOldItem = &p->a[i];
    pNewItem->zName = sqlite3DbStrDup(db, pOldItem->zName);
    pNewItem->idx = pOldItem->idx;
  }
  return pNew;
}
SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, Select *pDup, int flags){
  Select *pRet = 0;
  Select *pNext = 0;
  Select **pp = &pRet;
  Select *p;

  assert( db!=0 );
  for(p=pDup; p; p=p->pPrior){
    Select *pNew = sqlite3DbMallocRawNN(db, sizeof(*p) );
    if( pNew==0 ) break;
    pNew->pEList = sqlite3ExprListDup(db, p->pEList, flags);
    pNew->pSrc = sqlite3SrcListDup(db, p->pSrc, flags);







|



|







102991
102992
102993
102994
102995
102996
102997
102998
102999
103000
103001
103002
103003
103004
103005
103006
103007
103008
103009
    struct IdList_item *pNewItem = &pNew->a[i];
    struct IdList_item *pOldItem = &p->a[i];
    pNewItem->zName = sqlite3DbStrDup(db, pOldItem->zName);
    pNewItem->idx = pOldItem->idx;
  }
  return pNew;
}
SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, const Select *pDup, int flags){
  Select *pRet = 0;
  Select *pNext = 0;
  Select **pp = &pRet;
  const Select *p;

  assert( db!=0 );
  for(p=pDup; p; p=p->pPrior){
    Select *pNew = sqlite3DbMallocRawNN(db, sizeof(*p) );
    if( pNew==0 ) break;
    pNew->pEList = sqlite3ExprListDup(db, p->pEList, flags);
    pNew->pSrc = sqlite3SrcListDup(db, p->pSrc, flags);
103031
103032
103033
103034
103035
103036
103037
103038
103039
103040
103041
103042
103043
103044
103045
103046
103047
103048
103049
103050
103051
103052
103053
103054
103055
103056
103057
103058
103059
103060
103061
103062
103063
** pList might be NULL following an OOM error.  But pName should never be
** NULL.  If a memory allocation fails, the pParse->db->mallocFailed flag
** is set.
*/
SQLITE_PRIVATE void sqlite3ExprListSetName(
  Parse *pParse,          /* Parsing context */
  ExprList *pList,        /* List to which to add the span. */
  Token *pName,           /* Name to be added */
  int dequote             /* True to cause the name to be dequoted */
){
  assert( pList!=0 || pParse->db->mallocFailed!=0 );
  assert( pParse->eParseMode!=PARSE_MODE_UNMAP || dequote==0 );
  if( pList ){
    struct ExprList_item *pItem;
    assert( pList->nExpr>0 );
    pItem = &pList->a[pList->nExpr-1];
    assert( pItem->zEName==0 );
    assert( pItem->eEName==ENAME_NAME );
    pItem->zEName = sqlite3DbStrNDup(pParse->db, pName->z, pName->n);
    if( dequote ){
      /* If dequote==0, then pName->z does not point to part of a DDL
      ** statement handled by the parser. And so no token need be added
      ** to the token-map.  */
      sqlite3Dequote(pItem->zEName);
      if( IN_RENAME_OBJECT ){
        sqlite3RenameTokenMap(pParse, (void*)pItem->zEName, pName);
      }
    }
  }
}

/*
** Set the ExprList.a[].zSpan element of the most recently added item







|

















|







103236
103237
103238
103239
103240
103241
103242
103243
103244
103245
103246
103247
103248
103249
103250
103251
103252
103253
103254
103255
103256
103257
103258
103259
103260
103261
103262
103263
103264
103265
103266
103267
103268
** pList might be NULL following an OOM error.  But pName should never be
** NULL.  If a memory allocation fails, the pParse->db->mallocFailed flag
** is set.
*/
SQLITE_PRIVATE void sqlite3ExprListSetName(
  Parse *pParse,          /* Parsing context */
  ExprList *pList,        /* List to which to add the span. */
  const Token *pName,     /* Name to be added */
  int dequote             /* True to cause the name to be dequoted */
){
  assert( pList!=0 || pParse->db->mallocFailed!=0 );
  assert( pParse->eParseMode!=PARSE_MODE_UNMAP || dequote==0 );
  if( pList ){
    struct ExprList_item *pItem;
    assert( pList->nExpr>0 );
    pItem = &pList->a[pList->nExpr-1];
    assert( pItem->zEName==0 );
    assert( pItem->eEName==ENAME_NAME );
    pItem->zEName = sqlite3DbStrNDup(pParse->db, pName->z, pName->n);
    if( dequote ){
      /* If dequote==0, then pName->z does not point to part of a DDL
      ** statement handled by the parser. And so no token need be added
      ** to the token-map.  */
      sqlite3Dequote(pItem->zEName);
      if( IN_RENAME_OBJECT ){
        sqlite3RenameTokenMap(pParse, (const void*)pItem->zEName, pName);
      }
    }
  }
}

/*
** Set the ExprList.a[].zSpan element of the most recently added item
103477
103478
103479
103480
103481
103482
103483
103484
103485
103486
103487
103488
103489
103490
103491
103492
103493
103494
103495
103496
103497
103498
103499
103500
103501
103502
103503
103504
103505
103506
103507
103508
103509
103510
103511
103512

/*
** If the expression p codes a constant integer that is small enough
** to fit in a 32-bit integer, return 1 and put the value of the integer
** in *pValue.  If the expression is not an integer or if it is too big
** to fit in a signed 32-bit integer, return 0 and leave *pValue unchanged.
*/
SQLITE_PRIVATE int sqlite3ExprIsInteger(Expr *p, int *pValue){
  int rc = 0;
  if( NEVER(p==0) ) return 0;  /* Used to only happen following on OOM */

  /* If an expression is an integer literal that fits in a signed 32-bit
  ** integer, then the EP_IntValue flag will have already been set */
  assert( p->op!=TK_INTEGER || (p->flags & EP_IntValue)!=0
           || sqlite3GetInt32(p->u.zToken, &rc)==0 );

  if( p->flags & EP_IntValue ){
    *pValue = p->u.iValue;
    return 1;
  }
  switch( p->op ){
    case TK_UPLUS: {
      rc = sqlite3ExprIsInteger(p->pLeft, pValue);
      break;
    }
    case TK_UMINUS: {
      int v;
      if( sqlite3ExprIsInteger(p->pLeft, &v) ){
        assert( v!=(-2147483647-1) );
        *pValue = -v;
        rc = 1;
      }
      break;
    }
    default: break;
  }







|


















|

|







103682
103683
103684
103685
103686
103687
103688
103689
103690
103691
103692
103693
103694
103695
103696
103697
103698
103699
103700
103701
103702
103703
103704
103705
103706
103707
103708
103709
103710
103711
103712
103713
103714
103715
103716
103717

/*
** If the expression p codes a constant integer that is small enough
** to fit in a 32-bit integer, return 1 and put the value of the integer
** in *pValue.  If the expression is not an integer or if it is too big
** to fit in a signed 32-bit integer, return 0 and leave *pValue unchanged.
*/
SQLITE_PRIVATE int sqlite3ExprIsInteger(const Expr *p, int *pValue){
  int rc = 0;
  if( NEVER(p==0) ) return 0;  /* Used to only happen following on OOM */

  /* If an expression is an integer literal that fits in a signed 32-bit
  ** integer, then the EP_IntValue flag will have already been set */
  assert( p->op!=TK_INTEGER || (p->flags & EP_IntValue)!=0
           || sqlite3GetInt32(p->u.zToken, &rc)==0 );

  if( p->flags & EP_IntValue ){
    *pValue = p->u.iValue;
    return 1;
  }
  switch( p->op ){
    case TK_UPLUS: {
      rc = sqlite3ExprIsInteger(p->pLeft, pValue);
      break;
    }
    case TK_UMINUS: {
      int v = 0;
      if( sqlite3ExprIsInteger(p->pLeft, &v) ){
        assert( ((unsigned int)v)!=0x80000000 );
        *pValue = -v;
        rc = 1;
      }
      break;
    }
    default: break;
  }
103610
103611
103612
103613
103614
103615
103616
103617
103618
103619
103620
103621
103622
103623
103624
** pX is the RHS of an IN operator.  If pX is a SELECT statement
** that can be simplified to a direct table access, then return
** a pointer to the SELECT statement.  If pX is not a SELECT statement,
** or if the SELECT statement needs to be manifested into a transient
** table, then return NULL.
*/
#ifndef SQLITE_OMIT_SUBQUERY
static Select *isCandidateForInOpt(Expr *pX){
  Select *p;
  SrcList *pSrc;
  ExprList *pEList;
  Table *pTab;
  int i;
  if( !ExprHasProperty(pX, EP_xIsSelect) ) return 0;  /* Not a subquery */
  if( ExprHasProperty(pX, EP_VarSelect)  ) return 0;  /* Correlated subq */







|







103815
103816
103817
103818
103819
103820
103821
103822
103823
103824
103825
103826
103827
103828
103829
** pX is the RHS of an IN operator.  If pX is a SELECT statement
** that can be simplified to a direct table access, then return
** a pointer to the SELECT statement.  If pX is not a SELECT statement,
** or if the SELECT statement needs to be manifested into a transient
** table, then return NULL.
*/
#ifndef SQLITE_OMIT_SUBQUERY
static Select *isCandidateForInOpt(const Expr *pX){
  Select *p;
  SrcList *pSrc;
  ExprList *pEList;
  Table *pTab;
  int i;
  if( !ExprHasProperty(pX, EP_xIsSelect) ) return 0;  /* Not a subquery */
  if( ExprHasProperty(pX, EP_VarSelect)  ) return 0;  /* Correlated subq */
103988
103989
103990
103991
103992
103993
103994
103995
103996
103997
103998
103999
104000
104001
104002
** Argument pExpr is an (?, ?...) IN(...) expression. This
** function allocates and returns a nul-terminated string containing
** the affinities to be used for each column of the comparison.
**
** It is the responsibility of the caller to ensure that the returned
** string is eventually freed using sqlite3DbFree().
*/
static char *exprINAffinity(Parse *pParse, Expr *pExpr){
  Expr *pLeft = pExpr->pLeft;
  int nVal = sqlite3ExprVectorSize(pLeft);
  Select *pSelect = (pExpr->flags & EP_xIsSelect) ? pExpr->x.pSelect : 0;
  char *zRet;

  assert( pExpr->op==TK_IN );
  zRet = sqlite3DbMallocRaw(pParse->db, nVal+1);







|







104193
104194
104195
104196
104197
104198
104199
104200
104201
104202
104203
104204
104205
104206
104207
** Argument pExpr is an (?, ?...) IN(...) expression. This
** function allocates and returns a nul-terminated string containing
** the affinities to be used for each column of the comparison.
**
** It is the responsibility of the caller to ensure that the returned
** string is eventually freed using sqlite3DbFree().
*/
static char *exprINAffinity(Parse *pParse, const Expr *pExpr){
  Expr *pLeft = pExpr->pLeft;
  int nVal = sqlite3ExprVectorSize(pLeft);
  Select *pSelect = (pExpr->flags & EP_xIsSelect) ? pExpr->x.pSelect : 0;
  char *zRet;

  assert( pExpr->op==TK_IN );
  zRet = sqlite3DbMallocRaw(pParse->db, nVal+1);
104987
104988
104989
104990
104991
104992
104993

104994
104995
104996
104997
104998
104999
105000
      break;
    }

  /***********************************************************************
  ** Test-only SQL functions that are only usable if enabled
  ** via SQLITE_TESTCTRL_INTERNAL_FUNCTIONS
  */

    case INLINEFUNC_expr_compare: {
      /* Compare two expressions using sqlite3ExprCompare() */
      assert( nFarg==2 );
      sqlite3VdbeAddOp2(v, OP_Integer,
         sqlite3ExprCompare(0,pFarg->a[0].pExpr, pFarg->a[1].pExpr,-1),
         target);
      break;







>







105192
105193
105194
105195
105196
105197
105198
105199
105200
105201
105202
105203
105204
105205
105206
      break;
    }

  /***********************************************************************
  ** Test-only SQL functions that are only usable if enabled
  ** via SQLITE_TESTCTRL_INTERNAL_FUNCTIONS
  */
#if !defined(SQLITE_UNTESTABLE)
    case INLINEFUNC_expr_compare: {
      /* Compare two expressions using sqlite3ExprCompare() */
      assert( nFarg==2 );
      sqlite3VdbeAddOp2(v, OP_Integer,
         sqlite3ExprCompare(0,pFarg->a[0].pExpr, pFarg->a[1].pExpr,-1),
         target);
      break;
105020
105021
105022
105023
105024
105025
105026
105027
105028
105029
105030
105031
105032
105033
105034
105035
105036
105037
105038
105039
105040
105041
105042
105043
105044
105045
105046
105047
105048
           target);
      }else{
        sqlite3VdbeAddOp2(v, OP_Null, 0, target);
      }
      break;
    }

#ifdef SQLITE_DEBUG
    case INLINEFUNC_affinity: {
      /* The AFFINITY() function evaluates to a string that describes
      ** the type affinity of the argument.  This is used for testing of
      ** the SQLite type logic.
      */
      const char *azAff[] = { "blob", "text", "numeric", "integer", "real" };
      char aff;
      assert( nFarg==1 );
      aff = sqlite3ExprAffinity(pFarg->a[0].pExpr);
      sqlite3VdbeLoadString(v, target,
              (aff<=SQLITE_AFF_NONE) ? "none" : azAff[aff-SQLITE_AFF_BLOB]);
      break;
    }
#endif
  }
  return target;
}


/*
** Generate code into the current Vdbe to evaluate the given







<













|







105226
105227
105228
105229
105230
105231
105232

105233
105234
105235
105236
105237
105238
105239
105240
105241
105242
105243
105244
105245
105246
105247
105248
105249
105250
105251
105252
105253
           target);
      }else{
        sqlite3VdbeAddOp2(v, OP_Null, 0, target);
      }
      break;
    }


    case INLINEFUNC_affinity: {
      /* The AFFINITY() function evaluates to a string that describes
      ** the type affinity of the argument.  This is used for testing of
      ** the SQLite type logic.
      */
      const char *azAff[] = { "blob", "text", "numeric", "integer", "real" };
      char aff;
      assert( nFarg==1 );
      aff = sqlite3ExprAffinity(pFarg->a[0].pExpr);
      sqlite3VdbeLoadString(v, target,
              (aff<=SQLITE_AFF_NONE) ? "none" : azAff[aff-SQLITE_AFF_BLOB]);
      break;
    }
#endif /* !defined(SQLITE_UNTESTABLE) */
  }
  return target;
}


/*
** Generate code into the current Vdbe to evaluate the given
105508
105509
105510
105511
105512
105513
105514
105515
105516
105517
105518
105519
105520
105521
105522
      }
#endif
      if( pDef->funcFlags & SQLITE_FUNC_NEEDCOLL ){
        if( !pColl ) pColl = db->pDfltColl;
        sqlite3VdbeAddOp4(v, OP_CollSeq, 0, 0, 0, (char *)pColl, P4_COLLSEQ);
      }
#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
      if( pDef->funcFlags & SQLITE_FUNC_OFFSET ){
        Expr *pArg = pFarg->a[0].pExpr;
        if( pArg->op==TK_COLUMN ){
          sqlite3VdbeAddOp3(v, OP_Offset, pArg->iTable, pArg->iColumn, target);
        }else{
          sqlite3VdbeAddOp2(v, OP_Null, 0, target);
        }
      }else







|







105713
105714
105715
105716
105717
105718
105719
105720
105721
105722
105723
105724
105725
105726
105727
      }
#endif
      if( pDef->funcFlags & SQLITE_FUNC_NEEDCOLL ){
        if( !pColl ) pColl = db->pDfltColl;
        sqlite3VdbeAddOp4(v, OP_CollSeq, 0, 0, 0, (char *)pColl, P4_COLLSEQ);
      }
#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
      if( (pDef->funcFlags & SQLITE_FUNC_OFFSET)!=0 && ALWAYS(pFarg!=0) ){
        Expr *pArg = pFarg->a[0].pExpr;
        if( pArg->op==TK_COLUMN ){
          sqlite3VdbeAddOp3(v, OP_Offset, pArg->iTable, pArg->iColumn, target);
        }else{
          sqlite3VdbeAddOp2(v, OP_Null, 0, target);
        }
      }else
105907
105908
105909
105910
105911
105912
105913
105914
105915
105916
105917
105918
105919
105920
105921
  assert( pExpr==0 || !ExprHasVVAProperty(pExpr,EP_Immutable) );
  assert( target>0 && target<=pParse->nMem );
  assert( pParse->pVdbe!=0 || pParse->db->mallocFailed );
  if( pParse->pVdbe==0 ) return;
  inReg = sqlite3ExprCodeTarget(pParse, pExpr, target);
  if( inReg!=target ){
    u8 op;
    if( ExprHasProperty(pExpr,EP_Subquery) ){
      op = OP_Copy;
    }else{
      op = OP_SCopy;
    }
    sqlite3VdbeAddOp2(pParse->pVdbe, op, inReg, target);
  }
}







|







106112
106113
106114
106115
106116
106117
106118
106119
106120
106121
106122
106123
106124
106125
106126
  assert( pExpr==0 || !ExprHasVVAProperty(pExpr,EP_Immutable) );
  assert( target>0 && target<=pParse->nMem );
  assert( pParse->pVdbe!=0 || pParse->db->mallocFailed );
  if( pParse->pVdbe==0 ) return;
  inReg = sqlite3ExprCodeTarget(pParse, pExpr, target);
  if( inReg!=target ){
    u8 op;
    if( ALWAYS(pExpr) && ExprHasProperty(pExpr,EP_Subquery) ){
      op = OP_Copy;
    }else{
      op = OP_SCopy;
    }
    sqlite3VdbeAddOp2(pParse->pVdbe, op, inReg, target);
  }
}
106445
106446
106447
106448
106449
106450
106451
106452




106453
106454
106455
106456
106457
106458
106459
** to re-prepare each time a new value is bound to variable pVar.
**
** Additionally, if pExpr is a simple SQL value and the value is the
** same as that currently bound to variable pVar, non-zero is returned.
** Otherwise, if the values are not the same or if pExpr is not a simple
** SQL value, zero is returned.
*/
static int exprCompareVariable(Parse *pParse, Expr *pVar, Expr *pExpr){




  int res = 0;
  int iVar;
  sqlite3_value *pL, *pR = 0;

  sqlite3ValueFromExpr(pParse->db, pExpr, SQLITE_UTF8, SQLITE_AFF_BLOB, &pR);
  if( pR ){
    iVar = pVar->iColumn;







|
>
>
>
>







106650
106651
106652
106653
106654
106655
106656
106657
106658
106659
106660
106661
106662
106663
106664
106665
106666
106667
106668
** to re-prepare each time a new value is bound to variable pVar.
**
** Additionally, if pExpr is a simple SQL value and the value is the
** same as that currently bound to variable pVar, non-zero is returned.
** Otherwise, if the values are not the same or if pExpr is not a simple
** SQL value, zero is returned.
*/
static int exprCompareVariable(
  const Parse *pParse,
  const Expr *pVar,
  const Expr *pExpr
){
  int res = 0;
  int iVar;
  sqlite3_value *pL, *pR = 0;

  sqlite3ValueFromExpr(pParse->db, pExpr, SQLITE_UTF8, SQLITE_AFF_BLOB, &pR);
  if( pR ){
    iVar = pVar->iColumn;
106497
106498
106499
106500
106501
106502
106503
106504





106505
106506
106507
106508
106509
106510
106511
** If pParse is not NULL then TK_VARIABLE terms in pA with bindings in
** pParse->pReprepare can be matched against literals in pB.  The
** pParse->pVdbe->expmask bitmask is updated for each variable referenced.
** If pParse is NULL (the normal case) then any TK_VARIABLE term in
** Argument pParse should normally be NULL. If it is not NULL and pA or
** pB causes a return value of 2.
*/
SQLITE_PRIVATE int sqlite3ExprCompare(Parse *pParse, Expr *pA, Expr *pB, int iTab){





  u32 combinedFlags;
  if( pA==0 || pB==0 ){
    return pB==pA ? 0 : 2;
  }
  if( pParse && pA->op==TK_VARIABLE && exprCompareVariable(pParse, pA, pB) ){
    return 0;
  }







|
>
>
>
>
>







106706
106707
106708
106709
106710
106711
106712
106713
106714
106715
106716
106717
106718
106719
106720
106721
106722
106723
106724
106725
** If pParse is not NULL then TK_VARIABLE terms in pA with bindings in
** pParse->pReprepare can be matched against literals in pB.  The
** pParse->pVdbe->expmask bitmask is updated for each variable referenced.
** If pParse is NULL (the normal case) then any TK_VARIABLE term in
** Argument pParse should normally be NULL. If it is not NULL and pA or
** pB causes a return value of 2.
*/
SQLITE_PRIVATE int sqlite3ExprCompare(
  const Parse *pParse,
  const Expr *pA,
  const Expr *pB,
  int iTab
){
  u32 combinedFlags;
  if( pA==0 || pB==0 ){
    return pB==pA ? 0 : 2;
  }
  if( pParse && pA->op==TK_VARIABLE && exprCompareVariable(pParse, pA, pB) ){
    return 0;
  }
106581
106582
106583
106584
106585
106586
106587
106588
106589
106590
106591
106592
106593
106594
106595
106596
106597
106598
106599
106600
106601
106602
106603
106604
106605
106606
106607
106608
106609
106610
106611
106612
106613
106614
106615
106616
106617
106618
106619
106620
106621
106622
106623
106624
106625
106626
106627
106628
106629
106630
** only consequence will be disabled optimizations.  But this routine
** must never return 0 if the two ExprList objects are different, or
** a malfunction will result.
**
** Two NULL pointers are considered to be the same.  But a NULL pointer
** always differs from a non-NULL pointer.
*/
SQLITE_PRIVATE int sqlite3ExprListCompare(ExprList *pA, ExprList *pB, int iTab){
  int i;
  if( pA==0 && pB==0 ) return 0;
  if( pA==0 || pB==0 ) return 1;
  if( pA->nExpr!=pB->nExpr ) return 1;
  for(i=0; i<pA->nExpr; i++){
    int res;
    Expr *pExprA = pA->a[i].pExpr;
    Expr *pExprB = pB->a[i].pExpr;
    if( pA->a[i].sortFlags!=pB->a[i].sortFlags ) return 1;
    if( (res = sqlite3ExprCompare(0, pExprA, pExprB, iTab)) ) return res;
  }
  return 0;
}

/*
** Like sqlite3ExprCompare() except COLLATE operators at the top-level
** are ignored.
*/
SQLITE_PRIVATE int sqlite3ExprCompareSkip(Expr *pA, Expr *pB, int iTab){
  return sqlite3ExprCompare(0,
             sqlite3ExprSkipCollateAndLikely(pA),
             sqlite3ExprSkipCollateAndLikely(pB),
             iTab);
}

/*
** Return non-zero if Expr p can only be true if pNN is not NULL.
**
** Or if seenNot is true, return non-zero if Expr p can only be
** non-NULL if pNN is not NULL
*/
static int exprImpliesNotNull(
  Parse *pParse,      /* Parsing context */
  Expr *p,            /* The expression to be checked */
  Expr *pNN,          /* The expression that is NOT NULL */
  int iTab,           /* Table being evaluated */
  int seenNot         /* Return true only if p can be any non-NULL value */
){
  assert( p );
  assert( pNN );
  if( sqlite3ExprCompare(pParse, p, pNN, iTab)==0 ){
    return pNN->op!=TK_NULL;







|


















|













|
|
|







106795
106796
106797
106798
106799
106800
106801
106802
106803
106804
106805
106806
106807
106808
106809
106810
106811
106812
106813
106814
106815
106816
106817
106818
106819
106820
106821
106822
106823
106824
106825
106826
106827
106828
106829
106830
106831
106832
106833
106834
106835
106836
106837
106838
106839
106840
106841
106842
106843
106844
** only consequence will be disabled optimizations.  But this routine
** must never return 0 if the two ExprList objects are different, or
** a malfunction will result.
**
** Two NULL pointers are considered to be the same.  But a NULL pointer
** always differs from a non-NULL pointer.
*/
SQLITE_PRIVATE int sqlite3ExprListCompare(const ExprList *pA, const ExprList *pB, int iTab){
  int i;
  if( pA==0 && pB==0 ) return 0;
  if( pA==0 || pB==0 ) return 1;
  if( pA->nExpr!=pB->nExpr ) return 1;
  for(i=0; i<pA->nExpr; i++){
    int res;
    Expr *pExprA = pA->a[i].pExpr;
    Expr *pExprB = pB->a[i].pExpr;
    if( pA->a[i].sortFlags!=pB->a[i].sortFlags ) return 1;
    if( (res = sqlite3ExprCompare(0, pExprA, pExprB, iTab)) ) return res;
  }
  return 0;
}

/*
** Like sqlite3ExprCompare() except COLLATE operators at the top-level
** are ignored.
*/
SQLITE_PRIVATE int sqlite3ExprCompareSkip(Expr *pA,Expr *pB, int iTab){
  return sqlite3ExprCompare(0,
             sqlite3ExprSkipCollateAndLikely(pA),
             sqlite3ExprSkipCollateAndLikely(pB),
             iTab);
}

/*
** Return non-zero if Expr p can only be true if pNN is not NULL.
**
** Or if seenNot is true, return non-zero if Expr p can only be
** non-NULL if pNN is not NULL
*/
static int exprImpliesNotNull(
  const Parse *pParse,/* Parsing context */
  const Expr *p,      /* The expression to be checked */
  const Expr *pNN,    /* The expression that is NOT NULL */
  int iTab,           /* Table being evaluated */
  int seenNot         /* Return true only if p can be any non-NULL value */
){
  assert( p );
  assert( pNN );
  if( sqlite3ExprCompare(pParse, p, pNN, iTab)==0 ){
    return pNN->op!=TK_NULL;
106709
106710
106711
106712
106713
106714
106715
106716





106717
106718
106719
106720
106721
106722
106723
** modified to record which bound variables are referenced.  If pParse
** is NULL, then false will be returned if pE1 contains any bound variables.
**
** When in doubt, return false.  Returning true might give a performance
** improvement.  Returning false might cause a performance reduction, but
** it will always give the correct answer and is hence always safe.
*/
SQLITE_PRIVATE int sqlite3ExprImpliesExpr(Parse *pParse, Expr *pE1, Expr *pE2, int iTab){





  if( sqlite3ExprCompare(pParse, pE1, pE2, iTab)==0 ){
    return 1;
  }
  if( pE2->op==TK_OR
   && (sqlite3ExprImpliesExpr(pParse, pE1, pE2->pLeft, iTab)
             || sqlite3ExprImpliesExpr(pParse, pE1, pE2->pRight, iTab) )
  ){







|
>
>
>
>
>







106923
106924
106925
106926
106927
106928
106929
106930
106931
106932
106933
106934
106935
106936
106937
106938
106939
106940
106941
106942
** modified to record which bound variables are referenced.  If pParse
** is NULL, then false will be returned if pE1 contains any bound variables.
**
** When in doubt, return false.  Returning true might give a performance
** improvement.  Returning false might cause a performance reduction, but
** it will always give the correct answer and is hence always safe.
*/
SQLITE_PRIVATE int sqlite3ExprImpliesExpr(
  const Parse *pParse,
  const Expr *pE1,
  const Expr *pE2,
  int iTab
){
  if( sqlite3ExprCompare(pParse, pE1, pE2, iTab)==0 ){
    return 1;
  }
  if( pE2->op==TK_OR
   && (sqlite3ExprImpliesExpr(pParse, pE1, pE2->pLeft, iTab)
             || sqlite3ExprImpliesExpr(pParse, pE1, pE2->pRight, iTab) )
  ){
107998
107999
108000
108001
108002
108003
108004
108005
108006
108007
108008
108009
108010
108011
108012
108013
  if( !zNew ) goto exit_rename_column;
  assert( pNew->n>0 );
  bQuote = sqlite3Isquote(pNew->z[0]);
  sqlite3NestedParse(pParse,
      "UPDATE \"%w\"." DFLT_SCHEMA_TABLE " SET "
      "sql = sqlite_rename_column(sql, type, name, %Q, %Q, %d, %Q, %d, %d) "
      "WHERE name NOT LIKE 'sqliteX_%%' ESCAPE 'X' "
      " AND (type != 'index' OR tbl_name = %Q)"
      " AND sql NOT LIKE 'create virtual%%'",
      zDb,
      zDb, pTab->zName, iCol, zNew, bQuote, iSchema==1,
      pTab->zName
  );

  sqlite3NestedParse(pParse,
      "UPDATE temp." DFLT_SCHEMA_TABLE " SET "







|
<







108217
108218
108219
108220
108221
108222
108223
108224

108225
108226
108227
108228
108229
108230
108231
  if( !zNew ) goto exit_rename_column;
  assert( pNew->n>0 );
  bQuote = sqlite3Isquote(pNew->z[0]);
  sqlite3NestedParse(pParse,
      "UPDATE \"%w\"." DFLT_SCHEMA_TABLE " SET "
      "sql = sqlite_rename_column(sql, type, name, %Q, %Q, %d, %Q, %d, %d) "
      "WHERE name NOT LIKE 'sqliteX_%%' ESCAPE 'X' "
      " AND (type != 'index' OR tbl_name = %Q)",

      zDb,
      zDb, pTab->zName, iCol, zNew, bQuote, iSchema==1,
      pTab->zName
  );

  sqlite3NestedParse(pParse,
      "UPDATE temp." DFLT_SCHEMA_TABLE " SET "
108041
108042
108043
108044
108045
108046
108047
108048
108049
108050
108051
108052
108053
108054
108055
** routine is used to keep the mapping current.
**
** After the parse finishes, renameTokenFind() routine can be used
** to look up the actual token value that created some element in
** the parse tree.
*/
struct RenameToken {
  void *p;               /* Parse tree element created by token t */
  Token t;               /* The token that created parse tree element p */
  RenameToken *pNext;    /* Next is a list of all RenameToken objects */
};

/*
** The context of an ALTER TABLE RENAME COLUMN operation that gets passed
** down into the Walker.







|







108259
108260
108261
108262
108263
108264
108265
108266
108267
108268
108269
108270
108271
108272
108273
** routine is used to keep the mapping current.
**
** After the parse finishes, renameTokenFind() routine can be used
** to look up the actual token value that created some element in
** the parse tree.
*/
struct RenameToken {
  const void *p;         /* Parse tree element created by token t */
  Token t;               /* The token that created parse tree element p */
  RenameToken *pNext;    /* Next is a list of all RenameToken objects */
};

/*
** The context of an ALTER TABLE RENAME COLUMN operation that gets passed
** down into the Walker.
108083
108084
108085
108086
108087
108088
108089
108090
108091
108092
108093
108094
108095
108096
108097
108098
108099
**
**     sqlite3_free(x);
**     if( x==y ) ...
**
** Technically, as x no longer points into a valid object or to the byte
** following a valid object, it may not be used in comparison operations.
*/
static void renameTokenCheckAll(Parse *pParse, void *pPtr){
  if( pParse->nErr==0 && pParse->db->mallocFailed==0 ){
    RenameToken *p;
    u8 i = 0;
    for(p=pParse->pRename; p; p=p->pNext){
      if( p->p ){
        assert( p->p!=pPtr );
        i += *(u8*)(p->p);
      }
    }







|

|







108301
108302
108303
108304
108305
108306
108307
108308
108309
108310
108311
108312
108313
108314
108315
108316
108317
**
**     sqlite3_free(x);
**     if( x==y ) ...
**
** Technically, as x no longer points into a valid object or to the byte
** following a valid object, it may not be used in comparison operations.
*/
static void renameTokenCheckAll(Parse *pParse, const void *pPtr){
  if( pParse->nErr==0 && pParse->db->mallocFailed==0 ){
    const RenameToken *p;
    u8 i = 0;
    for(p=pParse->pRename; p; p=p->pNext){
      if( p->p ){
        assert( p->p!=pPtr );
        i += *(u8*)(p->p);
      }
    }
108111
108112
108113
108114
108115
108116
108117
108118




108119
108120
108121
108122
108123
108124
108125
** to the list of RenameToken objects currently being built up
** in pParse->pRename.
**
** The pPtr argument is returned so that this routine can be used
** with tail recursion in tokenExpr() routine, for a small performance
** improvement.
*/
SQLITE_PRIVATE void *sqlite3RenameTokenMap(Parse *pParse, void *pPtr, Token *pToken){




  RenameToken *pNew;
  assert( pPtr || pParse->db->mallocFailed );
  renameTokenCheckAll(pParse, pPtr);
  if( ALWAYS(pParse->eParseMode!=PARSE_MODE_UNMAP) ){
    pNew = sqlite3DbMallocZero(pParse->db, sizeof(RenameToken));
    if( pNew ){
      pNew->p = pPtr;







|
>
>
>
>







108329
108330
108331
108332
108333
108334
108335
108336
108337
108338
108339
108340
108341
108342
108343
108344
108345
108346
108347
** to the list of RenameToken objects currently being built up
** in pParse->pRename.
**
** The pPtr argument is returned so that this routine can be used
** with tail recursion in tokenExpr() routine, for a small performance
** improvement.
*/
SQLITE_PRIVATE const void *sqlite3RenameTokenMap(
  Parse *pParse,
  const void *pPtr,
  const Token *pToken
){
  RenameToken *pNew;
  assert( pPtr || pParse->db->mallocFailed );
  renameTokenCheckAll(pParse, pPtr);
  if( ALWAYS(pParse->eParseMode!=PARSE_MODE_UNMAP) ){
    pNew = sqlite3DbMallocZero(pParse->db, sizeof(RenameToken));
    if( pNew ){
      pNew->p = pPtr;
108133
108134
108135
108136
108137
108138
108139
108140
108141
108142
108143
108144
108145
108146
108147
108148
108149
108150
108151
108152
108153
108154
108155
108156

108157
108158
108159
108160
108161
108162
108163
}

/*
** It is assumed that there is already a RenameToken object associated
** with parse tree element pFrom. This function remaps the associated token
** to parse tree element pTo.
*/
SQLITE_PRIVATE void sqlite3RenameTokenRemap(Parse *pParse, void *pTo, void *pFrom){
  RenameToken *p;
  renameTokenCheckAll(pParse, pTo);
  for(p=pParse->pRename; p; p=p->pNext){
    if( p->p==pFrom ){
      p->p = pTo;
      break;
    }
  }
}

/*
** Walker callback used by sqlite3RenameExprUnmap().
*/
static int renameUnmapExprCb(Walker *pWalker, Expr *pExpr){
  Parse *pParse = pWalker->pParse;
  sqlite3RenameTokenRemap(pParse, 0, (void*)pExpr);

  return WRC_Continue;
}

/*
** Iterate through the Select objects that are part of WITH clauses attached
** to select statement pSelect.
*/







|















|
>







108355
108356
108357
108358
108359
108360
108361
108362
108363
108364
108365
108366
108367
108368
108369
108370
108371
108372
108373
108374
108375
108376
108377
108378
108379
108380
108381
108382
108383
108384
108385
108386
}

/*
** It is assumed that there is already a RenameToken object associated
** with parse tree element pFrom. This function remaps the associated token
** to parse tree element pTo.
*/
SQLITE_PRIVATE void sqlite3RenameTokenRemap(Parse *pParse, const void *pTo, const void *pFrom){
  RenameToken *p;
  renameTokenCheckAll(pParse, pTo);
  for(p=pParse->pRename; p; p=p->pNext){
    if( p->p==pFrom ){
      p->p = pTo;
      break;
    }
  }
}

/*
** Walker callback used by sqlite3RenameExprUnmap().
*/
static int renameUnmapExprCb(Walker *pWalker, Expr *pExpr){
  Parse *pParse = pWalker->pParse;
  sqlite3RenameTokenRemap(pParse, 0, (const void*)pExpr);
  sqlite3RenameTokenRemap(pParse, 0, (const void*)&pExpr->y.pTab);
  return WRC_Continue;
}

/*
** Iterate through the Select objects that are part of WITH clauses attached
** to select statement pSelect.
*/
108179
108180
108181
108182
108183
108184
108185

108186
108187
108188
108189
108190
108191
108192
108193
108194
108195
108196
108197
108198
108199
108200
108201
108202
108203
108204
108205
108206
108207
108208
108209
108210
108211
108212
108213
108214
108215
108216
108217
108218
108219
108220
108221
108222
108223
108224
108225
108226
108227
108228
108229
108230
108231
108232
108233
108234
108235
108236
108237
108238
108239
108240
108241
    }
    for(i=0; i<pWith->nCte; i++){
      Select *p = pWith->a[i].pSelect;
      NameContext sNC;
      memset(&sNC, 0, sizeof(sNC));
      sNC.pParse = pParse;
      if( pCopy ) sqlite3SelectPrep(sNC.pParse, p, &sNC);

      sqlite3WalkSelect(pWalker, p);
      sqlite3RenameExprlistUnmap(pParse, pWith->a[i].pCols);
    }
    if( pCopy && pParse->pWith==pCopy ){
      pParse->pWith = pCopy->pOuter;
    }
  }
}

/*
** Unmap all tokens in the IdList object passed as the second argument.
*/
static void unmapColumnIdlistNames(
  Parse *pParse,
  IdList *pIdList
){
  if( pIdList ){
    int ii;
    for(ii=0; ii<pIdList->nId; ii++){
      sqlite3RenameTokenRemap(pParse, 0, (void*)pIdList->a[ii].zName);
    }
  }
}

/*
** Walker callback used by sqlite3RenameExprUnmap().
*/
static int renameUnmapSelectCb(Walker *pWalker, Select *p){
  Parse *pParse = pWalker->pParse;
  int i;
  if( pParse->nErr ) return WRC_Abort;
  if( p->selFlags & (SF_View|SF_CopyCte) ){
    testcase( p->selFlags & SF_View );
    testcase( p->selFlags & SF_CopyCte );
    return WRC_Prune;
  }
  if( ALWAYS(p->pEList) ){
    ExprList *pList = p->pEList;
    for(i=0; i<pList->nExpr; i++){
      if( pList->a[i].zEName && pList->a[i].eEName==ENAME_NAME ){
        sqlite3RenameTokenRemap(pParse, 0, (void*)pList->a[i].zEName);
      }
    }
  }
  if( ALWAYS(p->pSrc) ){  /* Every Select as a SrcList, even if it is empty */
    SrcList *pSrc = p->pSrc;
    for(i=0; i<pSrc->nSrc; i++){
      sqlite3RenameTokenRemap(pParse, 0, (void*)pSrc->a[i].zName);
      if( sqlite3WalkExpr(pWalker, pSrc->a[i].pOn) ) return WRC_Abort;
      unmapColumnIdlistNames(pParse, pSrc->a[i].pUsing);
    }
  }

  renameWalkWith(pWalker, p);
  return WRC_Continue;
}







>














|




|











|
<
<














|







108402
108403
108404
108405
108406
108407
108408
108409
108410
108411
108412
108413
108414
108415
108416
108417
108418
108419
108420
108421
108422
108423
108424
108425
108426
108427
108428
108429
108430
108431
108432
108433
108434
108435
108436
108437
108438
108439
108440
108441


108442
108443
108444
108445
108446
108447
108448
108449
108450
108451
108452
108453
108454
108455
108456
108457
108458
108459
108460
108461
108462
108463
    }
    for(i=0; i<pWith->nCte; i++){
      Select *p = pWith->a[i].pSelect;
      NameContext sNC;
      memset(&sNC, 0, sizeof(sNC));
      sNC.pParse = pParse;
      if( pCopy ) sqlite3SelectPrep(sNC.pParse, p, &sNC);
      if( sNC.pParse->db->mallocFailed ) return;
      sqlite3WalkSelect(pWalker, p);
      sqlite3RenameExprlistUnmap(pParse, pWith->a[i].pCols);
    }
    if( pCopy && pParse->pWith==pCopy ){
      pParse->pWith = pCopy->pOuter;
    }
  }
}

/*
** Unmap all tokens in the IdList object passed as the second argument.
*/
static void unmapColumnIdlistNames(
  Parse *pParse,
  const IdList *pIdList
){
  if( pIdList ){
    int ii;
    for(ii=0; ii<pIdList->nId; ii++){
      sqlite3RenameTokenRemap(pParse, 0, (const void*)pIdList->a[ii].zName);
    }
  }
}

/*
** Walker callback used by sqlite3RenameExprUnmap().
*/
static int renameUnmapSelectCb(Walker *pWalker, Select *p){
  Parse *pParse = pWalker->pParse;
  int i;
  if( pParse->nErr ) return WRC_Abort;
  if( NEVER(p->selFlags & (SF_View|SF_CopyCte)) ){


    return WRC_Prune;
  }
  if( ALWAYS(p->pEList) ){
    ExprList *pList = p->pEList;
    for(i=0; i<pList->nExpr; i++){
      if( pList->a[i].zEName && pList->a[i].eEName==ENAME_NAME ){
        sqlite3RenameTokenRemap(pParse, 0, (void*)pList->a[i].zEName);
      }
    }
  }
  if( ALWAYS(p->pSrc) ){  /* Every Select as a SrcList, even if it is empty */
    SrcList *pSrc = p->pSrc;
    for(i=0; i<pSrc->nSrc; i++){
      sqlite3RenameTokenRemap(pParse, 0, (void*)pSrc->a[i].zName);
      sqlite3WalkExpr(pWalker, pSrc->a[i].pOn);
      unmapColumnIdlistNames(pParse, pSrc->a[i].pUsing);
    }
  }

  renameWalkWith(pWalker, p);
  return WRC_Continue;
}
108295
108296
108297
108298
108299
108300
108301
108302
108303
108304
108305
108306
108307
108308
108309
** If the second argument passed to this function is not NULL and a matching
** RenameToken object is found, remove it from the Parse object and add it to
** the list maintained by the RenameCtx object.
*/
static RenameToken *renameTokenFind(
  Parse *pParse,
  struct RenameCtx *pCtx,
  void *pPtr
){
  RenameToken **pp;
  if( NEVER(pPtr==0) ){
    return 0;
  }
  for(pp=&pParse->pRename; (*pp); pp=&(*pp)->pNext){
    if( (*pp)->p==pPtr ){







|







108517
108518
108519
108520
108521
108522
108523
108524
108525
108526
108527
108528
108529
108530
108531
** If the second argument passed to this function is not NULL and a matching
** RenameToken object is found, remove it from the Parse object and add it to
** the list maintained by the RenameCtx object.
*/
static RenameToken *renameTokenFind(
  Parse *pParse,
  struct RenameCtx *pCtx,
  const void *pPtr
){
  RenameToken **pp;
  if( NEVER(pPtr==0) ){
    return 0;
  }
  for(pp=&pParse->pRename; (*pp); pp=&(*pp)->pNext){
    if( (*pp)->p==pPtr ){
108414
108415
108416
108417
108418
108419
108420
108421
108422
108423
108424
108425
108426
108427
108428
108429
108430
108431
108432
108433
108434
108435
108436
108437
108438
108439
108440
108441
108442
108443
108444
108445
108446
108447
108448
108449
108450
108451
108452
108453
108454
108455
108456
108457
108458
108459
108460
108461
** pEList->a[i].zName) that matches the string in zOld, extract the
** corresponding rename-token from Parse object pParse and add it
** to the RenameCtx pCtx.
*/
static void renameColumnElistNames(
  Parse *pParse,
  RenameCtx *pCtx,
  ExprList *pEList,
  const char *zOld
){
  if( pEList ){
    int i;
    for(i=0; i<pEList->nExpr; i++){
      char *zName = pEList->a[i].zEName;
      if( ALWAYS(pEList->a[i].eEName==ENAME_NAME)
       && ALWAYS(zName!=0)
       && 0==sqlite3_stricmp(zName, zOld)
      ){
        renameTokenFind(pParse, pCtx, (void*)zName);
      }
    }
  }
}

/*
** For each name in the the id-list pIdList (i.e. each pIdList->a[i].zName)
** that matches the string in zOld, extract the corresponding rename-token
** from Parse object pParse and add it to the RenameCtx pCtx.
*/
static void renameColumnIdlistNames(
  Parse *pParse,
  RenameCtx *pCtx,
  IdList *pIdList,
  const char *zOld
){
  if( pIdList ){
    int i;
    for(i=0; i<pIdList->nId; i++){
      char *zName = pIdList->a[i].zName;
      if( 0==sqlite3_stricmp(zName, zOld) ){
        renameTokenFind(pParse, pCtx, (void*)zName);
      }
    }
  }
}


/*







|





|




|













|





|

|







108636
108637
108638
108639
108640
108641
108642
108643
108644
108645
108646
108647
108648
108649
108650
108651
108652
108653
108654
108655
108656
108657
108658
108659
108660
108661
108662
108663
108664
108665
108666
108667
108668
108669
108670
108671
108672
108673
108674
108675
108676
108677
108678
108679
108680
108681
108682
108683
** pEList->a[i].zName) that matches the string in zOld, extract the
** corresponding rename-token from Parse object pParse and add it
** to the RenameCtx pCtx.
*/
static void renameColumnElistNames(
  Parse *pParse,
  RenameCtx *pCtx,
  const ExprList *pEList,
  const char *zOld
){
  if( pEList ){
    int i;
    for(i=0; i<pEList->nExpr; i++){
      const char *zName = pEList->a[i].zEName;
      if( ALWAYS(pEList->a[i].eEName==ENAME_NAME)
       && ALWAYS(zName!=0)
       && 0==sqlite3_stricmp(zName, zOld)
      ){
        renameTokenFind(pParse, pCtx, (const void*)zName);
      }
    }
  }
}

/*
** For each name in the the id-list pIdList (i.e. each pIdList->a[i].zName)
** that matches the string in zOld, extract the corresponding rename-token
** from Parse object pParse and add it to the RenameCtx pCtx.
*/
static void renameColumnIdlistNames(
  Parse *pParse,
  RenameCtx *pCtx,
  const IdList *pIdList,
  const char *zOld
){
  if( pIdList ){
    int i;
    for(i=0; i<pIdList->nId; i++){
      const char *zName = pIdList->a[i].zName;
      if( 0==sqlite3_stricmp(zName, zOld) ){
        renameTokenFind(pParse, pCtx, (const void*)zName);
      }
    }
  }
}


/*
108849
108850
108851
108852
108853
108854
108855
108856
108857
108858
108859
108860
108861
108862
108863
      sParse.rc = SQLITE_OK;
      sqlite3SelectPrep(&sParse, pSelect, 0);
      rc = (db->mallocFailed ? SQLITE_NOMEM : sParse.rc);
      if( rc==SQLITE_OK ){
        sqlite3WalkSelect(&sWalker, pSelect);
      }
      if( rc!=SQLITE_OK ) goto renameColumnFunc_done;
    }else if( ALWAYS(IsOrdinaryTable(sParse.pNewTable)) ){
      /* A regular table */
      int bFKOnly = sqlite3_stricmp(zTable, sParse.pNewTable->zName);
      FKey *pFKey;
      sCtx.pTab = sParse.pNewTable;
      if( bFKOnly==0 ){
        if( iCol<sParse.pNewTable->nCol ){
          renameTokenFind(







|







109071
109072
109073
109074
109075
109076
109077
109078
109079
109080
109081
109082
109083
109084
109085
      sParse.rc = SQLITE_OK;
      sqlite3SelectPrep(&sParse, pSelect, 0);
      rc = (db->mallocFailed ? SQLITE_NOMEM : sParse.rc);
      if( rc==SQLITE_OK ){
        sqlite3WalkSelect(&sWalker, pSelect);
      }
      if( rc!=SQLITE_OK ) goto renameColumnFunc_done;
    }else if( IsOrdinaryTable(sParse.pNewTable) ){
      /* A regular table */
      int bFKOnly = sqlite3_stricmp(zTable, sParse.pNewTable->zName);
      FKey *pFKey;
      sCtx.pTab = sParse.pNewTable;
      if( bFKOnly==0 ){
        if( iCol<sParse.pNewTable->nCol ){
          renameTokenFind(
109147
109148
109149
109150
109151
109152
109153
109154
109155
109156
109157
109158
109159
109160
109161
  }

  return;
}

static int renameQuotefixExprCb(Walker *pWalker, Expr *pExpr){
  if( pExpr->op==TK_STRING && (pExpr->flags & EP_DblQuoted) ){
    renameTokenFind(pWalker->pParse, pWalker->u.pRename, (void*)pExpr);
  }
  return WRC_Continue;
}

/*
** The implementation of an SQL scalar function that rewrites DDL statements
** so that any string literals that use double-quotes are modified so that







|







109369
109370
109371
109372
109373
109374
109375
109376
109377
109378
109379
109380
109381
109382
109383
  }

  return;
}

static int renameQuotefixExprCb(Walker *pWalker, Expr *pExpr){
  if( pExpr->op==TK_STRING && (pExpr->flags & EP_DblQuoted) ){
    renameTokenFind(pWalker->pParse, pWalker->u.pRename, (const void*)pExpr);
  }
  return WRC_Continue;
}

/*
** The implementation of an SQL scalar function that rewrites DDL statements
** so that any string literals that use double-quotes are modified so that
109417
109418
109419
109420
109421
109422
109423
109424
109425
109426
109427
109428
109429
109430
109431
** This function is called by the parser upon parsing an
**
**     ALTER TABLE pSrc DROP COLUMN pName
**
** statement. Argument pSrc contains the possibly qualified name of the
** table being edited, and token pName the name of the column to drop.
*/
SQLITE_PRIVATE void sqlite3AlterDropColumn(Parse *pParse, SrcList *pSrc, Token *pName){
  sqlite3 *db = pParse->db;       /* Database handle */
  Table *pTab;                    /* Table to modify */
  int iDb;                        /* Index of db containing pTab in aDb[] */
  const char *zDb;                /* Database containing pTab ("main" etc.) */
  char *zCol = 0;                 /* Name of column to drop */
  int iCol;                       /* Index of column zCol in pTab->aCol[] */








|







109639
109640
109641
109642
109643
109644
109645
109646
109647
109648
109649
109650
109651
109652
109653
** This function is called by the parser upon parsing an
**
**     ALTER TABLE pSrc DROP COLUMN pName
**
** statement. Argument pSrc contains the possibly qualified name of the
** table being edited, and token pName the name of the column to drop.
*/
SQLITE_PRIVATE void sqlite3AlterDropColumn(Parse *pParse, SrcList *pSrc, const Token *pName){
  sqlite3 *db = pParse->db;       /* Database handle */
  Table *pTab;                    /* Table to modify */
  int iDb;                        /* Index of db containing pTab in aDb[] */
  const char *zDb;                /* Database containing pTab ("main" etc.) */
  char *zCol = 0;                 /* Name of column to drop */
  int iCol;                       /* Index of column zCol in pTab->aCol[] */

110002
110003
110004
110005
110006
110007
110008
110009
110010
110011
110012
110013
110014
110015
110016
#ifdef SQLITE_ENABLE_STAT4
  if( mxSample ){
    n += sizeof(tRowcnt)*nColUp                  /* StatAccum.anLt */
      + sizeof(StatSample)*(nCol+mxSample)       /* StatAccum.aBest[], a[] */
      + sizeof(tRowcnt)*3*nColUp*(nCol+mxSample);
  }
#endif
  db = sqlite3_context_db_handle(context);
  p = sqlite3DbMallocZero(db, n);
  if( p==0 ){
    sqlite3_result_error_nomem(context);
    return;
  }

  p->db = db;







<







110224
110225
110226
110227
110228
110229
110230

110231
110232
110233
110234
110235
110236
110237
#ifdef SQLITE_ENABLE_STAT4
  if( mxSample ){
    n += sizeof(tRowcnt)*nColUp                  /* StatAccum.anLt */
      + sizeof(StatSample)*(nCol+mxSample)       /* StatAccum.aBest[], a[] */
      + sizeof(tRowcnt)*3*nColUp*(nCol+mxSample);
  }
#endif

  p = sqlite3DbMallocZero(db, n);
  if( p==0 ){
    sqlite3_result_error_nomem(context);
    return;
  }

  p->db = db;
110421
110422
110423
110424
110425
110426
110427
110428
110429
110430
110431
110432
110433
110434
110435
110436
110437
110438
110439
110440
110441
110442
110443
110444
110445
110446
110447
110448
110449
110450
110451
110452
110453
110454
110455
110456
110457
110458
110459
110460
110461
110462
110463
110464
110465
110466
110467


110468
110469
110470
110471
110472
110473
110474
110475
110476
110477
110478
110479
110480
110481
110482
110483
110484
110485
110486
110487
110488
110489
110490
110491
110492

110493
110494
110495
110496
110497
110498
110499
110500
110501
110502
    **   * "WHERE a=? AND b=?" matches 2 rows.
    **
    ** If D is the count of distinct values and K is the total number of
    ** rows, then each estimate is computed as:
    **
    **        I = (K+D-1)/D
    */
    char *z;
    int i;

    char *zRet = sqlite3MallocZero( (p->nKeyCol+1)*25 );
    if( zRet==0 ){
      sqlite3_result_error_nomem(context);
      return;
    }

    sqlite3_snprintf(24, zRet, "%llu",
        p->nSkipAhead ? (u64)p->nEst : (u64)p->nRow);
    z = zRet + sqlite3Strlen30(zRet);
    for(i=0; i<p->nKeyCol; i++){
      u64 nDistinct = p->current.anDLt[i] + 1;
      u64 iVal = (p->nRow + nDistinct - 1) / nDistinct;
      sqlite3_snprintf(24, z, " %llu", iVal);
      z += sqlite3Strlen30(z);
      assert( p->current.anEq[i] );
    }
    assert( z[0]=='\0' && z>zRet );

    sqlite3_result_text(context, zRet, -1, sqlite3_free);
  }
#ifdef SQLITE_ENABLE_STAT4
  else if( eCall==STAT_GET_ROWID ){
    if( p->iGet<0 ){
      samplePushPrevious(p, 0);
      p->iGet = 0;
    }
    if( p->iGet<p->nSample ){
      StatSample *pS = p->a + p->iGet;
      if( pS->nRowid==0 ){
        sqlite3_result_int64(context, pS->u.iRowid);
      }else{
        sqlite3_result_blob(context, pS->u.aRowid, pS->nRowid,
                            SQLITE_TRANSIENT);
      }
    }
  }else{
    tRowcnt *aCnt = 0;



    assert( p->iGet<p->nSample );
    switch( eCall ){
      case STAT_GET_NEQ:  aCnt = p->a[p->iGet].anEq; break;
      case STAT_GET_NLT:  aCnt = p->a[p->iGet].anLt; break;
      default: {
        aCnt = p->a[p->iGet].anDLt;
        p->iGet++;
        break;
      }
    }

    {
      char *zRet = sqlite3MallocZero(p->nCol * 25);
      if( zRet==0 ){
        sqlite3_result_error_nomem(context);
      }else{
        int i;
        char *z = zRet;
        for(i=0; i<p->nCol; i++){
          sqlite3_snprintf(24, z, "%llu ", (u64)aCnt[i]);
          z += sqlite3Strlen30(z);
        }
        assert( z[0]=='\0' && z>zRet );
        z[-1] = '\0';

        sqlite3_result_text(context, zRet, -1, sqlite3_free);
      }
    }
  }
#endif /* SQLITE_ENABLE_STAT4 */
#ifndef SQLITE_DEBUG
  UNUSED_PARAMETER( argc );
#endif
}
static const FuncDef statGetFuncdef = {







|
|

<
<
<
<
<
|
|

<



|
<


<
|
<


















>
>











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







110642
110643
110644
110645
110646
110647
110648
110649
110650
110651





110652
110653
110654

110655
110656
110657
110658

110659
110660

110661

110662
110663
110664
110665
110666
110667
110668
110669
110670
110671
110672
110673
110674
110675
110676
110677
110678
110679
110680
110681
110682
110683
110684
110685
110686
110687
110688
110689
110690
110691
110692
110693







110694
110695

110696


110697
110698


110699
110700
110701
110702
110703
110704
110705
    **   * "WHERE a=? AND b=?" matches 2 rows.
    **
    ** If D is the count of distinct values and K is the total number of
    ** rows, then each estimate is computed as:
    **
    **        I = (K+D-1)/D
    */
    sqlite3_str sStat;   /* Text of the constructed "stat" line */
    int i;               /* Loop counter */






    sqlite3StrAccumInit(&sStat, 0, 0, 0, (p->nKeyCol+1)*100);
    sqlite3_str_appendf(&sStat, "%llu",
        p->nSkipAhead ? (u64)p->nEst : (u64)p->nRow);

    for(i=0; i<p->nKeyCol; i++){
      u64 nDistinct = p->current.anDLt[i] + 1;
      u64 iVal = (p->nRow + nDistinct - 1) / nDistinct;
      sqlite3_str_appendf(&sStat, " %llu", iVal);

      assert( p->current.anEq[i] );
    }

    sqlite3ResultStrAccum(context, &sStat);

  }
#ifdef SQLITE_ENABLE_STAT4
  else if( eCall==STAT_GET_ROWID ){
    if( p->iGet<0 ){
      samplePushPrevious(p, 0);
      p->iGet = 0;
    }
    if( p->iGet<p->nSample ){
      StatSample *pS = p->a + p->iGet;
      if( pS->nRowid==0 ){
        sqlite3_result_int64(context, pS->u.iRowid);
      }else{
        sqlite3_result_blob(context, pS->u.aRowid, pS->nRowid,
                            SQLITE_TRANSIENT);
      }
    }
  }else{
    tRowcnt *aCnt = 0;
    sqlite3_str sStat;
    int i;

    assert( p->iGet<p->nSample );
    switch( eCall ){
      case STAT_GET_NEQ:  aCnt = p->a[p->iGet].anEq; break;
      case STAT_GET_NLT:  aCnt = p->a[p->iGet].anLt; break;
      default: {
        aCnt = p->a[p->iGet].anDLt;
        p->iGet++;
        break;
      }
    }
    sqlite3StrAccumInit(&sStat, 0, 0, 0, p->nCol*100);







    for(i=0; i<p->nCol; i++){
      sqlite3_str_appendf(&sStat, "%llu ", (u64)aCnt[i]);

    }


    if( sStat.nChar ) sStat.nChar--;
    sqlite3ResultStrAccum(context, &sStat);


  }
#endif /* SQLITE_ENABLE_STAT4 */
#ifndef SQLITE_DEBUG
  UNUSED_PARAMETER( argc );
#endif
}
static const FuncDef statGetFuncdef = {
111409
111410
111411
111412
111413
111414
111415

111416
111417
111418


111419
111420
111421
111422
111423
111424
111425

/*
** Load content from the sqlite_stat4 table into
** the Index.aSample[] arrays of all indices.
*/
static int loadStat4(sqlite3 *db, const char *zDb){
  int rc = SQLITE_OK;             /* Result codes from subroutines */


  assert( db->lookaside.bDisable );
  if( sqlite3FindTable(db, "sqlite_stat4", zDb) ){


    rc = loadStatTbl(db,
      "SELECT idx,count(*) FROM %Q.sqlite_stat4 GROUP BY idx",
      "SELECT idx,neq,nlt,ndlt,sample FROM %Q.sqlite_stat4",
      zDb
    );
  }
  return rc;







>


|
>
>







111612
111613
111614
111615
111616
111617
111618
111619
111620
111621
111622
111623
111624
111625
111626
111627
111628
111629
111630
111631

/*
** Load content from the sqlite_stat4 table into
** the Index.aSample[] arrays of all indices.
*/
static int loadStat4(sqlite3 *db, const char *zDb){
  int rc = SQLITE_OK;             /* Result codes from subroutines */
  const Table *pStat4;

  assert( db->lookaside.bDisable );
  if( (pStat4 = sqlite3FindTable(db, "sqlite_stat4", zDb))!=0
   && IsOrdinaryTable(pStat4)
  ){
    rc = loadStatTbl(db,
      "SELECT idx,count(*) FROM %Q.sqlite_stat4 GROUP BY idx",
      "SELECT idx,neq,nlt,ndlt,sample FROM %Q.sqlite_stat4",
      zDb
    );
  }
  return rc;
111448
111449
111450
111451
111452
111453
111454

111455
111456
111457
111458
111459
111460
111461
*/
SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
  analysisInfo sInfo;
  HashElem *i;
  char *zSql;
  int rc = SQLITE_OK;
  Schema *pSchema = db->aDb[iDb].pSchema;


  assert( iDb>=0 && iDb<db->nDb );
  assert( db->aDb[iDb].pBt!=0 );

  /* Clear any prior statistics */
  assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
  for(i=sqliteHashFirst(&pSchema->tblHash); i; i=sqliteHashNext(i)){







>







111654
111655
111656
111657
111658
111659
111660
111661
111662
111663
111664
111665
111666
111667
111668
*/
SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
  analysisInfo sInfo;
  HashElem *i;
  char *zSql;
  int rc = SQLITE_OK;
  Schema *pSchema = db->aDb[iDb].pSchema;
  const Table *pStat1;

  assert( iDb>=0 && iDb<db->nDb );
  assert( db->aDb[iDb].pBt!=0 );

  /* Clear any prior statistics */
  assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
  for(i=sqliteHashFirst(&pSchema->tblHash); i; i=sqliteHashNext(i)){
111470
111471
111472
111473
111474
111475
111476
111477


111478
111479
111480
111481
111482
111483
111484
    pIdx->aSample = 0;
#endif
  }

  /* Load new statistics out of the sqlite_stat1 table */
  sInfo.db = db;
  sInfo.zDatabase = db->aDb[iDb].zDbSName;
  if( sqlite3FindTable(db, "sqlite_stat1", sInfo.zDatabase)!=0 ){


    zSql = sqlite3MPrintf(db,
        "SELECT tbl,idx,stat FROM %Q.sqlite_stat1", sInfo.zDatabase);
    if( zSql==0 ){
      rc = SQLITE_NOMEM_BKPT;
    }else{
      rc = sqlite3_exec(db, zSql, analysisLoader, &sInfo, 0);
      sqlite3DbFree(db, zSql);







|
>
>







111677
111678
111679
111680
111681
111682
111683
111684
111685
111686
111687
111688
111689
111690
111691
111692
111693
    pIdx->aSample = 0;
#endif
  }

  /* Load new statistics out of the sqlite_stat1 table */
  sInfo.db = db;
  sInfo.zDatabase = db->aDb[iDb].zDbSName;
  if( (pStat1 = sqlite3FindTable(db, "sqlite_stat1", sInfo.zDatabase))
   && IsOrdinaryTable(pStat1)
  ){
    zSql = sqlite3MPrintf(db,
        "SELECT tbl,idx,stat FROM %Q.sqlite_stat1", sInfo.zDatabase);
    if( zSql==0 ){
      rc = SQLITE_NOMEM_BKPT;
    }else{
      rc = sqlite3_exec(db, zSql, analysisLoader, &sInfo, 0);
      sqlite3DbFree(db, zSql);
111861
111862
111863
111864
111865
111866
111867
111868
111869
111870
111871
111872
111873
111874
111875
111876
111877
  int regArgs;

  if( pParse->nErr ) goto attach_end;
  memset(&sName, 0, sizeof(NameContext));
  sName.pParse = pParse;

  if(
      SQLITE_OK!=(rc = resolveAttachExpr(&sName, pFilename)) ||
      SQLITE_OK!=(rc = resolveAttachExpr(&sName, pDbname)) ||
      SQLITE_OK!=(rc = resolveAttachExpr(&sName, pKey))
  ){
    goto attach_end;
  }

#ifndef SQLITE_OMIT_AUTHORIZATION
  if( pAuthArg ){
    char *zAuthArg;







|
|
|







112070
112071
112072
112073
112074
112075
112076
112077
112078
112079
112080
112081
112082
112083
112084
112085
112086
  int regArgs;

  if( pParse->nErr ) goto attach_end;
  memset(&sName, 0, sizeof(NameContext));
  sName.pParse = pParse;

  if(
      SQLITE_OK!=resolveAttachExpr(&sName, pFilename) ||
      SQLITE_OK!=resolveAttachExpr(&sName, pDbname) ||
      SQLITE_OK!=resolveAttachExpr(&sName, pKey)
  ){
    goto attach_end;
  }

#ifndef SQLITE_OMIT_AUTHORIZATION
  if( pAuthArg ){
    char *zAuthArg;
113274
113275
113276
113277
113278
113279
113280
113281
113282
113283
113284
113285
113286
113287
113288
113289
113290
113291
** Any quotation marks (ex:  "name", 'name', [name], or `name`) that
** surround the body of the token are removed.
**
** Tokens are often just pointers into the original SQL text and so
** are not \000 terminated and are not persistent.  The returned string
** is \000 terminated and is persistent.
*/
SQLITE_PRIVATE char *sqlite3NameFromToken(sqlite3 *db, Token *pName){
  char *zName;
  if( pName ){
    zName = sqlite3DbStrNDup(db, (char*)pName->z, pName->n);
    sqlite3Dequote(zName);
  }else{
    zName = 0;
  }
  return zName;
}








|


|







113483
113484
113485
113486
113487
113488
113489
113490
113491
113492
113493
113494
113495
113496
113497
113498
113499
113500
** Any quotation marks (ex:  "name", 'name', [name], or `name`) that
** surround the body of the token are removed.
**
** Tokens are often just pointers into the original SQL text and so
** are not \000 terminated and are not persistent.  The returned string
** is \000 terminated and is persistent.
*/
SQLITE_PRIVATE char *sqlite3NameFromToken(sqlite3 *db, const Token *pName){
  char *zName;
  if( pName ){
    zName = sqlite3DbStrNDup(db, (const char*)pName->z, pName->n);
    sqlite3Dequote(zName);
  }else{
    zName = 0;
  }
  return zName;
}

113940
113941
113942
113943
113944
113945
113946
113947
113948
113949
113950
113951
113952
113953
113954
  pCol->hName = hName;
  sqlite3ColumnPropertiesFromName(p, pCol);

  if( sType.n==0 ){
    /* If there is no type specified, columns have the default affinity
    ** 'BLOB' with a default size of 4 bytes. */
    pCol->affinity = affinity;
    pCol->eType = eType;
    pCol->szEst = szEst;
#ifdef SQLITE_ENABLE_SORTER_REFERENCES
    if( affinity==SQLITE_AFF_BLOB ){
      if( 4>=sqlite3GlobalConfig.szSorterRef ){
        pCol->colFlags |= COLFLAG_SORTERREF;
      }
    }







|







114149
114150
114151
114152
114153
114154
114155
114156
114157
114158
114159
114160
114161
114162
114163
  pCol->hName = hName;
  sqlite3ColumnPropertiesFromName(p, pCol);

  if( sType.n==0 ){
    /* If there is no type specified, columns have the default affinity
    ** 'BLOB' with a default size of 4 bytes. */
    pCol->affinity = affinity;
    pCol->eCType = eType;
    pCol->szEst = szEst;
#ifdef SQLITE_ENABLE_SORTER_REFERENCES
    if( affinity==SQLITE_AFF_BLOB ){
      if( 4>=sqlite3GlobalConfig.szSorterRef ){
        pCol->colFlags |= COLFLAG_SORTERREF;
      }
    }
114235
114236
114237
114238
114239
114240
114241
114242
114243
114244
114245
114246
114247
114248
114249
          }
        }
      }
    }
  }
  if( nTerm==1
   && pCol
   && pCol->eType==COLTYPE_INTEGER
   && sortOrder!=SQLITE_SO_DESC
  ){
    if( IN_RENAME_OBJECT && pList ){
      Expr *pCExpr = sqlite3ExprSkipCollate(pList->a[0].pExpr);
      sqlite3RenameTokenRemap(pParse, &pTab->iPKey, pCExpr);
    }
    pTab->iPKey = iCol;







|







114444
114445
114446
114447
114448
114449
114450
114451
114452
114453
114454
114455
114456
114457
114458
          }
        }
      }
    }
  }
  if( nTerm==1
   && pCol
   && pCol->eCType==COLTYPE_INTEGER
   && sortOrder!=SQLITE_SO_DESC
  ){
    if( IN_RENAME_OBJECT && pList ){
      Expr *pCExpr = sqlite3ExprSkipCollate(pList->a[0].pExpr);
      sqlite3RenameTokenRemap(pParse, &pTab->iPKey, pCExpr);
    }
    pTab->iPKey = iCol;
114707
114708
114709
114710
114711
114712
114713
114714


114715
114716
114717
114718
114719
114720
114721
  sqlite3 *db = pParse->db;
  Vdbe *v = pParse->pVdbe;

  /* Mark every PRIMARY KEY column as NOT NULL (except for imposter tables)
  */
  if( !db->init.imposterTable ){
    for(i=0; i<pTab->nCol; i++){
      if( (pTab->aCol[i].colFlags & COLFLAG_PRIMKEY)!=0 ){


        pTab->aCol[i].notNull = OE_Abort;
      }
    }
    pTab->tabFlags |= TF_HasNotNull;
  }

  /* Convert the P3 operand of the OP_CreateBtree opcode from BTREE_INTKEY







|
>
>







114916
114917
114918
114919
114920
114921
114922
114923
114924
114925
114926
114927
114928
114929
114930
114931
114932
  sqlite3 *db = pParse->db;
  Vdbe *v = pParse->pVdbe;

  /* Mark every PRIMARY KEY column as NOT NULL (except for imposter tables)
  */
  if( !db->init.imposterTable ){
    for(i=0; i<pTab->nCol; i++){
      if( (pTab->aCol[i].colFlags & COLFLAG_PRIMKEY)!=0
       && (pTab->aCol[i].notNull==OE_None)
      ){
        pTab->aCol[i].notNull = OE_Abort;
      }
    }
    pTab->tabFlags |= TF_HasNotNull;
  }

  /* Convert the P3 operand of the OP_CreateBtree opcode from BTREE_INTKEY
114940
114941
114942
114943
114944
114945
114946
114947
114948
114949
114950
114951
114952
114953
114954
** "CREATE TABLE ... AS SELECT ..." statement.  The column names of
** the new table will match the result set of the SELECT.
*/
SQLITE_PRIVATE void sqlite3EndTable(
  Parse *pParse,          /* Parse context */
  Token *pCons,           /* The ',' token after the last column defn. */
  Token *pEnd,            /* The ')' before options in the CREATE TABLE */
  u8 tabOpts,             /* Extra table options. Usually 0. */
  Select *pSelect         /* Select from a "CREATE ... AS SELECT" */
){
  Table *p;                 /* The new table */
  sqlite3 *db = pParse->db; /* The database connection */
  int iDb;                  /* Database in which the table lives */
  Index *pIdx;              /* An implied index of the table */








|







115151
115152
115153
115154
115155
115156
115157
115158
115159
115160
115161
115162
115163
115164
115165
** "CREATE TABLE ... AS SELECT ..." statement.  The column names of
** the new table will match the result set of the SELECT.
*/
SQLITE_PRIVATE void sqlite3EndTable(
  Parse *pParse,          /* Parse context */
  Token *pCons,           /* The ',' token after the last column defn. */
  Token *pEnd,            /* The ')' before options in the CREATE TABLE */
  u32 tabOpts,            /* Extra table options. Usually 0. */
  Select *pSelect         /* Select from a "CREATE ... AS SELECT" */
){
  Table *p;                 /* The new table */
  sqlite3 *db = pParse->db; /* The database connection */
  int iDb;                  /* Database in which the table lives */
  Index *pIdx;              /* An implied index of the table */

114975
114976
114977
114978
114979
114980
114981






































114982
114983
114984
114985
114986
114987
114988
    if( pSelect ){
      sqlite3ErrorMsg(pParse, "");
      return;
    }
    p->tnum = db->init.newTnum;
    if( p->tnum==1 ) p->tabFlags |= TF_Readonly;
  }







































  assert( (p->tabFlags & TF_HasPrimaryKey)==0
       || p->iPKey>=0 || sqlite3PrimaryKeyIndex(p)!=0 );
  assert( (p->tabFlags & TF_HasPrimaryKey)!=0
       || (p->iPKey<0 && sqlite3PrimaryKeyIndex(p)==0) );

  /* Special processing for WITHOUT ROWID Tables */







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







115186
115187
115188
115189
115190
115191
115192
115193
115194
115195
115196
115197
115198
115199
115200
115201
115202
115203
115204
115205
115206
115207
115208
115209
115210
115211
115212
115213
115214
115215
115216
115217
115218
115219
115220
115221
115222
115223
115224
115225
115226
115227
115228
115229
115230
115231
115232
115233
115234
115235
115236
115237
    if( pSelect ){
      sqlite3ErrorMsg(pParse, "");
      return;
    }
    p->tnum = db->init.newTnum;
    if( p->tnum==1 ) p->tabFlags |= TF_Readonly;
  }

  /* Special processing for tables that include the STRICT keyword:
  **
  **   *  Do not allow custom column datatypes.  Every column must have
  **      a datatype that is one of INT, INTEGER, REAL, TEXT, or BLOB.
  **
  **   *  If a PRIMARY KEY is defined, other than the INTEGER PRIMARY KEY,
  **      then all columns of the PRIMARY KEY must have a NOT NULL
  **      constraint.
  */
  if( tabOpts & TF_Strict ){
    int ii;
    p->tabFlags |= TF_Strict;
    for(ii=0; ii<p->nCol; ii++){
      Column *pCol = &p->aCol[ii];
      if( pCol->eCType==COLTYPE_CUSTOM ){
        if( pCol->colFlags & COLFLAG_HASTYPE ){
          sqlite3ErrorMsg(pParse,
            "unknown datatype for %s.%s: \"%s\"",
            p->zName, pCol->zCnName, sqlite3ColumnType(pCol, "")
          );
        }else{
          sqlite3ErrorMsg(pParse, "missing datatype for %s.%s",
                          p->zName, pCol->zCnName);
        }
        return;
      }else if( pCol->eCType==COLTYPE_ANY ){
        pCol->affinity = SQLITE_AFF_BLOB;
      }
      if( (pCol->colFlags & COLFLAG_PRIMKEY)!=0
       && p->iPKey!=ii
       && pCol->notNull == OE_None
      ){
        pCol->notNull = OE_Abort;
        p->tabFlags |= TF_HasNotNull;
      }
    }
  }

  assert( (p->tabFlags & TF_HasPrimaryKey)==0
       || p->iPKey>=0 || sqlite3PrimaryKeyIndex(p)!=0 );
  assert( (p->tabFlags & TF_HasPrimaryKey)!=0
       || (p->iPKey<0 && sqlite3PrimaryKeyIndex(p)==0) );

  /* Special processing for WITHOUT ROWID Tables */
116728
116729
116730
116731
116732
116733
116734
116735
116736
116737
116738
116739
116740
116741
116742
exit_create_index:
  if( pIndex ) sqlite3FreeIndex(db, pIndex);
  if( pTab ){
    /* Ensure all REPLACE indexes on pTab are at the end of the pIndex list.
    ** The list was already ordered when this routine was entered, so at this
    ** point at most a single index (the newly added index) will be out of
    ** order.  So we have to reorder at most one index. */
    Index **ppFrom = &pTab->pIndex;
    Index *pThis;
    for(ppFrom=&pTab->pIndex; (pThis = *ppFrom)!=0; ppFrom=&pThis->pNext){
      Index *pNext;
      if( pThis->onError!=OE_Replace ) continue;
      while( (pNext = pThis->pNext)!=0 && pNext->onError!=OE_Replace ){
        *ppFrom = pNext;
        pThis->pNext = pNext->pNext;







|







116977
116978
116979
116980
116981
116982
116983
116984
116985
116986
116987
116988
116989
116990
116991
exit_create_index:
  if( pIndex ) sqlite3FreeIndex(db, pIndex);
  if( pTab ){
    /* Ensure all REPLACE indexes on pTab are at the end of the pIndex list.
    ** The list was already ordered when this routine was entered, so at this
    ** point at most a single index (the newly added index) will be out of
    ** order.  So we have to reorder at most one index. */
    Index **ppFrom;
    Index *pThis;
    for(ppFrom=&pTab->pIndex; (pThis = *ppFrom)!=0; ppFrom=&pThis->pNext){
      Index *pNext;
      if( pThis->onError!=OE_Replace ) continue;
      while( (pNext = pThis->pNext)!=0 && pNext->onError!=OE_Replace ){
        *ppFrom = pNext;
        pThis->pNext = pNext->pNext;
119995
119996
119997
119998
119999
120000
120001
120002
120003
120004
120005
120006
120007
120008
120009
120010
120011
  ** function. */
  sqlite3_result_int64(context, sqlite3_last_insert_rowid(db));
}

/*
** Implementation of the changes() SQL function.
**
** IMP: R-62073-11209 The changes() SQL function is a wrapper
** around the sqlite3_changes64() C/C++ function and hence follows the same
** rules for counting changes.
*/
static void changes(
  sqlite3_context *context,
  int NotUsed,
  sqlite3_value **NotUsed2
){
  sqlite3 *db = sqlite3_context_db_handle(context);







|
|
|







120244
120245
120246
120247
120248
120249
120250
120251
120252
120253
120254
120255
120256
120257
120258
120259
120260
  ** function. */
  sqlite3_result_int64(context, sqlite3_last_insert_rowid(db));
}

/*
** Implementation of the changes() SQL function.
**
** IMP: R-32760-32347 The changes() SQL function is a wrapper
** around the sqlite3_changes64() C/C++ function and hence follows the
** same rules for counting changes.
*/
static void changes(
  sqlite3_context *context,
  int NotUsed,
  sqlite3_value **NotUsed2
){
  sqlite3 *db = sqlite3_context_db_handle(context);
120020
120021
120022
120023
120024
120025
120026
120027
120028
120029
120030
120031
120032
120033
120034
120035
static void total_changes(
  sqlite3_context *context,
  int NotUsed,
  sqlite3_value **NotUsed2
){
  sqlite3 *db = sqlite3_context_db_handle(context);
  UNUSED_PARAMETER2(NotUsed, NotUsed2);
  /* IMP: R-52756-41993 This function was a wrapper around the
  ** sqlite3_total_changes() C/C++ interface. */
  sqlite3_result_int64(context, sqlite3_total_changes64(db));
}

/*
** A structure defining how to do GLOB-style comparisons.
*/
struct compareInfo {







|
|







120269
120270
120271
120272
120273
120274
120275
120276
120277
120278
120279
120280
120281
120282
120283
120284
static void total_changes(
  sqlite3_context *context,
  int NotUsed,
  sqlite3_value **NotUsed2
){
  sqlite3 *db = sqlite3_context_db_handle(context);
  UNUSED_PARAMETER2(NotUsed, NotUsed2);
  /* IMP: R-11217-42568 This function is a wrapper around the
  ** sqlite3_total_changes64() C/C++ interface. */
  sqlite3_result_int64(context, sqlite3_total_changes64(db));
}

/*
** A structure defining how to do GLOB-style comparisons.
*/
struct compareInfo {
121139
121140
121141
121142
121143
121144
121145






121146














121147
121148
121149
121150
121151
121152
121153
121154
121155
121156
121157
121158
121159
121160
121161
121162
121163

121164







121165
121166
121167




121168
121169

















121170


121171





121172
121173


121174
121175
121176
121177
121178

121179
121180
121181
121182
121183
121184
121185
121186
121187

121188
121189
121190
121191
121192
121193



121194
121195



121196
121197


121198
121199
121200
121201
121202
121203
121204

121205



121206
121207
121208
121209
121210
121211
121212
121213
121214
121215
121216
121217
121218
121219
121220
121221
121222

121223
121224
121225
121226
121227
121228
121229

121230
121231
121232
121233
121234
121235
121236
121237
121238
121239
121240
121241
121242
121243
#endif /* SQLITE_OMIT_WINDOWFUNC */
static void minMaxFinalize(sqlite3_context *context){
  minMaxValueFinalize(context, 0);
}

/*
** group_concat(EXPR, ?SEPARATOR?)






*/














static void groupConcatStep(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  const char *zVal;
  StrAccum *pAccum;
  const char *zSep;
  int nVal, nSep;
  assert( argc==1 || argc==2 );
  if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
  pAccum = (StrAccum*)sqlite3_aggregate_context(context, sizeof(*pAccum));

  if( pAccum ){
    sqlite3 *db = sqlite3_context_db_handle(context);
    int firstTerm = pAccum->mxAlloc==0;
    pAccum->mxAlloc = db->aLimit[SQLITE_LIMIT_LENGTH];

    if( !firstTerm ){







      if( argc==2 ){
        zSep = (char*)sqlite3_value_text(argv[1]);
        nSep = sqlite3_value_bytes(argv[1]);




      }else{
        zSep = ",";

















        nSep = 1;


      }





      if( zSep ) sqlite3_str_append(pAccum, zSep, nSep);
    }


    zVal = (char*)sqlite3_value_text(argv[0]);
    nVal = sqlite3_value_bytes(argv[0]);
    if( zVal ) sqlite3_str_append(pAccum, zVal, nVal);
  }
}

#ifndef SQLITE_OMIT_WINDOWFUNC
static void groupConcatInverse(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  int n;
  StrAccum *pAccum;
  assert( argc==1 || argc==2 );

  if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
  pAccum = (StrAccum*)sqlite3_aggregate_context(context, sizeof(*pAccum));
  /* pAccum is always non-NULL since groupConcatStep() will have always
  ** run frist to initialize it */
  if( ALWAYS(pAccum) ){
    n = sqlite3_value_bytes(argv[0]);



    if( argc==2 ){
      n += sqlite3_value_bytes(argv[1]);



    }else{
      n++;


    }
    if( n>=(int)pAccum->nChar ){
      pAccum->nChar = 0;
    }else{
      pAccum->nChar -= n;
      memmove(pAccum->zText, &pAccum->zText[n], pAccum->nChar);
    }

    if( pAccum->nChar==0 ) pAccum->mxAlloc = 0;



  }
}
#else
# define groupConcatInverse 0
#endif /* SQLITE_OMIT_WINDOWFUNC */
static void groupConcatFinalize(sqlite3_context *context){
  StrAccum *pAccum;
  pAccum = sqlite3_aggregate_context(context, 0);
  if( pAccum ){
    if( pAccum->accError==SQLITE_TOOBIG ){
      sqlite3_result_error_toobig(context);
    }else if( pAccum->accError==SQLITE_NOMEM ){
      sqlite3_result_error_nomem(context);
    }else{
      sqlite3_result_text(context, sqlite3StrAccumFinish(pAccum), -1,
                          sqlite3_free);
    }

  }
}
#ifndef SQLITE_OMIT_WINDOWFUNC
static void groupConcatValue(sqlite3_context *context){
  sqlite3_str *pAccum;
  pAccum = (sqlite3_str*)sqlite3_aggregate_context(context, 0);
  if( pAccum ){

    if( pAccum->accError==SQLITE_TOOBIG ){
      sqlite3_result_error_toobig(context);
    }else if( pAccum->accError==SQLITE_NOMEM ){
      sqlite3_result_error_nomem(context);
    }else{
      const char *zText = sqlite3_str_value(pAccum);
      sqlite3_result_text(context, zText, -1, SQLITE_TRANSIENT);
    }
  }
}
#else
# define groupConcatValue 0
#endif /* SQLITE_OMIT_WINDOWFUNC */








>
>
>
>
>
>

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






|




|
<
|

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

>
>


|


>






<
|

>

|
|

|
|
>
>
>
|
|
>
>
>

<
>
>

|
|

|
|

>
|
>
>
>






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




|
|
|
>






|







121388
121389
121390
121391
121392
121393
121394
121395
121396
121397
121398
121399
121400
121401
121402
121403
121404
121405
121406
121407
121408
121409
121410
121411
121412
121413
121414
121415
121416
121417
121418
121419
121420
121421
121422
121423
121424
121425
121426
121427

121428
121429
121430
121431
121432
121433
121434
121435
121436
121437
121438
121439
121440
121441
121442
121443
121444
121445
121446
121447
121448
121449
121450
121451
121452
121453
121454
121455
121456
121457
121458
121459
121460
121461
121462
121463
121464
121465
121466
121467
121468
121469
121470
121471
121472
121473
121474
121475
121476
121477
121478
121479
121480
121481
121482
121483
121484
121485
121486
121487
121488
121489
121490
121491

121492
121493
121494
121495
121496
121497
121498
121499
121500
121501
121502
121503
121504
121505
121506
121507
121508
121509

121510
121511
121512
121513
121514
121515
121516
121517
121518
121519
121520
121521
121522
121523
121524
121525
121526
121527
121528
121529
121530
121531
121532

121533
121534



121535

121536
121537
121538
121539
121540
121541
121542
121543
121544
121545
121546
121547
121548
121549
121550
121551
121552
121553
121554
121555
121556
121557
121558
#endif /* SQLITE_OMIT_WINDOWFUNC */
static void minMaxFinalize(sqlite3_context *context){
  minMaxValueFinalize(context, 0);
}

/*
** group_concat(EXPR, ?SEPARATOR?)
**
** The SEPARATOR goes before the EXPR string.  This is tragic.  The
** groupConcatInverse() implementation would have been easier if the
** SEPARATOR were appended after EXPR.  And the order is undocumented,
** so we could change it, in theory.  But the old behavior has been
** around for so long that we dare not, for fear of breaking something.
*/
typedef struct {
  StrAccum str;          /* The accumulated concatenation */
#ifndef SQLITE_OMIT_WINDOWFUNC
  int nAccum;            /* Number of strings presently concatenated */
  int nFirstSepLength;   /* Used to detect separator length change */
  /* If pnSepLengths!=0, refs an array of inter-string separator lengths,
  ** stored as actually incorporated into presently accumulated result.
  ** (Hence, its slots in use number nAccum-1 between method calls.)
  ** If pnSepLengths==0, nFirstSepLength is the length used throughout.
  */
  int *pnSepLengths;
#endif
} GroupConcatCtx;

static void groupConcatStep(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  const char *zVal;
  GroupConcatCtx *pGCC;
  const char *zSep;
  int nVal, nSep;
  assert( argc==1 || argc==2 );
  if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
  pGCC = (GroupConcatCtx*)sqlite3_aggregate_context(context, sizeof(*pGCC));

  if( pGCC ){
    sqlite3 *db = sqlite3_context_db_handle(context);
    int firstTerm = pGCC->str.mxAlloc==0;
    pGCC->str.mxAlloc = db->aLimit[SQLITE_LIMIT_LENGTH];
    if( argc==1 ){
      if( !firstTerm ){
        sqlite3_str_appendchar(&pGCC->str, 1, ',');
      }
#ifndef SQLITE_OMIT_WINDOWFUNC
      else{
        pGCC->nFirstSepLength = 1;
      }
#endif
    }else if( !firstTerm ){
      zSep = (char*)sqlite3_value_text(argv[1]);
      nSep = sqlite3_value_bytes(argv[1]);
      if( zSep ){
        sqlite3_str_append(&pGCC->str, zSep, nSep);
      }
#ifndef SQLITE_OMIT_WINDOWFUNC
      else{
        nSep = 0;
      }
      if( nSep != pGCC->nFirstSepLength || pGCC->pnSepLengths != 0 ){
        int *pnsl = pGCC->pnSepLengths;
        if( pnsl == 0 ){
          /* First separator length variation seen, start tracking them. */
          pnsl = (int*)sqlite3_malloc64((pGCC->nAccum+1) * sizeof(int));
          if( pnsl!=0 ){
            int i = 0, nA = pGCC->nAccum-1;
            while( i<nA ) pnsl[i++] = pGCC->nFirstSepLength;
          }
        }else{
          pnsl = (int*)sqlite3_realloc64(pnsl, pGCC->nAccum * sizeof(int));
        }
        if( pnsl!=0 ){
          if( ALWAYS(pGCC->nAccum>0) ){
            pnsl[pGCC->nAccum-1] = nSep;
          }
          pGCC->pnSepLengths = pnsl;
        }else{
          sqlite3StrAccumSetError(&pGCC->str, SQLITE_NOMEM);
        }
      }
#endif
    }
#ifndef SQLITE_OMIT_WINDOWFUNC
    else{
      pGCC->nFirstSepLength = sqlite3_value_bytes(argv[1]);
    }
    pGCC->nAccum += 1;
#endif
    zVal = (char*)sqlite3_value_text(argv[0]);
    nVal = sqlite3_value_bytes(argv[0]);
    if( zVal ) sqlite3_str_append(&pGCC->str, zVal, nVal);
  }
}

#ifndef SQLITE_OMIT_WINDOWFUNC
static void groupConcatInverse(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){

  GroupConcatCtx *pGCC;
  assert( argc==1 || argc==2 );
  (void)argc;  /* Suppress unused parameter warning */
  if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
  pGCC = (GroupConcatCtx*)sqlite3_aggregate_context(context, sizeof(*pGCC));
  /* pGCC is always non-NULL since groupConcatStep() will have always
  ** run frist to initialize it */
  if( ALWAYS(pGCC) ){
    int nVS = sqlite3_value_bytes(argv[0]);
    pGCC->nAccum -= 1;
    if( pGCC->pnSepLengths!=0 ){
      assert(pGCC->nAccum >= 0);
      if( pGCC->nAccum>0 ){
        nVS += *pGCC->pnSepLengths;
        memmove(pGCC->pnSepLengths, pGCC->pnSepLengths+1,
               (pGCC->nAccum-1)*sizeof(int));
      }
    }else{

      /* If removing single accumulated string, harmlessly over-do. */
      nVS += pGCC->nFirstSepLength;
    }
    if( nVS>=(int)pGCC->str.nChar ){
      pGCC->str.nChar = 0;
    }else{
      pGCC->str.nChar -= nVS;
      memmove(pGCC->str.zText, &pGCC->str.zText[nVS], pGCC->str.nChar);
    }
    if( pGCC->str.nChar==0 ){
      pGCC->str.mxAlloc = 0;
      sqlite3_free(pGCC->pnSepLengths);
      pGCC->pnSepLengths = 0;
    }
  }
}
#else
# define groupConcatInverse 0
#endif /* SQLITE_OMIT_WINDOWFUNC */
static void groupConcatFinalize(sqlite3_context *context){
  GroupConcatCtx *pGCC
    = (GroupConcatCtx*)sqlite3_aggregate_context(context, 0);
  if( pGCC ){

    sqlite3ResultStrAccum(context, &pGCC->str);
#ifndef SQLITE_OMIT_WINDOWFUNC



    sqlite3_free(pGCC->pnSepLengths);

#endif
  }
}
#ifndef SQLITE_OMIT_WINDOWFUNC
static void groupConcatValue(sqlite3_context *context){
  GroupConcatCtx *pGCC
    = (GroupConcatCtx*)sqlite3_aggregate_context(context, 0);
  if( pGCC ){
    StrAccum *pAccum = &pGCC->str;
    if( pAccum->accError==SQLITE_TOOBIG ){
      sqlite3_result_error_toobig(context);
    }else if( pAccum->accError==SQLITE_NOMEM ){
      sqlite3_result_error_nomem(context);
    }else{
      const char *zText = sqlite3_str_value(pAccum);
      sqlite3_result_text(context, zText, pAccum->nChar, SQLITE_TRANSIENT);
    }
  }
}
#else
# define groupConcatValue 0
#endif /* SQLITE_OMIT_WINDOWFUNC */

121547
121548
121549
121550
121551
121552
121553

121554
121555
121556
121557
121558
121559
121560
121561
121562
121563
121564
121565
121566
  ** FuncDef.pHash elements at start-time.  The elements of this array
  ** are read-only after initialization is complete.
  **
  ** For peak efficiency, put the most frequently used function last.
  */
  static FuncDef aBuiltinFunc[] = {
/***** Functions only available with SQLITE_TESTCTRL_INTERNAL_FUNCTIONS *****/

    TEST_FUNC(implies_nonnull_row, 2, INLINEFUNC_implies_nonnull_row, 0),
    TEST_FUNC(expr_compare,        2, INLINEFUNC_expr_compare,        0),
    TEST_FUNC(expr_implies_expr,   2, INLINEFUNC_expr_implies_expr,   0),
#ifdef SQLITE_DEBUG
    TEST_FUNC(affinity,          1, INLINEFUNC_affinity, 0),
#endif
/***** Regular functions *****/
#ifdef SQLITE_SOUNDEX
    FUNCTION(soundex,            1, 0, 0, soundexFunc      ),
#endif
#ifndef SQLITE_OMIT_LOAD_EXTENSION
    SFUNCTION(load_extension,    1, 0, 0, loadExt          ),
    SFUNCTION(load_extension,    2, 0, 0, loadExt          ),







>



<
|
|







121862
121863
121864
121865
121866
121867
121868
121869
121870
121871
121872

121873
121874
121875
121876
121877
121878
121879
121880
121881
  ** FuncDef.pHash elements at start-time.  The elements of this array
  ** are read-only after initialization is complete.
  **
  ** For peak efficiency, put the most frequently used function last.
  */
  static FuncDef aBuiltinFunc[] = {
/***** Functions only available with SQLITE_TESTCTRL_INTERNAL_FUNCTIONS *****/
#if !defined(SQLITE_UNTESTABLE)
    TEST_FUNC(implies_nonnull_row, 2, INLINEFUNC_implies_nonnull_row, 0),
    TEST_FUNC(expr_compare,        2, INLINEFUNC_expr_compare,        0),
    TEST_FUNC(expr_implies_expr,   2, INLINEFUNC_expr_implies_expr,   0),

    TEST_FUNC(affinity,            1, INLINEFUNC_affinity,            0),
#endif /* !defined(SQLITE_UNTESTABLE) */
/***** Regular functions *****/
#ifdef SQLITE_SOUNDEX
    FUNCTION(soundex,            1, 0, 0, soundexFunc      ),
#endif
#ifndef SQLITE_OMIT_LOAD_EXTENSION
    SFUNCTION(load_extension,    1, 0, 0, loadExt          ),
    SFUNCTION(load_extension,    2, 0, 0, loadExt          ),
123284
123285
123286
123287
123288
123289
123290






123291
123292
123293
123294


123295
123296
123297
123298
123299
123300
123301
123302
123303
123304
123305
123306
123307
123308












123309
123310
123311




















123312
123313
123314
123315
123316
123317
123318
123319
    pIdx->zColAff[n] = 0;
  }

  return pIdx->zColAff;
}

/*






** Compute the affinity string for table pTab, if it has not already been
** computed.  As an optimization, omit trailing SQLITE_AFF_BLOB affinities.
**
** If the affinity exists (if it is not entirely SQLITE_AFF_BLOB values) and


** if iReg>0 then code an OP_Affinity opcode that will set the affinities
** for register iReg and following.  Or if affinities exists and iReg==0,
** then just set the P4 operand of the previous opcode (which should  be
** an OP_MakeRecord) to the affinity string.
**
** A column affinity string has one character per column:
**
**  Character      Column affinity
**  ------------------------------
**  'A'            BLOB
**  'B'            TEXT
**  'C'            NUMERIC
**  'D'            INTEGER
**  'E'            REAL












*/
SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){
  int i, j;




















  char *zColAff = pTab->zColAff;
  if( zColAff==0 ){
    sqlite3 *db = sqlite3VdbeDb(v);
    zColAff = (char *)sqlite3DbMallocRaw(0, pTab->nCol+1);
    if( !zColAff ){
      sqlite3OomFault(db);
      return;
    }







>
>
>
>
>
>



|
>
>
|
|





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



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







123599
123600
123601
123602
123603
123604
123605
123606
123607
123608
123609
123610
123611
123612
123613
123614
123615
123616
123617
123618
123619
123620
123621
123622
123623
123624
123625
123626
123627
123628
123629
123630
123631
123632
123633
123634
123635
123636
123637
123638
123639
123640
123641
123642
123643
123644
123645
123646
123647
123648
123649
123650
123651
123652
123653
123654
123655
123656
123657
123658
123659
123660
123661
123662
123663
123664
123665
123666
123667
123668
123669
123670
123671
123672
123673
123674
    pIdx->zColAff[n] = 0;
  }

  return pIdx->zColAff;
}

/*
** Make changes to the evolving bytecode to do affinity transformations
** of values that are about to be gathered into a row for table pTab.
**
** For ordinary (legacy, non-strict) tables:
** -----------------------------------------
**
** Compute the affinity string for table pTab, if it has not already been
** computed.  As an optimization, omit trailing SQLITE_AFF_BLOB affinities.
**
** If the affinity string is empty (because it was all SQLITE_AFF_BLOB entries
** which were then optimized out) then this routine becomes a no-op.
**
** Otherwise if iReg>0 then code an OP_Affinity opcode that will set the
** affinities for register iReg and following.  Or if iReg==0,
** then just set the P4 operand of the previous opcode (which should  be
** an OP_MakeRecord) to the affinity string.
**
** A column affinity string has one character per column:
**
**    Character      Column affinity
**    ---------      ---------------
**    'A'            BLOB
**    'B'            TEXT
**    'C'            NUMERIC
**    'D'            INTEGER
**    'E'            REAL
**
** For STRICT tables:
** ------------------
**
** Generate an appropropriate OP_TypeCheck opcode that will verify the
** datatypes against the column definitions in pTab.  If iReg==0, that
** means an OP_MakeRecord opcode has already been generated and should be
** the last opcode generated.  The new OP_TypeCheck needs to be inserted
** before the OP_MakeRecord.  The new OP_TypeCheck should use the same
** register set as the OP_MakeRecord.  If iReg>0 then register iReg is
** the first of a series of registers that will form the new record.
** Apply the type checking to that array of registers.
*/
SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){
  int i, j;
  char *zColAff;
  if( pTab->tabFlags & TF_Strict ){
    if( iReg==0 ){
      /* Move the previous opcode (which should be OP_MakeRecord) forward
      ** by one slot and insert a new OP_TypeCheck where the current
      ** OP_MakeRecord is found */
      VdbeOp *pPrev;
      sqlite3VdbeAppendP4(v, pTab, P4_TABLE);
      pPrev = sqlite3VdbeGetOp(v, -1);
      assert( pPrev!=0 );
      assert( pPrev->opcode==OP_MakeRecord || sqlite3VdbeDb(v)->mallocFailed );
      pPrev->opcode = OP_TypeCheck;
      sqlite3VdbeAddOp3(v, OP_MakeRecord, pPrev->p1, pPrev->p2, pPrev->p3);
    }else{
      /* Insert an isolated OP_Typecheck */
      sqlite3VdbeAddOp2(v, OP_TypeCheck, iReg, pTab->nNVCol);
      sqlite3VdbeAppendP4(v, pTab, P4_TABLE);
    }
    return;
  }
  zColAff = pTab->zColAff;
  if( zColAff==0 ){
    sqlite3 *db = sqlite3VdbeDb(v);
    zColAff = (char *)sqlite3DbMallocRaw(0, pTab->nCol+1);
    if( !zColAff ){
      sqlite3OomFault(db);
      return;
    }
123331
123332
123333
123334
123335
123336
123337


123338
123339
123340
123341
123342
123343
123344
  }
  assert( zColAff!=0 );
  i = sqlite3Strlen30NN(zColAff);
  if( i ){
    if( iReg ){
      sqlite3VdbeAddOp4(v, OP_Affinity, iReg, i, 0, zColAff, i);
    }else{


      sqlite3VdbeChangeP4(v, -1, zColAff, i);
    }
  }
}

/*
** Return non-zero if the table pTab in database iDb or any of its indices







>
>







123686
123687
123688
123689
123690
123691
123692
123693
123694
123695
123696
123697
123698
123699
123700
123701
  }
  assert( zColAff!=0 );
  i = sqlite3Strlen30NN(zColAff);
  if( i ){
    if( iReg ){
      sqlite3VdbeAddOp4(v, OP_Affinity, iReg, i, 0, zColAff, i);
    }else{
      assert( sqlite3VdbeGetOp(v, -1)->opcode==OP_MakeRecord
              || sqlite3VdbeDb(v)->mallocFailed );
      sqlite3VdbeChangeP4(v, -1, zColAff, i);
    }
  }
}

/*
** Return non-zero if the table pTab in database iDb or any of its indices
125969
125970
125971
125972
125973
125974
125975



125976
125977
125978
125979
125980
125981
125982
  }
  if( pDest->nCol!=pSrc->nCol ){
    return 0;   /* Number of columns must be the same in tab1 and tab2 */
  }
  if( pDest->iPKey!=pSrc->iPKey ){
    return 0;   /* Both tables must have the same INTEGER PRIMARY KEY */
  }



  for(i=0; i<pDest->nCol; i++){
    Column *pDestCol = &pDest->aCol[i];
    Column *pSrcCol = &pSrc->aCol[i];
#ifdef SQLITE_ENABLE_HIDDEN_COLUMNS
    if( (db->mDbFlags & DBFLAG_Vacuum)==0
     && (pDestCol->colFlags | pSrcCol->colFlags) & COLFLAG_HIDDEN
    ){







>
>
>







126326
126327
126328
126329
126330
126331
126332
126333
126334
126335
126336
126337
126338
126339
126340
126341
126342
  }
  if( pDest->nCol!=pSrc->nCol ){
    return 0;   /* Number of columns must be the same in tab1 and tab2 */
  }
  if( pDest->iPKey!=pSrc->iPKey ){
    return 0;   /* Both tables must have the same INTEGER PRIMARY KEY */
  }
  if( (pDest->tabFlags & TF_Strict)!=0 && (pSrc->tabFlags & TF_Strict)==0 ){
    return 0;   /* Cannot feed from a non-strict into a strict table */
  }
  for(i=0; i<pDest->nCol; i++){
    Column *pDestCol = &pDest->aCol[i];
    Column *pSrcCol = &pSrc->aCol[i];
#ifdef SQLITE_ENABLE_HIDDEN_COLUMNS
    if( (db->mDbFlags & DBFLAG_Vacuum)==0
     && (pDestCol->colFlags | pSrcCol->colFlags) & COLFLAG_HIDDEN
    ){
128005
128006
128007
128008
128009
128010
128011

128012
128013
128014
128015
128016
128017
128018
128019
128020
128021
128022
128023
128024
128025
#define PragTyp_PAGE_SIZE                     31
#define PragTyp_PRAGMA_LIST                   32
#define PragTyp_SECURE_DELETE                 33
#define PragTyp_SHRINK_MEMORY                 34
#define PragTyp_SOFT_HEAP_LIMIT               35
#define PragTyp_SYNCHRONOUS                   36
#define PragTyp_TABLE_INFO                    37

#define PragTyp_TEMP_STORE                    38
#define PragTyp_TEMP_STORE_DIRECTORY          39
#define PragTyp_THREADS                       40
#define PragTyp_WAL_AUTOCHECKPOINT            41
#define PragTyp_WAL_CHECKPOINT                42
#define PragTyp_LOCK_STATUS                   43
#define PragTyp_STATS                         44

/* Property flags associated with various pragma. */
#define PragFlg_NeedSchema 0x01 /* Force schema load before running */
#define PragFlg_NoColumns  0x02 /* OP_ResultRow called with zero columns */
#define PragFlg_NoColumns1 0x04 /* zero columns if RHS argument is present */
#define PragFlg_ReadOnly   0x08 /* Read-only HEADER_VALUE */
#define PragFlg_Result0    0x10 /* Acts as query when no argument */







>
|
|
|
|
|
|
|







128365
128366
128367
128368
128369
128370
128371
128372
128373
128374
128375
128376
128377
128378
128379
128380
128381
128382
128383
128384
128385
128386
#define PragTyp_PAGE_SIZE                     31
#define PragTyp_PRAGMA_LIST                   32
#define PragTyp_SECURE_DELETE                 33
#define PragTyp_SHRINK_MEMORY                 34
#define PragTyp_SOFT_HEAP_LIMIT               35
#define PragTyp_SYNCHRONOUS                   36
#define PragTyp_TABLE_INFO                    37
#define PragTyp_TABLE_LIST                    38
#define PragTyp_TEMP_STORE                    39
#define PragTyp_TEMP_STORE_DIRECTORY          40
#define PragTyp_THREADS                       41
#define PragTyp_WAL_AUTOCHECKPOINT            42
#define PragTyp_WAL_CHECKPOINT                43
#define PragTyp_LOCK_STATUS                   44
#define PragTyp_STATS                         45

/* Property flags associated with various pragma. */
#define PragFlg_NeedSchema 0x01 /* Force schema load before running */
#define PragFlg_NoColumns  0x02 /* OP_ResultRow called with zero columns */
#define PragFlg_NoColumns1 0x04 /* zero columns if RHS argument is present */
#define PragFlg_ReadOnly   0x08 /* Read-only HEADER_VALUE */
#define PragFlg_Result0    0x10 /* Acts as query when no argument */
128044
128045
128046
128047
128048
128049
128050
128051
128052
128053
128054
128055
128056
128057
128058
128059
128060
128061
128062
128063
128064
128065
128066
128067
128068
128069
128070
128071
128072
128073
128074
128075
128076






128077
128078
128079
128080
128081
128082
128083
128084
128085
128086
128087
128088
128089
128090
128091
128092
128093
128094
128095
128096
  /*   9 */ "name",
  /*  10 */ "type",
  /*  11 */ "notnull",
  /*  12 */ "dflt_value",
  /*  13 */ "pk",
  /*  14 */ "hidden",
                           /* table_info reuses 8 */
  /*  15 */ "seqno",       /* Used by: index_xinfo */
  /*  16 */ "cid",
  /*  17 */ "name",
  /*  18 */ "desc",
  /*  19 */ "coll",
  /*  20 */ "key",
  /*  21 */ "name",        /* Used by: function_list */
  /*  22 */ "builtin",
  /*  23 */ "type",
  /*  24 */ "enc",
  /*  25 */ "narg",
  /*  26 */ "flags",
  /*  27 */ "tbl",         /* Used by: stats */
  /*  28 */ "idx",
  /*  29 */ "wdth",
  /*  30 */ "hght",
  /*  31 */ "flgs",
  /*  32 */ "seq",         /* Used by: index_list */
  /*  33 */ "name",
  /*  34 */ "unique",
  /*  35 */ "origin",
  /*  36 */ "partial",
  /*  37 */ "table",       /* Used by: foreign_key_check */
  /*  38 */ "rowid",
  /*  39 */ "parent",
  /*  40 */ "fkid",






                           /* index_info reuses 15 */
  /*  41 */ "seq",         /* Used by: database_list */
  /*  42 */ "name",
  /*  43 */ "file",
  /*  44 */ "busy",        /* Used by: wal_checkpoint */
  /*  45 */ "log",
  /*  46 */ "checkpointed",
                           /* collation_list reuses 32 */
  /*  47 */ "database",    /* Used by: lock_status */
  /*  48 */ "status",
  /*  49 */ "cache_size",  /* Used by: default_cache_size */
                           /* module_list pragma_list reuses 9 */
  /*  50 */ "timeout",     /* Used by: busy_timeout */
};

/* Definitions of all built-in pragmas */
typedef struct PragmaName {
  const char *const zName; /* Name of pragma */
  u8 ePragTyp;             /* PragTyp_XXX value */
  u8 mPragFlg;             /* Zero or more PragFlg_XXX values */







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

|







128405
128406
128407
128408
128409
128410
128411
128412
128413
128414
128415
128416
128417
128418
128419
128420
128421
128422
128423
128424
128425
128426
128427
128428
128429
128430
128431
128432
128433
128434
128435
128436
128437
128438
128439
128440
128441
128442
128443
128444
128445
128446
128447
128448
128449
128450
128451
128452
128453
128454
128455
128456
128457
128458
128459
128460
128461
128462
128463
  /*   9 */ "name",
  /*  10 */ "type",
  /*  11 */ "notnull",
  /*  12 */ "dflt_value",
  /*  13 */ "pk",
  /*  14 */ "hidden",
                           /* table_info reuses 8 */
  /*  15 */ "schema",      /* Used by: table_list */
  /*  16 */ "name",
  /*  17 */ "type",
  /*  18 */ "ncol",
  /*  19 */ "wr",
  /*  20 */ "strict",
  /*  21 */ "seqno",       /* Used by: index_xinfo */
  /*  22 */ "cid",
  /*  23 */ "name",
  /*  24 */ "desc",
  /*  25 */ "coll",
  /*  26 */ "key",
  /*  27 */ "name",        /* Used by: function_list */
  /*  28 */ "builtin",
  /*  29 */ "type",
  /*  30 */ "enc",
  /*  31 */ "narg",
  /*  32 */ "flags",
  /*  33 */ "tbl",         /* Used by: stats */
  /*  34 */ "idx",
  /*  35 */ "wdth",
  /*  36 */ "hght",
  /*  37 */ "flgs",
  /*  38 */ "seq",         /* Used by: index_list */
  /*  39 */ "name",
  /*  40 */ "unique",
  /*  41 */ "origin",
  /*  42 */ "partial",
  /*  43 */ "table",       /* Used by: foreign_key_check */
  /*  44 */ "rowid",
  /*  45 */ "parent",
  /*  46 */ "fkid",
                           /* index_info reuses 21 */
  /*  47 */ "seq",         /* Used by: database_list */
  /*  48 */ "name",
  /*  49 */ "file",
  /*  50 */ "busy",        /* Used by: wal_checkpoint */
  /*  51 */ "log",
  /*  52 */ "checkpointed",
                           /* collation_list reuses 38 */
  /*  53 */ "database",    /* Used by: lock_status */
  /*  54 */ "status",
  /*  55 */ "cache_size",  /* Used by: default_cache_size */
                           /* module_list pragma_list reuses 9 */
  /*  56 */ "timeout",     /* Used by: busy_timeout */
};

/* Definitions of all built-in pragmas */
typedef struct PragmaName {
  const char *const zName; /* Name of pragma */
  u8 ePragTyp;             /* PragTyp_XXX value */
  u8 mPragFlg;             /* Zero or more PragFlg_XXX values */
128133
128134
128135
128136
128137
128138
128139
128140
128141
128142
128143
128144
128145
128146
128147
  /* ColNames:  */ 0, 0,
  /* iArg:      */ SQLITE_AutoIndex },
#endif
#endif
 {/* zName:     */ "busy_timeout",
  /* ePragTyp:  */ PragTyp_BUSY_TIMEOUT,
  /* ePragFlg:  */ PragFlg_Result0,
  /* ColNames:  */ 50, 1,
  /* iArg:      */ 0 },
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
 {/* zName:     */ "cache_size",
  /* ePragTyp:  */ PragTyp_CACHE_SIZE,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },







|







128500
128501
128502
128503
128504
128505
128506
128507
128508
128509
128510
128511
128512
128513
128514
  /* ColNames:  */ 0, 0,
  /* iArg:      */ SQLITE_AutoIndex },
#endif
#endif
 {/* zName:     */ "busy_timeout",
  /* ePragTyp:  */ PragTyp_BUSY_TIMEOUT,
  /* ePragFlg:  */ PragFlg_Result0,
  /* ColNames:  */ 56, 1,
  /* iArg:      */ 0 },
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
 {/* zName:     */ "cache_size",
  /* ePragTyp:  */ PragTyp_CACHE_SIZE,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
128172
128173
128174
128175
128176
128177
128178
128179
128180
128181
128182
128183
128184
128185
128186
  /* ColNames:  */ 0, 0,
  /* iArg:      */ SQLITE_CkptFullFSync },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
 {/* zName:     */ "collation_list",
  /* ePragTyp:  */ PragTyp_COLLATION_LIST,
  /* ePragFlg:  */ PragFlg_Result0,
  /* ColNames:  */ 32, 2,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_COMPILEOPTION_DIAGS)
 {/* zName:     */ "compile_options",
  /* ePragTyp:  */ PragTyp_COMPILE_OPTIONS,
  /* ePragFlg:  */ PragFlg_Result0,
  /* ColNames:  */ 0, 0,







|







128539
128540
128541
128542
128543
128544
128545
128546
128547
128548
128549
128550
128551
128552
128553
  /* ColNames:  */ 0, 0,
  /* iArg:      */ SQLITE_CkptFullFSync },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
 {/* zName:     */ "collation_list",
  /* ePragTyp:  */ PragTyp_COLLATION_LIST,
  /* ePragFlg:  */ PragFlg_Result0,
  /* ColNames:  */ 38, 2,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_COMPILEOPTION_DIAGS)
 {/* zName:     */ "compile_options",
  /* ePragTyp:  */ PragTyp_COMPILE_OPTIONS,
  /* ePragFlg:  */ PragFlg_Result0,
  /* ColNames:  */ 0, 0,
128207
128208
128209
128210
128211
128212
128213
128214
128215
128216
128217
128218
128219
128220
128221
128222
128223
128224
128225
128226
128227
128228
  /* ColNames:  */ 0, 0,
  /* iArg:      */ BTREE_DATA_VERSION },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
 {/* zName:     */ "database_list",
  /* ePragTyp:  */ PragTyp_DATABASE_LIST,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0,
  /* ColNames:  */ 41, 3,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED)
 {/* zName:     */ "default_cache_size",
  /* ePragTyp:  */ PragTyp_DEFAULT_CACHE_SIZE,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1,
  /* ColNames:  */ 49, 1,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
 {/* zName:     */ "defer_foreign_keys",
  /* ePragTyp:  */ PragTyp_FLAG,
  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,







|






|







128574
128575
128576
128577
128578
128579
128580
128581
128582
128583
128584
128585
128586
128587
128588
128589
128590
128591
128592
128593
128594
128595
  /* ColNames:  */ 0, 0,
  /* iArg:      */ BTREE_DATA_VERSION },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
 {/* zName:     */ "database_list",
  /* ePragTyp:  */ PragTyp_DATABASE_LIST,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0,
  /* ColNames:  */ 47, 3,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED)
 {/* zName:     */ "default_cache_size",
  /* ePragTyp:  */ PragTyp_DEFAULT_CACHE_SIZE,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1,
  /* ColNames:  */ 55, 1,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
 {/* zName:     */ "defer_foreign_keys",
  /* ePragTyp:  */ PragTyp_FLAG,
  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
128244
128245
128246
128247
128248
128249
128250
128251
128252
128253
128254
128255
128256
128257
128258
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
 {/* zName:     */ "foreign_key_check",
  /* ePragTyp:  */ PragTyp_FOREIGN_KEY_CHECK,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1|PragFlg_SchemaOpt,
  /* ColNames:  */ 37, 4,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_FOREIGN_KEY)
 {/* zName:     */ "foreign_key_list",
  /* ePragTyp:  */ PragTyp_FOREIGN_KEY_LIST,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
  /* ColNames:  */ 0, 8,







|







128611
128612
128613
128614
128615
128616
128617
128618
128619
128620
128621
128622
128623
128624
128625
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
 {/* zName:     */ "foreign_key_check",
  /* ePragTyp:  */ PragTyp_FOREIGN_KEY_CHECK,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1|PragFlg_SchemaOpt,
  /* ColNames:  */ 43, 4,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_FOREIGN_KEY)
 {/* zName:     */ "foreign_key_list",
  /* ePragTyp:  */ PragTyp_FOREIGN_KEY_LIST,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
  /* ColNames:  */ 0, 8,
128287
128288
128289
128290
128291
128292
128293
128294
128295
128296
128297
128298
128299
128300
128301
  /* iArg:      */ SQLITE_FullFSync },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
#if !defined(SQLITE_OMIT_INTROSPECTION_PRAGMAS)
 {/* zName:     */ "function_list",
  /* ePragTyp:  */ PragTyp_FUNCTION_LIST,
  /* ePragFlg:  */ PragFlg_Result0,
  /* ColNames:  */ 21, 6,
  /* iArg:      */ 0 },
#endif
#endif
 {/* zName:     */ "hard_heap_limit",
  /* ePragTyp:  */ PragTyp_HARD_HEAP_LIMIT,
  /* ePragFlg:  */ PragFlg_Result0,
  /* ColNames:  */ 0, 0,







|







128654
128655
128656
128657
128658
128659
128660
128661
128662
128663
128664
128665
128666
128667
128668
  /* iArg:      */ SQLITE_FullFSync },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
#if !defined(SQLITE_OMIT_INTROSPECTION_PRAGMAS)
 {/* zName:     */ "function_list",
  /* ePragTyp:  */ PragTyp_FUNCTION_LIST,
  /* ePragFlg:  */ PragFlg_Result0,
  /* ColNames:  */ 27, 6,
  /* iArg:      */ 0 },
#endif
#endif
 {/* zName:     */ "hard_heap_limit",
  /* ePragTyp:  */ PragTyp_HARD_HEAP_LIMIT,
  /* ePragFlg:  */ PragFlg_Result0,
  /* ColNames:  */ 0, 0,
128316
128317
128318
128319
128320
128321
128322
128323
128324
128325
128326
128327
128328
128329
128330
128331
128332
128333
128334
128335
128336
128337
128338
128339
128340
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
 {/* zName:     */ "index_info",
  /* ePragTyp:  */ PragTyp_INDEX_INFO,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
  /* ColNames:  */ 15, 3,
  /* iArg:      */ 0 },
 {/* zName:     */ "index_list",
  /* ePragTyp:  */ PragTyp_INDEX_LIST,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
  /* ColNames:  */ 32, 5,
  /* iArg:      */ 0 },
 {/* zName:     */ "index_xinfo",
  /* ePragTyp:  */ PragTyp_INDEX_INFO,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
  /* ColNames:  */ 15, 6,
  /* iArg:      */ 1 },
#endif
#if !defined(SQLITE_OMIT_INTEGRITY_CHECK)
 {/* zName:     */ "integrity_check",
  /* ePragTyp:  */ PragTyp_INTEGRITY_CHECK,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1|PragFlg_SchemaOpt,
  /* ColNames:  */ 0, 0,







|




|




|







128683
128684
128685
128686
128687
128688
128689
128690
128691
128692
128693
128694
128695
128696
128697
128698
128699
128700
128701
128702
128703
128704
128705
128706
128707
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
 {/* zName:     */ "index_info",
  /* ePragTyp:  */ PragTyp_INDEX_INFO,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
  /* ColNames:  */ 21, 3,
  /* iArg:      */ 0 },
 {/* zName:     */ "index_list",
  /* ePragTyp:  */ PragTyp_INDEX_LIST,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
  /* ColNames:  */ 38, 5,
  /* iArg:      */ 0 },
 {/* zName:     */ "index_xinfo",
  /* ePragTyp:  */ PragTyp_INDEX_INFO,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
  /* ColNames:  */ 21, 6,
  /* iArg:      */ 1 },
#endif
#if !defined(SQLITE_OMIT_INTEGRITY_CHECK)
 {/* zName:     */ "integrity_check",
  /* ePragTyp:  */ PragTyp_INTEGRITY_CHECK,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1|PragFlg_SchemaOpt,
  /* ColNames:  */ 0, 0,
128366
128367
128368
128369
128370
128371
128372
128373
128374
128375
128376
128377
128378
128379
128380
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
#endif
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
 {/* zName:     */ "lock_status",
  /* ePragTyp:  */ PragTyp_LOCK_STATUS,
  /* ePragFlg:  */ PragFlg_Result0,
  /* ColNames:  */ 47, 2,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
 {/* zName:     */ "locking_mode",
  /* ePragTyp:  */ PragTyp_LOCKING_MODE,
  /* ePragFlg:  */ PragFlg_Result0|PragFlg_SchemaReq,
  /* ColNames:  */ 0, 0,







|







128733
128734
128735
128736
128737
128738
128739
128740
128741
128742
128743
128744
128745
128746
128747
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
#endif
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
 {/* zName:     */ "lock_status",
  /* ePragTyp:  */ PragTyp_LOCK_STATUS,
  /* ePragFlg:  */ PragFlg_Result0,
  /* ColNames:  */ 53, 2,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
 {/* zName:     */ "locking_mode",
  /* ePragTyp:  */ PragTyp_LOCKING_MODE,
  /* ePragFlg:  */ PragFlg_Result0|PragFlg_SchemaReq,
  /* ColNames:  */ 0, 0,
128505
128506
128507
128508
128509
128510
128511
128512
128513
128514
128515
128516
128517
128518
128519
128520
128521
128522
128523
128524
128525
128526





128527
128528
128529
128530
128531
128532
128533
  /* iArg:      */ SQLITE_SqlTrace },
#endif
#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) && defined(SQLITE_DEBUG)
 {/* zName:     */ "stats",
  /* ePragTyp:  */ PragTyp_STATS,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq,
  /* ColNames:  */ 27, 5,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
 {/* zName:     */ "synchronous",
  /* ePragTyp:  */ PragTyp_SYNCHRONOUS,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
 {/* zName:     */ "table_info",
  /* ePragTyp:  */ PragTyp_TABLE_INFO,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
  /* ColNames:  */ 8, 6,





  /* iArg:      */ 0 },
 {/* zName:     */ "table_xinfo",
  /* ePragTyp:  */ PragTyp_TABLE_INFO,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
  /* ColNames:  */ 8, 7,
  /* iArg:      */ 1 },
#endif







|














>
>
>
>
>







128872
128873
128874
128875
128876
128877
128878
128879
128880
128881
128882
128883
128884
128885
128886
128887
128888
128889
128890
128891
128892
128893
128894
128895
128896
128897
128898
128899
128900
128901
128902
128903
128904
128905
  /* iArg:      */ SQLITE_SqlTrace },
#endif
#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) && defined(SQLITE_DEBUG)
 {/* zName:     */ "stats",
  /* ePragTyp:  */ PragTyp_STATS,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq,
  /* ColNames:  */ 33, 5,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
 {/* zName:     */ "synchronous",
  /* ePragTyp:  */ PragTyp_SYNCHRONOUS,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
 {/* zName:     */ "table_info",
  /* ePragTyp:  */ PragTyp_TABLE_INFO,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
  /* ColNames:  */ 8, 6,
  /* iArg:      */ 0 },
 {/* zName:     */ "table_list",
  /* ePragTyp:  */ PragTyp_TABLE_LIST,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result1,
  /* ColNames:  */ 15, 6,
  /* iArg:      */ 0 },
 {/* zName:     */ "table_xinfo",
  /* ePragTyp:  */ PragTyp_TABLE_INFO,
  /* ePragFlg:  */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
  /* ColNames:  */ 8, 7,
  /* iArg:      */ 1 },
#endif
128596
128597
128598
128599
128600
128601
128602
128603
128604
128605
128606
128607
128608
128609
128610
128611
128612
128613
128614
128615
128616
128617
128618
128619
128620
128621
  /* ePragTyp:  */ PragTyp_WAL_AUTOCHECKPOINT,
  /* ePragFlg:  */ 0,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
 {/* zName:     */ "wal_checkpoint",
  /* ePragTyp:  */ PragTyp_WAL_CHECKPOINT,
  /* ePragFlg:  */ PragFlg_NeedSchema,
  /* ColNames:  */ 44, 3,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
 {/* zName:     */ "writable_schema",
  /* ePragTyp:  */ PragTyp_FLAG,
  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ SQLITE_WriteSchema|SQLITE_NoSchemaError },
#endif
};
/* Number of pragmas: 67 on by default, 77 total. */

/************** End of pragma.h **********************************************/
/************** Continuing where we left off in pragma.c *********************/

/*
** Interpret the given string as a safety level.  Return 0 for OFF,
** 1 for ON or NORMAL, 2 for FULL, and 3 for EXTRA.  Return 1 for an empty or







|










|







128968
128969
128970
128971
128972
128973
128974
128975
128976
128977
128978
128979
128980
128981
128982
128983
128984
128985
128986
128987
128988
128989
128990
128991
128992
128993
  /* ePragTyp:  */ PragTyp_WAL_AUTOCHECKPOINT,
  /* ePragFlg:  */ 0,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ 0 },
 {/* zName:     */ "wal_checkpoint",
  /* ePragTyp:  */ PragTyp_WAL_CHECKPOINT,
  /* ePragFlg:  */ PragFlg_NeedSchema,
  /* ColNames:  */ 50, 3,
  /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
 {/* zName:     */ "writable_schema",
  /* ePragTyp:  */ PragTyp_FLAG,
  /* ePragFlg:  */ PragFlg_Result0|PragFlg_NoColumns1,
  /* ColNames:  */ 0, 0,
  /* iArg:      */ SQLITE_WriteSchema|SQLITE_NoSchemaError },
#endif
};
/* Number of pragmas: 68 on by default, 78 total. */

/************** End of pragma.h **********************************************/
/************** Continuing where we left off in pragma.c *********************/

/*
** Interpret the given string as a safety level.  Return 0 for OFF,
** 1 for ON or NORMAL, 2 for FULL, and 3 for EXTRA.  Return 1 for an empty or
129776
129777
129778
129779
129780
129781
129782
















































129783
129784
129785
129786
129787
129788
129789
               k,
               isHidden);
      }
    }
  }
  break;

















































#ifdef SQLITE_DEBUG
  case PragTyp_STATS: {
    Index *pIdx;
    HashElem *i;
    pParse->nMem = 5;
    sqlite3CodeVerifySchema(pParse, iDb);
    for(i=sqliteHashFirst(&pDb->pSchema->tblHash); i; i=sqliteHashNext(i)){







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







130148
130149
130150
130151
130152
130153
130154
130155
130156
130157
130158
130159
130160
130161
130162
130163
130164
130165
130166
130167
130168
130169
130170
130171
130172
130173
130174
130175
130176
130177
130178
130179
130180
130181
130182
130183
130184
130185
130186
130187
130188
130189
130190
130191
130192
130193
130194
130195
130196
130197
130198
130199
130200
130201
130202
130203
130204
130205
130206
130207
130208
130209
               k,
               isHidden);
      }
    }
  }
  break;

  /*
  **   PRAGMA table_list
  **
  ** Return a single row for each table, virtual table, or view in the
  ** entire schema.
  **
  ** schema:     Name of attached database hold this table
  ** name:       Name of the table itself
  ** type:       "table", "view", "virtual", "shadow"
  ** ncol:       Number of columns
  ** wr:         True for a WITHOUT ROWID table
  ** strict:     True for a STRICT table
  */
  case PragTyp_TABLE_LIST: {
    int ii;
    pParse->nMem = 6;
    sqlite3CodeVerifyNamedSchema(pParse, zDb);
    for(ii=0; ii<db->nDb; ii++){
      HashElem *k;
      Hash *pHash;
      if( zDb && sqlite3_stricmp(zDb, db->aDb[ii].zDbSName)!=0 ) continue;
      pHash = &db->aDb[ii].pSchema->tblHash;
      for(k=sqliteHashFirst(pHash); k; k=sqliteHashNext(k) ){
        Table *pTab = sqliteHashData(k);
        const char *zType;
        if( zRight && sqlite3_stricmp(zRight, pTab->zName)!=0 ) continue;
        if( IsView(pTab) ){
          zType = "view";
        }else if( IsVirtual(pTab) ){
          zType = "virtual";
        }else if( pTab->tabFlags & TF_Shadow ){
          zType = "shadow";
        }else{
          zType = "table";
        }
        sqlite3VdbeMultiLoad(v, 1, "sssiii",
           db->aDb[ii].zDbSName,
           pTab->zName,
           zType,
           pTab->nCol,
           (pTab->tabFlags & TF_WithoutRowid)!=0,
           (pTab->tabFlags & TF_Strict)!=0
        );
      }
    }
  }
  break;

#ifdef SQLITE_DEBUG
  case PragTyp_STATS: {
    Index *pIdx;
    HashElem *i;
    pParse->nMem = 5;
    sqlite3CodeVerifySchema(pParse, iDb);
    for(i=sqliteHashFirst(&pDb->pSchema->tblHash); i; i=sqliteHashNext(i)){
130235
130236
130237
130238
130239
130240
130241

130242
130243
130244
130245
130246
130247
130248
      for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
        Table *pTab = sqliteHashData(x);
        Index *pIdx, *pPk;
        Index *pPrior = 0;
        int loopTop;
        int iDataCur, iIdxCur;
        int r1 = -1;


        if( pTab->tnum<1 ) continue;  /* Skip VIEWs or VIRTUAL TABLEs */
        if( pObjTab && pObjTab!=pTab ) continue;
        pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab);
        sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenRead, 0,
                                   1, 0, &iDataCur, &iIdxCur);
        /* reg[7] counts the number of entries in the table.







>







130655
130656
130657
130658
130659
130660
130661
130662
130663
130664
130665
130666
130667
130668
130669
      for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
        Table *pTab = sqliteHashData(x);
        Index *pIdx, *pPk;
        Index *pPrior = 0;
        int loopTop;
        int iDataCur, iIdxCur;
        int r1 = -1;
        int bStrict;

        if( pTab->tnum<1 ) continue;  /* Skip VIEWs or VIRTUAL TABLEs */
        if( pObjTab && pObjTab!=pTab ) continue;
        pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab);
        sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenRead, 0,
                                   1, 0, &iDataCur, &iIdxCur);
        /* reg[7] counts the number of entries in the table.
130256
130257
130258
130259
130260
130261
130262

130263
130264


130265
130266

130267
130268
130269

130270
130271
130272
130273

130274
130275

















130276
130277

130278
130279

130280
130281
130282
130283
130284
130285
130286
        assert( sqlite3NoTempsInRange(pParse,1,7+j) );
        sqlite3VdbeAddOp2(v, OP_Rewind, iDataCur, 0); VdbeCoverage(v);
        loopTop = sqlite3VdbeAddOp2(v, OP_AddImm, 7, 1);
        if( !isQuick ){
          /* Sanity check on record header decoding */
          sqlite3VdbeAddOp3(v, OP_Column, iDataCur, pTab->nNVCol-1,3);
          sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG);

        }
        /* Verify that all NOT NULL columns really are NOT NULL */


        for(j=0; j<pTab->nCol; j++){
          char *zErr;

          int jmp2;
          if( j==pTab->iPKey ) continue;
          if( pTab->aCol[j].notNull==0 ) continue;

          sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, j, 3);
          if( sqlite3VdbeGetOp(v,-1)->opcode==OP_Column ){
            sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG);
          }

          jmp2 = sqlite3VdbeAddOp1(v, OP_NotNull, 3); VdbeCoverage(v);
          zErr = sqlite3MPrintf(db, "NULL value in %s.%s", pTab->zName,

















                              pTab->aCol[j].zCnName);
          sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);

          integrityCheckResultRow(v);
          sqlite3VdbeJumpHere(v, jmp2);

        }
        /* Verify CHECK constraints */
        if( pTab->pCheck && (db->flags & SQLITE_IgnoreChecks)==0 ){
          ExprList *pCheck = sqlite3ExprListDup(db, pTab->pCheck, 0);
          if( db->mallocFailed==0 ){
            int addrCkFault = sqlite3VdbeMakeLabel(pParse);
            int addrCkOk = sqlite3VdbeMakeLabel(pParse);







>

|
>
>


>
|

|
>




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







130677
130678
130679
130680
130681
130682
130683
130684
130685
130686
130687
130688
130689
130690
130691
130692
130693
130694
130695
130696
130697
130698
130699
130700
130701
130702
130703
130704
130705
130706
130707
130708
130709
130710
130711
130712
130713
130714
130715
130716
130717
130718
130719
130720
130721
130722
130723
130724
130725
130726
130727
130728
130729
130730
130731
130732
        assert( sqlite3NoTempsInRange(pParse,1,7+j) );
        sqlite3VdbeAddOp2(v, OP_Rewind, iDataCur, 0); VdbeCoverage(v);
        loopTop = sqlite3VdbeAddOp2(v, OP_AddImm, 7, 1);
        if( !isQuick ){
          /* Sanity check on record header decoding */
          sqlite3VdbeAddOp3(v, OP_Column, iDataCur, pTab->nNVCol-1,3);
          sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG);
          VdbeComment((v, "(right-most column)"));
        }
        /* Verify that all NOT NULL columns really are NOT NULL.  At the
        ** same time verify the type of the content of STRICT tables */
        bStrict = (pTab->tabFlags & TF_Strict)!=0;
        for(j=0; j<pTab->nCol; j++){
          char *zErr;
          Column *pCol = pTab->aCol + j;
          int doError, jmp2;
          if( j==pTab->iPKey ) continue;
          if( pCol->notNull==0 && !bStrict ) continue;
          doError = bStrict ? sqlite3VdbeMakeLabel(pParse) : 0;
          sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, j, 3);
          if( sqlite3VdbeGetOp(v,-1)->opcode==OP_Column ){
            sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG);
          }
          if( pCol->notNull ){
            jmp2 = sqlite3VdbeAddOp1(v, OP_NotNull, 3); VdbeCoverage(v);
            zErr = sqlite3MPrintf(db, "NULL value in %s.%s", pTab->zName,
                                pCol->zCnName);
            sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
            if( bStrict ){
              sqlite3VdbeGoto(v, doError);
            }else{
              integrityCheckResultRow(v);
            }
            sqlite3VdbeJumpHere(v, jmp2);
          }
          if( (pTab->tabFlags & TF_Strict)!=0
           && pCol->eCType!=COLTYPE_ANY
          ){
            jmp2 = sqlite3VdbeAddOp3(v, OP_IsNullOrType, 3, 0,
                                     sqlite3StdTypeMap[pCol->eCType-1]);
            VdbeCoverage(v);
            zErr = sqlite3MPrintf(db, "non-%s value in %s.%s",
                                  sqlite3StdType[pCol->eCType-1],
                                  pTab->zName, pTab->aCol[j].zCnName);
            sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
            sqlite3VdbeResolveLabel(v, doError);
            integrityCheckResultRow(v);
            sqlite3VdbeJumpHere(v, jmp2);
          }
        }
        /* Verify CHECK constraints */
        if( pTab->pCheck && (db->flags & SQLITE_IgnoreChecks)==0 ){
          ExprList *pCheck = sqlite3ExprListDup(db, pTab->pCheck, 0);
          if( db->mallocFailed==0 ){
            int addrCkFault = sqlite3VdbeMakeLabel(pParse);
            int addrCkOk = sqlite3VdbeMakeLabel(pParse);
131318
131319
131320
131321
131322
131323
131324
131325
131326
131327
131328
131329
131330
131331
131332
131333
131334
131335
131336
131337
131338
131339
131340
131341
131342
131343

131344
131345
131346
131347
131348
131349
131350
     || (db->init.newTnum>pData->mxPage && pData->mxPage>0)
    ){
      if( sqlite3Config.bExtraSchemaChecks ){
        corruptSchema(pData, argv, "invalid rootpage");
      }
    }
    db->init.orphanTrigger = 0;
    db->init.azInit = argv;
    pStmt = 0;
    TESTONLY(rcp = ) sqlite3Prepare(db, argv[4], -1, 0, 0, &pStmt, 0);
    rc = db->errCode;
    assert( (rc&0xFF)==(rcp&0xFF) );
    db->init.iDb = saved_iDb;
    /* assert( saved_iDb==0 || (db->mDbFlags & DBFLAG_Vacuum)!=0 ); */
    if( SQLITE_OK!=rc ){
      if( db->init.orphanTrigger ){
        assert( iDb==1 );
      }else{
        if( rc > pData->rc ) pData->rc = rc;
        if( rc==SQLITE_NOMEM ){
          sqlite3OomFault(db);
        }else if( rc!=SQLITE_INTERRUPT && (rc&0xFF)!=SQLITE_LOCKED ){
          corruptSchema(pData, argv, sqlite3_errmsg(db));
        }
      }
    }

    sqlite3_finalize(pStmt);
  }else if( argv[1]==0 || (argv[4]!=0 && argv[4][0]!=0) ){
    corruptSchema(pData, argv, 0);
  }else{
    /* If the SQL column is blank it means this is an index that
    ** was created to be the PRIMARY KEY or to fulfill a UNIQUE
    ** constraint for a CREATE TABLE.  The index should have already







|


















>







131764
131765
131766
131767
131768
131769
131770
131771
131772
131773
131774
131775
131776
131777
131778
131779
131780
131781
131782
131783
131784
131785
131786
131787
131788
131789
131790
131791
131792
131793
131794
131795
131796
131797
     || (db->init.newTnum>pData->mxPage && pData->mxPage>0)
    ){
      if( sqlite3Config.bExtraSchemaChecks ){
        corruptSchema(pData, argv, "invalid rootpage");
      }
    }
    db->init.orphanTrigger = 0;
    db->init.azInit = (const char**)argv;
    pStmt = 0;
    TESTONLY(rcp = ) sqlite3Prepare(db, argv[4], -1, 0, 0, &pStmt, 0);
    rc = db->errCode;
    assert( (rc&0xFF)==(rcp&0xFF) );
    db->init.iDb = saved_iDb;
    /* assert( saved_iDb==0 || (db->mDbFlags & DBFLAG_Vacuum)!=0 ); */
    if( SQLITE_OK!=rc ){
      if( db->init.orphanTrigger ){
        assert( iDb==1 );
      }else{
        if( rc > pData->rc ) pData->rc = rc;
        if( rc==SQLITE_NOMEM ){
          sqlite3OomFault(db);
        }else if( rc!=SQLITE_INTERRUPT && (rc&0xFF)!=SQLITE_LOCKED ){
          corruptSchema(pData, argv, sqlite3_errmsg(db));
        }
      }
    }
    db->init.azInit = sqlite3StdType; /* Any array of string ptrs will do */
    sqlite3_finalize(pStmt);
  }else if( argv[1]==0 || (argv[4]!=0 && argv[4][0]!=0) ){
    corruptSchema(pData, argv, 0);
  }else{
    /* If the SQL column is blank it means this is an index that
    ** was created to be the PRIMARY KEY or to fulfill a UNIQUE
    ** constraint for a CREATE TABLE.  The index should have already
132553
132554
132555
132556
132557
132558
132559



132560
132561
132562
132563
132564
132565
132566
  assert( pSrc->a[iLeft].pTab );
  assert( pSrc->a[iRight].pTab );

  pE1 = sqlite3CreateColumnExpr(db, pSrc, iLeft, iColLeft);
  pE2 = sqlite3CreateColumnExpr(db, pSrc, iRight, iColRight);

  pEq = sqlite3PExpr(pParse, TK_EQ, pE1, pE2);



  if( pEq && isOuterJoin ){
    ExprSetProperty(pEq, EP_FromJoin);
    assert( !ExprHasProperty(pEq, EP_TokenOnly|EP_Reduced) );
    ExprSetVVAProperty(pEq, EP_NoReduce);
    pEq->iRightJoinTable = pE2->iTable;
  }
  *ppWhere = sqlite3ExprAnd(pParse, *ppWhere, pEq);







>
>
>







133000
133001
133002
133003
133004
133005
133006
133007
133008
133009
133010
133011
133012
133013
133014
133015
133016
  assert( pSrc->a[iLeft].pTab );
  assert( pSrc->a[iRight].pTab );

  pE1 = sqlite3CreateColumnExpr(db, pSrc, iLeft, iColLeft);
  pE2 = sqlite3CreateColumnExpr(db, pSrc, iRight, iColRight);

  pEq = sqlite3PExpr(pParse, TK_EQ, pE1, pE2);
  assert( pE2!=0 || pEq==0 );  /* Due to db->mallocFailed test
                               ** in sqlite3DbMallocRawNN() called from
                               ** sqlite3PExpr(). */
  if( pEq && isOuterJoin ){
    ExprSetProperty(pEq, EP_FromJoin);
    assert( !ExprHasProperty(pEq, EP_TokenOnly|EP_Reduced) );
    ExprSetVVAProperty(pEq, EP_NoReduce);
    pEq->iRightJoinTable = pE2->iTable;
  }
  *ppWhere = sqlite3ExprAnd(pParse, *ppWhere, pEq);
134399
134400
134401
134402
134403
134404
134405
134406
134407
134408
134409
134410
134411
134412
134413
      if( pCol->zCnName ){
        memcpy(&pCol->zCnName[n+1], zType, m+1);
        pCol->colFlags |= COLFLAG_HASTYPE;
      }
    }
    if( pCol->affinity<=SQLITE_AFF_NONE ) pCol->affinity = aff;
    pColl = sqlite3ExprCollSeq(pParse, p);
    if( pColl && (pCol->colFlags & COLFLAG_HASCOLL)==0 ){
      assert( pTab->pIndex==0 );
      sqlite3ColumnSetColl(db, pCol, pColl->zName);
    }
  }
  pTab->szTabRow = 1; /* Any non-zero value works */
}








|







134849
134850
134851
134852
134853
134854
134855
134856
134857
134858
134859
134860
134861
134862
134863
      if( pCol->zCnName ){
        memcpy(&pCol->zCnName[n+1], zType, m+1);
        pCol->colFlags |= COLFLAG_HASTYPE;
      }
    }
    if( pCol->affinity<=SQLITE_AFF_NONE ) pCol->affinity = aff;
    pColl = sqlite3ExprCollSeq(pParse, p);
    if( pColl ){
      assert( pTab->pIndex==0 );
      sqlite3ColumnSetColl(db, pCol, pColl->zName);
    }
  }
  pTab->szTabRow = 1; /* Any non-zero value works */
}

134565
134566
134567
134568
134569
134570
134571
134572
134573
134574
134575
134576
134577
134578
134579
**
** Space to hold the KeyInfo structure is obtained from malloc. The calling
** function is responsible for ensuring that this structure is eventually
** freed.
*/
static KeyInfo *multiSelectOrderByKeyInfo(Parse *pParse, Select *p, int nExtra){
  ExprList *pOrderBy = p->pOrderBy;
  int nOrderBy = p->pOrderBy->nExpr;
  sqlite3 *db = pParse->db;
  KeyInfo *pRet = sqlite3KeyInfoAlloc(db, nOrderBy+nExtra, 1);
  if( pRet ){
    int i;
    for(i=0; i<nOrderBy; i++){
      struct ExprList_item *pItem = &pOrderBy->a[i];
      Expr *pTerm = pItem->pExpr;







|







135015
135016
135017
135018
135019
135020
135021
135022
135023
135024
135025
135026
135027
135028
135029
**
** Space to hold the KeyInfo structure is obtained from malloc. The calling
** function is responsible for ensuring that this structure is eventually
** freed.
*/
static KeyInfo *multiSelectOrderByKeyInfo(Parse *pParse, Select *p, int nExtra){
  ExprList *pOrderBy = p->pOrderBy;
  int nOrderBy = ALWAYS(pOrderBy!=0) ? pOrderBy->nExpr : 0;
  sqlite3 *db = pParse->db;
  KeyInfo *pRet = sqlite3KeyInfoAlloc(db, nOrderBy+nExtra, 1);
  if( pRet ){
    int i;
    for(i=0; i<nOrderBy; i++){
      struct ExprList_item *pItem = &pOrderBy->a[i];
      Expr *pTerm = pItem->pExpr;
134637
134638
134639
134640
134641
134642
134643
134644
134645
134646
134647
134648
134649
134650
134651
  Parse *pParse,        /* Parsing context */
  Select *p,            /* The recursive SELECT to be coded */
  SelectDest *pDest     /* What to do with query results */
){
  SrcList *pSrc = p->pSrc;      /* The FROM clause of the recursive query */
  int nCol = p->pEList->nExpr;  /* Number of columns in the recursive table */
  Vdbe *v = pParse->pVdbe;      /* The prepared statement under construction */
  Select *pSetup = p->pPrior;   /* The setup query */
  Select *pFirstRec;            /* Left-most recursive term */
  int addrTop;                  /* Top of the loop */
  int addrCont, addrBreak;      /* CONTINUE and BREAK addresses */
  int iCurrent = 0;             /* The Current table */
  int regCurrent;               /* Register holding Current table */
  int iQueue;                   /* The Queue table */
  int iDistinct = 0;            /* To ensure unique results if UNION */







|







135087
135088
135089
135090
135091
135092
135093
135094
135095
135096
135097
135098
135099
135100
135101
  Parse *pParse,        /* Parsing context */
  Select *p,            /* The recursive SELECT to be coded */
  SelectDest *pDest     /* What to do with query results */
){
  SrcList *pSrc = p->pSrc;      /* The FROM clause of the recursive query */
  int nCol = p->pEList->nExpr;  /* Number of columns in the recursive table */
  Vdbe *v = pParse->pVdbe;      /* The prepared statement under construction */
  Select *pSetup;               /* The setup query */
  Select *pFirstRec;            /* Left-most recursive term */
  int addrTop;                  /* Top of the loop */
  int addrCont, addrBreak;      /* CONTINUE and BREAK addresses */
  int iCurrent = 0;             /* The Current table */
  int regCurrent;               /* Register holding Current table */
  int iQueue;                   /* The Queue table */
  int iDistinct = 0;            /* To ensure unique results if UNION */
134721
134722
134723
134724
134725
134726
134727
134728
134729
134730
134731
134732
134733
134734
134735
  /* Figure out how many elements of the compound SELECT are part of the
  ** recursive query.  Make sure no recursive elements use aggregate
  ** functions.  Mark the recursive elements as UNION ALL even if they
  ** are really UNION because the distinctness will be enforced by the
  ** iDistinct table.  pFirstRec is left pointing to the left-most
  ** recursive term of the CTE.
  */
  pFirstRec = p;
  for(pFirstRec=p; ALWAYS(pFirstRec!=0); pFirstRec=pFirstRec->pPrior){
    if( pFirstRec->selFlags & SF_Aggregate ){
      sqlite3ErrorMsg(pParse, "recursive aggregate queries not supported");
      goto end_of_recursive_query;
    }
    pFirstRec->op = TK_ALL;
    if( (pFirstRec->pPrior->selFlags & SF_Recursive)==0 ) break;







<







135171
135172
135173
135174
135175
135176
135177

135178
135179
135180
135181
135182
135183
135184
  /* Figure out how many elements of the compound SELECT are part of the
  ** recursive query.  Make sure no recursive elements use aggregate
  ** functions.  Mark the recursive elements as UNION ALL even if they
  ** are really UNION because the distinctness will be enforced by the
  ** iDistinct table.  pFirstRec is left pointing to the left-most
  ** recursive term of the CTE.
  */

  for(pFirstRec=p; ALWAYS(pFirstRec!=0); pFirstRec=pFirstRec->pPrior){
    if( pFirstRec->selFlags & SF_Aggregate ){
      sqlite3ErrorMsg(pParse, "recursive aggregate queries not supported");
      goto end_of_recursive_query;
    }
    pFirstRec->op = TK_ALL;
    if( (pFirstRec->pPrior->selFlags & SF_Recursive)==0 ) break;
135187
135188
135189
135190
135191
135192
135193

135194
135195
135196
135197
135198
135199
135200
    int i;                        /* Loop counter */
    KeyInfo *pKeyInfo;            /* Collating sequence for the result set */
    Select *pLoop;                /* For looping through SELECT statements */
    CollSeq **apColl;             /* For looping through pKeyInfo->aColl[] */
    int nCol;                     /* Number of columns in result set */

    assert( p->pNext==0 );

    nCol = p->pEList->nExpr;
    pKeyInfo = sqlite3KeyInfoAlloc(db, nCol, 1);
    if( !pKeyInfo ){
      rc = SQLITE_NOMEM_BKPT;
      goto multi_select_end;
    }
    for(i=0, apColl=pKeyInfo->aColl; i<nCol; i++, apColl++){







>







135636
135637
135638
135639
135640
135641
135642
135643
135644
135645
135646
135647
135648
135649
135650
    int i;                        /* Loop counter */
    KeyInfo *pKeyInfo;            /* Collating sequence for the result set */
    Select *pLoop;                /* For looping through SELECT statements */
    CollSeq **apColl;             /* For looping through pKeyInfo->aColl[] */
    int nCol;                     /* Number of columns in result set */

    assert( p->pNext==0 );
    assert( p->pEList!=0 );
    nCol = p->pEList->nExpr;
    pKeyInfo = sqlite3KeyInfoAlloc(db, nCol, 1);
    if( !pKeyInfo ){
      rc = SQLITE_NOMEM_BKPT;
      goto multi_select_end;
    }
    for(i=0, apColl=pKeyInfo->aColl; i<nCol; i++, apColl++){
135221
135222
135223
135224
135225
135226
135227


135228


135229
135230
135231
135232
135233
135234
135235
    }
    sqlite3KeyInfoUnref(pKeyInfo);
  }

multi_select_end:
  pDest->iSdst = dest.iSdst;
  pDest->nSdst = dest.nSdst;


  sqlite3SelectDelete(db, pDelete);


  return rc;
}
#endif /* SQLITE_OMIT_COMPOUND_SELECT */

/*
** Error message for when two or more terms of a compound select have different
** size result sets.







>
>
|
>
>







135671
135672
135673
135674
135675
135676
135677
135678
135679
135680
135681
135682
135683
135684
135685
135686
135687
135688
135689
    }
    sqlite3KeyInfoUnref(pKeyInfo);
  }

multi_select_end:
  pDest->iSdst = dest.iSdst;
  pDest->nSdst = dest.nSdst;
  if( pDelete ){
    sqlite3ParserAddCleanup(pParse,
        (void(*)(sqlite3*,void*))sqlite3SelectDelete,
        pDelete);
  }
  return rc;
}
#endif /* SQLITE_OMIT_COMPOUND_SELECT */

/*
** Error message for when two or more terms of a compound select have different
** size result sets.
135534
135535
135536
135537
135538
135539
135540

135541
135542
135543
135544
135545
135546
135547
  ** the ORDER BY clause covers every term of the result set.  Add
  ** terms to the ORDER BY clause as necessary.
  */
  if( op!=TK_ALL ){
    for(i=1; db->mallocFailed==0 && i<=p->pEList->nExpr; i++){
      struct ExprList_item *pItem;
      for(j=0, pItem=pOrderBy->a; j<nOrderBy; j++, pItem++){

        assert( pItem->u.x.iOrderByCol>0 );
        if( pItem->u.x.iOrderByCol==i ) break;
      }
      if( j==nOrderBy ){
        Expr *pNew = sqlite3Expr(db, TK_INTEGER, 0);
        if( pNew==0 ) return SQLITE_NOMEM_BKPT;
        pNew->flags |= EP_IntValue;







>







135988
135989
135990
135991
135992
135993
135994
135995
135996
135997
135998
135999
136000
136001
136002
  ** the ORDER BY clause covers every term of the result set.  Add
  ** terms to the ORDER BY clause as necessary.
  */
  if( op!=TK_ALL ){
    for(i=1; db->mallocFailed==0 && i<=p->pEList->nExpr; i++){
      struct ExprList_item *pItem;
      for(j=0, pItem=pOrderBy->a; j<nOrderBy; j++, pItem++){
        assert( pItem!=0 );
        assert( pItem->u.x.iOrderByCol>0 );
        if( pItem->u.x.iOrderByCol==i ) break;
      }
      if( j==nOrderBy ){
        Expr *pNew = sqlite3Expr(db, TK_INTEGER, 0);
        if( pNew==0 ) return SQLITE_NOMEM_BKPT;
        pNew->flags |= EP_IntValue;
135560
135561
135562
135563
135564
135565
135566

135567
135568
135569
135570
135571
135572
135573
  ** collation.
  */
  aPermute = sqlite3DbMallocRawNN(db, sizeof(u32)*(nOrderBy + 1));
  if( aPermute ){
    struct ExprList_item *pItem;
    aPermute[0] = nOrderBy;
    for(i=1, pItem=pOrderBy->a; i<=nOrderBy; i++, pItem++){

      assert( pItem->u.x.iOrderByCol>0 );
      assert( pItem->u.x.iOrderByCol<=p->pEList->nExpr );
      aPermute[i] = pItem->u.x.iOrderByCol - 1;
    }
    pKeyMerge = multiSelectOrderByKeyInfo(pParse, p, 1);
  }else{
    pKeyMerge = 0;







>







136015
136016
136017
136018
136019
136020
136021
136022
136023
136024
136025
136026
136027
136028
136029
  ** collation.
  */
  aPermute = sqlite3DbMallocRawNN(db, sizeof(u32)*(nOrderBy + 1));
  if( aPermute ){
    struct ExprList_item *pItem;
    aPermute[0] = nOrderBy;
    for(i=1, pItem=pOrderBy->a; i<=nOrderBy; i++, pItem++){
      assert( pItem!=0 );
      assert( pItem->u.x.iOrderByCol>0 );
      assert( pItem->u.x.iOrderByCol<=p->pEList->nExpr );
      aPermute[i] = pItem->u.x.iOrderByCol - 1;
    }
    pKeyMerge = multiSelectOrderByKeyInfo(pParse, p, 1);
  }else{
    pKeyMerge = 0;
137698
137699
137700
137701
137702
137703
137704
137705

137706
137707
137708
137709
137710
137711
137712
137713
137714
          if( (db->flags & SQLITE_EnableView)==0
           && pTab->pSchema!=db->aDb[1].pSchema
          ){
            sqlite3ErrorMsg(pParse, "access to view \"%s\" prohibited",
              pTab->zName);
          }
          pFrom->pSelect = sqlite3SelectDup(db, pTab->u.view.pSelect, 0);
        }else

#ifndef SQLITE_OMIT_VIRTUALTABLE
        if( ALWAYS(IsVirtual(pTab))
         && pFrom->fg.fromDDL
         && ALWAYS(pTab->u.vtab.p!=0)
         && pTab->u.vtab.p->eVtabRisk > ((db->flags & SQLITE_TrustedSchema)!=0)
        ){
          sqlite3ErrorMsg(pParse, "unsafe use of virtual table \"%s\"",
                                  pTab->zName);
        }







<
>

|







138154
138155
138156
138157
138158
138159
138160

138161
138162
138163
138164
138165
138166
138167
138168
138169
138170
          if( (db->flags & SQLITE_EnableView)==0
           && pTab->pSchema!=db->aDb[1].pSchema
          ){
            sqlite3ErrorMsg(pParse, "access to view \"%s\" prohibited",
              pTab->zName);
          }
          pFrom->pSelect = sqlite3SelectDup(db, pTab->u.view.pSelect, 0);

        }
#ifndef SQLITE_OMIT_VIRTUALTABLE
        else if( ALWAYS(IsVirtual(pTab))
         && pFrom->fg.fromDDL
         && ALWAYS(pTab->u.vtab.p!=0)
         && pTab->u.vtab.p->eVtabRisk > ((db->flags & SQLITE_TrustedSchema)!=0)
        ){
          sqlite3ErrorMsg(pParse, "unsafe use of virtual table \"%s\"",
                                  pTab->zName);
        }
138789
138790
138791
138792
138793
138794
138795
138796

138797
138798
138799
138800
138801
138802
138803
    */
    pParse->nHeight += sqlite3SelectExprHeight(p);

    /* Make copies of constant WHERE-clause terms in the outer query down
    ** inside the subquery.  This can help the subquery to run more efficiently.
    */
    if( OptimizationEnabled(db, SQLITE_PushDown)
     && (pItem->fg.isCte==0 || pItem->u2.pCteUse->eM10d!=M10d_Yes)

     && pushDownWhereTerms(pParse, pSub, p->pWhere, pItem->iCursor,
                           (pItem->fg.jointype & JT_OUTER)!=0)
    ){
#if SELECTTRACE_ENABLED
      if( sqlite3SelectTrace & 0x100 ){
        SELECTTRACE(0x100,pParse,p,
            ("After WHERE-clause push-down into subquery %d:\n", pSub->selId));







|
>







139245
139246
139247
139248
139249
139250
139251
139252
139253
139254
139255
139256
139257
139258
139259
139260
    */
    pParse->nHeight += sqlite3SelectExprHeight(p);

    /* Make copies of constant WHERE-clause terms in the outer query down
    ** inside the subquery.  This can help the subquery to run more efficiently.
    */
    if( OptimizationEnabled(db, SQLITE_PushDown)
     && (pItem->fg.isCte==0
         || (pItem->u2.pCteUse->eM10d!=M10d_Yes && pItem->u2.pCteUse->nUse<2))
     && pushDownWhereTerms(pParse, pSub, p->pWhere, pItem->iCursor,
                           (pItem->fg.jointype & JT_OUTER)!=0)
    ){
#if SELECTTRACE_ENABLED
      if( sqlite3SelectTrace & 0x100 ){
        SELECTTRACE(0x100,pParse,p,
            ("After WHERE-clause push-down into subquery %d:\n", pSub->selId));
138850
138851
138852
138853
138854
138855
138856

138857
138858
138859
138860
138861
138862
138863
      ** generated.  Invoke the subroutine to compute the materialization,
      ** the make the pItem->iCursor be a copy of the ephemerial table that
      ** holds the result of the materialization. */
      CteUse *pCteUse = pItem->u2.pCteUse;
      sqlite3VdbeAddOp2(v, OP_Gosub, pCteUse->regRtn, pCteUse->addrM9e);
      if( pItem->iCursor!=pCteUse->iCur ){
        sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pCteUse->iCur);

      }
      pSub->nSelectRow = pCteUse->nRowEst;
    }else if( (pPrior = isSelfJoinView(pTabList, pItem))!=0 ){
      /* This view has already been materialized by a prior entry in
      ** this same FROM clause.  Reuse it. */
      if( pPrior->addrFillSub ){
        sqlite3VdbeAddOp2(v, OP_Gosub, pPrior->regReturn, pPrior->addrFillSub);







>







139307
139308
139309
139310
139311
139312
139313
139314
139315
139316
139317
139318
139319
139320
139321
      ** generated.  Invoke the subroutine to compute the materialization,
      ** the make the pItem->iCursor be a copy of the ephemerial table that
      ** holds the result of the materialization. */
      CteUse *pCteUse = pItem->u2.pCteUse;
      sqlite3VdbeAddOp2(v, OP_Gosub, pCteUse->regRtn, pCteUse->addrM9e);
      if( pItem->iCursor!=pCteUse->iCur ){
        sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pCteUse->iCur);
        VdbeComment((v, "%!S", pItem));
      }
      pSub->nSelectRow = pCteUse->nRowEst;
    }else if( (pPrior = isSelfJoinView(pTabList, pItem))!=0 ){
      /* This view has already been materialized by a prior entry in
      ** this same FROM clause.  Reuse it. */
      if( pPrior->addrFillSub ){
        sqlite3VdbeAddOp2(v, OP_Gosub, pPrior->regReturn, pPrior->addrFillSub);
143565
143566
143567
143568
143569
143570
143571
143572

143573
143574
143575
143576
143577
143578
143579
** reaches zero, call the xDisconnect() method to delete the object.
*/
SQLITE_PRIVATE void sqlite3VtabUnlock(VTable *pVTab){
  sqlite3 *db = pVTab->db;

  assert( db );
  assert( pVTab->nRef>0 );
  assert( db->magic==SQLITE_MAGIC_OPEN || db->magic==SQLITE_MAGIC_ZOMBIE );


  pVTab->nRef--;
  if( pVTab->nRef==0 ){
    sqlite3_vtab *p = pVTab->pVtab;
    sqlite3VtabModuleUnref(pVTab->db, pVTab->pMod);
    if( p ){
      p->pModule->xDisconnect(p);







|
>







144023
144024
144025
144026
144027
144028
144029
144030
144031
144032
144033
144034
144035
144036
144037
144038
** reaches zero, call the xDisconnect() method to delete the object.
*/
SQLITE_PRIVATE void sqlite3VtabUnlock(VTable *pVTab){
  sqlite3 *db = pVTab->db;

  assert( db );
  assert( pVTab->nRef>0 );
  assert( db->eOpenState==SQLITE_STATE_OPEN
       || db->eOpenState==SQLITE_STATE_ZOMBIE );

  pVTab->nRef--;
  if( pVTab->nRef==0 ){
    sqlite3_vtab *p = pVTab->pVtab;
    sqlite3VtabModuleUnref(pVTab->db, pVTab->pMod);
    if( p ){
      p->pModule->xDisconnect(p);
144160
144161
144162
144163
144164
144165
144166

144167
144168
144169
144170
144171
144172
144173
144174
144175
144176
144177
144178
144179
144180
144181
144182
144183
144184
144185






144186
144187
144188
144189
144190
144191
144192
*/
SQLITE_API int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
  VtabCtx *pCtx;
  int rc = SQLITE_OK;
  Table *pTab;
  char *zErr = 0;
  Parse sParse;


#ifdef SQLITE_ENABLE_API_ARMOR
  if( !sqlite3SafetyCheckOk(db) || zCreateTable==0 ){
    return SQLITE_MISUSE_BKPT;
  }
#endif
  sqlite3_mutex_enter(db->mutex);
  pCtx = db->pVtabCtx;
  if( !pCtx || pCtx->bDeclared ){
    sqlite3Error(db, SQLITE_MISUSE);
    sqlite3_mutex_leave(db->mutex);
    return SQLITE_MISUSE_BKPT;
  }
  pTab = pCtx->pTab;
  assert( IsVirtual(pTab) );

  memset(&sParse, 0, sizeof(sParse));
  sParse.eParseMode = PARSE_MODE_DECLARE_VTAB;
  sParse.db = db;






  sParse.nQueryLoop = 1;
  if( SQLITE_OK==sqlite3RunParser(&sParse, zCreateTable, &zErr)
   && sParse.pNewTable
   && !db->mallocFailed
   && IsOrdinaryTable(sParse.pNewTable)
  ){
    if( !pTab->aCol ){







>



















>
>
>
>
>
>







144619
144620
144621
144622
144623
144624
144625
144626
144627
144628
144629
144630
144631
144632
144633
144634
144635
144636
144637
144638
144639
144640
144641
144642
144643
144644
144645
144646
144647
144648
144649
144650
144651
144652
144653
144654
144655
144656
144657
144658
*/
SQLITE_API int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
  VtabCtx *pCtx;
  int rc = SQLITE_OK;
  Table *pTab;
  char *zErr = 0;
  Parse sParse;
  int initBusy;

#ifdef SQLITE_ENABLE_API_ARMOR
  if( !sqlite3SafetyCheckOk(db) || zCreateTable==0 ){
    return SQLITE_MISUSE_BKPT;
  }
#endif
  sqlite3_mutex_enter(db->mutex);
  pCtx = db->pVtabCtx;
  if( !pCtx || pCtx->bDeclared ){
    sqlite3Error(db, SQLITE_MISUSE);
    sqlite3_mutex_leave(db->mutex);
    return SQLITE_MISUSE_BKPT;
  }
  pTab = pCtx->pTab;
  assert( IsVirtual(pTab) );

  memset(&sParse, 0, sizeof(sParse));
  sParse.eParseMode = PARSE_MODE_DECLARE_VTAB;
  sParse.db = db;
  /* We should never be able to reach this point while loading the
  ** schema.  Nevertheless, defend against that (turn off db->init.busy)
  ** in case a bug arises. */
  assert( db->init.busy==0 );
  initBusy = db->init.busy;
  db->init.busy = 0;
  sParse.nQueryLoop = 1;
  if( SQLITE_OK==sqlite3RunParser(&sParse, zCreateTable, &zErr)
   && sParse.pNewTable
   && !db->mallocFailed
   && IsOrdinaryTable(sParse.pNewTable)
  ){
    if( !pTab->aCol ){
144225
144226
144227
144228
144229
144230
144231

144232
144233
144234
144235
144236
144237
144238
  sParse.eParseMode = PARSE_MODE_NORMAL;

  if( sParse.pVdbe ){
    sqlite3VdbeFinalize(sParse.pVdbe);
  }
  sqlite3DeleteTable(db, sParse.pNewTable);
  sqlite3ParserReset(&sParse);


  assert( (rc&0xff)==rc );
  rc = sqlite3ApiExit(db, rc);
  sqlite3_mutex_leave(db->mutex);
  return rc;
}








>







144691
144692
144693
144694
144695
144696
144697
144698
144699
144700
144701
144702
144703
144704
144705
  sParse.eParseMode = PARSE_MODE_NORMAL;

  if( sParse.pVdbe ){
    sqlite3VdbeFinalize(sParse.pVdbe);
  }
  sqlite3DeleteTable(db, sParse.pNewTable);
  sqlite3ParserReset(&sParse);
  db->init.busy = initBusy;

  assert( (rc&0xff)==rc );
  rc = sqlite3ApiExit(db, rc);
  sqlite3_mutex_leave(db->mutex);
  return rc;
}

146531
146532
146533
146534
146535
146536
146537
146538
146539
146540
146541
146542
146543
146544
146545
  x.iTabCur = iTabCur;
  x.iIdxCur = iIdxCur;
  x.pWInfo = pWInfo;
  x.db = pWInfo->pParse->db;
  for(iIdxCol=0; iIdxCol<pIdx->nColumn; iIdxCol++){
    i16 iRef = pIdx->aiColumn[iIdxCol];
    if( iRef==XN_EXPR ){
      assert( aColExpr->a[iIdxCol].pExpr!=0 );
      x.pIdxExpr = aColExpr->a[iIdxCol].pExpr;
      if( sqlite3ExprIsConstant(x.pIdxExpr) ) continue;
      w.xExprCallback = whereIndexExprTransNode;
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
    }else if( iRef>=0
       && (pTab->aCol[iRef].colFlags & COLFLAG_VIRTUAL)!=0
       && ((pTab->aCol[iRef].colFlags & COLFLAG_HASCOLL)==0







|







146998
146999
147000
147001
147002
147003
147004
147005
147006
147007
147008
147009
147010
147011
147012
  x.iTabCur = iTabCur;
  x.iIdxCur = iIdxCur;
  x.pWInfo = pWInfo;
  x.db = pWInfo->pParse->db;
  for(iIdxCol=0; iIdxCol<pIdx->nColumn; iIdxCol++){
    i16 iRef = pIdx->aiColumn[iIdxCol];
    if( iRef==XN_EXPR ){
      assert( aColExpr!=0 && aColExpr->a[iIdxCol].pExpr!=0 );
      x.pIdxExpr = aColExpr->a[iIdxCol].pExpr;
      if( sqlite3ExprIsConstant(x.pIdxExpr) ) continue;
      w.xExprCallback = whereIndexExprTransNode;
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
    }else if( iRef>=0
       && (pTab->aCol[iRef].colFlags & COLFLAG_VIRTUAL)!=0
       && ((pTab->aCol[iRef].colFlags & COLFLAG_HASCOLL)==0
146797
146798
146799
146800
146801
146802
146803
146804
146805
146806
146807
146808
146809
146810
146811
146812
146813
    iReleaseReg = ++pParse->nMem;
    iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, 0, bRev, iReleaseReg);
    if( iRowidReg!=iReleaseReg ) sqlite3ReleaseTempReg(pParse, iReleaseReg);
    addrNxt = pLevel->addrNxt;
    sqlite3VdbeAddOp3(v, OP_SeekRowid, iCur, addrNxt, iRowidReg);
    VdbeCoverage(v);
    pLevel->op = OP_Noop;
    if( (pTerm->prereqAll & pLevel->notReady)==0 ){
      pTerm->wtFlags |= TERM_CODED;
    }
  }else if( (pLoop->wsFlags & WHERE_IPK)!=0
         && (pLoop->wsFlags & WHERE_COLUMN_RANGE)!=0
  ){
    /* Case 3:  We have an inequality comparison against the ROWID field.
    */
    int testOp = OP_Noop;
    int start;







<
<
<







147264
147265
147266
147267
147268
147269
147270



147271
147272
147273
147274
147275
147276
147277
    iReleaseReg = ++pParse->nMem;
    iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, 0, bRev, iReleaseReg);
    if( iRowidReg!=iReleaseReg ) sqlite3ReleaseTempReg(pParse, iReleaseReg);
    addrNxt = pLevel->addrNxt;
    sqlite3VdbeAddOp3(v, OP_SeekRowid, iCur, addrNxt, iRowidReg);
    VdbeCoverage(v);
    pLevel->op = OP_Noop;



  }else if( (pLoop->wsFlags & WHERE_IPK)!=0
         && (pLoop->wsFlags & WHERE_COLUMN_RANGE)!=0
  ){
    /* Case 3:  We have an inequality comparison against the ROWID field.
    */
    int testOp = OP_Noop;
    int start;
148078
148079
148080
148081
148082
148083
148084
148085
148086
148087
148088
148089
148090
148091
148092
        **    2019-05-02 https://sqlite.org/src/info/b043a54c3de54b28
        **    2019-06-10 https://sqlite.org/src/info/fd76310a5e843e07
        **    2019-06-14 https://sqlite.org/src/info/ce8717f0885af975
        **    2019-09-03 https://sqlite.org/src/info/0f0428096f17252a
        */
        if( pLeft->op!=TK_COLUMN
         || sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT
         || IsVirtual(pLeft->y.pTab)  /* Value might be numeric */
        ){
          int isNum;
          double rDummy;
          isNum = sqlite3AtoF(zNew, &rDummy, iTo, SQLITE_UTF8);
          if( isNum<=0 ){
            if( iTo==1 && zNew[0]=='-' ){
              isNum = +1;







|







148542
148543
148544
148545
148546
148547
148548
148549
148550
148551
148552
148553
148554
148555
148556
        **    2019-05-02 https://sqlite.org/src/info/b043a54c3de54b28
        **    2019-06-10 https://sqlite.org/src/info/fd76310a5e843e07
        **    2019-06-14 https://sqlite.org/src/info/ce8717f0885af975
        **    2019-09-03 https://sqlite.org/src/info/0f0428096f17252a
        */
        if( pLeft->op!=TK_COLUMN
         || sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT
         || (pLeft->y.pTab && IsVirtual(pLeft->y.pTab))  /* Might be numeric */
        ){
          int isNum;
          double rDummy;
          isNum = sqlite3AtoF(zNew, &rDummy, iTo, SQLITE_UTF8);
          if( isNum<=0 ){
            if( iTo==1 && zNew[0]=='-' ){
              isNum = +1;
149774
149775
149776
149777
149778
149779
149780
149781

149782
149783
149784
149785
149786
149787
149788
              pColl = sqlite3ExprCompareCollSeq(pParse, pX);
              if( pColl==0 ) pColl = pParse->db->pDfltColl;
              if( sqlite3StrICmp(pColl->zName, pScan->zCollName) ){
                continue;
              }
            }
            if( (pTerm->eOperator & (WO_EQ|WO_IS))!=0
             && (pX = pTerm->pExpr->pRight)->op==TK_COLUMN

             && pX->iTable==pScan->aiCur[0]
             && pX->iColumn==pScan->aiColumn[0]
            ){
              testcase( pTerm->eOperator & WO_IS );
              continue;
            }
            pScan->pWC = pWC;







|
>







150238
150239
150240
150241
150242
150243
150244
150245
150246
150247
150248
150249
150250
150251
150252
150253
              pColl = sqlite3ExprCompareCollSeq(pParse, pX);
              if( pColl==0 ) pColl = pParse->db->pDfltColl;
              if( sqlite3StrICmp(pColl->zName, pScan->zCollName) ){
                continue;
              }
            }
            if( (pTerm->eOperator & (WO_EQ|WO_IS))!=0
             && (pX = pTerm->pExpr->pRight, ALWAYS(pX!=0))
             && pX->op==TK_COLUMN
             && pX->iTable==pScan->aiCur[0]
             && pX->iColumn==pScan->aiColumn[0]
            ){
              testcase( pTerm->eOperator & WO_IS );
              continue;
            }
            pScan->pWC = pWC;
151456
151457
151458
151459
151460
151461
151462
151463

151464
151465
151466
151467
151468
151469
151470
    sqlite3DbFree(pWInfo->pParse->db, p);
  }
}

/*
** Return TRUE if all of the following are true:
**
**   (1)  X has the same or lower cost that Y

**   (2)  X uses fewer WHERE clause terms than Y
**   (3)  Every WHERE clause term used by X is also used by Y
**   (4)  X skips at least as many columns as Y
**   (5)  If X is a covering index, than Y is too
**
** Conditions (2) and (3) mean that X is a "proper subset" of Y.
** If X is a proper subset of Y then Y is a better choice and ought







|
>







151921
151922
151923
151924
151925
151926
151927
151928
151929
151930
151931
151932
151933
151934
151935
151936
    sqlite3DbFree(pWInfo->pParse->db, p);
  }
}

/*
** Return TRUE if all of the following are true:
**
**   (1)  X has the same or lower cost, or returns the same or fewer rows,
**        than Y.
**   (2)  X uses fewer WHERE clause terms than Y
**   (3)  Every WHERE clause term used by X is also used by Y
**   (4)  X skips at least as many columns as Y
**   (5)  If X is a covering index, than Y is too
**
** Conditions (2) and (3) mean that X is a "proper subset" of Y.
** If X is a proper subset of Y then Y is a better choice and ought
151479
151480
151481
151482
151483
151484
151485

151486
151487
151488
151489
151490
151491
151492
151493
151494
151495
151496
151497
151498
151499
151500
151501
151502
151503
151504
151505
151506
151507
151508
151509
151510
151511
151512
151513
151514
151515
151516
151517
151518
151519
151520
151521
151522
151523
151524
151525
151526
151527
151528


151529
151530
151531
151532
151533
151534
151535


151536
151537
151538
151539
151540
151541
151542
151543
151544
  const WhereLoop *pX,       /* First WhereLoop to compare */
  const WhereLoop *pY        /* Compare against this WhereLoop */
){
  int i, j;
  if( pX->nLTerm-pX->nSkip >= pY->nLTerm-pY->nSkip ){
    return 0; /* X is not a subset of Y */
  }

  if( pY->nSkip > pX->nSkip ) return 0;
  if( pX->rRun >= pY->rRun ){
    if( pX->rRun > pY->rRun ) return 0;    /* X costs more than Y */
    if( pX->nOut > pY->nOut ) return 0;    /* X costs more than Y */
  }
  for(i=pX->nLTerm-1; i>=0; i--){
    if( pX->aLTerm[i]==0 ) continue;
    for(j=pY->nLTerm-1; j>=0; j--){
      if( pY->aLTerm[j]==pX->aLTerm[i] ) break;
    }
    if( j<0 ) return 0;  /* X not a subset of Y since term X[i] not used by Y */
  }
  if( (pX->wsFlags&WHERE_IDX_ONLY)!=0
   && (pY->wsFlags&WHERE_IDX_ONLY)==0 ){
    return 0;  /* Constraint (5) */
  }
  return 1;  /* All conditions meet */
}

/*
** Try to adjust the cost of WhereLoop pTemplate upwards or downwards so
** that:
**
**   (1) pTemplate costs less than any other WhereLoops that are a proper
**       subset of pTemplate
**
**   (2) pTemplate costs more than any other WhereLoops for which pTemplate
**       is a proper subset.
**
** To say "WhereLoop X is a proper subset of Y" means that X uses fewer
** WHERE clause terms than Y and that every WHERE clause term used by X is
** also used by Y.
*/
static void whereLoopAdjustCost(const WhereLoop *p, WhereLoop *pTemplate){
  if( (pTemplate->wsFlags & WHERE_INDEXED)==0 ) return;
  for(; p; p=p->pNextLoop){
    if( p->iTab!=pTemplate->iTab ) continue;
    if( (p->wsFlags & WHERE_INDEXED)==0 ) continue;
    if( whereLoopCheaperProperSubset(p, pTemplate) ){
      /* Adjust pTemplate cost downward so that it is cheaper than its
      ** subset p. */
      WHERETRACE(0x80,("subset cost adjustment %d,%d to %d,%d\n",
                       pTemplate->rRun, pTemplate->nOut, p->rRun, p->nOut-1));


      pTemplate->rRun = p->rRun;
      pTemplate->nOut = p->nOut - 1;
    }else if( whereLoopCheaperProperSubset(pTemplate, p) ){
      /* Adjust pTemplate cost upward so that it is costlier than p since
      ** pTemplate is a proper subset of p */
      WHERETRACE(0x80,("subset cost adjustment %d,%d to %d,%d\n",
                       pTemplate->rRun, pTemplate->nOut, p->rRun, p->nOut+1));


      pTemplate->rRun = p->rRun;
      pTemplate->nOut = p->nOut + 1;
    }
  }
}

/*
** Search the list of WhereLoops in *ppPrev looking for one that can be
** replaced by pTemplate.







>

<
<
<
<















|
|




















|
>
>
|
|




|
>
>
|
|







151945
151946
151947
151948
151949
151950
151951
151952
151953




151954
151955
151956
151957
151958
151959
151960
151961
151962
151963
151964
151965
151966
151967
151968
151969
151970
151971
151972
151973
151974
151975
151976
151977
151978
151979
151980
151981
151982
151983
151984
151985
151986
151987
151988
151989
151990
151991
151992
151993
151994
151995
151996
151997
151998
151999
152000
152001
152002
152003
152004
152005
152006
152007
152008
152009
152010
152011
  const WhereLoop *pX,       /* First WhereLoop to compare */
  const WhereLoop *pY        /* Compare against this WhereLoop */
){
  int i, j;
  if( pX->nLTerm-pX->nSkip >= pY->nLTerm-pY->nSkip ){
    return 0; /* X is not a subset of Y */
  }
  if( pX->rRun>pY->rRun && pX->nOut>pY->nOut ) return 0;
  if( pY->nSkip > pX->nSkip ) return 0;




  for(i=pX->nLTerm-1; i>=0; i--){
    if( pX->aLTerm[i]==0 ) continue;
    for(j=pY->nLTerm-1; j>=0; j--){
      if( pY->aLTerm[j]==pX->aLTerm[i] ) break;
    }
    if( j<0 ) return 0;  /* X not a subset of Y since term X[i] not used by Y */
  }
  if( (pX->wsFlags&WHERE_IDX_ONLY)!=0
   && (pY->wsFlags&WHERE_IDX_ONLY)==0 ){
    return 0;  /* Constraint (5) */
  }
  return 1;  /* All conditions meet */
}

/*
** Try to adjust the cost and number of output rows of WhereLoop pTemplate
** upwards or downwards so that:
**
**   (1) pTemplate costs less than any other WhereLoops that are a proper
**       subset of pTemplate
**
**   (2) pTemplate costs more than any other WhereLoops for which pTemplate
**       is a proper subset.
**
** To say "WhereLoop X is a proper subset of Y" means that X uses fewer
** WHERE clause terms than Y and that every WHERE clause term used by X is
** also used by Y.
*/
static void whereLoopAdjustCost(const WhereLoop *p, WhereLoop *pTemplate){
  if( (pTemplate->wsFlags & WHERE_INDEXED)==0 ) return;
  for(; p; p=p->pNextLoop){
    if( p->iTab!=pTemplate->iTab ) continue;
    if( (p->wsFlags & WHERE_INDEXED)==0 ) continue;
    if( whereLoopCheaperProperSubset(p, pTemplate) ){
      /* Adjust pTemplate cost downward so that it is cheaper than its
      ** subset p. */
      WHERETRACE(0x80,("subset cost adjustment %d,%d to %d,%d\n",
                       pTemplate->rRun, pTemplate->nOut,
                       MIN(p->rRun, pTemplate->rRun),
                       MIN(p->nOut - 1, pTemplate->nOut)));
      pTemplate->rRun = MIN(p->rRun, pTemplate->rRun);
      pTemplate->nOut = MIN(p->nOut - 1, pTemplate->nOut);
    }else if( whereLoopCheaperProperSubset(pTemplate, p) ){
      /* Adjust pTemplate cost upward so that it is costlier than p since
      ** pTemplate is a proper subset of p */
      WHERETRACE(0x80,("subset cost adjustment %d,%d to %d,%d\n",
                       pTemplate->rRun, pTemplate->nOut,
                       MAX(p->rRun, pTemplate->rRun),
                       MAX(p->nOut + 1, pTemplate->nOut)));
      pTemplate->rRun = MAX(p->rRun, pTemplate->rRun);
      pTemplate->nOut = MAX(p->nOut + 1, pTemplate->nOut);
    }
  }
}

/*
** Search the list of WhereLoops in *ppPrev looking for one that can be
** replaced by pTemplate.
153527
153528
153529
153530
153531
153532
153533
153534
153535
153536
153537
153538
153539
153540
153541
        }
      }
    }
  } /* End the loop over all WhereLoops from outer-most down to inner-most */
  if( obSat==obDone ) return (i8)nOrderBy;
  if( !isOrderDistinct ){
    for(i=nOrderBy-1; i>0; i--){
      Bitmask m = MASKBIT(i) - 1;
      if( (obSat&m)==m ) return i;
    }
    return 0;
  }
  return -1;
}








|







153994
153995
153996
153997
153998
153999
154000
154001
154002
154003
154004
154005
154006
154007
154008
        }
      }
    }
  } /* End the loop over all WhereLoops from outer-most down to inner-most */
  if( obSat==obDone ) return (i8)nOrderBy;
  if( !isOrderDistinct ){
    for(i=nOrderBy-1; i>0; i--){
      Bitmask m = ALWAYS(i<BMS) ? MASKBIT(i) - 1 : 0;
      if( (obSat&m)==m ) return i;
    }
    return 0;
  }
  return -1;
}

154037
154038
154039
154040
154041
154042
154043

154044
154045
154046
154047
154048
154049
154050
154051
154052
154053
154054
154055
154056
154057

154058
154059
154060
154061
154062
154063
154064
154065
154066
154067
154068
154069
154070
154071
154072
154073
154074
154075
154076

154077
154078
154079
154080
154081
154082
154083
  WhereClause *pWC;
  WhereTerm *pTerm;
  WhereLoop *pLoop;
  int iCur;
  int j;
  Table *pTab;
  Index *pIdx;


  pWInfo = pBuilder->pWInfo;
  if( pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE ) return 0;
  assert( pWInfo->pTabList->nSrc>=1 );
  pItem = pWInfo->pTabList->a;
  pTab = pItem->pTab;
  if( IsVirtual(pTab) ) return 0;
  if( pItem->fg.isIndexedBy ) return 0;
  iCur = pItem->iCursor;
  pWC = &pWInfo->sWC;
  pLoop = pBuilder->pNew;
  pLoop->wsFlags = 0;
  pLoop->nSkip = 0;
  pTerm = sqlite3WhereFindTerm(pWC, iCur, -1, 0, WO_EQ|WO_IS, 0);

  if( pTerm ){
    testcase( pTerm->eOperator & WO_IS );
    pLoop->wsFlags = WHERE_COLUMN_EQ|WHERE_IPK|WHERE_ONEROW;
    pLoop->aLTerm[0] = pTerm;
    pLoop->nLTerm = 1;
    pLoop->u.btree.nEq = 1;
    /* TUNING: Cost of a rowid lookup is 10 */
    pLoop->rRun = 33;  /* 33==sqlite3LogEst(10) */
  }else{
    for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
      int opMask;
      assert( pLoop->aLTermSpace==pLoop->aLTerm );
      if( !IsUniqueIndex(pIdx)
       || pIdx->pPartIdxWhere!=0
       || pIdx->nKeyCol>ArraySize(pLoop->aLTermSpace)
      ) continue;
      opMask = pIdx->uniqNotNull ? (WO_EQ|WO_IS) : WO_EQ;
      for(j=0; j<pIdx->nKeyCol; j++){
        pTerm = sqlite3WhereFindTerm(pWC, iCur, j, 0, opMask, pIdx);

        if( pTerm==0 ) break;
        testcase( pTerm->eOperator & WO_IS );
        pLoop->aLTerm[j] = pTerm;
      }
      if( j!=pIdx->nKeyCol ) continue;
      pLoop->wsFlags = WHERE_COLUMN_EQ|WHERE_ONEROW|WHERE_INDEXED;
      if( pIdx->isCovering || (pItem->colUsed & pIdx->colNotIdxed)==0 ){







>













|
>


















|
>







154504
154505
154506
154507
154508
154509
154510
154511
154512
154513
154514
154515
154516
154517
154518
154519
154520
154521
154522
154523
154524
154525
154526
154527
154528
154529
154530
154531
154532
154533
154534
154535
154536
154537
154538
154539
154540
154541
154542
154543
154544
154545
154546
154547
154548
154549
154550
154551
154552
154553
  WhereClause *pWC;
  WhereTerm *pTerm;
  WhereLoop *pLoop;
  int iCur;
  int j;
  Table *pTab;
  Index *pIdx;
  WhereScan scan;

  pWInfo = pBuilder->pWInfo;
  if( pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE ) return 0;
  assert( pWInfo->pTabList->nSrc>=1 );
  pItem = pWInfo->pTabList->a;
  pTab = pItem->pTab;
  if( IsVirtual(pTab) ) return 0;
  if( pItem->fg.isIndexedBy ) return 0;
  iCur = pItem->iCursor;
  pWC = &pWInfo->sWC;
  pLoop = pBuilder->pNew;
  pLoop->wsFlags = 0;
  pLoop->nSkip = 0;
  pTerm = whereScanInit(&scan, pWC, iCur, -1, WO_EQ|WO_IS, 0);
  while( pTerm && pTerm->prereqRight ) pTerm = whereScanNext(&scan);
  if( pTerm ){
    testcase( pTerm->eOperator & WO_IS );
    pLoop->wsFlags = WHERE_COLUMN_EQ|WHERE_IPK|WHERE_ONEROW;
    pLoop->aLTerm[0] = pTerm;
    pLoop->nLTerm = 1;
    pLoop->u.btree.nEq = 1;
    /* TUNING: Cost of a rowid lookup is 10 */
    pLoop->rRun = 33;  /* 33==sqlite3LogEst(10) */
  }else{
    for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
      int opMask;
      assert( pLoop->aLTermSpace==pLoop->aLTerm );
      if( !IsUniqueIndex(pIdx)
       || pIdx->pPartIdxWhere!=0
       || pIdx->nKeyCol>ArraySize(pLoop->aLTermSpace)
      ) continue;
      opMask = pIdx->uniqNotNull ? (WO_EQ|WO_IS) : WO_EQ;
      for(j=0; j<pIdx->nKeyCol; j++){
        pTerm = whereScanInit(&scan, pWC, iCur, j, opMask, pIdx);
        while( pTerm && pTerm->prereqRight ) pTerm = whereScanNext(&scan);
        if( pTerm==0 ) break;
        testcase( pTerm->eOperator & WO_IS );
        pLoop->aLTerm[j] = pTerm;
      }
      if( j!=pIdx->nKeyCol ) continue;
      pLoop->wsFlags = WHERE_COLUMN_EQ|WHERE_ONEROW|WHERE_INDEXED;
      if( pIdx->isCovering || (pItem->colUsed & pIdx->colNotIdxed)==0 ){
154098
154099
154100
154101
154102
154103
154104

154105
154106





154107
154108
154109
154110
154111
154112
154113
    pLoop->maskSelf = 1; /* sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur); */
    pWInfo->a[0].iTabCur = iCur;
    pWInfo->nRowOut = 1;
    if( pWInfo->pOrderBy ) pWInfo->nOBSat =  pWInfo->pOrderBy->nExpr;
    if( pWInfo->wctrlFlags & WHERE_WANT_DISTINCT ){
      pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE;
    }

#ifdef SQLITE_DEBUG
    pLoop->cId = '0';





#endif
    return 1;
  }
  return 0;
}

/*







>


>
>
>
>
>







154568
154569
154570
154571
154572
154573
154574
154575
154576
154577
154578
154579
154580
154581
154582
154583
154584
154585
154586
154587
154588
154589
    pLoop->maskSelf = 1; /* sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur); */
    pWInfo->a[0].iTabCur = iCur;
    pWInfo->nRowOut = 1;
    if( pWInfo->pOrderBy ) pWInfo->nOBSat =  pWInfo->pOrderBy->nExpr;
    if( pWInfo->wctrlFlags & WHERE_WANT_DISTINCT ){
      pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE;
    }
    if( scan.iEquiv>1 ) pLoop->wsFlags |= WHERE_TRANSCONS;
#ifdef SQLITE_DEBUG
    pLoop->cId = '0';
#endif
#ifdef WHERETRACE_ENABLED
    if( sqlite3WhereTrace ){
      sqlite3DebugPrintf("whereShortCut() used to compute solution\n");
    }
#endif
    return 1;
  }
  return 0;
}

/*
156201
156202
156203
156204
156205
156206
156207



156208
156209
156210
156211
156212
156213
156214
    pSub = sqlite3SelectNew(
        pParse, pSublist, pSrc, pWhere, pGroupBy, pHaving, pSort, 0, 0
    );
    SELECTTRACE(1,pParse,pSub,
       ("New window-function subquery in FROM clause of (%u/%p)\n",
       p->selId, p));
    p->pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);



    if( p->pSrc ){
      Table *pTab2;
      p->pSrc->a[0].pSelect = pSub;
      sqlite3SrcListAssignCursors(pParse, p->pSrc);
      pSub->selFlags |= SF_Expanded|SF_OrderByReqd;
      pTab2 = sqlite3ResultSetOfSelect(pParse, pSub, SQLITE_AFF_NONE);
      pSub->selFlags |= (selFlags & SF_Aggregate);







>
>
>







156677
156678
156679
156680
156681
156682
156683
156684
156685
156686
156687
156688
156689
156690
156691
156692
156693
    pSub = sqlite3SelectNew(
        pParse, pSublist, pSrc, pWhere, pGroupBy, pHaving, pSort, 0, 0
    );
    SELECTTRACE(1,pParse,pSub,
       ("New window-function subquery in FROM clause of (%u/%p)\n",
       p->selId, p));
    p->pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
    assert( pSub!=0 || p->pSrc==0 ); /* Due to db->mallocFailed test inside
                                     ** of sqlite3DbMallocRawNN() called from
                                     ** sqlite3SrcListAppend() */
    if( p->pSrc ){
      Table *pTab2;
      p->pSrc->a[0].pSelect = pSub;
      sqlite3SrcListAssignCursors(pParse, p->pSrc);
      pSub->selFlags |= SF_Expanded|SF_OrderByReqd;
      pTab2 = sqlite3ResultSetOfSelect(pParse, pSub, SQLITE_AFF_NONE);
      pSub->selFlags |= (selFlags & SF_Aggregate);
156477
156478
156479
156480
156481
156482
156483
156484





156485
156486
156487
156488
156489
156490
156491
}

/*
** Return 0 if the two window objects are identical, 1 if they are
** different, or 2 if it cannot be determined if the objects are identical
** or not. Identical window objects can be processed in a single scan.
*/
SQLITE_PRIVATE int sqlite3WindowCompare(Parse *pParse, Window *p1, Window *p2, int bFilter){





  int res;
  if( NEVER(p1==0) || NEVER(p2==0) ) return 1;
  if( p1->eFrmType!=p2->eFrmType ) return 1;
  if( p1->eStart!=p2->eStart ) return 1;
  if( p1->eEnd!=p2->eEnd ) return 1;
  if( p1->eExclude!=p2->eExclude ) return 1;
  if( sqlite3ExprCompare(pParse, p1->pStart, p2->pStart, -1) ) return 1;







|
>
>
>
>
>







156956
156957
156958
156959
156960
156961
156962
156963
156964
156965
156966
156967
156968
156969
156970
156971
156972
156973
156974
156975
}

/*
** Return 0 if the two window objects are identical, 1 if they are
** different, or 2 if it cannot be determined if the objects are identical
** or not. Identical window objects can be processed in a single scan.
*/
SQLITE_PRIVATE int sqlite3WindowCompare(
  const Parse *pParse,
  const Window *p1,
  const Window *p2,
  int bFilter
){
  int res;
  if( NEVER(p1==0) || NEVER(p2==0) ) return 1;
  if( p1->eFrmType!=p2->eFrmType ) return 1;
  if( p1->eStart!=p2->eStart ) return 1;
  if( p1->eEnd!=p2->eEnd ) return 1;
  if( p1->eExclude!=p2->eExclude ) return 1;
  if( sqlite3ExprCompare(pParse, p1->pStart, p2->pStart, -1) ) return 1;
158472
158473
158474
158475
158476
158477
158478
158479
158480

158481
158482
158483
158484
158485
158486
158487
#define TK_IF                             18
#define TK_NOT                            19
#define TK_EXISTS                         20
#define TK_TEMP                           21
#define TK_LP                             22
#define TK_RP                             23
#define TK_AS                             24
#define TK_WITHOUT                        25
#define TK_COMMA                          26

#define TK_ABORT                          27
#define TK_ACTION                         28
#define TK_AFTER                          29
#define TK_ANALYZE                        30
#define TK_ASC                            31
#define TK_ATTACH                         32
#define TK_BEFORE                         33







<
|
>







158956
158957
158958
158959
158960
158961
158962

158963
158964
158965
158966
158967
158968
158969
158970
158971
#define TK_IF                             18
#define TK_NOT                            19
#define TK_EXISTS                         20
#define TK_TEMP                           21
#define TK_LP                             22
#define TK_RP                             23
#define TK_AS                             24

#define TK_COMMA                          25
#define TK_WITHOUT                        26
#define TK_ABORT                          27
#define TK_ACTION                         28
#define TK_AFTER                          29
#define TK_ANALYZE                        30
#define TK_ASC                            31
#define TK_ATTACH                         32
#define TK_BEFORE                         33
158690
158691
158692
158693
158694
158695
158696
158697
158698
158699
158700
158701
158702
158703
158704
158705
158706
158707
158708
158709
158710
158711
158712
158713
158714

158715
158716
158717

158718

158719
158720
158721
158722
158723
158724
158725
158726
158727
158728
158729
158730
158731
158732
158733
158734
158735
158736
158737
158738
158739
158740
158741
158742
158743
158744
158745
158746
158747
158748
158749
158750
158751
158752
158753
**    YY_MAX_REDUCE      Maximum value for reduce actions
*/
#ifndef INTERFACE
# define INTERFACE 1
#endif
/************* Begin control #defines *****************************************/
#define YYCODETYPE unsigned short int
#define YYNOCODE 317
#define YYACTIONTYPE unsigned short int
#define YYWILDCARD 101
#define sqlite3ParserTOKENTYPE Token
typedef union {
  int yyinit;
  sqlite3ParserTOKENTYPE yy0;
  Window* yy49;
  ExprList* yy70;
  Select* yy81;
  With* yy103;
  struct FrameBound yy117;
  struct {int value; int mask;} yy139;
  SrcList* yy153;
  TriggerStep* yy157;
  Upsert* yy190;
  struct TrigEvent yy262;
  Cte* yy329;

  int yy376;
  Expr* yy404;
  IdList* yy436;

  const char* yy504;

  u8 yy552;
} YYMINORTYPE;
#ifndef YYSTACKDEPTH
#define YYSTACKDEPTH 100
#endif
#define sqlite3ParserARG_SDECL
#define sqlite3ParserARG_PDECL
#define sqlite3ParserARG_PARAM
#define sqlite3ParserARG_FETCH
#define sqlite3ParserARG_STORE
#define sqlite3ParserCTX_SDECL Parse *pParse;
#define sqlite3ParserCTX_PDECL ,Parse *pParse
#define sqlite3ParserCTX_PARAM ,pParse
#define sqlite3ParserCTX_FETCH Parse *pParse=yypParser->pParse;
#define sqlite3ParserCTX_STORE yypParser->pParse=pParse;
#define YYFALLBACK 1
#define YYNSTATE             570
#define YYNRULE              398
#define YYNRULE_WITH_ACTION  337
#define YYNTOKEN             184
#define YY_MAX_SHIFT         569
#define YY_MIN_SHIFTREDUCE   825
#define YY_MAX_SHIFTREDUCE   1222
#define YY_ERROR_ACTION      1223
#define YY_ACCEPT_ACTION     1224
#define YY_NO_ACTION         1225
#define YY_MIN_REDUCE        1226
#define YY_MAX_REDUCE        1623
/************* End control #defines *******************************************/
#define YY_NLOOKAHEAD ((int)(sizeof(yy_lookahead)/sizeof(yy_lookahead[0])))

/* Define the yytestcase() macro to be a no-op if is not already defined
** otherwise.
**
** Applications can choose to define yytestcase() in the %include section







|






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















|
|
|

|
|
|
|
|
|
|
|







159174
159175
159176
159177
159178
159179
159180
159181
159182
159183
159184
159185
159186
159187
159188

159189
159190
159191
159192

159193
159194
159195
159196
159197
159198
159199
159200
159201
159202
159203
159204
159205
159206
159207
159208
159209
159210
159211
159212
159213
159214
159215
159216
159217
159218
159219
159220
159221
159222
159223
159224
159225
159226
159227
159228
159229
159230
159231
159232
159233
159234
159235
159236
159237
159238
**    YY_MAX_REDUCE      Maximum value for reduce actions
*/
#ifndef INTERFACE
# define INTERFACE 1
#endif
/************* Begin control #defines *****************************************/
#define YYCODETYPE unsigned short int
#define YYNOCODE 318
#define YYACTIONTYPE unsigned short int
#define YYWILDCARD 101
#define sqlite3ParserTOKENTYPE Token
typedef union {
  int yyinit;
  sqlite3ParserTOKENTYPE yy0;
  With* yy43;

  u32 yy51;
  int yy64;
  struct FrameBound yy81;
  struct {int value; int mask;} yy83;

  TriggerStep* yy95;
  Upsert* yy138;
  IdList* yy240;
  Cte* yy255;
  Select* yy303;
  Window* yy375;
  u8 yy534;
  ExprList* yy562;
  struct TrigEvent yy570;
  const char* yy600;
  SrcList* yy607;
  Expr* yy626;
} YYMINORTYPE;
#ifndef YYSTACKDEPTH
#define YYSTACKDEPTH 100
#endif
#define sqlite3ParserARG_SDECL
#define sqlite3ParserARG_PDECL
#define sqlite3ParserARG_PARAM
#define sqlite3ParserARG_FETCH
#define sqlite3ParserARG_STORE
#define sqlite3ParserCTX_SDECL Parse *pParse;
#define sqlite3ParserCTX_PDECL ,Parse *pParse
#define sqlite3ParserCTX_PARAM ,pParse
#define sqlite3ParserCTX_FETCH Parse *pParse=yypParser->pParse;
#define sqlite3ParserCTX_STORE yypParser->pParse=pParse;
#define YYFALLBACK 1
#define YYNSTATE             572
#define YYNRULE              401
#define YYNRULE_WITH_ACTION  339
#define YYNTOKEN             184
#define YY_MAX_SHIFT         571
#define YY_MIN_SHIFTREDUCE   829
#define YY_MAX_SHIFTREDUCE   1229
#define YY_ERROR_ACTION      1230
#define YY_ACCEPT_ACTION     1231
#define YY_NO_ACTION         1232
#define YY_MIN_REDUCE        1233
#define YY_MAX_REDUCE        1633
/************* End control #defines *******************************************/
#define YY_NLOOKAHEAD ((int)(sizeof(yy_lookahead)/sizeof(yy_lookahead[0])))

/* Define the yytestcase() macro to be a no-op if is not already defined
** otherwise.
**
** Applications can choose to define yytestcase() in the %include section
158806
158807
158808
158809
158810
158811
158812
158813
158814
158815
158816
158817
158818
158819
158820
158821
158822
158823
158824
158825
158826
158827
158828
158829
158830
158831
158832
158833
158834
158835
158836
158837
158838
158839
158840
158841
158842
158843
158844
158845
158846
158847
158848
158849
158850
158851
158852
158853
158854
158855
158856
158857
158858
158859
158860
158861
158862
158863
158864
158865
158866
158867
158868
158869
158870
158871
158872
158873
158874
158875
158876
158877
158878
158879
158880
158881
158882
158883
158884
158885
158886
158887
158888
158889
158890
158891
158892
158893
158894
158895
158896
158897
158898
158899
158900
158901
158902
158903
158904
158905
158906
158907
158908




158909
158910
158911
158912
158913
158914
158915
158916
158917
158918
158919
158920
158921
158922
158923
158924
158925
158926
158927
158928
158929
158930
158931
158932
158933
158934
158935
158936
158937
158938
158939
158940
158941
158942
158943
158944
158945
158946
158947
158948
158949
158950
158951
158952
158953
158954
158955
158956
158957
158958
158959
158960
158961
158962
158963
158964
158965
158966
158967
158968
158969
158970
158971
158972
158973
158974
158975
158976
158977
158978
158979
158980
158981
158982
158983
158984
158985
158986
158987
158988
158989
158990
158991
158992
158993
158994
158995
158996
158997
158998
158999
159000
159001
159002
159003
159004
159005
159006
159007
159008
159009
159010
159011
159012
159013
159014
159015
159016
159017

159018
159019
159020
159021
159022
159023
159024
159025
159026
159027
159028
159029
159030
159031
159032
159033
159034
159035
159036
159037
159038
159039
159040
159041
159042
159043
159044
159045
159046
159047
159048
159049
159050
159051
159052
159053
159054
159055
159056
159057
159058
159059
159060
159061
159062
159063
159064
159065
159066
159067
159068
159069
159070
159071
159072
159073
159074
159075
159076
159077
159078
159079
159080
159081
159082
159083
159084
159085
159086
159087
159088
159089
159090
159091
159092
159093
159094
159095
159096
159097
159098
159099
159100
159101
159102
159103
159104
159105
159106
159107
159108
159109
159110
159111
159112
159113
159114
159115
159116
159117
159118
159119
159120
159121
159122
159123
159124
159125
159126
159127
159128
159129
159130
159131
159132
159133
159134
159135
159136
159137
159138
159139
159140
159141
159142
159143
159144
159145
159146
159147
159148
159149
159150
159151
159152
159153
159154
159155
159156
159157
159158
159159
159160
159161
159162
159163
159164
159165
159166
159167
159168
159169
159170
159171
159172
159173
159174
159175
159176
159177
159178
159179
159180
159181
159182
159183
159184
159185
159186
159187
159188
159189
159190
159191
159192
159193
159194
159195
159196
159197
159198
159199
159200
159201
159202
159203
159204
159205
159206
159207
159208

159209
159210
159211
159212
159213
159214
159215
159216
159217
159218
159219
159220
159221
159222
159223
159224
159225
159226
159227
159228
159229
159230
159231
159232
159233
159234
159235
159236
159237
159238
159239
159240


159241
159242
159243
159244
159245
159246
159247
159248
159249
159250
159251
159252
159253
159254
159255
159256
159257
159258
159259
159260
159261
159262
159263
159264
159265
159266
159267
159268
159269
159270
159271
159272
159273
159274
159275
159276
159277
159278
159279
159280
159281
159282
159283
159284
159285
159286
159287
159288
159289
159290
159291
159292
159293
159294
159295
159296
159297
159298
159299
159300
159301
159302

159303
159304
159305
159306
159307
159308
159309
159310
159311
159312
159313
159314
159315
159316
159317
159318
159319
159320
159321
159322
159323
159324
159325
159326
159327
159328
159329
159330
159331
159332
159333
159334
159335
159336
159337
159338
159339
159340
159341
159342
159343
159344
159345
159346
159347
159348
159349
159350
159351
159352
159353
159354
159355
159356
159357
159358
159359
159360
159361
159362
159363
159364
159365
159366
159367
159368
159369
159370
159371
159372
159373
159374
159375
159376
159377
159378
159379
159380
159381
159382
159383
159384
159385
159386
159387
159388
159389
159390
159391
159392
159393
159394
159395
159396
159397
159398
159399
159400
159401
159402
159403
159404
159405
159406
159407

159408
159409
159410
159411
159412
159413
159414
**  yy_shift_ofst[]    For each state, the offset into yy_action for
**                     shifting terminals.
**  yy_reduce_ofst[]   For each state, the offset into yy_action for
**                     shifting non-terminals after a reduce.
**  yy_default[]       Default action for each state.
**
*********** Begin parsing tables **********************************************/
#define YY_ACTTAB_COUNT (2023)
static const YYACTIONTYPE yy_action[] = {
 /*     0 */   563, 1295,  563, 1274,  168, 1257,  115,  112,  218,  373,
 /*    10 */   563, 1295,  374,  563,  488,  563,  115,  112,  218,  406,
 /*    20 */  1300, 1300,   41,   41,   41,   41,  514, 1504,  520, 1298,
 /*    30 */  1298,  959,   41,   41, 1260,   71,   71,   51,   51,  960,
 /*    40 */   557,  557,  557,  122,  123,  113, 1200, 1200, 1035, 1038,
 /*    50 */  1028, 1028,  120,  120,  121,  121,  121,  121,  414,  406,
 /*    60 */   273,  273,  273,  273,  115,  112,  218,  115,  112,  218,
 /*    70 */   197,  268,  545,  560,  515,  560,  211,  563,  385,  248,
 /*    80 */   215,  521,  399,  122,  123,  113, 1200, 1200, 1035, 1038,
 /*    90 */  1028, 1028,  120,  120,  121,  121,  121,  121,  540,   13,
 /*   100 */    13, 1259,  119,  119,  119,  119,  118,  118,  117,  117,
 /*   110 */   117,  116,  441, 1176,  419,  197,  446,  320,  512, 1539,
 /*   120 */  1545,  372, 1547,    6,  371, 1176, 1148,  394, 1148,  406,
 /*   130 */  1545,  534,  115,  112,  218, 1415,   99,   30,  121,  121,
 /*   140 */   121,  121,  119,  119,  119,  119,  118,  118,  117,  117,
 /*   150 */   117,  116,  441,  122,  123,  113, 1200, 1200, 1035, 1038,
 /*   160 */  1028, 1028,  120,  120,  121,  121,  121,  121,   31, 1176,
 /*   170 */  1177, 1178,  241,  357, 1558,  501,  498,  497,  317,  124,
 /*   180 */   319, 1176, 1177, 1178, 1176,  496,  119,  119,  119,  119,
 /*   190 */   118,  118,  117,  117,  117,  116,  441,  139,   96,  406,
 /*   200 */   121,  121,  121,  121,  114,  117,  117,  117,  116,  441,
 /*   210 */   541, 1532,  119,  119,  119,  119,  118,  118,  117,  117,
 /*   220 */   117,  116,  441,  122,  123,  113, 1200, 1200, 1035, 1038,
 /*   230 */  1028, 1028,  120,  120,  121,  121,  121,  121,  406,  441,
 /*   240 */  1176, 1177, 1178,   81,  439,  439,  439,   80,  119,  119,
 /*   250 */   119,  119,  118,  118,  117,  117,  117,  116,  441,  488,
 /*   260 */  1176,  318,  122,  123,  113, 1200, 1200, 1035, 1038, 1028,
 /*   270 */  1028,  120,  120,  121,  121,  121,  121,  493, 1025, 1025,
 /*   280 */  1036, 1039,  119,  119,  119,  119,  118,  118,  117,  117,
 /*   290 */   117,  116,  441, 1584,  995, 1224,    1,    1,  569,    2,
 /*   300 */  1228, 1267,  137, 1503,  245,  305,  473,  140,  406,  860,
 /*   310 */   561, 1176,  914,  914, 1308,  359, 1176, 1177, 1178,  462,
 /*   320 */   330,  119,  119,  119,  119,  118,  118,  117,  117,  117,
 /*   330 */   116,  441,  122,  123,  113, 1200, 1200, 1035, 1038, 1028,
 /*   340 */  1028,  120,  120,  121,  121,  121,  121,  328,  273,  273,
 /*   350 */  1015,   83, 1029,  425, 1564,  569,    2, 1228,  304,  554,
 /*   360 */   925,  560,  305,  944,  140,  860, 1006, 1176, 1177, 1178,
 /*   370 */  1005, 1308,  411,  213,  511,  229,  119,  119,  119,  119,
 /*   380 */   118,  118,  117,  117,  117,  116,  441,  519,  347,  116,
 /*   390 */   441,  119,  119,  119,  119,  118,  118,  117,  117,  117,
 /*   400 */   116,  441, 1005, 1005, 1007,  273,  273,  445,  563,   16,
 /*   410 */    16, 1590,  563, 1540,  563,  406, 1176,    6,  560,  344,
 /*   420 */   182,  118,  118,  117,  117,  117,  116,  441,  416,  142,
 /*   430 */    71,   71,  229,  563,   71,   71,   55,   55,  203,  122,
 /*   440 */   123,  113, 1200, 1200, 1035, 1038, 1028, 1028,  120,  120,
 /*   450 */   121,  121,  121,  121,  217,   13,   13, 1176,  406,  568,
 /*   460 */  1400, 1228,  502,  137,  445,  168,  305,  545,  140, 1180,
 /*   470 */   424,  545, 1176, 1177, 1178, 1308,  544,  438,  437,  944,
 /*   480 */   513,  452,  122,  123,  113, 1200, 1200, 1035, 1038, 1028,
 /*   490 */  1028,  120,  120,  121,  121,  121,  121,  315,  119,  119,
 /*   500 */   119,  119,  118,  118,  117,  117,  117,  116,  441,  273,
 /*   510 */   273, 1143,  416, 1176, 1177, 1178,  543,  563, 1143,  304,
 /*   520 */   554, 1561,  560, 1207, 1143, 1207, 1180, 1143,  406,  530,
 /*   530 */   421, 1143,  864,  183, 1143,  143,  229,  562,   32,   71,
 /*   540 */    71,  119,  119,  119,  119,  118,  118,  117,  117,  117,
 /*   550 */   116,  441,  122,  123,  113, 1200, 1200, 1035, 1038, 1028,
 /*   560 */  1028,  120,  120,  121,  121,  121,  121,  406,  445,  241,
 /*   570 */  1176,  857,  501,  498,  497, 1176,  526,  189,  245,  538,
 /*   580 */  1539,  282,  496,  370,    6,  563,  529,  477,    5,  279,
 /*   590 */  1015,  122,  123,  113, 1200, 1200, 1035, 1038, 1028, 1028,
 /*   600 */   120,  120,  121,  121,  121,  121, 1006,   13,   13, 1414,
 /*   610 */  1005,  119,  119,  119,  119,  118,  118,  117,  117,  117,
 /*   620 */   116,  441,  426,  273,  273, 1176, 1176, 1177, 1178, 1619,
 /*   630 */   392, 1176, 1177, 1178, 1176,  342,  560,  406,  525,  361,
 /*   640 */   430, 1161, 1005, 1005, 1007,  348,  411,  357, 1558,  488,
 /*   650 */   119,  119,  119,  119,  118,  118,  117,  117,  117,  116,
 /*   660 */   441,  122,  123,  113, 1200, 1200, 1035, 1038, 1028, 1028,
 /*   670 */   120,  120,  121,  121,  121,  121,  406,  830,  831,  832,
 /*   680 */  1016, 1176, 1177, 1178,  396,  285,  148, 1312,  304,  554,
 /*   690 */  1176, 1177, 1178, 1467,  216,    3,  337,  137,  340,  560,
 /*   700 */   122,  123,  113, 1200, 1200, 1035, 1038, 1028, 1028,  120,
 /*   710 */   120,  121,  121,  121,  121,  563,  504,  946,  273,  273,
 /*   720 */   119,  119,  119,  119,  118,  118,  117,  117,  117,  116,
 /*   730 */   441,  560, 1176,  427,  563,  451,   98,   13,   13,  259,
 /*   740 */   276,  356,  507,  351,  506,  246,  406,  361,  469, 1530,
 /*   750 */  1000,  347,  293,  304,  554, 1589,   71,   71,  889,  119,
 /*   760 */   119,  119,  119,  118,  118,  117,  117,  117,  116,  441,
 /*   770 */   122,  123,  113, 1200, 1200, 1035, 1038, 1028, 1028,  120,
 /*   780 */   120,  121,  121,  121,  121,  406, 1143, 1078, 1176, 1177,
 /*   790 */  1178,  416, 1080,  300,  150,  995, 1080,  361,  361, 1143,
 /*   800 */   361,  378, 1143,  477,  563,  244,  243,  242, 1278,  122,
 /*   810 */   123,  113, 1200, 1200, 1035, 1038, 1028, 1028,  120,  120,
 /*   820 */   121,  121,  121,  121,  563,  880,   13,   13,  483,  119,
 /*   830 */   119,  119,  119,  118,  118,  117,  117,  117,  116,  441,
 /*   840 */  1176,  191,  540,  563,  147,  149,   13,   13,  328,  457,
 /*   850 */   316, 1083, 1083,  485, 1537,  406,  505, 1530,    6, 1514,
 /*   860 */   284,  192, 1277,  145,  881,   71,   71,  488,  119,  119,
 /*   870 */   119,  119,  118,  118,  117,  117,  117,  116,  441,  122,
 /*   880 */   123,  113, 1200, 1200, 1035, 1038, 1028, 1028,  120,  120,
 /*   890 */   121,  121,  121,  121,  563,  471, 1176, 1177, 1178,  406,
 /*   900 */   852,  327,  301,  462,  330, 1516,  270, 1530, 1530,  944,
 /*   910 */  1531, 1307,  313,    9,  842,  251,   71,   71,  477,  428,
 /*   920 */   146,  488,   38,  945,  101,  113, 1200, 1200, 1035, 1038,
 /*   930 */  1028, 1028,  120,  120,  121,  121,  121,  121,  119,  119,




 /*   940 */   119,  119,  118,  118,  117,  117,  117,  116,  441,  563,
 /*   950 */  1197, 1099,  563,  436,  563, 1533,  563,  852, 1122, 1617,
 /*   960 */   454,  290, 1617,  546,  251, 1303, 1100,  267,  267,  281,
 /*   970 */   404,   70,   70,  460,   71,   71,   71,   71,   13,   13,
 /*   980 */   560, 1101,  119,  119,  119,  119,  118,  118,  117,  117,
 /*   990 */   117,  116,  441,  542,  104,  273,  273,  273,  273, 1197,
 /*  1000 */   217, 1468,  900,  471,  450,  563, 1473, 1197,  560,  447,
 /*  1010 */   560,  545,  901,  440,  406, 1058,  292,  274,  274,  198,
 /*  1020 */   547,  450,  449, 1473, 1475,  944,  455,   56,   56,  410,
 /*  1030 */   560, 1122, 1618,  379,  406, 1618,  404, 1120,  122,  123,
 /*  1040 */   113, 1200, 1200, 1035, 1038, 1028, 1028,  120,  120,  121,
 /*  1050 */   121,  121,  121, 1460,  406,   12, 1197, 1512,  122,  123,
 /*  1060 */   113, 1200, 1200, 1035, 1038, 1028, 1028,  120,  120,  121,
 /*  1070 */   121,  121,  121,  308,  471,  126,  359,  286,  122,  111,
 /*  1080 */   113, 1200, 1200, 1035, 1038, 1028, 1028,  120,  120,  121,
 /*  1090 */   121,  121,  121,  309,  450,  471, 1473,  119,  119,  119,
 /*  1100 */   119,  118,  118,  117,  117,  117,  116,  441, 1176,  563,
 /*  1110 */  1120,  482,  563,  312,  433,  479,  197,  119,  119,  119,
 /*  1120 */   119,  118,  118,  117,  117,  117,  116,  441,  405,   12,
 /*  1130 */   536,   15,   15,  478,   43,   43,  509,  119,  119,  119,
 /*  1140 */   119,  118,  118,  117,  117,  117,  116,  441,  289,  535,
 /*  1150 */   294,  563,  294,  391, 1220,  438,  437,  406, 1154,  403,
 /*  1160 */   402, 1400,  920, 1204, 1176, 1177, 1178,  919, 1206,  291,
 /*  1170 */  1306, 1249,  412,   57,   57,  488, 1205,  563,  556,  412,
 /*  1180 */  1176, 1344,  123,  113, 1200, 1200, 1035, 1038, 1028, 1028,
 /*  1190 */   120,  120,  121,  121,  121,  121, 1400, 1143,  563,   44,
 /*  1200 */    44, 1207,  194, 1207,  273,  273, 1400,  461,  537, 1154,
 /*  1210 */  1143,  108,  555, 1143,    4,  391, 1121,  560, 1538,  335,
 /*  1220 */    58,   58,    6, 1246, 1099,  380, 1400,  376,  558, 1536,
 /*  1230 */   563,  422, 1221,    6,  304,  554, 1176, 1177, 1178, 1100,
 /*  1240 */   119,  119,  119,  119,  118,  118,  117,  117,  117,  116,
 /*  1250 */   441,  442,   59,   59, 1101,  516, 1535,  273,  273,  563,
 /*  1260 */     6,  563,  110,  552,  563,  528,  423,  413,  169,  548,
 /*  1270 */   560,  108,  555,  137,    4,  551,  484,  272,  215,  222,
 /*  1280 */   211,   60,   60,   61,   61,   98,   62,   62,  558,  273,
 /*  1290 */   273,  563, 1015,  467, 1221,  563,  434,  563,  106,  106,
 /*  1300 */     8,  920,  560,  273,  273,  107,  919,  442,  565,  564,
 /*  1310 */   563,  442, 1005,   45,   45,  464,  560,   46,   46,   47,
 /*  1320 */    47,   84,  202,  552, 1215,  404,  468,  563,  205,  304,
 /*  1330 */   554,  563,   49,   49,  563,  522,  404,  532,  563,  867,
 /*  1340 */   563,  105,  531,  103, 1005, 1005, 1007, 1008,   27,   50,
 /*  1350 */    50,  563, 1015,   63,   63,  475,   64,   64,  106,  106,
 /*  1360 */    65,   65,   14,   14,   17,  107,  563,  442,  565,  564,
 /*  1370 */   563,  303, 1005,   66,   66,  563,  226,  563,  959,  563,
 /*  1380 */   543,  404, 1196, 1343,  871,  278,  960,  456,  128,  128,
 /*  1390 */   563, 1065,   67,   67,  563,  206,  867,   52,   52,   68,
 /*  1400 */    68,   69,   69,  417, 1005, 1005, 1007, 1008,   27, 1563,
 /*  1410 */  1165,  444,   53,   53,  277, 1519,  156,  156,  307,  389,
 /*  1420 */   389,  388,  262,  386, 1165,  444,  839,  321,  277,  108,
 /*  1430 */   555,  523,    4,  389,  389,  388,  262,  386,  563,  223,
 /*  1440 */   839,  311,  326, 1492, 1117,   98,  558,  393, 1065,  310,
 /*  1450 */   563,  476,  563,  223,  563,  311,  879,  878, 1009,  277,
 /*  1460 */   157,  157,  463,  310,  389,  389,  388,  262,  386,  442,
 /*  1470 */   518,  839,   76,   76,   54,   54,   72,   72,  355,  225,
 /*  1480 */   563,  552,  275,  563,  223,  325,  311,  161,  354,  465,
 /*  1490 */   135,  563,  228,  225,  310,  532,  563,  206,  886,  887,
 /*  1500 */   533,  161,  129,  129,  135,   73,   73,  224,  962,  963,
 /*  1510 */  1015,  563,  287,  130,  130, 1009,  106,  106,  131,  131,
 /*  1520 */   563,  224,  563,  107,  225,  442,  565,  564,  997, 1276,
 /*  1530 */  1005,  250,  161,  127,  127,  135,  108,  555, 1077,    4,
 /*  1540 */  1077,  407,  155,  155,  154,  154,  304,  554, 1126,  563,
 /*  1550 */  1331,  563,  224,  558,  470,  407,  563,  250,  563, 1491,
 /*  1560 */   304,  554, 1005, 1005, 1007, 1008,   27,  563,  480,  332,
 /*  1570 */   448,  136,  136,  134,  134, 1340,  442,  336,  132,  132,
 /*  1580 */   133,  133,  563, 1076,  448, 1076,  407,  563,  552,   75,
 /*  1590 */    75,  304,  554,  339,  341,  343,  108,  555,  563,    4,
 /*  1600 */  1577,  299,  532,  563,   77,   77, 1291,  531,  472,   74,
 /*  1610 */    74,  250, 1275,  558,  350,  448,  331, 1015,  360,   98,
 /*  1620 */    42,   42, 1352,  106,  106,   48,   48, 1399,  494, 1327,
 /*  1630 */   107,  247,  442,  565,  564,  345,  442, 1005,   98, 1061,
 /*  1640 */   953,  917,  247,  250,  110, 1552,  550,  850,  552,  918,
 /*  1650 */   144, 1338,  110,  549, 1405, 1256, 1248, 1237, 1236, 1238,
 /*  1660 */  1571, 1324,  208,  390,  489,  265,  363,  200,  365, 1005,
 /*  1670 */  1005, 1007, 1008,   27,   11,  280,  221, 1015,  323,  474,
 /*  1680 */  1274,  367,  212,  106,  106,  924, 1386,  324,  288, 1381,
 /*  1690 */   107,  453,  442,  565,  564,  283,  329, 1005, 1391,  499,
 /*  1700 */   353, 1374, 1464,  108,  555, 1463,    4, 1574, 1390,  397,
 /*  1710 */  1215,  171,  254,  369,  383,  207,  195,  196, 1511,  553,
 /*  1720 */   558, 1509,  415, 1212,  100,  555,   83,    4,  204, 1005,
 /*  1730 */  1005, 1007, 1008,   27,  180,  166,  173,  219,   79,   82,
 /*  1740 */   458,  558,  175,  442,   35, 1387,  176,  459,  177,  178,
 /*  1750 */   492,  231,   96, 1469,  395,  552, 1393, 1392,   36,  466,
 /*  1760 */  1395,  184,  398,  481,  442, 1458,  235,   89, 1480,  487,
 /*  1770 */   266,  334,  237,  188,  490,  400,  552,  338,  238,  508,
 /*  1780 */  1239,  239, 1294, 1293, 1015, 1292, 1285,  429,   91,  871,
 /*  1790 */   106,  106, 1588,  213,  401, 1587,  431,  107, 1264,  442,
 /*  1800 */   565,  564, 1263,  352, 1005, 1015, 1262, 1586, 1557,  517,
 /*  1810 */   432,  106,  106, 1284,  297,  298,  358,  524,  107, 1335,
 /*  1820 */   442,  565,  564,   95, 1336, 1005,  252,  253,  435,  125,
 /*  1830 */   543, 1543,   10, 1444,  377, 1542, 1005, 1005, 1007, 1008,
 /*  1840 */    27,   97,  527,  375,  362,  102,  260,  364,  381, 1317,
 /*  1850 */   382, 1334,  366, 1245, 1333, 1316,  368, 1005, 1005, 1007,
 /*  1860 */  1008,   27, 1359, 1358,   34,  199, 1171,  566,  261,  263,
 /*  1870 */   264,  567, 1234,  158, 1229,  141,  295,  159, 1496,  302,
 /*  1880 */  1497, 1495, 1494,  160,  826,  209,  443,  201,  306,  210,
 /*  1890 */    78,  220, 1075,  138, 1073,  314,  162,  172, 1196,  227,
 /*  1900 */   174,  903,  322,  230, 1089,  179,  163,  164,  418,  408,
 /*  1910 */   409,  170,  181,   85,   86,  420,   87,  165, 1092,   88,
 /*  1920 */   233,  232, 1088,  151,   18,  234, 1081,  250,  333, 1209,
 /*  1930 */   185,  486,  236,  186,   37,  841,  491,  354,  240,  346,
 /*  1940 */   495,  187,   90,  869,   19,   20,  500,  503,  349,   92,
 /*  1950 */   167,  152,  296,  882,   93,  510,   94, 1159,  153, 1041,
 /*  1960 */  1128,   39,  214,  269, 1127,  271,  249,  952,  190,  947,
 /*  1970 */   110, 1149,   21,    7, 1153,   22, 1145,   23, 1147,   24,
 /*  1980 */  1133,   25, 1152,   33,  539,  193,   26, 1056,   98, 1042,
 /*  1990 */  1040, 1044, 1098, 1045, 1097,  256,  255,   28,   40,  257,
 /*  2000 */  1010,  851,  109,   29,  913,  559,  384,  387,  258, 1167,
 /*  2010 */  1166, 1225, 1225, 1225, 1579, 1225, 1225, 1225, 1225, 1225,
 /*  2020 */  1225, 1225, 1578,

};
static const YYCODETYPE yy_lookahead[] = {
 /*     0 */   192,  221,  192,  223,  192,  214,  272,  273,  274,  217,
 /*    10 */   192,  231,  217,  192,  192,  192,  272,  273,  274,   19,
 /*    20 */   233,  234,  214,  215,  214,  215,  203,  293,  203,  233,
 /*    30 */   234,   31,  214,  215,  214,  214,  215,  214,  215,   39,
 /*    40 */   208,  209,  210,   43,   44,   45,   46,   47,   48,   49,
 /*    50 */    50,   51,   52,   53,   54,   55,   56,   57,  236,   19,
 /*    60 */   237,  238,  237,  238,  272,  273,  274,  272,  273,  274,
 /*    70 */   192,  211,  251,  250,  251,  250,   26,  192,  200,  254,
 /*    80 */   255,  260,  204,   43,   44,   45,   46,   47,   48,   49,
 /*    90 */    50,   51,   52,   53,   54,   55,   56,   57,  192,  214,
 /*   100 */   215,  214,  102,  103,  104,  105,  106,  107,  108,  109,
 /*   110 */   110,  111,  112,   59,  229,  192,  294,   16,  306,  307,
 /*   120 */   312,  313,  312,  311,  314,   59,   86,  204,   88,   19,
 /*   130 */   312,  313,  272,  273,  274,  271,   26,   22,   54,   55,
 /*   140 */    56,   57,  102,  103,  104,  105,  106,  107,  108,  109,
 /*   150 */   110,  111,  112,   43,   44,   45,   46,   47,   48,   49,
 /*   160 */    50,   51,   52,   53,   54,   55,   56,   57,   53,  115,
 /*   170 */   116,  117,  118,  309,  310,  121,  122,  123,   77,   69,
 /*   180 */    79,  115,  116,  117,   59,  131,  102,  103,  104,  105,
 /*   190 */   106,  107,  108,  109,  110,  111,  112,   72,  148,   19,
 /*   200 */    54,   55,   56,   57,   58,  108,  109,  110,  111,  112,
 /*   210 */   304,  305,  102,  103,  104,  105,  106,  107,  108,  109,
 /*   220 */   110,  111,  112,   43,   44,   45,   46,   47,   48,   49,
 /*   230 */    50,   51,   52,   53,   54,   55,   56,   57,   19,  112,
 /*   240 */   115,  116,  117,   24,  208,  209,  210,   67,  102,  103,
 /*   250 */   104,  105,  106,  107,  108,  109,  110,  111,  112,  192,
 /*   260 */    59,  160,   43,   44,   45,   46,   47,   48,   49,   50,
 /*   270 */    51,   52,   53,   54,   55,   56,   57,   19,   46,   47,
 /*   280 */    48,   49,  102,  103,  104,  105,  106,  107,  108,  109,
 /*   290 */   110,  111,  112,  213,   73,  184,  185,  186,  187,  188,
 /*   300 */   189,  221,   81,  236,   46,  194,  192,  196,   19,   59,
 /*   310 */   133,   59,  135,  136,  203,  192,  115,  116,  117,  127,
 /*   320 */   128,  102,  103,  104,  105,  106,  107,  108,  109,  110,
 /*   330 */   111,  112,   43,   44,   45,   46,   47,   48,   49,   50,
 /*   340 */    51,   52,   53,   54,   55,   56,   57,  126,  237,  238,
 /*   350 */   100,  150,  120,  230,  186,  187,  188,  189,  137,  138,
 /*   360 */   108,  250,  194,   26,  196,  115,  116,  115,  116,  117,
 /*   370 */   120,  203,  114,  164,  165,  264,  102,  103,  104,  105,
 /*   380 */   106,  107,  108,  109,  110,  111,  112,  192,  130,  111,
 /*   390 */   112,  102,  103,  104,  105,  106,  107,  108,  109,  110,
 /*   400 */   111,  112,  152,  153,  154,  237,  238,  296,  192,  214,
 /*   410 */   215,  228,  192,  307,  192,   19,   59,  311,  250,   23,
 /*   420 */    22,  106,  107,  108,  109,  110,  111,  112,  192,   72,
 /*   430 */   214,  215,  264,  192,  214,  215,  214,  215,  149,   43,
 /*   440 */    44,   45,   46,   47,   48,   49,   50,   51,   52,   53,
 /*   450 */    54,   55,   56,   57,  117,  214,  215,   59,   19,  187,
 /*   460 */   192,  189,   23,   81,  296,  192,  194,  251,  196,   59,
 /*   470 */   229,  251,  115,  116,  117,  203,  260,  106,  107,  142,
 /*   480 */   260,  267,   43,   44,   45,   46,   47,   48,   49,   50,
 /*   490 */    51,   52,   53,   54,   55,   56,   57,  261,  102,  103,
 /*   500 */   104,  105,  106,  107,  108,  109,  110,  111,  112,  237,
 /*   510 */   238,   76,  192,  115,  116,  117,  144,  192,   76,  137,
 /*   520 */   138,  192,  250,  152,   89,  154,  116,   92,   19,   87,
 /*   530 */   262,   89,   23,   22,   92,  163,  264,  192,   22,  214,
 /*   540 */   215,  102,  103,  104,  105,  106,  107,  108,  109,  110,
 /*   550 */   111,  112,   43,   44,   45,   46,   47,   48,   49,   50,
 /*   560 */    51,   52,   53,   54,   55,   56,   57,   19,  296,  118,
 /*   570 */    59,   23,  121,  122,  123,   59,  251,   26,   46,  306,
 /*   580 */   307,  261,  131,  192,  311,  192,  144,  192,   22,  203,
 /*   590 */   100,   43,   44,   45,   46,   47,   48,   49,   50,   51,
 /*   600 */    52,   53,   54,   55,   56,   57,  116,  214,  215,  271,
 /*   610 */   120,  102,  103,  104,  105,  106,  107,  108,  109,  110,
 /*   620 */   111,  112,  229,  237,  238,   59,  115,  116,  117,  299,
 /*   630 */   300,  115,  116,  117,   59,   16,  250,   19,  192,  192,
 /*   640 */    19,   23,  152,  153,  154,   24,  114,  309,  310,  192,
 /*   650 */   102,  103,  104,  105,  106,  107,  108,  109,  110,  111,
 /*   660 */   112,   43,   44,   45,   46,   47,   48,   49,   50,   51,
 /*   670 */    52,   53,   54,   55,   56,   57,   19,    7,    8,    9,
 /*   680 */    23,  115,  116,  117,  203,  290,  239,  238,  137,  138,
 /*   690 */   115,  116,  117,  236,  192,   22,   77,   81,   79,  250,
 /*   700 */    43,   44,   45,   46,   47,   48,   49,   50,   51,   52,
 /*   710 */    53,   54,   55,   56,   57,  192,   95,  142,  237,  238,
 /*   720 */   102,  103,  104,  105,  106,  107,  108,  109,  110,  111,
 /*   730 */   112,  250,   59,  112,  192,  119,   26,  214,  215,  118,
 /*   740 */   119,  120,  121,  122,  123,  124,   19,  192,  267,  302,
 /*   750 */    23,  130,  229,  137,  138,   23,  214,  215,   26,  102,
 /*   760 */   103,  104,  105,  106,  107,  108,  109,  110,  111,  112,
 /*   770 */    43,   44,   45,   46,   47,   48,   49,   50,   51,   52,
 /*   780 */    53,   54,   55,   56,   57,   19,   76,   11,  115,  116,
 /*   790 */   117,  192,   29,  251,  239,   73,   33,  192,  192,   89,
 /*   800 */   192,  192,   92,  192,  192,  126,  127,  128,  224,   43,
 /*   810 */    44,   45,   46,   47,   48,   49,   50,   51,   52,   53,
 /*   820 */    54,   55,   56,   57,  192,   35,  214,  215,   65,  102,
 /*   830 */   103,  104,  105,  106,  107,  108,  109,  110,  111,  112,
 /*   840 */    59,  229,  192,  192,  239,  239,  214,  215,  126,  127,
 /*   850 */   128,  126,  127,  128,  307,   19,   66,  302,  311,  192,
 /*   860 */   261,  229,  224,   22,   74,  214,  215,  192,  102,  103,
 /*   870 */   104,  105,  106,  107,  108,  109,  110,  111,  112,   43,
 /*   880 */    44,   45,   46,   47,   48,   49,   50,   51,   52,   53,
 /*   890 */    54,   55,   56,   57,  192,  192,  115,  116,  117,   19,
 /*   900 */    59,  290,  251,  127,  128,  192,   23,  302,  302,   26,
 /*   910 */   302,  236,  192,   22,   21,   24,  214,  215,  192,  129,
 /*   920 */    22,  192,   24,  142,  158,   45,   46,   47,   48,   49,
 /*   930 */    50,   51,   52,   53,   54,   55,   56,   57,  102,  103,
 /*   940 */   104,  105,  106,  107,  108,  109,  110,  111,  112,  192,
 /*   950 */    59,   12,  192,  251,  192,  305,  192,  116,   22,   23,
 /*   960 */   242,  203,   26,  203,   24,  236,   27,  237,  238,  266,
 /*   970 */   252,  214,  215,   80,  214,  215,  214,  215,  214,  215,
 /*   980 */   250,   42,  102,  103,  104,  105,  106,  107,  108,  109,
 /*   990 */   110,  111,  112,  229,  158,  237,  238,  237,  238,   59,
 /*  1000 */   117,  281,   63,  192,  192,  192,  192,  116,  250,  192,
 /*  1010 */   250,  251,   73,  251,   19,  122,  290,  237,  238,   24,
 /*  1020 */   260,  209,  210,  209,  210,  142,  242,  214,  215,  197,
 /*  1030 */   250,   22,   23,  276,   19,   26,  252,  101,   43,   44,
 /*  1040 */    45,   46,   47,   48,   49,   50,   51,   52,   53,   54,
 /*  1050 */    55,   56,   57,  160,   19,  211,  116,  192,   43,   44,
 /*  1060 */    45,   46,   47,   48,   49,   50,   51,   52,   53,   54,
 /*  1070 */    55,   56,   57,  192,  192,   22,  192,  266,   43,   44,
 /*  1080 */    45,   46,   47,   48,   49,   50,   51,   52,   53,   54,
 /*  1090 */    55,   56,   57,  192,  282,  192,  282,  102,  103,  104,
 /*  1100 */   105,  106,  107,  108,  109,  110,  111,  112,   59,  192,
 /*  1110 */   101,  279,  192,  192,  230,  283,  192,  102,  103,  104,
 /*  1120 */   105,  106,  107,  108,  109,  110,  111,  112,  204,  211,
 /*  1130 */    66,  214,  215,  289,  214,  215,  108,  102,  103,  104,
 /*  1140 */   105,  106,  107,  108,  109,  110,  111,  112,  266,   85,
 /*  1150 */   226,  192,  228,   22,   23,  106,  107,   19,   94,  106,
 /*  1160 */   107,  192,  134,  114,  115,  116,  117,  139,  119,  266,
 /*  1170 */   203,  206,  207,  214,  215,  192,  127,  192,  206,  207,
 /*  1180 */    59,  192,   44,   45,   46,   47,   48,   49,   50,   51,
 /*  1190 */    52,   53,   54,   55,   56,   57,  192,   76,  192,  214,
 /*  1200 */   215,  152,  284,  154,  237,  238,  192,  289,   87,  145,
 /*  1210 */    89,   19,   20,   92,   22,   22,   23,  250,  307,  236,
 /*  1220 */   214,  215,  311,  203,   12,  247,  192,  249,   36,  307,
 /*  1230 */   192,  262,  101,  311,  137,  138,  115,  116,  117,   27,
 /*  1240 */   102,  103,  104,  105,  106,  107,  108,  109,  110,  111,
 /*  1250 */   112,   59,  214,  215,   42,  203,  307,  237,  238,  192,
 /*  1260 */   311,  192,   26,   71,  192,  144,  262,  297,  298,  203,
 /*  1270 */   250,   19,   20,   81,   22,   63,  262,  254,  255,   15,
 /*  1280 */    26,  214,  215,  214,  215,   26,  214,  215,   36,  237,
 /*  1290 */   238,  192,  100,  114,  101,  192,  262,  192,  106,  107,
 /*  1300 */    48,  134,  250,  237,  238,  113,  139,  115,  116,  117,
 /*  1310 */   192,   59,  120,  214,  215,  242,  250,  214,  215,  214,
 /*  1320 */   215,  148,  149,   71,   60,  252,  242,  192,  149,  137,
 /*  1330 */   138,  192,  214,  215,  192,   19,  252,   85,  192,   59,
 /*  1340 */   192,  157,   90,  159,  152,  153,  154,  155,  156,  214,
 /*  1350 */   215,  192,  100,  214,  215,   19,  214,  215,  106,  107,
 /*  1360 */   214,  215,  214,  215,   22,  113,  192,  115,  116,  117,
 /*  1370 */   192,  242,  120,  214,  215,  192,   24,  192,   31,  192,
 /*  1380 */   144,  252,   26,  192,  125,   99,   39,  192,  214,  215,
 /*  1390 */   192,   59,  214,  215,  192,  141,  116,  214,  215,  214,
 /*  1400 */   215,  214,  215,   61,  152,  153,  154,  155,  156,    0,
 /*  1410 */     1,    2,  214,  215,    5,  192,  214,  215,  132,   10,
 /*  1420 */    11,   12,   13,   14,    1,    2,   17,  192,    5,   19,
 /*  1430 */    20,  115,   22,   10,   11,   12,   13,   14,  192,   30,
 /*  1440 */    17,   32,   23,  192,   23,   26,   36,   26,  116,   40,
 /*  1450 */   192,  115,  192,   30,  192,   32,  119,  120,   59,    5,
 /*  1460 */   214,  215,  128,   40,   10,   11,   12,   13,   14,   59,
 /*  1470 */    19,   17,  214,  215,  214,  215,  214,  215,  120,   70,
 /*  1480 */   192,   71,   22,  192,   30,  151,   32,   78,  130,  128,
 /*  1490 */    81,  192,  140,   70,   40,   85,  192,  141,    7,    8,
 /*  1500 */    90,   78,  214,  215,   81,  214,  215,   98,   83,   84,
 /*  1510 */   100,  192,  151,  214,  215,  116,  106,  107,  214,  215,
 /*  1520 */   192,   98,  192,  113,   70,  115,  116,  117,   23,  224,
 /*  1530 */   120,   26,   78,  214,  215,   81,   19,   20,  152,   22,
 /*  1540 */   154,  132,  214,  215,  214,  215,  137,  138,   97,  192,
 /*  1550 */   256,  192,   98,   36,   23,  132,  192,   26,  192,  192,
 /*  1560 */   137,  138,  152,  153,  154,  155,  156,  192,  192,  192,
 /*  1570 */   161,  214,  215,  214,  215,  192,   59,  192,  214,  215,
 /*  1580 */   214,  215,  192,  152,  161,  154,  132,  192,   71,  214,
 /*  1590 */   215,  137,  138,  192,  192,  192,   19,   20,  192,   22,
 /*  1600 */   140,  253,   85,  192,  214,  215,  192,   90,   23,  214,
 /*  1610 */   215,   26,  192,   36,  192,  161,   23,  100,  192,   26,
 /*  1620 */   214,  215,  192,  106,  107,  214,  215,  192,   23,  192,
 /*  1630 */   113,   26,  115,  116,  117,   23,   59,  120,   26,   23,
 /*  1640 */    23,   23,   26,   26,   26,  316,  234,   23,   71,   23,
 /*  1650 */    26,  192,   26,  192,  192,  192,  192,  192,  192,  192,
 /*  1660 */   192,  253,  212,  190,  286,  285,  253,  240,  253,  152,
 /*  1670 */   153,  154,  155,  156,  241,  243,  295,  100,  291,  291,
 /*  1680 */   223,  253,  227,  106,  107,  108,  269,  244,  244,  265,
 /*  1690 */   113,  257,  115,  116,  117,  257,  243,  120,  269,  218,
 /*  1700 */   217,  265,  217,   19,   20,  217,   22,  195,  269,  269,
 /*  1710 */    60,  295,  140,  257,  243,  241,  247,  247,  199,  278,
 /*  1720 */    36,  199,  199,   38,   19,   20,  150,   22,  149,  152,
 /*  1730 */   153,  154,  155,  156,   22,   43,  232,  295,  292,  292,
 /*  1740 */    18,   36,  235,   59,  268,  270,  235,  199,  235,  235,
 /*  1750 */    18,  198,  148,  281,  244,   71,  270,  270,  268,  244,
 /*  1760 */   232,  232,  244,  199,   59,  244,  198,  157,  288,   62,
 /*  1770 */   199,  287,  198,   22,  219,  219,   71,  199,  198,  114,
 /*  1780 */   199,  198,  216,  216,  100,  216,  225,   64,   22,  125,
 /*  1790 */   106,  107,  222,  164,  219,  222,   24,  113,  216,  115,
 /*  1800 */   116,  117,  218,  216,  120,  100,  216,  216,  310,  303,
 /*  1810 */   112,  106,  107,  225,  280,  280,  219,  143,  113,  259,
 /*  1820 */   115,  116,  117,  114,  259,  120,  199,   91,   82,  147,
 /*  1830 */   144,  315,   22,  275,  199,  315,  152,  153,  154,  155,
 /*  1840 */   156,  146,  145,  247,  258,  157,   25,  258,  245,  248,
 /*  1850 */   244,  259,  258,  202,  259,  248,  258,  152,  153,  154,
 /*  1860 */   155,  156,  263,  263,   26,  246,   13,  201,  193,  193,
 /*  1870 */     6,  191,  191,  205,  191,  220,  220,  205,  211,  277,
 /*  1880 */   211,  211,  211,  205,    4,  212,    3,   22,  162,  212,

 /*  1890 */   211,   15,   23,   16,   23,  138,  129,  150,   26,   24,
 /*  1900 */   141,   20,   16,  143,    1,  141,  129,  129,   61,  301,
 /*  1910 */   301,  298,  150,   53,   53,   37,   53,  129,  115,   53,
 /*  1920 */   140,   34,    1,    5,   22,  114,   68,   26,  160,   75,
 /*  1930 */    68,   41,  140,  114,   24,   20,   19,  130,  124,   23,
 /*  1940 */    67,   22,   22,   59,   22,   22,   67,   96,   24,   22,
 /*  1950 */    37,   23,   67,   28,  148,   22,   26,   23,   23,   23,
 /*  1960 */    23,   22,  140,   23,   97,   23,   34,  115,   22,  142,
 /*  1970 */    26,   75,   34,   44,   75,   34,   88,   34,   86,   34,
 /*  1980 */    23,   34,   93,   22,   24,   26,   34,   23,   26,   23,
 /*  1990 */    23,   23,   23,   11,   23,   22,   26,   22,   22,  140,
 /*  2000 */    23,   23,   22,   22,  134,   26,   23,   15,  140,    1,
 /*  2010 */     1,  317,  317,  317,  140,  317,  317,  317,  317,  317,
 /*  2020 */   317,  317,  140,  317,  317,  317,  317,  317,  317,  317,
 /*  2030 */   317,  317,  317,  317,  317,  317,  317,  317,  317,  317,
 /*  2040 */   317,  317,  317,  317,  317,  317,  317,  317,  317,  317,
 /*  2050 */   317,  317,  317,  317,  317,  317,  317,  317,  317,  317,
 /*  2060 */   317,  317,  317,  317,  317,  317,  317,  317,  317,  317,
 /*  2070 */   317,  317,  317,  317,  317,  317,  317,  317,  317,  317,
 /*  2080 */   317,  317,  317,  317,  317,  317,  317,  317,  317,  317,
 /*  2090 */   317,  317,  317,  317,  317,  317,  317,  317,  317,  317,
 /*  2100 */   317,  317,  317,  317,  317,  317,  317,  317,  317,  317,
 /*  2110 */   317,  317,  317,  317,  317,  317,  317,  317,  317,  317,
 /*  2120 */   317,  317,  317,  317,  317,  317,  317,  317,  317,  317,
 /*  2130 */   317,  317,  317,  317,  317,  317,  317,  317,  317,  317,
 /*  2140 */   317,  317,  317,  317,  317,  317,  317,  317,  317,  317,
 /*  2150 */   317,  317,  317,  317,  317,  317,  317,  317,  317,  317,
 /*  2160 */   317,  317,  317,  317,  317,  317,  317,  317,  317,  317,
 /*  2170 */   317,  317,  317,  317,  317,  317,  317,  317,  317,  317,
 /*  2180 */   317,  317,  317,  317,  317,  317,  317,  317,  317,  317,
 /*  2190 */   317,  317,  317,  317,  317,  317,  317,  317,  317,  317,
 /*  2200 */   317,  317,  317,  317,  317,  317,  317,


};
#define YY_SHIFT_COUNT    (569)
#define YY_SHIFT_MIN      (0)
#define YY_SHIFT_MAX      (2009)
static const unsigned short int yy_shift_ofst[] = {
 /*     0 */  1423, 1409, 1454, 1192, 1192,  382, 1252, 1410, 1517, 1684,
 /*    10 */  1684, 1684,  221,    0,    0,  180, 1015, 1684, 1684, 1684,
 /*    20 */  1684, 1684, 1684, 1684, 1684, 1684, 1684, 1684, 1684, 1684,
 /*    30 */  1049, 1049, 1121, 1121,   54,  616,  382,  382,  382,  382,
 /*    40 */   382,   40,  110,  219,  289,  396,  439,  509,  548,  618,
 /*    50 */   657,  727,  766,  836,  995, 1015, 1015, 1015, 1015, 1015,
 /*    60 */  1015, 1015, 1015, 1015, 1015, 1015, 1015, 1015, 1015, 1015,
 /*    70 */  1015, 1015, 1015, 1035, 1015, 1138,  880,  880, 1577, 1684,
 /*    80 */  1684, 1684, 1684, 1684, 1684, 1684, 1684, 1684, 1684, 1684,
 /*    90 */  1684, 1684, 1684, 1684, 1684, 1684, 1684, 1684, 1684, 1684,
 /*   100 */  1684, 1684, 1684, 1684, 1684, 1684, 1684, 1684, 1684, 1684,
 /*   110 */  1684, 1684, 1684, 1705, 1684, 1684, 1684, 1684, 1684, 1684,
 /*   120 */  1684, 1684, 1684, 1684, 1684, 1684, 1684,  146,   84,   84,
 /*   130 */    84,   84,   84,  274,  315,  125,   97,  357,   66,   66,
 /*   140 */   893,  258,   66,   66,  371,  371,   66,  551,  551,  551,
 /*   150 */   551,  192,  209,  209,  278,  127, 2023, 2023,  621,  621,
 /*   160 */   621,  201,  398,  398,  398,  398,  939,  939,  442,  936,
 /*   170 */  1009,   66,   66,   66,   66,   66,   66,   66,   66,   66,
 /*   180 */    66,   66,   66,   66,   66,   66,   66,   66,   66,   66,
 /*   190 */    66,  710,  710,   66,  776,  435,  435,  410,  410,  372,
 /*   200 */  1097, 2023, 2023, 2023, 2023, 2023, 2023, 2023,  250,  490,
 /*   210 */   490,  511,  451,  516,  252,  566,  575,  781,  673,   66,
 /*   220 */    66,   66,   66,   66,   66,   66,   66,   66,   66,  722,
 /*   230 */    66,   66,   66,   66,   66,   66,   66,   66,   66,   66,
 /*   240 */    66,   66,  790,  790,  790,   66,   66,   66,  883,   66,
 /*   250 */    66,   66,  891, 1064,   66,   66, 1212,   66,   66,   66,
 /*   260 */    66,   66,   66,   66,   66,  725,  763,  177,  940,  940,
 /*   270 */   940,  940,  337,  177,  177, 1028, 1053,  670, 1264, 1179,
 /*   280 */  1173, 1254, 1316, 1173, 1316, 1336,   50, 1179, 1179,   50,
 /*   290 */  1179, 1254, 1336, 1259,  732,  532, 1347, 1347, 1347, 1316,
 /*   300 */  1236, 1236, 1184, 1356, 1167,  898, 1650, 1650, 1572, 1572,
 /*   310 */  1685, 1685, 1572, 1576, 1579, 1712, 1692, 1722, 1722, 1722,
 /*   320 */  1722, 1572, 1732, 1604, 1579, 1579, 1604, 1712, 1692, 1604,
 /*   330 */  1692, 1604, 1572, 1732, 1610, 1707, 1572, 1732, 1751, 1572,
 /*   340 */  1732, 1572, 1732, 1751, 1665, 1665, 1665, 1723, 1766, 1766,
 /*   350 */  1751, 1665, 1664, 1665, 1723, 1665, 1665, 1629, 1772, 1698,
 /*   360 */  1698, 1751, 1674, 1709, 1674, 1709, 1674, 1709, 1674, 1709,
 /*   370 */  1572, 1736, 1736, 1746, 1746, 1682, 1686, 1810, 1572, 1688,
 /*   380 */  1682, 1695, 1697, 1604, 1821, 1838, 1853, 1853, 1864, 1864,
 /*   390 */  1864, 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2023,
 /*   400 */  2023, 2023, 2023, 2023, 2023, 2023,  232,  101, 1131, 1193,
 /*   410 */   619,  679,  841, 1421, 1286,  115, 1352, 1334, 1361, 1419,
 /*   420 */  1342, 1505, 1531, 1585, 1593, 1605, 1612, 1280, 1337, 1491,
 /*   430 */  1358, 1451, 1332, 1616, 1617, 1425, 1618, 1386, 1431, 1624,
 /*   440 */  1626, 1399, 1460, 1880, 1883, 1865, 1726, 1876, 1877, 1869,
 /*   450 */  1871, 1757, 1747, 1767, 1872, 1872, 1875, 1759, 1881, 1760,
 /*   460 */  1886, 1903, 1764, 1777, 1872, 1778, 1847, 1878, 1872, 1762,
 /*   470 */  1860, 1861, 1863, 1866, 1788, 1803, 1887, 1780, 1921, 1918,
 /*   480 */  1902, 1811, 1768, 1858, 1901, 1862, 1854, 1890, 1792, 1819,
 /*   490 */  1910, 1915, 1917, 1807, 1814, 1919, 1873, 1920, 1922, 1916,
 /*   500 */  1923, 1879, 1884, 1924, 1851, 1925, 1927, 1885, 1913, 1928,
 /*   510 */  1806, 1933, 1934, 1935, 1936, 1930, 1937, 1939, 1867, 1822,
 /*   520 */  1940, 1942, 1852, 1932, 1946, 1827, 1944, 1938, 1941, 1943,
 /*   530 */  1945, 1888, 1896, 1892, 1929, 1899, 1889, 1947, 1957, 1961,
 /*   540 */  1960, 1959, 1962, 1952, 1964, 1944, 1966, 1967, 1968, 1969,
 /*   550 */  1970, 1971, 1973, 1982, 1975, 1976, 1977, 1978, 1980, 1981,
 /*   560 */  1979, 1870, 1859, 1868, 1874, 1882, 1983, 1992, 2008, 2009,

};
#define YY_REDUCE_COUNT (405)
#define YY_REDUCE_MIN   (-266)
#define YY_REDUCE_MAX   (1683)
static const short yy_reduce_ofst[] = {
 /*     0 */   111,  168,  272,  760, -177, -175, -192, -190, -182, -179,
 /*    10 */   216,  220,  481, -208, -205, -266, -140, -115,  241,  393,
 /*    20 */   523,  325,  612,  632,  542,  651,  764,  757,  702,  762,
 /*    30 */   812,  814, -188,  273,  924,  386,  758,  967, 1020, 1052,
 /*    40 */  1066, -256, -256, -256, -256, -256, -256, -256, -256, -256,
 /*    50 */  -256, -256, -256, -256, -256, -256, -256, -256, -256, -256,
 /*    60 */  -256, -256, -256, -256, -256, -256, -256, -256, -256, -256,
 /*    70 */  -256, -256, -256, -256, -256, -256, -256, -256,  195,  222,
 /*    80 */   813,  917,  920,  959,  985, 1006, 1038, 1067, 1069, 1072,
 /*    90 */  1099, 1103, 1105, 1118, 1135, 1139, 1142, 1146, 1148, 1159,
 /*   100 */  1174, 1178, 1183, 1185, 1187, 1198, 1202, 1246, 1258, 1260,
 /*   110 */  1262, 1288, 1291, 1299, 1304, 1319, 1328, 1330, 1357, 1359,
 /*   120 */  1364, 1366, 1375, 1390, 1395, 1406, 1411, -256, -256, -256,
 /*   130 */  -256, -256, -256, -256, -256,  447, -256,  555, -178,  605,
 /*   140 */   832, -220,  606,  -94, -168,   36, -122,  730,  780,  730,
 /*   150 */   780,  918, -136,  338, -256, -256, -256, -256,   80,   80,
 /*   160 */    80,  720,  703,  811,  882,  903, -213, -204,  106,  330,
 /*   170 */   330,  -77,  236,  320,  599,   67,  457,  675,  729,  395,
 /*   180 */   268,  611,  969, 1004,  726, 1014,  983,  123,  884,  608,
 /*   190 */  1034,  547,  911,  650,  844,  922,  949,  965,  972,  978,
 /*   200 */   449,  970,  718,  784, 1073, 1084, 1023, 1129, -209, -180,
 /*   210 */  -113,  114,  183,  329,  345,  391,  446,  502,  609,  667,
 /*   220 */   713,  817,  865,  881,  901,  921,  989, 1191, 1195,  214,
 /*   230 */  1223, 1235, 1251, 1367, 1376, 1377, 1383, 1385, 1401, 1402,
 /*   240 */  1403, 1414,  584,  638, 1305, 1420, 1422, 1426, 1294, 1430,
 /*   250 */  1435, 1437, 1348, 1329, 1459, 1461, 1412, 1462,  345, 1463,
 /*   260 */  1464, 1465, 1466, 1467, 1468, 1378, 1380, 1427, 1408, 1413,
 /*   270 */  1415, 1428, 1294, 1427, 1427, 1433, 1450, 1473, 1381, 1417,
 /*   280 */  1424, 1432, 1434, 1436, 1438, 1387, 1443, 1429, 1439, 1444,
 /*   290 */  1440, 1453, 1388, 1481, 1455, 1457, 1483, 1485, 1488, 1456,
 /*   300 */  1469, 1470, 1441, 1471, 1474, 1512, 1416, 1442, 1519, 1522,
 /*   310 */  1446, 1447, 1523, 1472, 1475, 1476, 1504, 1507, 1511, 1513,
 /*   320 */  1514, 1548, 1553, 1510, 1486, 1487, 1515, 1490, 1528, 1518,
 /*   330 */  1529, 1521, 1564, 1568, 1480, 1484, 1571, 1574, 1555, 1578,
 /*   340 */  1580, 1581, 1583, 1556, 1566, 1567, 1569, 1561, 1570, 1573,
 /*   350 */  1575, 1582, 1584, 1587, 1588, 1590, 1591, 1498, 1506, 1534,
 /*   360 */  1535, 1597, 1560, 1586, 1565, 1589, 1592, 1594, 1595, 1598,
 /*   370 */  1627, 1516, 1520, 1599, 1600, 1601, 1596, 1558, 1635, 1602,
 /*   380 */  1607, 1619, 1603, 1606, 1651, 1666, 1675, 1676, 1680, 1681,
 /*   390 */  1683, 1608, 1609, 1613, 1668, 1667, 1669, 1670, 1671, 1672,
 /*   400 */  1655, 1656, 1673, 1677, 1679, 1678,
};
static const YYACTIONTYPE yy_default[] = {
 /*     0 */  1623, 1623, 1623, 1453, 1223, 1332, 1223, 1223, 1223, 1453,
 /*    10 */  1453, 1453, 1223, 1362, 1362, 1506, 1254, 1223, 1223, 1223,
 /*    20 */  1223, 1223, 1223, 1223, 1223, 1223, 1223, 1452, 1223, 1223,
 /*    30 */  1223, 1223, 1541, 1541, 1223, 1223, 1223, 1223, 1223, 1223,
 /*    40 */  1223, 1223, 1371, 1223, 1378, 1223, 1223, 1223, 1223, 1223,
 /*    50 */  1454, 1455, 1223, 1223, 1223, 1505, 1507, 1470, 1385, 1384,
 /*    60 */  1383, 1382, 1488, 1349, 1376, 1369, 1373, 1448, 1449, 1447,
 /*    70 */  1451, 1455, 1454, 1223, 1372, 1419, 1433, 1418, 1223, 1223,
 /*    80 */  1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223,
 /*    90 */  1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223,
 /*   100 */  1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223,
 /*   110 */  1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223,
 /*   120 */  1223, 1223, 1223, 1223, 1223, 1223, 1223, 1427, 1432, 1438,
 /*   130 */  1431, 1428, 1421, 1420, 1422, 1223, 1423, 1223, 1223, 1223,
 /*   140 */  1244, 1296, 1223, 1223, 1223, 1223, 1223, 1525, 1524, 1223,
 /*   150 */  1223, 1254, 1413, 1412, 1424, 1425, 1435, 1434, 1513, 1576,
 /*   160 */  1575, 1471, 1223, 1223, 1223, 1223, 1223, 1223, 1541, 1223,
 /*   170 */  1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223,
 /*   180 */  1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223,
 /*   190 */  1223, 1541, 1541, 1223, 1254, 1541, 1541, 1250, 1250, 1356,
 /*   200 */  1223, 1520, 1323, 1323, 1323, 1323, 1332, 1323, 1223, 1223,
 /*   210 */  1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223,
 /*   220 */  1223, 1223, 1223, 1510, 1508, 1223, 1223, 1223, 1223, 1223,
 /*   230 */  1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223,
 /*   240 */  1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223,
 /*   250 */  1223, 1223, 1328, 1223, 1223, 1223, 1223, 1223, 1223, 1223,
 /*   260 */  1223, 1223, 1223, 1223, 1570, 1223, 1483, 1310, 1328, 1328,
 /*   270 */  1328, 1328, 1330, 1311, 1309, 1322, 1255, 1230, 1615, 1388,
 /*   280 */  1377, 1329, 1351, 1377, 1351, 1612, 1375, 1388, 1388, 1375,
 /*   290 */  1388, 1329, 1612, 1271, 1592, 1266, 1362, 1362, 1362, 1351,
 /*   300 */  1356, 1356, 1450, 1329, 1322, 1223, 1615, 1615, 1337, 1337,
 /*   310 */  1614, 1614, 1337, 1471, 1599, 1397, 1299, 1305, 1305, 1305,
 /*   320 */  1305, 1337, 1241, 1375, 1599, 1599, 1375, 1397, 1299, 1375,
 /*   330 */  1299, 1375, 1337, 1241, 1487, 1609, 1337, 1241, 1461, 1337,
 /*   340 */  1241, 1337, 1241, 1461, 1297, 1297, 1297, 1286, 1223, 1223,
 /*   350 */  1461, 1297, 1271, 1297, 1286, 1297, 1297, 1559, 1223, 1465,
 /*   360 */  1465, 1461, 1355, 1350, 1355, 1350, 1355, 1350, 1355, 1350,
 /*   370 */  1337, 1551, 1551, 1365, 1365, 1370, 1356, 1456, 1337, 1223,
 /*   380 */  1370, 1368, 1366, 1375, 1247, 1289, 1573, 1573, 1569, 1569,
 /*   390 */  1569, 1620, 1620, 1520, 1585, 1254, 1254, 1254, 1254, 1585,
 /*   400 */  1273, 1273, 1255, 1255, 1254, 1585, 1223, 1223, 1223, 1223,
 /*   410 */  1223, 1223, 1580, 1223, 1515, 1472, 1341, 1223, 1223, 1223,
 /*   420 */  1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223,
 /*   430 */  1223, 1526, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223,
 /*   440 */  1223, 1223, 1402, 1223, 1226, 1517, 1223, 1223, 1223, 1223,
 /*   450 */  1223, 1223, 1223, 1223, 1379, 1380, 1342, 1223, 1223, 1223,
 /*   460 */  1223, 1223, 1223, 1223, 1394, 1223, 1223, 1223, 1389, 1223,
 /*   470 */  1223, 1223, 1223, 1223, 1223, 1223, 1223, 1611, 1223, 1223,
 /*   480 */  1223, 1223, 1223, 1223, 1486, 1485, 1223, 1223, 1339, 1223,
 /*   490 */  1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223,
 /*   500 */  1223, 1223, 1269, 1223, 1223, 1223, 1223, 1223, 1223, 1223,
 /*   510 */  1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223,
 /*   520 */  1223, 1223, 1223, 1223, 1223, 1223, 1367, 1223, 1223, 1223,
 /*   530 */  1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223,
 /*   540 */  1223, 1556, 1357, 1223, 1223, 1602, 1223, 1223, 1223, 1223,
 /*   550 */  1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223, 1223,
 /*   560 */  1596, 1313, 1404, 1223, 1403, 1407, 1223, 1235, 1223, 1223,

};
/********** End of lemon-generated parsing tables *****************************/

/* The next table maps tokens (terminal symbols) into fallback tokens.
** If a construct like the following:
**
**      %fallback ID X Y Z.







|

|
|
|
|
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|

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

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


|
|
|
|
|
|
|
|
|
|
|
|
|
|


|
|
|
|

|

|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|


|
|
|

|

|
|
|


|
|
|

|

|
|
|


|
|
|
|

|
|
|
|
|
|
|
|
|
|

|

|

|

|
|
|
|
|
|
|

|
|
|
|
|

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

|

|

|
|

|
|








|
|
|
|
|

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

|
|
|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|


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







159291
159292
159293
159294
159295
159296
159297
159298
159299
159300
159301
159302
159303
159304
159305
159306
159307
159308
159309
159310
159311
159312
159313
159314
159315
159316
159317
159318
159319
159320
159321
159322
159323
159324
159325
159326
159327
159328
159329
159330
159331
159332
159333
159334
159335
159336
159337
159338
159339
159340
159341
159342
159343
159344
159345
159346
159347
159348
159349
159350
159351
159352
159353
159354
159355
159356
159357
159358
159359
159360
159361
159362
159363
159364
159365
159366
159367
159368
159369
159370
159371
159372
159373
159374
159375
159376
159377
159378
159379
159380
159381
159382
159383
159384
159385
159386
159387
159388
159389
159390
159391
159392
159393
159394
159395
159396
159397




159398
159399
159400
159401
159402
159403
159404
159405
159406
159407
159408
159409
159410
159411
159412
159413
159414
159415
159416
159417
159418
159419
159420
159421
159422
159423
159424
159425
159426
159427
159428
159429
159430
159431
159432
159433
159434
159435
159436
159437
159438
159439
159440
159441
159442
159443
159444
159445
159446
159447
159448
159449
159450
159451
159452
159453
159454
159455
159456
159457
159458
159459
159460
159461
159462
159463
159464
159465
159466
159467
159468
159469
159470
159471
159472
159473
159474
159475
159476
159477
159478
159479
159480
159481
159482
159483
159484
159485
159486
159487
159488
159489
159490
159491
159492
159493
159494
159495
159496
159497
159498
159499
159500
159501
159502
159503
159504
159505
159506
159507
159508
159509
159510
159511
159512
159513
159514
159515
159516
159517
159518
159519
159520
159521
159522
159523
159524
159525
159526
159527
159528
159529
159530
159531
159532
159533
159534
159535
159536
159537
159538
159539
159540
159541
159542
159543
159544
159545
159546
159547
159548
159549
159550
159551
159552
159553
159554
159555
159556
159557
159558
159559
159560
159561
159562
159563
159564
159565
159566
159567
159568
159569
159570
159571
159572
159573
159574
159575
159576
159577
159578
159579
159580
159581
159582
159583
159584
159585
159586
159587
159588
159589
159590
159591
159592
159593
159594
159595
159596
159597
159598
159599
159600
159601
159602
159603
159604
159605
159606
159607
159608
159609
159610
159611
159612
159613
159614
159615
159616
159617
159618
159619
159620
159621
159622
159623
159624
159625
159626
159627
159628
159629
159630
159631
159632
159633
159634
159635
159636
159637
159638
159639
159640
159641
159642
159643
159644
159645
159646
159647
159648
159649
159650
159651
159652
159653
159654
159655
159656
159657
159658
159659
159660
159661
159662
159663
159664
159665
159666
159667
159668
159669
159670
159671
159672
159673
159674
159675
159676
159677
159678
159679
159680
159681
159682
159683
159684
159685
159686
159687
159688
159689
159690
159691
159692
159693
159694
159695
159696
159697
159698
159699
159700
159701

159702
159703
159704
159705
159706
159707
159708
159709
159710
159711
159712
159713
159714
159715
159716
159717
159718
159719
159720
159721
159722
159723
159724
159725
159726
159727
159728
159729
159730
159731
159732
159733
159734
159735
159736
159737
159738
159739
159740
159741
159742
159743
159744
159745
159746
159747
159748
159749
159750
159751
159752
159753
159754
159755
159756
159757
159758
159759
159760
159761
159762
159763
159764
159765
159766
159767
159768
159769
159770
159771
159772
159773
159774
159775
159776
159777
159778
159779
159780
159781
159782
159783
159784
159785
159786
159787
159788
159789
159790
159791
159792
159793
159794
159795
159796
159797
159798
159799
159800
159801
159802
159803
159804
159805
159806
159807
159808
159809
159810
159811
159812
159813
159814
159815
159816
159817
159818
159819
159820
159821
159822
159823
159824
159825
159826
159827
159828
159829
159830
159831
159832
159833
159834
159835
159836
159837
159838
159839
159840
159841
159842
159843
159844
159845
159846
159847
159848
159849
159850
159851
159852
159853
159854
159855
159856
159857
159858
159859
159860
159861
159862
159863
159864
159865
159866
159867
159868
159869
159870
159871
159872
159873
159874
159875
159876
159877
159878
159879
159880
159881
159882
159883
159884
159885
159886
159887
159888
159889
159890
159891
159892
159893
159894
159895
159896
159897
159898
159899
159900
159901
159902
159903
159904
**  yy_shift_ofst[]    For each state, the offset into yy_action for
**                     shifting terminals.
**  yy_reduce_ofst[]   For each state, the offset into yy_action for
**                     shifting non-terminals after a reduce.
**  yy_default[]       Default action for each state.
**
*********** Begin parsing tables **********************************************/
#define YY_ACTTAB_COUNT (2037)
static const YYACTIONTYPE yy_action[] = {
 /*     0 */   564,  115,  112,  220,  169,  199,  115,  112,  220,  564,
 /*    10 */   375, 1266,  564,  376,  564,  270, 1309, 1309,  406,  407,
 /*    20 */  1084,  199, 1513,   41,   41,  515,  489,  521,  558,  558,
 /*    30 */   558,  965,   41,   41,  395,   41,   41,   51,   51,  966,
 /*    40 */   296, 1269,  296,  122,  123,  113, 1207, 1207, 1041, 1044,
 /*    50 */  1034, 1034,  120,  120,  121,  121,  121,  121,  564,  407,
 /*    60 */   275,  275,  275,  275, 1268,  115,  112,  220,  115,  112,
 /*    70 */   220, 1512,  846,  561,  516,  561,  115,  112,  220,  250,
 /*    80 */   217,   71,   71,  122,  123,  113, 1207, 1207, 1041, 1044,
 /*    90 */  1034, 1034,  120,  120,  121,  121,  121,  121,  440,  440,
 /*   100 */   440, 1149,  119,  119,  119,  119,  118,  118,  117,  117,
 /*   110 */   117,  116,  442, 1183, 1149,  116,  442, 1149,  546,  513,
 /*   120 */  1548, 1554,  374,  442,    6, 1183, 1154,  522, 1154,  407,
 /*   130 */  1556,  461,  373, 1554,  535,   99,  463,  332,  121,  121,
 /*   140 */   121,  121,  119,  119,  119,  119,  118,  118,  117,  117,
 /*   150 */   117,  116,  442,  122,  123,  113, 1207, 1207, 1041, 1044,
 /*   160 */  1034, 1034,  120,  120,  121,  121,  121,  121, 1257, 1183,
 /*   170 */  1184, 1185,  243, 1064,  564,  502,  499,  498,  567,  124,
 /*   180 */   567, 1183, 1184, 1185,  474,  497,  119,  119,  119,  119,
 /*   190 */   118,  118,  117,  117,  117,  116,  442,   70,   70,  407,
 /*   200 */   121,  121,  121,  121,  114,  117,  117,  117,  116,  442,
 /*   210 */  1409, 1469,  119,  119,  119,  119,  118,  118,  117,  117,
 /*   220 */   117,  116,  442,  122,  123,  113, 1207, 1207, 1041, 1044,
 /*   230 */  1034, 1034,  120,  120,  121,  121,  121,  121,  407, 1031,
 /*   240 */  1031, 1042, 1045,   81,  382,  541,  378,   80,  119,  119,
 /*   250 */   119,  119,  118,  118,  117,  117,  117,  116,  442,  381,
 /*   260 */   463,  332,  122,  123,  113, 1207, 1207, 1041, 1044, 1034,
 /*   270 */  1034,  120,  120,  121,  121,  121,  121,  262,  215,  512,
 /*   280 */  1424,  422,  119,  119,  119,  119,  118,  118,  117,  117,
 /*   290 */   117,  116,  442, 1231,    1,    1,  571,    2, 1235, 1573,
 /*   300 */   571,    2, 1235,  307, 1149,  141, 1600,  307,  407,  141,
 /*   310 */  1183,  361, 1317, 1035,  866,  531, 1317, 1149,  359, 1567,
 /*   320 */  1149,  119,  119,  119,  119,  118,  118,  117,  117,  117,
 /*   330 */   116,  442,  122,  123,  113, 1207, 1207, 1041, 1044, 1034,
 /*   340 */  1034,  120,  120,  121,  121,  121,  121,  275,  275, 1001,
 /*   350 */   426,  275,  275, 1128, 1627, 1021, 1627,  137,  542, 1541,
 /*   360 */   561,  272,  950,  950,  561, 1423, 1183, 1184, 1185, 1594,
 /*   370 */   866, 1012,  530,  315,  231, 1011,  468, 1276,  231,  119,
 /*   380 */   119,  119,  119,  118,  118,  117,  117,  117,  116,  442,
 /*   390 */  1570,  119,  119,  119,  119,  118,  118,  117,  117,  117,
 /*   400 */   116,  442,  330,  359, 1567,  564,  446, 1011, 1011, 1013,
 /*   410 */   446,  207,  564,  306,  555,  407,  363, 1021,  363,  346,
 /*   420 */   184,  118,  118,  117,  117,  117,  116,  442,   71,   71,
 /*   430 */   439,  438, 1126, 1012,  472,   71,   71, 1011,  205,  122,
 /*   440 */   123,  113, 1207, 1207, 1041, 1044, 1034, 1034,  120,  120,
 /*   450 */   121,  121,  121,  121,  219,  219,  472, 1183,  407,  570,
 /*   460 */  1183, 1235,  503, 1477,  149,  546,  307,  489,  141, 1011,
 /*   470 */  1011, 1013,  546,  140,  545, 1317, 1214,  191, 1214,  950,
 /*   480 */   950,  514,  122,  123,  113, 1207, 1207, 1041, 1044, 1034,
 /*   490 */  1034,  120,  120,  121,  121,  121,  121,  563,  119,  119,
 /*   500 */   119,  119,  118,  118,  117,  117,  117,  116,  442,  283,
 /*   510 */   275,  275,  415, 1183, 1184, 1185, 1183, 1184, 1185,  372,
 /*   520 */  1183,  243,  344,  561,  502,  499,  498, 1539,  407, 1540,
 /*   530 */  1183,  288,  870,  143,  497, 1549,  185,  231,    9,    6,
 /*   540 */   253,  119,  119,  119,  119,  118,  118,  117,  117,  117,
 /*   550 */   116,  442,  122,  123,  113, 1207, 1207, 1041, 1044, 1034,
 /*   560 */  1034,  120,  120,  121,  121,  121,  121,  407,  137,  446,
 /*   570 */   447,  863,  169, 1183,  397, 1204, 1183, 1184, 1185,  931,
 /*   580 */   526, 1001,   98,  339,  564,  342, 1183, 1184, 1185,  306,
 /*   590 */   555,  122,  123,  113, 1207, 1207, 1041, 1044, 1034, 1034,
 /*   600 */   120,  120,  121,  121,  121,  121,  452,   71,   71,  275,
 /*   610 */   275,  119,  119,  119,  119,  118,  118,  117,  117,  117,
 /*   620 */   116,  442,  561,  417,  306,  555, 1183, 1307, 1307, 1183,
 /*   630 */  1184, 1185, 1204, 1149,  330,  458,  318,  407,  363,  470,
 /*   640 */   431, 1167,   32,  541,  527,  350, 1149, 1629,  393, 1149,
 /*   650 */   119,  119,  119,  119,  118,  118,  117,  117,  117,  116,
 /*   660 */   442,  122,  123,  113, 1207, 1207, 1041, 1044, 1034, 1034,
 /*   670 */   120,  120,  121,  121,  121,  121,  407,  199,  472, 1183,
 /*   680 */  1022,  472, 1183, 1184, 1185,  386,  151,  539, 1548,  277,
 /*   690 */   400,  137,    6,  317,    5,  564,  562,    3,  920,  920,
 /*   700 */   122,  123,  113, 1207, 1207, 1041, 1044, 1034, 1034,  120,
 /*   710 */   120,  121,  121,  121,  121,  411,  505,   83,   71,   71,
 /*   720 */   119,  119,  119,  119,  118,  118,  117,  117,  117,  116,
 /*   730 */   442, 1183,  218,  428, 1183, 1183, 1184, 1185,  363,  261,
 /*   740 */   278,  358,  508,  353,  507,  248,  407,  306,  555, 1539,
 /*   750 */  1006,  349,  363,  291,  489,  302,  293, 1542,  281,  119,
 /*   760 */   119,  119,  119,  118,  118,  117,  117,  117,  116,  442,
 /*   770 */   122,  123,  113, 1207, 1207, 1041, 1044, 1034, 1034,  120,
 /*   780 */   120,  121,  121,  121,  121,  407,  148, 1183, 1184, 1185,
 /*   790 */  1183, 1184, 1185,  275,  275, 1304, 1257, 1283,  483, 1476,
 /*   800 */   150,  489,  480,  564, 1187, 1304,  561, 1587, 1255,  122,
 /*   810 */   123,  113, 1207, 1207, 1041, 1044, 1034, 1034,  120,  120,
 /*   820 */   121,  121,  121,  121,  564,  886,   13,   13,  520,  119,
 /*   830 */   119,  119,  119,  118,  118,  117,  117,  117,  116,  442,
 /*   840 */  1183,  420,  417,  564,  269,  269, 1316,   13,   13, 1539,
 /*   850 */  1546,   16,   16,  322,    6,  407,  506,  561, 1089, 1089,
 /*   860 */   486, 1187,  425, 1539,  887,  292,   71,   71,  119,  119,
 /*   870 */   119,  119,  118,  118,  117,  117,  117,  116,  442,  122,
 /*   880 */   123,  113, 1207, 1207, 1041, 1044, 1034, 1034,  120,  120,
 /*   890 */   121,  121,  121,  121,  564,   12, 1183, 1184, 1185,  407,
 /*   900 */   275,  275,  451,  303,  834,  835,  836,  417,  489,  276,
 /*   910 */   276, 1547,  284,  561,  319,    6,  321,   71,   71,  429,
 /*   920 */   451,  450,  561,  952,  101,  113, 1207, 1207, 1041, 1044,
 /*   930 */  1034, 1034,  120,  120,  121,  121,  121,  121,  119,  119,
 /*   940 */   119,  119,  118,  118,  117,  117,  117,  116,  442, 1105,
 /*   950 */  1183,  489,  564, 1312,  437,  455,  478,  564,  246,  245,
 /*   960 */   244, 1409, 1545,  547, 1106,  405,    6, 1544,  196, 1258,
 /*   970 */   413,    6,  105,  462,  103,   71,   71,  286,  564, 1107,




 /*   980 */    13,   13,  119,  119,  119,  119,  118,  118,  117,  117,
 /*   990 */   117,  116,  442,  451,  104,  427,  337,  320,  275,  275,
 /*  1000 */   906,   13,   13,  564, 1482, 1105, 1183, 1184, 1185,  126,
 /*  1010 */   907,  561,  546,  564,  407,  478,  295, 1321,  253,  200,
 /*  1020 */  1106,  548, 1482, 1484,  280, 1409,   55,   55, 1287,  561,
 /*  1030 */   478,  380,  423,  951,  407, 1107,   71,   71,  122,  123,
 /*  1040 */   113, 1207, 1207, 1041, 1044, 1034, 1034,  120,  120,  121,
 /*  1050 */   121,  121,  121, 1204,  407,  287,  552,  309,  122,  123,
 /*  1060 */   113, 1207, 1207, 1041, 1044, 1034, 1034,  120,  120,  121,
 /*  1070 */   121,  121,  121,  441, 1128, 1628,  146, 1628,  122,  111,
 /*  1080 */   113, 1207, 1207, 1041, 1044, 1034, 1034,  120,  120,  121,
 /*  1090 */   121,  121,  121,  404,  403, 1482,  424,  119,  119,  119,
 /*  1100 */   119,  118,  118,  117,  117,  117,  116,  442, 1183,  564,
 /*  1110 */  1204,  544, 1086,  858,  329,  361, 1086,  119,  119,  119,
 /*  1120 */   119,  118,  118,  117,  117,  117,  116,  442,  564,  294,
 /*  1130 */   144,  523,   56,   56,  224,  564,  510,  119,  119,  119,
 /*  1140 */   119,  118,  118,  117,  117,  117,  116,  442,  484, 1409,
 /*  1150 */   537,   15,   15, 1126,  434,  439,  438,  407,   13,   13,
 /*  1160 */  1523,   12,  926, 1211, 1183, 1184, 1185,  925, 1213,  536,
 /*  1170 */   858,  557,  413,  193, 1525,  494, 1212,  448, 1160, 1222,
 /*  1180 */  1183,  564,  123,  113, 1207, 1207, 1041, 1044, 1034, 1034,
 /*  1190 */   120,  120,  121,  121,  121,  121, 1521, 1149,  564,  965,
 /*  1200 */   564, 1214,  247, 1214,   13,   13, 1409,  966,  538,  564,
 /*  1210 */  1149,  108,  556, 1149,    4,  310,  392, 1227,   17,  194,
 /*  1220 */   485,   43,   43,   57,   57,  306,  555,  524,  559, 1160,
 /*  1230 */   464,  564,   44,   44,  392, 1127, 1183, 1184, 1185,  479,
 /*  1240 */   119,  119,  119,  119,  118,  118,  117,  117,  117,  116,
 /*  1250 */   442,  443,  564,  327,   13,   13,  564,  418, 1315,  414,
 /*  1260 */   171,  564,  311,  553,  213,  529, 1253,  564,  517,  543,
 /*  1270 */   412,  108,  556,  137,    4,   58,   58,  435,  314,   59,
 /*  1280 */    59,  274,  217,  549,   60,   60,  349,  476,  559, 1353,
 /*  1290 */    61,   61, 1021,  275,  275, 1228,  213,  564,  106,  106,
 /*  1300 */     8,  275,  275,  275,  275,  107,  561,  443,  566,  565,
 /*  1310 */   564,  443, 1011, 1228,  561,  564,  561,  564,  275,  275,
 /*  1320 */    62,   62, 1352,  553,  247,  456,  564,   98,  110,  306,
 /*  1330 */   555,  561,  564,   45,   45,  405, 1203,  533,   46,   46,
 /*  1340 */    47,   47,  532,  465, 1011, 1011, 1013, 1014,   27,   49,
 /*  1350 */    49,  564, 1021,  405,  469,   50,   50,  564,  106,  106,
 /*  1360 */   305,  564,   84,  204,  405,  107,  564,  443,  566,  565,
 /*  1370 */   405,  564, 1011,  564,   63,   63,  564, 1599,  564,  895,
 /*  1380 */    64,   64,  457,  477,   65,   65,  147,   96,   38,   14,
 /*  1390 */    14, 1528,  412,  564,   66,   66,  128,  128,  926,   67,
 /*  1400 */    67,   52,   52,  925, 1011, 1011, 1013, 1014,   27, 1572,
 /*  1410 */  1171,  445,  208, 1123,  279,  394,   68,   68,  228,  390,
 /*  1420 */   390,  389,  264,  387, 1171,  445,  843,  877,  279,  108,
 /*  1430 */   556,  453,    4,  390,  390,  389,  264,  387,  564,  225,
 /*  1440 */   843,  313,  328, 1003,   98,  252,  559,  544,  471,  312,
 /*  1450 */   252,  564,  208,  225,  564,  313,  473,   30,  252,  279,
 /*  1460 */   466,   69,   69,  312,  390,  390,  389,  264,  387,  443,
 /*  1470 */   333,  843,   98,  564,   53,   53,  323,  157,  157,  227,
 /*  1480 */   495,  553,  249,  289,  225,  564,  313,  162,   31, 1501,
 /*  1490 */   135,  564, 1500,  227,  312,  533,  158,  158,  885,  884,
 /*  1500 */   534,  162,  873,  301,  135,  564,  481,  226,   76,   76,
 /*  1510 */  1021,  347, 1071,   98,   54,   54,  106,  106, 1067,  564,
 /*  1520 */   249,  226,  519,  107,  227,  443,  566,  565,   72,   72,
 /*  1530 */  1011,  334,  162,  564,  230,  135,  108,  556,  959,    4,
 /*  1540 */   252,  408,  129,  129,  564, 1349,  306,  555,  564,  923,
 /*  1550 */   564,  110,  226,  559,  564,  408,   73,   73,  564,  873,
 /*  1560 */   306,  555, 1011, 1011, 1013, 1014,   27,  130,  130, 1071,
 /*  1570 */   449,  131,  131,  127,  127,  357,  443,  156,  156,  892,
 /*  1580 */   893,  155,  155,  338,  449,  356,  408,  564,  553,  968,
 /*  1590 */   969,  306,  555, 1015,  341,  564,  108,  556,  564,    4,
 /*  1600 */  1132, 1286,  533,  564,  856,  343,  145,  532,  345, 1300,
 /*  1610 */   136,  136, 1083,  559, 1083,  449,  564, 1021,  134,  134,
 /*  1620 */  1284,  132,  132,  106,  106, 1285,  133,  133,  564,  352,
 /*  1630 */   107,  564,  443,  566,  565, 1340,  443, 1011,  362,   75,
 /*  1640 */    75, 1082,  564, 1082,  564,  924, 1561,  110,  553,  551,
 /*  1650 */  1015,   77,   77, 1361,   74,   74, 1408, 1336, 1347,  550,
 /*  1660 */  1414, 1265, 1256, 1244, 1243,   42,   42,   48,   48, 1011,
 /*  1670 */  1011, 1013, 1014,   27, 1245, 1580,  490, 1021,  267,  202,
 /*  1680 */  1333,  365,   11,  106,  106,  930,  367,  210,  369,  391,
 /*  1690 */   107, 1395,  443,  566,  565,  223, 1390, 1011,  500,  454,
 /*  1700 */   282, 1400,  285,  108,  556,  214,    4,  325, 1383, 1283,
 /*  1710 */   475,  355, 1473, 1583, 1472, 1399,  371, 1222,  326,  398,
 /*  1720 */   559,  290,  331,  197,  100,  556,  209,    4,  198, 1011,
 /*  1730 */  1011, 1013, 1014,   27,  385,  256, 1520, 1518,  554, 1219,
 /*  1740 */   416,  559,   83,  443,  173,  206,  182,  221,  459,  167,
 /*  1750 */   177,  460,  175,  493,  233,  553,   79,  178, 1396,  179,
 /*  1760 */    35,  180,   96, 1402,  443,  396,   36,  467, 1478, 1401,
 /*  1770 */   482,  237, 1404,  399,   82,  186,  553, 1467,   89,  488,
 /*  1780 */   190,  268,  239,  491, 1021,  340,  240,  401, 1246, 1489,
 /*  1790 */   106,  106,  336,  509, 1294,  241, 1303,  107,  430,  443,
 /*  1800 */   566,  565, 1302,   91, 1011, 1021, 1598, 1301, 1273,  215,
 /*  1810 */  1597,  106,  106,  402,  877,  432,  354, 1272,  107, 1271,
 /*  1820 */   443,  566,  565, 1596, 1566, 1011, 1293,  433,  518,  299,
 /*  1830 */   300,  360,   95,  525, 1344,  364, 1011, 1011, 1013, 1014,
 /*  1840 */    27,  254,  255, 1552,  436, 1551,  125,  544,   10,  379,
 /*  1850 */  1326, 1453,  102,   97, 1345,  528,  304, 1011, 1011, 1013,
 /*  1860 */  1014,   27,  366,  377, 1343, 1342,  368,  370, 1325,  384,
 /*  1870 */   201,  383,   34, 1368, 1367,  568, 1177,  266,  263,  265,
 /*  1880 */  1505,  159,  569, 1241, 1236, 1506,  160,  142, 1504, 1503,
 /*  1890 */   297,  211,  830,  161,  212,   78,  444,  203,  308,  222,
 /*  1900 */  1081,  139, 1079,  316,  174,  163, 1203,  229,  176,  909,
 /*  1910 */   324,  232, 1095,  181,  409,  410,  172,  164,  165,  419,
 /*  1920 */   183,   85,   86,  421,  166,   87,   88, 1098, 1094,  234,
 /*  1930 */   235,  152,   18,  236,  335, 1087, 1216,  252,  187,  487,
 /*  1940 */   238,  188,   37,  845,  492,  356,  242,  496,  351,  501,
 /*  1950 */   189,   90,   19,  504,  348,   20,  875,   92,  298,  168,
 /*  1960 */   888,  153,   93,  511,   94, 1165,  154, 1047, 1134,   39,
 /*  1970 */   216, 1133,  271,  273,  958,  192,  953,  110, 1151, 1155,
 /*  1980 */   251,    7,   21, 1159, 1139,   22, 1153,   33,   23,   24,
 /*  1990 */    25,  540, 1158,  195,   98, 1062,   26, 1048, 1046, 1050,
 /*  2000 */  1104, 1051, 1103,  257,  258,   28,   40, 1173, 1016,  857,
 /*  2010 */   109,   29,  560,  388,  138, 1172,  259,  170,  260, 1232,
 /*  2020 */  1232,  919, 1232, 1232, 1232, 1232, 1232, 1232, 1232, 1232,
 /*  2030 */  1232, 1232, 1589, 1232, 1232, 1232, 1588,
};
static const YYCODETYPE yy_lookahead[] = {
 /*     0 */   192,  273,  274,  275,  192,  192,  273,  274,  275,  192,
 /*    10 */   218,  215,  192,  218,  192,  212,  234,  235,  205,   19,
 /*    20 */    11,  192,  294,  215,  216,  203,  192,  203,  209,  210,
 /*    30 */   211,   31,  215,  216,  205,  215,  216,  215,  216,   39,
 /*    40 */   227,  215,  229,   43,   44,   45,   46,   47,   48,   49,
 /*    50 */    50,   51,   52,   53,   54,   55,   56,   57,  192,   19,
 /*    60 */   238,  239,  238,  239,  215,  273,  274,  275,  273,  274,
 /*    70 */   275,  237,   21,  251,  252,  251,  273,  274,  275,  255,
 /*    80 */   256,  215,  216,   43,   44,   45,   46,   47,   48,   49,
 /*    90 */    50,   51,   52,   53,   54,   55,   56,   57,  209,  210,
 /*   100 */   211,   76,  102,  103,  104,  105,  106,  107,  108,  109,
 /*   110 */   110,  111,  112,   59,   89,  111,  112,   92,  252,  307,
 /*   120 */   308,  313,  314,  112,  312,   59,   86,  261,   88,   19,
 /*   130 */   313,   80,  315,  313,  314,   25,  127,  128,   54,   55,
 /*   140 */    56,   57,  102,  103,  104,  105,  106,  107,  108,  109,
 /*   150 */   110,  111,  112,   43,   44,   45,   46,   47,   48,   49,
 /*   160 */    50,   51,   52,   53,   54,   55,   56,   57,  192,  115,
 /*   170 */   116,  117,  118,  122,  192,  121,  122,  123,  202,   69,
 /*   180 */   204,  115,  116,  117,  192,  131,  102,  103,  104,  105,
 /*   190 */   106,  107,  108,  109,  110,  111,  112,  215,  216,   19,
 /*   200 */    54,   55,   56,   57,   58,  108,  109,  110,  111,  112,
 /*   210 */   192,  160,  102,  103,  104,  105,  106,  107,  108,  109,
 /*   220 */   110,  111,  112,   43,   44,   45,   46,   47,   48,   49,
 /*   230 */    50,   51,   52,   53,   54,   55,   56,   57,   19,   46,
 /*   240 */    47,   48,   49,   24,  248,  192,  250,   67,  102,  103,
 /*   250 */   104,  105,  106,  107,  108,  109,  110,  111,  112,  277,
 /*   260 */   127,  128,   43,   44,   45,   46,   47,   48,   49,   50,
 /*   270 */    51,   52,   53,   54,   55,   56,   57,   26,  164,  165,
 /*   280 */   272,  263,  102,  103,  104,  105,  106,  107,  108,  109,
 /*   290 */   110,  111,  112,  184,  185,  186,  187,  188,  189,  186,
 /*   300 */   187,  188,  189,  194,   76,  196,  229,  194,   19,  196,
 /*   310 */    59,  192,  203,  120,   59,   87,  203,   89,  310,  311,
 /*   320 */    92,  102,  103,  104,  105,  106,  107,  108,  109,  110,
 /*   330 */   111,  112,   43,   44,   45,   46,   47,   48,   49,   50,
 /*   340 */    51,   52,   53,   54,   55,   56,   57,  238,  239,   73,
 /*   350 */   231,  238,  239,   22,   23,  100,   25,   81,  305,  306,
 /*   360 */   251,   23,   25,   25,  251,  272,  115,  116,  117,  214,
 /*   370 */   115,  116,  144,  192,  265,  120,  114,  222,  265,  102,
 /*   380 */   103,  104,  105,  106,  107,  108,  109,  110,  111,  112,
 /*   390 */   192,  102,  103,  104,  105,  106,  107,  108,  109,  110,
 /*   400 */   111,  112,  126,  310,  311,  192,  297,  152,  153,  154,
 /*   410 */   297,  149,  192,  137,  138,   19,  192,  100,  192,   23,
 /*   420 */    22,  106,  107,  108,  109,  110,  111,  112,  215,  216,
 /*   430 */   106,  107,  101,  116,  192,  215,  216,  120,  149,   43,
 /*   440 */    44,   45,   46,   47,   48,   49,   50,   51,   52,   53,
 /*   450 */    54,   55,   56,   57,  117,  117,  192,   59,   19,  187,
 /*   460 */    59,  189,   23,  282,  240,  252,  194,  192,  196,  152,
 /*   470 */   153,  154,  252,   72,  261,  203,  152,   25,  154,  142,
 /*   480 */   142,  261,   43,   44,   45,   46,   47,   48,   49,   50,
 /*   490 */    51,   52,   53,   54,   55,   56,   57,  192,  102,  103,
 /*   500 */   104,  105,  106,  107,  108,  109,  110,  111,  112,  267,
 /*   510 */   238,  239,  237,  115,  116,  117,  115,  116,  117,  192,
 /*   520 */    59,  118,   16,  251,  121,  122,  123,  303,   19,  303,
 /*   530 */    59,  267,   23,   72,  131,  308,   22,  265,   22,  312,
 /*   540 */    24,  102,  103,  104,  105,  106,  107,  108,  109,  110,
 /*   550 */   111,  112,   43,   44,   45,   46,   47,   48,   49,   50,
 /*   560 */    51,   52,   53,   54,   55,   56,   57,   19,   81,  297,
 /*   570 */   295,   23,  192,   59,  203,   59,  115,  116,  117,  108,
 /*   580 */   192,   73,   25,   77,  192,   79,  115,  116,  117,  137,
 /*   590 */   138,   43,   44,   45,   46,   47,   48,   49,   50,   51,
 /*   600 */    52,   53,   54,   55,   56,   57,  119,  215,  216,  238,
 /*   610 */   239,  102,  103,  104,  105,  106,  107,  108,  109,  110,
 /*   620 */   111,  112,  251,  192,  137,  138,   59,  234,  235,  115,
 /*   630 */   116,  117,  116,   76,  126,  127,  128,   19,  192,  268,
 /*   640 */    19,   23,   22,  192,  252,   24,   89,  300,  301,   92,
 /*   650 */   102,  103,  104,  105,  106,  107,  108,  109,  110,  111,
 /*   660 */   112,   43,   44,   45,   46,   47,   48,   49,   50,   51,
 /*   670 */    52,   53,   54,   55,   56,   57,   19,  192,  192,   59,
 /*   680 */    23,  192,  115,  116,  117,  200,  240,  307,  308,   22,
 /*   690 */   205,   81,  312,  262,   22,  192,  133,   22,  135,  136,
 /*   700 */    43,   44,   45,   46,   47,   48,   49,   50,   51,   52,
 /*   710 */    53,   54,   55,   56,   57,  197,   95,  150,  215,  216,
 /*   720 */   102,  103,  104,  105,  106,  107,  108,  109,  110,  111,
 /*   730 */   112,   59,  192,  112,   59,  115,  116,  117,  192,  118,
 /*   740 */   119,  120,  121,  122,  123,  124,   19,  137,  138,  303,
 /*   750 */    23,  130,  192,  267,  192,  252,  267,  306,  203,  102,
 /*   760 */   103,  104,  105,  106,  107,  108,  109,  110,  111,  112,
 /*   770 */    43,   44,   45,   46,   47,   48,   49,   50,   51,   52,
 /*   780 */    53,   54,   55,   56,   57,   19,  240,  115,  116,  117,
 /*   790 */   115,  116,  117,  238,  239,  222,  192,  224,  280,  237,
 /*   800 */   240,  192,  284,  192,   59,  232,  251,  140,  204,   43,
 /*   810 */    44,   45,   46,   47,   48,   49,   50,   51,   52,   53,
 /*   820 */    54,   55,   56,   57,  192,   35,  215,  216,  192,  102,
 /*   830 */   103,  104,  105,  106,  107,  108,  109,  110,  111,  112,
 /*   840 */    59,  230,  192,  192,  238,  239,  237,  215,  216,  303,
 /*   850 */   308,  215,  216,   16,  312,   19,   66,  251,  126,  127,
 /*   860 */   128,  116,  230,  303,   74,  203,  215,  216,  102,  103,
 /*   870 */   104,  105,  106,  107,  108,  109,  110,  111,  112,   43,
 /*   880 */    44,   45,   46,   47,   48,   49,   50,   51,   52,   53,
 /*   890 */    54,   55,   56,   57,  192,  212,  115,  116,  117,   19,
 /*   900 */   238,  239,  192,  252,    7,    8,    9,  192,  192,  238,
 /*   910 */   239,  308,  262,  251,   77,  312,   79,  215,  216,  129,
 /*   920 */   210,  211,  251,  142,  158,   45,   46,   47,   48,   49,
 /*   930 */    50,   51,   52,   53,   54,   55,   56,   57,  102,  103,
 /*   940 */   104,  105,  106,  107,  108,  109,  110,  111,  112,   12,
 /*   950 */    59,  192,  192,  237,  252,  243,  192,  192,  126,  127,
 /*   960 */   128,  192,  308,  203,   27,  253,  312,  308,  285,  207,
 /*   970 */   208,  312,  157,  290,  159,  215,  216,  262,  192,   42,
 /*   980 */   215,  216,  102,  103,  104,  105,  106,  107,  108,  109,
 /*   990 */   110,  111,  112,  283,  158,  230,  237,  160,  238,  239,
 /*  1000 */    63,  215,  216,  192,  192,   12,  115,  116,  117,   22,
 /*  1010 */    73,  251,  252,  192,   19,  192,  230,  239,   24,   24,
 /*  1020 */    27,  261,  210,  211,   99,  192,  215,  216,  225,  251,
 /*  1030 */   192,  192,  263,  142,   19,   42,  215,  216,   43,   44,
 /*  1040 */    45,   46,   47,   48,   49,   50,   51,   52,   53,   54,
 /*  1050 */    55,   56,   57,   59,   19,  291,   63,  132,   43,   44,
 /*  1060 */    45,   46,   47,   48,   49,   50,   51,   52,   53,   54,
 /*  1070 */    55,   56,   57,  252,   22,   23,   22,   25,   43,   44,
 /*  1080 */    45,   46,   47,   48,   49,   50,   51,   52,   53,   54,
 /*  1090 */    55,   56,   57,  106,  107,  283,  263,  102,  103,  104,
 /*  1100 */   105,  106,  107,  108,  109,  110,  111,  112,   59,  192,
 /*  1110 */   116,  144,   29,   59,  291,  192,   33,  102,  103,  104,
 /*  1120 */   105,  106,  107,  108,  109,  110,  111,  112,  192,  291,
 /*  1130 */   163,   19,  215,  216,   15,  192,  108,  102,  103,  104,
 /*  1140 */   105,  106,  107,  108,  109,  110,  111,  112,   65,  192,
 /*  1150 */    66,  215,  216,  101,  231,  106,  107,   19,  215,  216,
 /*  1160 */   192,  212,  134,  114,  115,  116,  117,  139,  119,   85,
 /*  1170 */   116,  207,  208,  230,  192,   19,  127,  192,   94,   60,
 /*  1180 */    59,  192,   44,   45,   46,   47,   48,   49,   50,   51,
 /*  1190 */    52,   53,   54,   55,   56,   57,  192,   76,  192,   31,
 /*  1200 */   192,  152,   46,  154,  215,  216,  192,   39,   87,  192,
 /*  1210 */    89,   19,   20,   92,   22,  192,   22,   23,   22,  230,
 /*  1220 */   263,  215,  216,  215,  216,  137,  138,  115,   36,  145,
 /*  1230 */   128,  192,  215,  216,   22,   23,  115,  116,  117,  290,
 /*  1240 */   102,  103,  104,  105,  106,  107,  108,  109,  110,  111,
 /*  1250 */   112,   59,  192,  151,  215,  216,  192,   61,  203,  298,
 /*  1260 */   299,  192,  192,   71,   25,  144,  203,  192,  203,  230,
 /*  1270 */   114,   19,   20,   81,   22,  215,  216,  263,  192,  215,
 /*  1280 */   216,  255,  256,  203,  215,  216,  130,   19,   36,  192,
 /*  1290 */   215,  216,  100,  238,  239,  101,   25,  192,  106,  107,
 /*  1300 */    48,  238,  239,  238,  239,  113,  251,  115,  116,  117,
 /*  1310 */   192,   59,  120,  101,  251,  192,  251,  192,  238,  239,
 /*  1320 */   215,  216,  192,   71,   46,  243,  192,   25,   25,  137,
 /*  1330 */   138,  251,  192,  215,  216,  253,   25,   85,  215,  216,
 /*  1340 */   215,  216,   90,  243,  152,  153,  154,  155,  156,  215,
 /*  1350 */   216,  192,  100,  253,  243,  215,  216,  192,  106,  107,
 /*  1360 */   243,  192,  148,  149,  253,  113,  192,  115,  116,  117,
 /*  1370 */   253,  192,  120,  192,  215,  216,  192,   23,  192,   25,
 /*  1380 */   215,  216,  192,  115,  215,  216,   22,  148,   24,  215,
 /*  1390 */   216,  192,  114,  192,  215,  216,  215,  216,  134,  215,
 /*  1400 */   216,  215,  216,  139,  152,  153,  154,  155,  156,    0,
 /*  1410 */     1,    2,  141,   23,    5,   25,  215,  216,   24,   10,
 /*  1420 */    11,   12,   13,   14,    1,    2,   17,  125,    5,   19,
 /*  1430 */    20,  268,   22,   10,   11,   12,   13,   14,  192,   30,
 /*  1440 */    17,   32,   23,   23,   25,   25,   36,  144,   23,   40,
 /*  1450 */    25,  192,  141,   30,  192,   32,   23,   22,   25,    5,
 /*  1460 */   128,  215,  216,   40,   10,   11,   12,   13,   14,   59,
 /*  1470 */    23,   17,   25,  192,  215,  216,  192,  215,  216,   70,
 /*  1480 */    23,   71,   25,  151,   30,  192,   32,   78,   53,  192,
 /*  1490 */    81,  192,  192,   70,   40,   85,  215,  216,  119,  120,
 /*  1500 */    90,   78,   59,  254,   81,  192,  192,   98,  215,  216,
 /*  1510 */   100,   23,   59,   25,  215,  216,  106,  107,   23,  192,
 /*  1520 */    25,   98,   19,  113,   70,  115,  116,  117,  215,  216,
 /*  1530 */   120,  192,   78,  192,  140,   81,   19,   20,   23,   22,
 /*  1540 */    25,  132,  215,  216,  192,  192,  137,  138,  192,   23,
 /*  1550 */   192,   25,   98,   36,  192,  132,  215,  216,  192,  116,
 /*  1560 */   137,  138,  152,  153,  154,  155,  156,  215,  216,  116,
 /*  1570 */   161,  215,  216,  215,  216,  120,   59,  215,  216,    7,
 /*  1580 */     8,  215,  216,  192,  161,  130,  132,  192,   71,   83,
 /*  1590 */    84,  137,  138,   59,  192,  192,   19,   20,  192,   22,
 /*  1600 */    97,  225,   85,  192,   23,  192,   25,   90,  192,  192,
 /*  1610 */   215,  216,  152,   36,  154,  161,  192,  100,  215,  216,
 /*  1620 */   192,  215,  216,  106,  107,  225,  215,  216,  192,  192,
 /*  1630 */   113,  192,  115,  116,  117,  257,   59,  120,  192,  215,
 /*  1640 */   216,  152,  192,  154,  192,   23,  317,   25,   71,  235,
 /*  1650 */   116,  215,  216,  192,  215,  216,  192,  192,  192,  192,
 /*  1660 */   192,  192,  192,  192,  192,  215,  216,  215,  216,  152,
 /*  1670 */   153,  154,  155,  156,  192,  192,  287,  100,  286,  241,
 /*  1680 */   254,  254,  242,  106,  107,  108,  254,  213,  254,  190,
 /*  1690 */   113,  270,  115,  116,  117,  296,  266,  120,  219,  258,
 /*  1700 */   244,  270,  258,   19,   20,  228,   22,  292,  266,  224,
 /*  1710 */   292,  218,  218,  195,  218,  270,  258,   60,  245,  270,
 /*  1720 */    36,  245,  244,  248,   19,   20,  242,   22,  248,  152,
 /*  1730 */   153,  154,  155,  156,  244,  140,  199,  199,  279,   38,
 /*  1740 */   199,   36,  150,   59,  296,  149,   22,  296,   18,   43,
 /*  1750 */   236,  199,  233,   18,  198,   71,  293,  236,  271,  236,
 /*  1760 */   269,  236,  148,  271,   59,  245,  269,  245,  282,  271,
 /*  1770 */   199,  198,  233,  245,  293,  233,   71,  245,  157,   62,
 /*  1780 */    22,  199,  198,  220,  100,  199,  198,  220,  199,  289,
 /*  1790 */   106,  107,  288,  114,  226,  198,  217,  113,   64,  115,
 /*  1800 */   116,  117,  217,   22,  120,  100,  223,  217,  217,  164,
 /*  1810 */   223,  106,  107,  220,  125,   24,  217,  219,  113,  217,
 /*  1820 */   115,  116,  117,  217,  311,  120,  226,  112,  304,  281,
 /*  1830 */   281,  220,  114,  143,  260,  259,  152,  153,  154,  155,
 /*  1840 */   156,  199,   91,  316,   82,  316,  147,  144,   22,  199,
 /*  1850 */   249,  276,  157,  146,  260,  145,  278,  152,  153,  154,
 /*  1860 */   155,  156,  259,  248,  260,  260,  259,  259,  249,  245,
 /*  1870 */   247,  246,   25,  264,  264,  201,   13,    6,  193,  193,
 /*  1880 */   212,  206,  191,  191,  191,  212,  206,  221,  212,  212,
 /*  1890 */   221,  213,    4,  206,  213,  212,    3,   22,  162,   15,
 /*  1900 */    23,   16,   23,  138,  150,  129,   25,   24,  141,   20,
 /*  1910 */    16,  143,    1,  141,  302,  302,  299,  129,  129,   61,
 /*  1920 */   150,   53,   53,   37,  129,   53,   53,  115,    1,   34,
 /*  1930 */   140,    5,   22,  114,  160,   68,   75,   25,   68,   41,
 /*  1940 */   140,  114,   24,   20,   19,  130,  124,   67,   24,   67,
 /*  1950 */    22,   22,   22,   96,   23,   22,   59,   22,   67,   37,

 /*  1960 */    28,   23,  148,   22,   25,   23,   23,   23,   23,   22,
 /*  1970 */   140,   97,   23,   23,  115,   22,  142,   25,   88,   75,
 /*  1980 */    34,   44,   34,   75,   23,   34,   86,   22,   34,   34,
 /*  1990 */    34,   24,   93,   25,   25,   23,   34,   23,   23,   23,
 /*  2000 */    23,   11,   23,   25,   22,   22,   22,    1,   23,   23,
 /*  2010 */    22,   22,   25,   15,   23,    1,  140,   25,  140,  318,
 /*  2020 */   318,  134,  318,  318,  318,  318,  318,  318,  318,  318,
 /*  2030 */   318,  318,  140,  318,  318,  318,  140,  318,  318,  318,
 /*  2040 */   318,  318,  318,  318,  318,  318,  318,  318,  318,  318,
 /*  2050 */   318,  318,  318,  318,  318,  318,  318,  318,  318,  318,
 /*  2060 */   318,  318,  318,  318,  318,  318,  318,  318,  318,  318,
 /*  2070 */   318,  318,  318,  318,  318,  318,  318,  318,  318,  318,
 /*  2080 */   318,  318,  318,  318,  318,  318,  318,  318,  318,  318,
 /*  2090 */   318,  318,  318,  318,  318,  318,  318,  318,  318,  318,
 /*  2100 */   318,  318,  318,  318,  318,  318,  318,  318,  318,  318,
 /*  2110 */   318,  318,  318,  318,  318,  318,  318,  318,  318,  318,
 /*  2120 */   318,  318,  318,  318,  318,  318,  318,  318,  318,  318,
 /*  2130 */   318,  318,  318,  318,  318,  318,  318,  318,  318,  318,
 /*  2140 */   318,  318,  318,  318,  318,  318,  318,  318,  318,  318,
 /*  2150 */   318,  318,  318,  318,  318,  318,  318,  318,  318,  318,
 /*  2160 */   318,  318,  318,  318,  318,  318,  318,  318,  318,  318,
 /*  2170 */   318,  318,  318,  318,  318,  318,  318,  318,  318,  318,
 /*  2180 */   318,  318,  318,  318,  318,  318,  318,  318,  318,  318,
 /*  2190 */   318,  318,  318,  318,  318,  318,  318,  318,  318,  318,
 /*  2200 */   318,  318,  318,  318,  318,  318,  318,  318,  318,  318,
 /*  2210 */   318,  318,  318,  318,  318,  318,  318,  318,  318,  318,
 /*  2220 */   318,
};
#define YY_SHIFT_COUNT    (571)
#define YY_SHIFT_MIN      (0)
#define YY_SHIFT_MAX      (2014)
static const unsigned short int yy_shift_ofst[] = {
 /*     0 */  1423, 1409, 1454, 1192, 1192,  610, 1252, 1410, 1517, 1684,
 /*    10 */  1684, 1684,  276,    0,    0,  180, 1015, 1684, 1684, 1684,
 /*    20 */  1684, 1684, 1684, 1684, 1684, 1684, 1684, 1684, 1684, 1684,
 /*    30 */  1049, 1049, 1121, 1121,   54,  487,  610,  610,  610,  610,
 /*    40 */   610,   40,  110,  219,  289,  396,  439,  509,  548,  618,
 /*    50 */   657,  727,  766,  836,  995, 1015, 1015, 1015, 1015, 1015,
 /*    60 */  1015, 1015, 1015, 1015, 1015, 1015, 1015, 1015, 1015, 1015,
 /*    70 */  1015, 1015, 1015, 1035, 1015, 1138,  880,  880, 1577, 1684,
 /*    80 */  1684, 1684, 1684, 1684, 1684, 1684, 1684, 1684, 1684, 1684,
 /*    90 */  1684, 1684, 1684, 1684, 1684, 1684, 1684, 1684, 1684, 1684,
 /*   100 */  1684, 1684, 1684, 1684, 1684, 1684, 1684, 1684, 1684, 1684,
 /*   110 */  1684, 1684, 1684, 1705, 1684, 1684, 1684, 1684, 1684, 1684,
 /*   120 */  1684, 1684, 1684, 1684, 1684, 1684, 1684,  146,   84,   84,
 /*   130 */    84,   84,   84,  277,  315,  401,   97,  461,  251,   66,
 /*   140 */    66,   51, 1156,   66,   66,  324,  324,   66,  452,  452,
 /*   150 */   452,  452,  133,  114,  114,    4,   11, 2037, 2037,  621,
 /*   160 */   621,  621,  567,  398,  398,  398,  398,  937,  937,  228,
 /*   170 */   251,  331, 1052,   66,   66,   66,   66,   66,   66,   66,
 /*   180 */    66,   66,   66,   66,   66,   66,   66,   66,   66,   66,
 /*   190 */    66,   66,   66,  557,  557,   66,    9,   25,   25,  745,
 /*   200 */   745,  967, 1088, 2037, 2037, 2037, 2037, 2037, 2037, 2037,
 /*   210 */   255,  317,  317,  514,  403,  620,  471,  672,  781,  891,
 /*   220 */   675,   66,   66,   66,   66,   66,   66,   66,   66,   66,
 /*   230 */    66,  508,   66,   66,   66,   66,   66,   66,   66,   66,
 /*   240 */    66,   66,   66,   66,  790,  790,  790,   66,   66,   66,
 /*   250 */   338,   66,   66,   66,  516, 1084,   66,   66,  993,   66,
 /*   260 */    66,   66,   66,   66,   66,   66,   66,  732, 1083,  563,
 /*   270 */   994,  994,  994,  994,  337,  563,  563, 1028,  987,  897,
 /*   280 */  1119,  262, 1214, 1271, 1112, 1214, 1112, 1268, 1239,  262,
 /*   290 */   262, 1239,  262, 1271, 1268, 1302, 1354, 1278, 1168, 1168,
 /*   300 */  1168, 1112, 1303, 1303,  815, 1311, 1264, 1364, 1657, 1657,
 /*   310 */  1595, 1595, 1701, 1701, 1595, 1592, 1596, 1724, 1706, 1730,
 /*   320 */  1730, 1730, 1730, 1595, 1735, 1614, 1596, 1596, 1614, 1724,
 /*   330 */  1706, 1614, 1706, 1614, 1595, 1735, 1621, 1717, 1595, 1735,
 /*   340 */  1758, 1595, 1735, 1595, 1735, 1758, 1679, 1679, 1679, 1734,
 /*   350 */  1781, 1781, 1758, 1679, 1689, 1679, 1734, 1679, 1679, 1645,
 /*   360 */  1791, 1715, 1715, 1758, 1690, 1718, 1690, 1718, 1690, 1718,
 /*   370 */  1690, 1718, 1595, 1751, 1751, 1762, 1762, 1699, 1703, 1826,
 /*   380 */  1595, 1695, 1699, 1707, 1710, 1614, 1847, 1863, 1863, 1871,
 /*   390 */  1871, 1871, 2037, 2037, 2037, 2037, 2037, 2037, 2037, 2037,
 /*   400 */  2037, 2037, 2037, 2037, 2037, 2037, 2037,  193,  837, 1194,
 /*   410 */  1212,  506,  832, 1054, 1390,  925, 1435, 1394, 1102, 1332,
 /*   420 */  1419, 1196, 1420, 1425, 1433, 1447, 1457, 1488, 1443, 1379,
 /*   430 */  1572, 1455, 1503, 1453, 1495, 1515, 1506, 1526, 1460, 1489,
 /*   440 */  1581, 1622, 1534,  667, 1888, 1893, 1875, 1736, 1884, 1885,
 /*   450 */  1877, 1879, 1765, 1754, 1776, 1881, 1881, 1883, 1767, 1889,
 /*   460 */  1768, 1894, 1911, 1772, 1788, 1881, 1789, 1858, 1886, 1881,
 /*   470 */  1770, 1868, 1869, 1872, 1873, 1795, 1812, 1895, 1790, 1927,
 /*   480 */  1926, 1910, 1819, 1774, 1867, 1912, 1870, 1861, 1898, 1800,
 /*   490 */  1827, 1918, 1923, 1925, 1815, 1822, 1928, 1880, 1929, 1930,
 /*   500 */  1931, 1933, 1882, 1897, 1924, 1857, 1932, 1935, 1891, 1922,
 /*   510 */  1938, 1814, 1941, 1942, 1943, 1944, 1939, 1945, 1947, 1874,
 /*   520 */  1830, 1949, 1950, 1859, 1946, 1953, 1834, 1952, 1948, 1951,
 /*   530 */  1954, 1955, 1890, 1904, 1900, 1937, 1908, 1899, 1956, 1961,
 /*   540 */  1965, 1967, 1968, 1969, 1962, 1972, 1952, 1974, 1975, 1976,
 /*   550 */  1977, 1978, 1979, 1982, 1990, 1983, 1984, 1985, 1986, 1988,
 /*   560 */  1989, 1987, 1887, 1876, 1878, 1892, 1896, 1992, 1991, 1998,
 /*   570 */  2006, 2014,
};
#define YY_REDUCE_COUNT (406)
#define YY_REDUCE_MIN   (-272)
#define YY_REDUCE_MAX   (1693)
static const short yy_reduce_ofst[] = {
 /*     0 */   109,  113,  272,  760, -178, -176, -192, -183, -180, -134,
 /*    10 */   213,  220,  371, -208, -205, -272, -197,  611,  632,  765,
 /*    20 */   786,  392,  943,  989,  503,  651, 1039,  -18,  702,  821,
 /*    30 */   710,  812, -188,  380, -187,  555,  662, 1055, 1063, 1065,
 /*    40 */  1080, -267, -267, -267, -267, -267, -267, -267, -267, -267,
 /*    50 */  -267, -267, -267, -267, -267, -267, -267, -267, -267, -267,
 /*    60 */  -267, -267, -267, -267, -267, -267, -267, -267, -267, -267,
 /*    70 */  -267, -267, -267, -267, -267, -267, -267, -267,  636,  811,
 /*    80 */   917,  936, 1006, 1008, 1017, 1060, 1064, 1069, 1075, 1105,
 /*    90 */  1118, 1123, 1125, 1134, 1140, 1159, 1165, 1169, 1174, 1179,
 /*   100 */  1181, 1184, 1186, 1201, 1246, 1259, 1262, 1281, 1293, 1299,
 /*   110 */  1313, 1327, 1341, 1352, 1356, 1358, 1362, 1366, 1395, 1403,
 /*   120 */  1406, 1411, 1424, 1436, 1439, 1450, 1452, -267, -267, -267,
 /*   130 */  -267, -267, -267, -267, -267,  224, -267,  446,  -24,  275,
 /*   140 */   546,  518,  573,  560,   53, -181, -111,  485,  606,  671,
 /*   150 */   606,  671,  683,    8,   93, -267, -267, -267, -267,  155,
 /*   160 */   155,  155,  181,  242,  264,  486,  489, -218,  393,  227,
 /*   170 */   604,  347,  347, -171,  431,  650,  715, -166,  562,  609,
 /*   180 */   716,  764,   18,  823,  769,  833,  838,  957,  759,  119,
 /*   190 */   923,  226, 1014,  542,  603,  451,  949,  654,  659,  762,
 /*   200 */   964,   -4,  778,  961,  712, 1082, 1100, 1111, 1026, 1117,
 /*   210 */  -204, -174, -151,   -8,   77,  198,  305,  327,  388,  540,
 /*   220 */   839,  968,  982,  985, 1004, 1023, 1070, 1086, 1097, 1130,
 /*   230 */  1190, 1163, 1199, 1284, 1297, 1300, 1314, 1339, 1353, 1391,
 /*   240 */  1402, 1413, 1416, 1417,  803, 1376, 1400, 1428, 1437, 1446,
 /*   250 */  1378, 1461, 1464, 1465, 1249, 1329, 1466, 1467, 1414, 1468,
 /*   260 */   305, 1469, 1470, 1471, 1472, 1482, 1483, 1389, 1392, 1438,
 /*   270 */  1426, 1427, 1432, 1434, 1378, 1438, 1438, 1440, 1474, 1499,
 /*   280 */  1399, 1421, 1430, 1456, 1441, 1442, 1444, 1415, 1473, 1431,
 /*   290 */  1445, 1476, 1449, 1478, 1418, 1479, 1477, 1485, 1493, 1494,
 /*   300 */  1496, 1458, 1475, 1480, 1459, 1490, 1484, 1518, 1448, 1451,
 /*   310 */  1537, 1538, 1463, 1481, 1541, 1486, 1487, 1491, 1519, 1514,
 /*   320 */  1521, 1523, 1525, 1552, 1556, 1520, 1492, 1498, 1522, 1497,
 /*   330 */  1539, 1528, 1542, 1532, 1571, 1573, 1500, 1504, 1582, 1584,
 /*   340 */  1563, 1586, 1588, 1589, 1597, 1567, 1579, 1585, 1590, 1568,
 /*   350 */  1583, 1587, 1593, 1591, 1598, 1599, 1600, 1602, 1606, 1513,
 /*   360 */  1524, 1548, 1549, 1611, 1574, 1576, 1594, 1603, 1604, 1607,
 /*   370 */  1605, 1608, 1642, 1527, 1529, 1609, 1610, 1601, 1615, 1575,
 /*   380 */  1650, 1578, 1619, 1623, 1625, 1624, 1674, 1685, 1686, 1691,
 /*   390 */  1692, 1693, 1612, 1613, 1617, 1675, 1668, 1673, 1676, 1677,
 /*   400 */  1680, 1666, 1669, 1678, 1681, 1683, 1687,
};
static const YYACTIONTYPE yy_default[] = {
 /*     0 */  1633, 1633, 1633, 1462, 1230, 1341, 1230, 1230, 1230, 1462,
 /*    10 */  1462, 1462, 1230, 1371, 1371, 1515, 1263, 1230, 1230, 1230,
 /*    20 */  1230, 1230, 1230, 1230, 1230, 1230, 1230, 1461, 1230, 1230,
 /*    30 */  1230, 1230, 1550, 1550, 1230, 1230, 1230, 1230, 1230, 1230,
 /*    40 */  1230, 1230, 1380, 1230, 1387, 1230, 1230, 1230, 1230, 1230,
 /*    50 */  1463, 1464, 1230, 1230, 1230, 1514, 1516, 1479, 1394, 1393,
 /*    60 */  1392, 1391, 1497, 1358, 1385, 1378, 1382, 1457, 1458, 1456,
 /*    70 */  1460, 1464, 1463, 1230, 1381, 1428, 1442, 1427, 1230, 1230,
 /*    80 */  1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230,
 /*    90 */  1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230,
 /*   100 */  1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230,
 /*   110 */  1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230,
 /*   120 */  1230, 1230, 1230, 1230, 1230, 1230, 1230, 1436, 1441, 1447,
 /*   130 */  1440, 1437, 1430, 1429, 1431, 1230, 1432, 1230, 1254, 1230,
 /*   140 */  1230, 1251, 1305, 1230, 1230, 1230, 1230, 1230, 1534, 1533,
 /*   150 */  1230, 1230, 1263, 1422, 1421, 1433, 1434, 1444, 1443, 1522,
 /*   160 */  1586, 1585, 1480, 1230, 1230, 1230, 1230, 1230, 1230, 1550,
 /*   170 */  1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230,
 /*   180 */  1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230,
 /*   190 */  1230, 1230, 1230, 1550, 1550, 1230, 1263, 1550, 1550, 1259,
 /*   200 */  1259, 1365, 1230, 1529, 1332, 1332, 1332, 1332, 1341, 1332,
 /*   210 */  1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230,
 /*   220 */  1230, 1230, 1230, 1230, 1230, 1519, 1517, 1230, 1230, 1230,
 /*   230 */  1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230,
 /*   240 */  1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230,
 /*   250 */  1230, 1230, 1230, 1230, 1337, 1230, 1230, 1230, 1230, 1230,
 /*   260 */  1230, 1230, 1230, 1230, 1230, 1230, 1579, 1230, 1492, 1319,
 /*   270 */  1337, 1337, 1337, 1337, 1339, 1320, 1318, 1331, 1264, 1237,
 /*   280 */  1625, 1397, 1386, 1338, 1360, 1386, 1360, 1622, 1384, 1397,
 /*   290 */  1397, 1384, 1397, 1338, 1622, 1280, 1602, 1275, 1371, 1371,
 /*   300 */  1371, 1360, 1365, 1365, 1459, 1338, 1331, 1230, 1625, 1625,
 /*   310 */  1346, 1346, 1624, 1624, 1346, 1480, 1609, 1406, 1308, 1314,
 /*   320 */  1314, 1314, 1314, 1346, 1248, 1384, 1609, 1609, 1384, 1406,
 /*   330 */  1308, 1384, 1308, 1384, 1346, 1248, 1496, 1619, 1346, 1248,
 /*   340 */  1470, 1346, 1248, 1346, 1248, 1470, 1306, 1306, 1306, 1295,
 /*   350 */  1230, 1230, 1470, 1306, 1280, 1306, 1295, 1306, 1306, 1568,
 /*   360 */  1230, 1474, 1474, 1470, 1364, 1359, 1364, 1359, 1364, 1359,
 /*   370 */  1364, 1359, 1346, 1560, 1560, 1374, 1374, 1379, 1365, 1465,
 /*   380 */  1346, 1230, 1379, 1377, 1375, 1384, 1298, 1582, 1582, 1578,
 /*   390 */  1578, 1578, 1630, 1630, 1529, 1595, 1263, 1263, 1263, 1263,
 /*   400 */  1595, 1282, 1282, 1264, 1264, 1263, 1595, 1230, 1230, 1230,
 /*   410 */  1230, 1230, 1230, 1590, 1230, 1524, 1481, 1350, 1230, 1230,
 /*   420 */  1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230,
 /*   430 */  1230, 1230, 1535, 1230, 1230, 1230, 1230, 1230, 1230, 1230,
 /*   440 */  1230, 1230, 1230, 1411, 1230, 1233, 1526, 1230, 1230, 1230,
 /*   450 */  1230, 1230, 1230, 1230, 1230, 1388, 1389, 1351, 1230, 1230,
 /*   460 */  1230, 1230, 1230, 1230, 1230, 1403, 1230, 1230, 1230, 1398,
 /*   470 */  1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1621, 1230,
 /*   480 */  1230, 1230, 1230, 1230, 1230, 1495, 1494, 1230, 1230, 1348,
 /*   490 */  1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230,
 /*   500 */  1230, 1230, 1230, 1278, 1230, 1230, 1230, 1230, 1230, 1230,
 /*   510 */  1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230,
 /*   520 */  1230, 1230, 1230, 1230, 1230, 1230, 1230, 1376, 1230, 1230,
 /*   530 */  1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230,
 /*   540 */  1230, 1230, 1565, 1366, 1230, 1230, 1612, 1230, 1230, 1230,
 /*   550 */  1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230, 1230,
 /*   560 */  1230, 1606, 1322, 1413, 1230, 1412, 1416, 1252, 1230, 1242,
 /*   570 */  1230, 1230,
};
/********** End of lemon-generated parsing tables *****************************/

/* The next table maps tokens (terminal symbols) into fallback tokens.
** If a construct like the following:
**
**      %fallback ID X Y Z.
159445
159446
159447
159448
159449
159450
159451
159452
159453

159454
159455
159456
159457
159458
159459
159460
   59,  /*         IF => ID */
    0,  /*        NOT => nothing */
    0,  /*     EXISTS => nothing */
   59,  /*       TEMP => ID */
    0,  /*         LP => nothing */
    0,  /*         RP => nothing */
    0,  /*         AS => nothing */
   59,  /*    WITHOUT => ID */
    0,  /*      COMMA => nothing */

   59,  /*      ABORT => ID */
   59,  /*     ACTION => ID */
   59,  /*      AFTER => ID */
   59,  /*    ANALYZE => ID */
   59,  /*        ASC => ID */
   59,  /*     ATTACH => ID */
   59,  /*     BEFORE => ID */







<

>







159935
159936
159937
159938
159939
159940
159941

159942
159943
159944
159945
159946
159947
159948
159949
159950
   59,  /*         IF => ID */
    0,  /*        NOT => nothing */
    0,  /*     EXISTS => nothing */
   59,  /*       TEMP => ID */
    0,  /*         LP => nothing */
    0,  /*         RP => nothing */
    0,  /*         AS => nothing */

    0,  /*      COMMA => nothing */
   59,  /*    WITHOUT => ID */
   59,  /*      ABORT => ID */
   59,  /*     ACTION => ID */
   59,  /*      AFTER => ID */
   59,  /*    ANALYZE => ID */
   59,  /*        ASC => ID */
   59,  /*     ATTACH => ID */
   59,  /*     BEFORE => ID */
159717
159718
159719
159720
159721
159722
159723
159724
159725
159726
159727
159728
159729
159730
159731
159732
  /*   18 */ "IF",
  /*   19 */ "NOT",
  /*   20 */ "EXISTS",
  /*   21 */ "TEMP",
  /*   22 */ "LP",
  /*   23 */ "RP",
  /*   24 */ "AS",
  /*   25 */ "WITHOUT",
  /*   26 */ "COMMA",
  /*   27 */ "ABORT",
  /*   28 */ "ACTION",
  /*   29 */ "AFTER",
  /*   30 */ "ANALYZE",
  /*   31 */ "ASC",
  /*   32 */ "ATTACH",
  /*   33 */ "BEFORE",







|
|







160207
160208
160209
160210
160211
160212
160213
160214
160215
160216
160217
160218
160219
160220
160221
160222
  /*   18 */ "IF",
  /*   19 */ "NOT",
  /*   20 */ "EXISTS",
  /*   21 */ "TEMP",
  /*   22 */ "LP",
  /*   23 */ "RP",
  /*   24 */ "AS",
  /*   25 */ "COMMA",
  /*   26 */ "WITHOUT",
  /*   27 */ "ABORT",
  /*   28 */ "ACTION",
  /*   29 */ "AFTER",
  /*   30 */ "ANALYZE",
  /*   31 */ "ASC",
  /*   32 */ "ATTACH",
  /*   33 */ "BEFORE",
159894
159895
159896
159897
159898
159899
159900
159901
159902
159903
159904
159905
159906
159907
159908
159909
159910
159911
159912
159913
159914
159915
159916
159917
159918
159919
159920
159921
159922
159923
159924
159925
159926
159927
159928
159929
159930
159931
159932
159933
159934
159935
159936
159937
159938
159939
159940
159941
159942
159943
159944
159945
159946
159947
159948
159949
159950
159951
159952
159953
159954
159955
159956
159957
159958
159959
159960
159961
159962
159963
159964
159965
159966
159967
159968
159969
159970
159971
159972
159973
159974
159975
159976
159977
159978
159979
159980
159981
159982
159983
159984
159985

159986
159987
159988
159989
159990
159991
159992
159993
159994
159995
159996
159997
159998
159999
160000
160001
160002
160003
160004
160005
160006
160007
160008
160009
160010
160011
160012
160013
160014
160015

160016
160017
160018
160019
160020
160021
160022
  /*  195 */ "create_table_args",
  /*  196 */ "createkw",
  /*  197 */ "temp",
  /*  198 */ "ifnotexists",
  /*  199 */ "dbnm",
  /*  200 */ "columnlist",
  /*  201 */ "conslist_opt",
  /*  202 */ "table_options",
  /*  203 */ "select",
  /*  204 */ "columnname",
  /*  205 */ "carglist",
  /*  206 */ "typetoken",
  /*  207 */ "typename",
  /*  208 */ "signed",
  /*  209 */ "plus_num",
  /*  210 */ "minus_num",
  /*  211 */ "scanpt",
  /*  212 */ "scantok",
  /*  213 */ "ccons",
  /*  214 */ "term",
  /*  215 */ "expr",
  /*  216 */ "onconf",
  /*  217 */ "sortorder",
  /*  218 */ "autoinc",
  /*  219 */ "eidlist_opt",
  /*  220 */ "refargs",
  /*  221 */ "defer_subclause",
  /*  222 */ "generated",
  /*  223 */ "refarg",
  /*  224 */ "refact",
  /*  225 */ "init_deferred_pred_opt",
  /*  226 */ "conslist",
  /*  227 */ "tconscomma",
  /*  228 */ "tcons",
  /*  229 */ "sortlist",
  /*  230 */ "eidlist",
  /*  231 */ "defer_subclause_opt",
  /*  232 */ "orconf",
  /*  233 */ "resolvetype",
  /*  234 */ "raisetype",
  /*  235 */ "ifexists",
  /*  236 */ "fullname",
  /*  237 */ "selectnowith",
  /*  238 */ "oneselect",
  /*  239 */ "wqlist",
  /*  240 */ "multiselect_op",
  /*  241 */ "distinct",
  /*  242 */ "selcollist",
  /*  243 */ "from",
  /*  244 */ "where_opt",
  /*  245 */ "groupby_opt",
  /*  246 */ "having_opt",
  /*  247 */ "orderby_opt",
  /*  248 */ "limit_opt",
  /*  249 */ "window_clause",
  /*  250 */ "values",
  /*  251 */ "nexprlist",
  /*  252 */ "sclp",
  /*  253 */ "as",
  /*  254 */ "seltablist",
  /*  255 */ "stl_prefix",
  /*  256 */ "joinop",
  /*  257 */ "indexed_opt",
  /*  258 */ "on_opt",
  /*  259 */ "using_opt",
  /*  260 */ "exprlist",
  /*  261 */ "xfullname",
  /*  262 */ "idlist",
  /*  263 */ "nulls",
  /*  264 */ "with",
  /*  265 */ "where_opt_ret",
  /*  266 */ "setlist",
  /*  267 */ "insert_cmd",
  /*  268 */ "idlist_opt",
  /*  269 */ "upsert",
  /*  270 */ "returning",
  /*  271 */ "filter_over",
  /*  272 */ "likeop",
  /*  273 */ "between_op",
  /*  274 */ "in_op",
  /*  275 */ "paren_exprlist",
  /*  276 */ "case_operand",
  /*  277 */ "case_exprlist",
  /*  278 */ "case_else",
  /*  279 */ "uniqueflag",
  /*  280 */ "collate",
  /*  281 */ "vinto",
  /*  282 */ "nmnum",
  /*  283 */ "trigger_decl",
  /*  284 */ "trigger_cmd_list",
  /*  285 */ "trigger_time",
  /*  286 */ "trigger_event",

  /*  287 */ "foreach_clause",
  /*  288 */ "when_clause",
  /*  289 */ "trigger_cmd",
  /*  290 */ "trnm",
  /*  291 */ "tridxby",
  /*  292 */ "database_kw_opt",
  /*  293 */ "key_opt",
  /*  294 */ "add_column_fullname",
  /*  295 */ "kwcolumn_opt",
  /*  296 */ "create_vtab",
  /*  297 */ "vtabarglist",
  /*  298 */ "vtabarg",
  /*  299 */ "vtabargtoken",
  /*  300 */ "lp",
  /*  301 */ "anylist",
  /*  302 */ "wqitem",
  /*  303 */ "wqas",
  /*  304 */ "windowdefn_list",
  /*  305 */ "windowdefn",
  /*  306 */ "window",
  /*  307 */ "frame_opt",
  /*  308 */ "part_opt",
  /*  309 */ "filter_clause",
  /*  310 */ "over_clause",
  /*  311 */ "range_or_rows",
  /*  312 */ "frame_bound",
  /*  313 */ "frame_bound_s",
  /*  314 */ "frame_bound_e",
  /*  315 */ "frame_exclude_opt",
  /*  316 */ "frame_exclude",

};
#endif /* defined(YYCOVERAGE) || !defined(NDEBUG) */

#ifndef NDEBUG
/* For tracing reduce actions, the names of all rules are required.
*/
static const char *const yyRuleName[] = {







|

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







160384
160385
160386
160387
160388
160389
160390
160391
160392
160393
160394
160395
160396
160397
160398
160399
160400
160401
160402
160403
160404
160405
160406
160407
160408
160409
160410
160411
160412
160413
160414
160415
160416
160417
160418
160419
160420
160421
160422
160423
160424
160425
160426
160427
160428
160429
160430
160431
160432
160433
160434
160435
160436
160437
160438
160439
160440
160441
160442
160443
160444
160445
160446
160447
160448
160449
160450
160451
160452
160453
160454
160455
160456
160457
160458
160459
160460
160461
160462
160463
160464
160465
160466
160467
160468
160469
160470
160471
160472
160473
160474
160475
160476
160477
160478

160479
160480
160481
160482
160483
160484
160485
160486
160487
160488
160489
160490
160491
160492
160493
160494
160495
160496
160497
160498
160499
160500
160501
160502
160503
160504
160505
160506
160507
160508
160509
160510
160511
160512
160513
  /*  195 */ "create_table_args",
  /*  196 */ "createkw",
  /*  197 */ "temp",
  /*  198 */ "ifnotexists",
  /*  199 */ "dbnm",
  /*  200 */ "columnlist",
  /*  201 */ "conslist_opt",
  /*  202 */ "table_option_set",
  /*  203 */ "select",
  /*  204 */ "table_option",
  /*  205 */ "columnname",
  /*  206 */ "carglist",
  /*  207 */ "typetoken",
  /*  208 */ "typename",
  /*  209 */ "signed",
  /*  210 */ "plus_num",
  /*  211 */ "minus_num",
  /*  212 */ "scanpt",
  /*  213 */ "scantok",
  /*  214 */ "ccons",
  /*  215 */ "term",
  /*  216 */ "expr",
  /*  217 */ "onconf",
  /*  218 */ "sortorder",
  /*  219 */ "autoinc",
  /*  220 */ "eidlist_opt",
  /*  221 */ "refargs",
  /*  222 */ "defer_subclause",
  /*  223 */ "generated",
  /*  224 */ "refarg",
  /*  225 */ "refact",
  /*  226 */ "init_deferred_pred_opt",
  /*  227 */ "conslist",
  /*  228 */ "tconscomma",
  /*  229 */ "tcons",
  /*  230 */ "sortlist",
  /*  231 */ "eidlist",
  /*  232 */ "defer_subclause_opt",
  /*  233 */ "orconf",
  /*  234 */ "resolvetype",
  /*  235 */ "raisetype",
  /*  236 */ "ifexists",
  /*  237 */ "fullname",
  /*  238 */ "selectnowith",
  /*  239 */ "oneselect",
  /*  240 */ "wqlist",
  /*  241 */ "multiselect_op",
  /*  242 */ "distinct",
  /*  243 */ "selcollist",
  /*  244 */ "from",
  /*  245 */ "where_opt",
  /*  246 */ "groupby_opt",
  /*  247 */ "having_opt",
  /*  248 */ "orderby_opt",
  /*  249 */ "limit_opt",
  /*  250 */ "window_clause",
  /*  251 */ "values",
  /*  252 */ "nexprlist",
  /*  253 */ "sclp",
  /*  254 */ "as",
  /*  255 */ "seltablist",
  /*  256 */ "stl_prefix",
  /*  257 */ "joinop",
  /*  258 */ "indexed_opt",
  /*  259 */ "on_opt",
  /*  260 */ "using_opt",
  /*  261 */ "exprlist",
  /*  262 */ "xfullname",
  /*  263 */ "idlist",
  /*  264 */ "nulls",
  /*  265 */ "with",
  /*  266 */ "where_opt_ret",
  /*  267 */ "setlist",
  /*  268 */ "insert_cmd",
  /*  269 */ "idlist_opt",
  /*  270 */ "upsert",
  /*  271 */ "returning",
  /*  272 */ "filter_over",
  /*  273 */ "likeop",
  /*  274 */ "between_op",
  /*  275 */ "in_op",
  /*  276 */ "paren_exprlist",
  /*  277 */ "case_operand",
  /*  278 */ "case_exprlist",
  /*  279 */ "case_else",
  /*  280 */ "uniqueflag",
  /*  281 */ "collate",
  /*  282 */ "vinto",
  /*  283 */ "nmnum",
  /*  284 */ "trigger_decl",
  /*  285 */ "trigger_cmd_list",
  /*  286 */ "trigger_time",
  /*  287 */ "trigger_event",
  /*  288 */ "foreach_clause",
  /*  289 */ "when_clause",

  /*  290 */ "trigger_cmd",
  /*  291 */ "trnm",
  /*  292 */ "tridxby",
  /*  293 */ "database_kw_opt",
  /*  294 */ "key_opt",
  /*  295 */ "add_column_fullname",
  /*  296 */ "kwcolumn_opt",
  /*  297 */ "create_vtab",
  /*  298 */ "vtabarglist",
  /*  299 */ "vtabarg",
  /*  300 */ "vtabargtoken",
  /*  301 */ "lp",
  /*  302 */ "anylist",
  /*  303 */ "wqitem",
  /*  304 */ "wqas",
  /*  305 */ "windowdefn_list",
  /*  306 */ "windowdefn",
  /*  307 */ "window",
  /*  308 */ "frame_opt",
  /*  309 */ "part_opt",
  /*  310 */ "filter_clause",
  /*  311 */ "over_clause",
  /*  312 */ "range_or_rows",
  /*  313 */ "frame_bound",
  /*  314 */ "frame_bound_s",
  /*  315 */ "frame_bound_e",
  /*  316 */ "frame_exclude_opt",
  /*  317 */ "frame_exclude",
};
#endif /* defined(YYCOVERAGE) || !defined(NDEBUG) */

#ifndef NDEBUG
/* For tracing reduce actions, the names of all rules are required.
*/
static const char *const yyRuleName[] = {
160035
160036
160037
160038
160039
160040
160041
160042
160043
160044
160045


160046
160047
160048
160049
160050
160051
160052
160053
160054
160055
160056
160057
160058
160059
160060
160061
160062
160063
160064
160065
160066
160067
160068
160069
160070
160071
160072
160073
160074
160075
160076
160077
160078
160079
160080
160081
160082
160083
160084
160085
160086
160087
160088
160089
160090
160091
160092
160093
160094
160095
160096
160097
160098
160099
160100
160101
160102
160103
160104
160105
160106
160107
160108
160109
160110
160111
160112
160113
160114
160115
160116
160117
160118
160119
160120
160121
160122
160123
160124
160125
160126
160127
160128
160129
160130
160131
160132
160133
160134
160135
160136
160137
160138
160139
160140
160141
160142
160143
160144
160145
160146
160147
160148
160149
160150
160151
160152
160153
160154
160155
160156
160157
160158
160159
160160
160161
160162


160163
160164
160165
160166
160167
160168
160169
160170
160171
160172
160173
160174
160175
160176
160177
160178
160179
160180
160181
160182
160183
160184
160185
160186
160187
160188
160189
160190
160191
160192
160193
160194
160195
160196
160197
160198
160199
160200
160201
160202
160203
160204
160205
160206
160207
160208
160209
160210
160211
160212
160213
160214
160215
160216
160217
160218
160219
160220
160221
160222
160223
160224
160225
160226
160227
160228
160229
160230
160231
160232
160233
160234
160235
160236
160237
160238
160239
160240
160241
160242
160243
160244
160245
160246
160247
160248
160249
160250
160251
160252
160253
160254
160255
160256
160257
160258
160259
160260
160261
160262
160263
160264
160265
160266
160267
160268
160269
160270
160271
160272
160273
160274
160275
160276
160277
160278
160279
160280
160281
160282
160283
160284
160285
160286
160287
160288
160289
160290
160291
160292
160293
160294
160295
160296
160297
160298
160299
160300
160301
160302
160303
160304
160305
160306
160307
160308
160309
160310
160311
160312
160313
160314
160315
160316
160317
160318
160319
160320
160321
160322
160323
160324
160325
160326
160327
160328
160329
160330
160331
160332
160333
160334
160335
160336
160337
160338
160339
160340
160341
160342
160343
160344
160345
160346
160347
160348
160349
160350
160351
160352


160353
160354
160355
160356
160357
160358
160359
160360
160361
160362
160363
160364
160365
160366
160367
160368
160369
160370
160371

160372
160373
160374
160375
160376
160377
160378
160379
160380
160381
160382
160383
160384
160385
160386
160387
160388
160389
160390
160391
160392
160393
160394
160395
160396
160397
160398
160399
160400
160401
160402
160403
160404
160405
160406
160407
160408
160409
160410
160411
160412
160413
160414
160415
160416
160417
160418
160419
160420
160421
160422
160423
160424
160425
160426
160427
 /*  12 */ "cmd ::= ROLLBACK trans_opt TO savepoint_opt nm",
 /*  13 */ "create_table ::= createkw temp TABLE ifnotexists nm dbnm",
 /*  14 */ "createkw ::= CREATE",
 /*  15 */ "ifnotexists ::=",
 /*  16 */ "ifnotexists ::= IF NOT EXISTS",
 /*  17 */ "temp ::= TEMP",
 /*  18 */ "temp ::=",
 /*  19 */ "create_table_args ::= LP columnlist conslist_opt RP table_options",
 /*  20 */ "create_table_args ::= AS select",
 /*  21 */ "table_options ::=",
 /*  22 */ "table_options ::= WITHOUT nm",


 /*  23 */ "columnname ::= nm typetoken",
 /*  24 */ "typetoken ::=",
 /*  25 */ "typetoken ::= typename LP signed RP",
 /*  26 */ "typetoken ::= typename LP signed COMMA signed RP",
 /*  27 */ "typename ::= typename ID|STRING",
 /*  28 */ "scanpt ::=",
 /*  29 */ "scantok ::=",
 /*  30 */ "ccons ::= CONSTRAINT nm",
 /*  31 */ "ccons ::= DEFAULT scantok term",
 /*  32 */ "ccons ::= DEFAULT LP expr RP",
 /*  33 */ "ccons ::= DEFAULT PLUS scantok term",
 /*  34 */ "ccons ::= DEFAULT MINUS scantok term",
 /*  35 */ "ccons ::= DEFAULT scantok ID|INDEXED",
 /*  36 */ "ccons ::= NOT NULL onconf",
 /*  37 */ "ccons ::= PRIMARY KEY sortorder onconf autoinc",
 /*  38 */ "ccons ::= UNIQUE onconf",
 /*  39 */ "ccons ::= CHECK LP expr RP",
 /*  40 */ "ccons ::= REFERENCES nm eidlist_opt refargs",
 /*  41 */ "ccons ::= defer_subclause",
 /*  42 */ "ccons ::= COLLATE ID|STRING",
 /*  43 */ "generated ::= LP expr RP",
 /*  44 */ "generated ::= LP expr RP ID",
 /*  45 */ "autoinc ::=",
 /*  46 */ "autoinc ::= AUTOINCR",
 /*  47 */ "refargs ::=",
 /*  48 */ "refargs ::= refargs refarg",
 /*  49 */ "refarg ::= MATCH nm",
 /*  50 */ "refarg ::= ON INSERT refact",
 /*  51 */ "refarg ::= ON DELETE refact",
 /*  52 */ "refarg ::= ON UPDATE refact",
 /*  53 */ "refact ::= SET NULL",
 /*  54 */ "refact ::= SET DEFAULT",
 /*  55 */ "refact ::= CASCADE",
 /*  56 */ "refact ::= RESTRICT",
 /*  57 */ "refact ::= NO ACTION",
 /*  58 */ "defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt",
 /*  59 */ "defer_subclause ::= DEFERRABLE init_deferred_pred_opt",
 /*  60 */ "init_deferred_pred_opt ::=",
 /*  61 */ "init_deferred_pred_opt ::= INITIALLY DEFERRED",
 /*  62 */ "init_deferred_pred_opt ::= INITIALLY IMMEDIATE",
 /*  63 */ "conslist_opt ::=",
 /*  64 */ "tconscomma ::= COMMA",
 /*  65 */ "tcons ::= CONSTRAINT nm",
 /*  66 */ "tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf",
 /*  67 */ "tcons ::= UNIQUE LP sortlist RP onconf",
 /*  68 */ "tcons ::= CHECK LP expr RP onconf",
 /*  69 */ "tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt",
 /*  70 */ "defer_subclause_opt ::=",
 /*  71 */ "onconf ::=",
 /*  72 */ "onconf ::= ON CONFLICT resolvetype",
 /*  73 */ "orconf ::=",
 /*  74 */ "orconf ::= OR resolvetype",
 /*  75 */ "resolvetype ::= IGNORE",
 /*  76 */ "resolvetype ::= REPLACE",
 /*  77 */ "cmd ::= DROP TABLE ifexists fullname",
 /*  78 */ "ifexists ::= IF EXISTS",
 /*  79 */ "ifexists ::=",
 /*  80 */ "cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select",
 /*  81 */ "cmd ::= DROP VIEW ifexists fullname",
 /*  82 */ "cmd ::= select",
 /*  83 */ "select ::= WITH wqlist selectnowith",
 /*  84 */ "select ::= WITH RECURSIVE wqlist selectnowith",
 /*  85 */ "select ::= selectnowith",
 /*  86 */ "selectnowith ::= selectnowith multiselect_op oneselect",
 /*  87 */ "multiselect_op ::= UNION",
 /*  88 */ "multiselect_op ::= UNION ALL",
 /*  89 */ "multiselect_op ::= EXCEPT|INTERSECT",
 /*  90 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt",
 /*  91 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt",
 /*  92 */ "values ::= VALUES LP nexprlist RP",
 /*  93 */ "values ::= values COMMA LP nexprlist RP",
 /*  94 */ "distinct ::= DISTINCT",
 /*  95 */ "distinct ::= ALL",
 /*  96 */ "distinct ::=",
 /*  97 */ "sclp ::=",
 /*  98 */ "selcollist ::= sclp scanpt expr scanpt as",
 /*  99 */ "selcollist ::= sclp scanpt STAR",
 /* 100 */ "selcollist ::= sclp scanpt nm DOT STAR",
 /* 101 */ "as ::= AS nm",
 /* 102 */ "as ::=",
 /* 103 */ "from ::=",
 /* 104 */ "from ::= FROM seltablist",
 /* 105 */ "stl_prefix ::= seltablist joinop",
 /* 106 */ "stl_prefix ::=",
 /* 107 */ "seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt",
 /* 108 */ "seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt",
 /* 109 */ "seltablist ::= stl_prefix LP select RP as on_opt using_opt",
 /* 110 */ "seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt",
 /* 111 */ "dbnm ::=",
 /* 112 */ "dbnm ::= DOT nm",
 /* 113 */ "fullname ::= nm",
 /* 114 */ "fullname ::= nm DOT nm",
 /* 115 */ "xfullname ::= nm",
 /* 116 */ "xfullname ::= nm DOT nm",
 /* 117 */ "xfullname ::= nm DOT nm AS nm",
 /* 118 */ "xfullname ::= nm AS nm",
 /* 119 */ "joinop ::= COMMA|JOIN",
 /* 120 */ "joinop ::= JOIN_KW JOIN",
 /* 121 */ "joinop ::= JOIN_KW nm JOIN",
 /* 122 */ "joinop ::= JOIN_KW nm nm JOIN",
 /* 123 */ "on_opt ::= ON expr",
 /* 124 */ "on_opt ::=",
 /* 125 */ "indexed_opt ::=",
 /* 126 */ "indexed_opt ::= INDEXED BY nm",
 /* 127 */ "indexed_opt ::= NOT INDEXED",
 /* 128 */ "using_opt ::= USING LP idlist RP",
 /* 129 */ "using_opt ::=",
 /* 130 */ "orderby_opt ::=",
 /* 131 */ "orderby_opt ::= ORDER BY sortlist",
 /* 132 */ "sortlist ::= sortlist COMMA expr sortorder nulls",
 /* 133 */ "sortlist ::= expr sortorder nulls",
 /* 134 */ "sortorder ::= ASC",
 /* 135 */ "sortorder ::= DESC",
 /* 136 */ "sortorder ::=",
 /* 137 */ "nulls ::= NULLS FIRST",
 /* 138 */ "nulls ::= NULLS LAST",
 /* 139 */ "nulls ::=",


 /* 140 */ "groupby_opt ::=",
 /* 141 */ "groupby_opt ::= GROUP BY nexprlist",
 /* 142 */ "having_opt ::=",
 /* 143 */ "having_opt ::= HAVING expr",
 /* 144 */ "limit_opt ::=",
 /* 145 */ "limit_opt ::= LIMIT expr",
 /* 146 */ "limit_opt ::= LIMIT expr OFFSET expr",
 /* 147 */ "limit_opt ::= LIMIT expr COMMA expr",
 /* 148 */ "cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret",
 /* 149 */ "where_opt ::=",
 /* 150 */ "where_opt ::= WHERE expr",
 /* 151 */ "where_opt_ret ::=",
 /* 152 */ "where_opt_ret ::= WHERE expr",
 /* 153 */ "where_opt_ret ::= RETURNING selcollist",
 /* 154 */ "where_opt_ret ::= WHERE expr RETURNING selcollist",
 /* 155 */ "cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret",
 /* 156 */ "setlist ::= setlist COMMA nm EQ expr",
 /* 157 */ "setlist ::= setlist COMMA LP idlist RP EQ expr",
 /* 158 */ "setlist ::= nm EQ expr",
 /* 159 */ "setlist ::= LP idlist RP EQ expr",
 /* 160 */ "cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert",
 /* 161 */ "cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning",
 /* 162 */ "upsert ::=",
 /* 163 */ "upsert ::= RETURNING selcollist",
 /* 164 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert",
 /* 165 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert",
 /* 166 */ "upsert ::= ON CONFLICT DO NOTHING returning",
 /* 167 */ "upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning",
 /* 168 */ "returning ::= RETURNING selcollist",
 /* 169 */ "insert_cmd ::= INSERT orconf",
 /* 170 */ "insert_cmd ::= REPLACE",
 /* 171 */ "idlist_opt ::=",
 /* 172 */ "idlist_opt ::= LP idlist RP",
 /* 173 */ "idlist ::= idlist COMMA nm",
 /* 174 */ "idlist ::= nm",
 /* 175 */ "expr ::= LP expr RP",
 /* 176 */ "expr ::= ID|INDEXED",
 /* 177 */ "expr ::= JOIN_KW",
 /* 178 */ "expr ::= nm DOT nm",
 /* 179 */ "expr ::= nm DOT nm DOT nm",
 /* 180 */ "term ::= NULL|FLOAT|BLOB",
 /* 181 */ "term ::= STRING",
 /* 182 */ "term ::= INTEGER",
 /* 183 */ "expr ::= VARIABLE",
 /* 184 */ "expr ::= expr COLLATE ID|STRING",
 /* 185 */ "expr ::= CAST LP expr AS typetoken RP",
 /* 186 */ "expr ::= ID|INDEXED LP distinct exprlist RP",
 /* 187 */ "expr ::= ID|INDEXED LP STAR RP",
 /* 188 */ "expr ::= ID|INDEXED LP distinct exprlist RP filter_over",
 /* 189 */ "expr ::= ID|INDEXED LP STAR RP filter_over",
 /* 190 */ "term ::= CTIME_KW",
 /* 191 */ "expr ::= LP nexprlist COMMA expr RP",
 /* 192 */ "expr ::= expr AND expr",
 /* 193 */ "expr ::= expr OR expr",
 /* 194 */ "expr ::= expr LT|GT|GE|LE expr",
 /* 195 */ "expr ::= expr EQ|NE expr",
 /* 196 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr",
 /* 197 */ "expr ::= expr PLUS|MINUS expr",
 /* 198 */ "expr ::= expr STAR|SLASH|REM expr",
 /* 199 */ "expr ::= expr CONCAT expr",
 /* 200 */ "likeop ::= NOT LIKE_KW|MATCH",
 /* 201 */ "expr ::= expr likeop expr",
 /* 202 */ "expr ::= expr likeop expr ESCAPE expr",
 /* 203 */ "expr ::= expr ISNULL|NOTNULL",
 /* 204 */ "expr ::= expr NOT NULL",
 /* 205 */ "expr ::= expr IS expr",
 /* 206 */ "expr ::= expr IS NOT expr",
 /* 207 */ "expr ::= NOT expr",
 /* 208 */ "expr ::= BITNOT expr",
 /* 209 */ "expr ::= PLUS|MINUS expr",
 /* 210 */ "between_op ::= BETWEEN",
 /* 211 */ "between_op ::= NOT BETWEEN",
 /* 212 */ "expr ::= expr between_op expr AND expr",
 /* 213 */ "in_op ::= IN",
 /* 214 */ "in_op ::= NOT IN",
 /* 215 */ "expr ::= expr in_op LP exprlist RP",
 /* 216 */ "expr ::= LP select RP",
 /* 217 */ "expr ::= expr in_op LP select RP",
 /* 218 */ "expr ::= expr in_op nm dbnm paren_exprlist",
 /* 219 */ "expr ::= EXISTS LP select RP",
 /* 220 */ "expr ::= CASE case_operand case_exprlist case_else END",
 /* 221 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr",
 /* 222 */ "case_exprlist ::= WHEN expr THEN expr",
 /* 223 */ "case_else ::= ELSE expr",
 /* 224 */ "case_else ::=",
 /* 225 */ "case_operand ::= expr",
 /* 226 */ "case_operand ::=",
 /* 227 */ "exprlist ::=",
 /* 228 */ "nexprlist ::= nexprlist COMMA expr",
 /* 229 */ "nexprlist ::= expr",
 /* 230 */ "paren_exprlist ::=",
 /* 231 */ "paren_exprlist ::= LP exprlist RP",
 /* 232 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt",
 /* 233 */ "uniqueflag ::= UNIQUE",
 /* 234 */ "uniqueflag ::=",
 /* 235 */ "eidlist_opt ::=",
 /* 236 */ "eidlist_opt ::= LP eidlist RP",
 /* 237 */ "eidlist ::= eidlist COMMA nm collate sortorder",
 /* 238 */ "eidlist ::= nm collate sortorder",
 /* 239 */ "collate ::=",
 /* 240 */ "collate ::= COLLATE ID|STRING",
 /* 241 */ "cmd ::= DROP INDEX ifexists fullname",
 /* 242 */ "cmd ::= VACUUM vinto",
 /* 243 */ "cmd ::= VACUUM nm vinto",
 /* 244 */ "vinto ::= INTO expr",
 /* 245 */ "vinto ::=",
 /* 246 */ "cmd ::= PRAGMA nm dbnm",
 /* 247 */ "cmd ::= PRAGMA nm dbnm EQ nmnum",
 /* 248 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP",
 /* 249 */ "cmd ::= PRAGMA nm dbnm EQ minus_num",
 /* 250 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP",
 /* 251 */ "plus_num ::= PLUS INTEGER|FLOAT",
 /* 252 */ "minus_num ::= MINUS INTEGER|FLOAT",
 /* 253 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END",
 /* 254 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause",
 /* 255 */ "trigger_time ::= BEFORE|AFTER",
 /* 256 */ "trigger_time ::= INSTEAD OF",
 /* 257 */ "trigger_time ::=",
 /* 258 */ "trigger_event ::= DELETE|INSERT",
 /* 259 */ "trigger_event ::= UPDATE",
 /* 260 */ "trigger_event ::= UPDATE OF idlist",
 /* 261 */ "when_clause ::=",
 /* 262 */ "when_clause ::= WHEN expr",
 /* 263 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI",
 /* 264 */ "trigger_cmd_list ::= trigger_cmd SEMI",
 /* 265 */ "trnm ::= nm DOT nm",
 /* 266 */ "tridxby ::= INDEXED BY nm",
 /* 267 */ "tridxby ::= NOT INDEXED",
 /* 268 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt",
 /* 269 */ "trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt",
 /* 270 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt",
 /* 271 */ "trigger_cmd ::= scanpt select scanpt",
 /* 272 */ "expr ::= RAISE LP IGNORE RP",
 /* 273 */ "expr ::= RAISE LP raisetype COMMA nm RP",
 /* 274 */ "raisetype ::= ROLLBACK",
 /* 275 */ "raisetype ::= ABORT",
 /* 276 */ "raisetype ::= FAIL",
 /* 277 */ "cmd ::= DROP TRIGGER ifexists fullname",
 /* 278 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt",
 /* 279 */ "cmd ::= DETACH database_kw_opt expr",
 /* 280 */ "key_opt ::=",
 /* 281 */ "key_opt ::= KEY expr",
 /* 282 */ "cmd ::= REINDEX",
 /* 283 */ "cmd ::= REINDEX nm dbnm",
 /* 284 */ "cmd ::= ANALYZE",
 /* 285 */ "cmd ::= ANALYZE nm dbnm",
 /* 286 */ "cmd ::= ALTER TABLE fullname RENAME TO nm",
 /* 287 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist",
 /* 288 */ "cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm",
 /* 289 */ "add_column_fullname ::= fullname",
 /* 290 */ "cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm",
 /* 291 */ "cmd ::= create_vtab",
 /* 292 */ "cmd ::= create_vtab LP vtabarglist RP",
 /* 293 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm",
 /* 294 */ "vtabarg ::=",
 /* 295 */ "vtabargtoken ::= ANY",
 /* 296 */ "vtabargtoken ::= lp anylist RP",
 /* 297 */ "lp ::= LP",
 /* 298 */ "with ::= WITH wqlist",
 /* 299 */ "with ::= WITH RECURSIVE wqlist",
 /* 300 */ "wqas ::= AS",
 /* 301 */ "wqas ::= AS MATERIALIZED",
 /* 302 */ "wqas ::= AS NOT MATERIALIZED",
 /* 303 */ "wqitem ::= nm eidlist_opt wqas LP select RP",
 /* 304 */ "wqlist ::= wqitem",
 /* 305 */ "wqlist ::= wqlist COMMA wqitem",
 /* 306 */ "windowdefn_list ::= windowdefn",
 /* 307 */ "windowdefn_list ::= windowdefn_list COMMA windowdefn",
 /* 308 */ "windowdefn ::= nm AS LP window RP",
 /* 309 */ "window ::= PARTITION BY nexprlist orderby_opt frame_opt",
 /* 310 */ "window ::= nm PARTITION BY nexprlist orderby_opt frame_opt",
 /* 311 */ "window ::= ORDER BY sortlist frame_opt",
 /* 312 */ "window ::= nm ORDER BY sortlist frame_opt",
 /* 313 */ "window ::= frame_opt",
 /* 314 */ "window ::= nm frame_opt",
 /* 315 */ "frame_opt ::=",
 /* 316 */ "frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt",
 /* 317 */ "frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt",
 /* 318 */ "range_or_rows ::= RANGE|ROWS|GROUPS",
 /* 319 */ "frame_bound_s ::= frame_bound",
 /* 320 */ "frame_bound_s ::= UNBOUNDED PRECEDING",
 /* 321 */ "frame_bound_e ::= frame_bound",
 /* 322 */ "frame_bound_e ::= UNBOUNDED FOLLOWING",
 /* 323 */ "frame_bound ::= expr PRECEDING|FOLLOWING",
 /* 324 */ "frame_bound ::= CURRENT ROW",
 /* 325 */ "frame_exclude_opt ::=",
 /* 326 */ "frame_exclude_opt ::= EXCLUDE frame_exclude",
 /* 327 */ "frame_exclude ::= NO OTHERS",
 /* 328 */ "frame_exclude ::= CURRENT ROW",
 /* 329 */ "frame_exclude ::= GROUP|TIES",


 /* 330 */ "window_clause ::= WINDOW windowdefn_list",
 /* 331 */ "filter_over ::= filter_clause over_clause",
 /* 332 */ "filter_over ::= over_clause",
 /* 333 */ "filter_over ::= filter_clause",
 /* 334 */ "over_clause ::= OVER LP window RP",
 /* 335 */ "over_clause ::= OVER nm",
 /* 336 */ "filter_clause ::= FILTER LP WHERE expr RP",
 /* 337 */ "input ::= cmdlist",
 /* 338 */ "cmdlist ::= cmdlist ecmd",
 /* 339 */ "cmdlist ::= ecmd",
 /* 340 */ "ecmd ::= SEMI",
 /* 341 */ "ecmd ::= cmdx SEMI",
 /* 342 */ "ecmd ::= explain cmdx SEMI",
 /* 343 */ "trans_opt ::=",
 /* 344 */ "trans_opt ::= TRANSACTION",
 /* 345 */ "trans_opt ::= TRANSACTION nm",
 /* 346 */ "savepoint_opt ::= SAVEPOINT",
 /* 347 */ "savepoint_opt ::=",
 /* 348 */ "cmd ::= create_table create_table_args",

 /* 349 */ "columnlist ::= columnlist COMMA columnname carglist",
 /* 350 */ "columnlist ::= columnname carglist",
 /* 351 */ "nm ::= ID|INDEXED",
 /* 352 */ "nm ::= STRING",
 /* 353 */ "nm ::= JOIN_KW",
 /* 354 */ "typetoken ::= typename",
 /* 355 */ "typename ::= ID|STRING",
 /* 356 */ "signed ::= plus_num",
 /* 357 */ "signed ::= minus_num",
 /* 358 */ "carglist ::= carglist ccons",
 /* 359 */ "carglist ::=",
 /* 360 */ "ccons ::= NULL onconf",
 /* 361 */ "ccons ::= GENERATED ALWAYS AS generated",
 /* 362 */ "ccons ::= AS generated",
 /* 363 */ "conslist_opt ::= COMMA conslist",
 /* 364 */ "conslist ::= conslist tconscomma tcons",
 /* 365 */ "conslist ::= tcons",
 /* 366 */ "tconscomma ::=",
 /* 367 */ "defer_subclause_opt ::= defer_subclause",
 /* 368 */ "resolvetype ::= raisetype",
 /* 369 */ "selectnowith ::= oneselect",
 /* 370 */ "oneselect ::= values",
 /* 371 */ "sclp ::= selcollist COMMA",
 /* 372 */ "as ::= ID|STRING",
 /* 373 */ "returning ::=",
 /* 374 */ "expr ::= term",
 /* 375 */ "likeop ::= LIKE_KW|MATCH",
 /* 376 */ "exprlist ::= nexprlist",
 /* 377 */ "nmnum ::= plus_num",
 /* 378 */ "nmnum ::= nm",
 /* 379 */ "nmnum ::= ON",
 /* 380 */ "nmnum ::= DELETE",
 /* 381 */ "nmnum ::= DEFAULT",
 /* 382 */ "plus_num ::= INTEGER|FLOAT",
 /* 383 */ "foreach_clause ::=",
 /* 384 */ "foreach_clause ::= FOR EACH ROW",
 /* 385 */ "trnm ::= nm",
 /* 386 */ "tridxby ::=",
 /* 387 */ "database_kw_opt ::= DATABASE",
 /* 388 */ "database_kw_opt ::=",
 /* 389 */ "kwcolumn_opt ::=",
 /* 390 */ "kwcolumn_opt ::= COLUMNKW",
 /* 391 */ "vtabarglist ::= vtabarg",
 /* 392 */ "vtabarglist ::= vtabarglist COMMA vtabarg",
 /* 393 */ "vtabarg ::= vtabarg vtabargtoken",
 /* 394 */ "anylist ::=",
 /* 395 */ "anylist ::= anylist LP anylist RP",
 /* 396 */ "anylist ::= anylist ANY",
 /* 397 */ "with ::=",
};
#endif /* NDEBUG */


#if YYSTACKDEPTH<=0
/*
** Try to increase the size of the parser stack.  Return the number







|

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







160526
160527
160528
160529
160530
160531
160532
160533
160534
160535
160536
160537
160538
160539
160540
160541
160542
160543
160544
160545
160546
160547
160548
160549
160550
160551
160552
160553
160554
160555
160556
160557
160558
160559
160560
160561
160562
160563
160564
160565
160566
160567
160568
160569
160570
160571
160572
160573
160574
160575
160576
160577
160578
160579
160580
160581
160582
160583
160584
160585
160586
160587
160588
160589
160590
160591
160592
160593
160594
160595
160596
160597
160598
160599
160600
160601
160602
160603
160604
160605
160606
160607
160608
160609
160610
160611
160612
160613
160614
160615
160616
160617
160618
160619
160620
160621
160622
160623
160624
160625
160626
160627
160628
160629
160630
160631
160632
160633
160634
160635
160636
160637
160638
160639
160640
160641
160642
160643
160644
160645
160646
160647
160648
160649
160650
160651
160652


160653
160654
160655
160656
160657
160658
160659
160660
160661
160662
160663
160664
160665
160666
160667
160668
160669
160670
160671
160672
160673
160674
160675
160676
160677
160678
160679
160680
160681
160682
160683
160684
160685
160686
160687
160688
160689
160690
160691
160692
160693
160694
160695
160696
160697
160698
160699
160700
160701
160702
160703
160704
160705
160706
160707
160708
160709
160710
160711
160712
160713
160714
160715
160716
160717
160718
160719
160720
160721
160722
160723
160724
160725
160726
160727
160728
160729
160730
160731
160732
160733
160734
160735
160736
160737
160738
160739
160740
160741
160742
160743
160744
160745
160746
160747
160748
160749
160750
160751
160752
160753
160754
160755
160756
160757
160758
160759
160760
160761
160762
160763
160764
160765
160766
160767
160768
160769
160770
160771
160772
160773
160774
160775
160776
160777
160778
160779
160780
160781
160782
160783
160784
160785
160786
160787
160788
160789
160790
160791
160792
160793
160794
160795
160796
160797
160798
160799
160800
160801
160802
160803
160804
160805
160806
160807
160808
160809
160810
160811
160812
160813
160814
160815
160816
160817
160818
160819
160820
160821
160822
160823
160824
160825
160826
160827
160828
160829
160830
160831
160832
160833
160834
160835
160836
160837
160838
160839
160840


160841
160842
160843
160844
160845
160846
160847
160848
160849
160850
160851
160852
160853
160854
160855
160856
160857
160858
160859
160860
160861
160862
160863
160864
160865
160866
160867
160868
160869
160870
160871
160872
160873
160874
160875
160876
160877
160878
160879
160880
160881
160882
160883
160884
160885
160886
160887
160888
160889
160890
160891
160892
160893
160894
160895
160896
160897
160898
160899
160900
160901
160902
160903
160904
160905
160906
160907
160908
160909
160910
160911
160912
160913
160914
160915
160916
160917
160918
160919
160920
160921
 /*  12 */ "cmd ::= ROLLBACK trans_opt TO savepoint_opt nm",
 /*  13 */ "create_table ::= createkw temp TABLE ifnotexists nm dbnm",
 /*  14 */ "createkw ::= CREATE",
 /*  15 */ "ifnotexists ::=",
 /*  16 */ "ifnotexists ::= IF NOT EXISTS",
 /*  17 */ "temp ::= TEMP",
 /*  18 */ "temp ::=",
 /*  19 */ "create_table_args ::= LP columnlist conslist_opt RP table_option_set",
 /*  20 */ "create_table_args ::= AS select",
 /*  21 */ "table_option_set ::=",
 /*  22 */ "table_option_set ::= table_option_set COMMA table_option",
 /*  23 */ "table_option ::= WITHOUT nm",
 /*  24 */ "table_option ::= nm",
 /*  25 */ "columnname ::= nm typetoken",
 /*  26 */ "typetoken ::=",
 /*  27 */ "typetoken ::= typename LP signed RP",
 /*  28 */ "typetoken ::= typename LP signed COMMA signed RP",
 /*  29 */ "typename ::= typename ID|STRING",
 /*  30 */ "scanpt ::=",
 /*  31 */ "scantok ::=",
 /*  32 */ "ccons ::= CONSTRAINT nm",
 /*  33 */ "ccons ::= DEFAULT scantok term",
 /*  34 */ "ccons ::= DEFAULT LP expr RP",
 /*  35 */ "ccons ::= DEFAULT PLUS scantok term",
 /*  36 */ "ccons ::= DEFAULT MINUS scantok term",
 /*  37 */ "ccons ::= DEFAULT scantok ID|INDEXED",
 /*  38 */ "ccons ::= NOT NULL onconf",
 /*  39 */ "ccons ::= PRIMARY KEY sortorder onconf autoinc",
 /*  40 */ "ccons ::= UNIQUE onconf",
 /*  41 */ "ccons ::= CHECK LP expr RP",
 /*  42 */ "ccons ::= REFERENCES nm eidlist_opt refargs",
 /*  43 */ "ccons ::= defer_subclause",
 /*  44 */ "ccons ::= COLLATE ID|STRING",
 /*  45 */ "generated ::= LP expr RP",
 /*  46 */ "generated ::= LP expr RP ID",
 /*  47 */ "autoinc ::=",
 /*  48 */ "autoinc ::= AUTOINCR",
 /*  49 */ "refargs ::=",
 /*  50 */ "refargs ::= refargs refarg",
 /*  51 */ "refarg ::= MATCH nm",
 /*  52 */ "refarg ::= ON INSERT refact",
 /*  53 */ "refarg ::= ON DELETE refact",
 /*  54 */ "refarg ::= ON UPDATE refact",
 /*  55 */ "refact ::= SET NULL",
 /*  56 */ "refact ::= SET DEFAULT",
 /*  57 */ "refact ::= CASCADE",
 /*  58 */ "refact ::= RESTRICT",
 /*  59 */ "refact ::= NO ACTION",
 /*  60 */ "defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt",
 /*  61 */ "defer_subclause ::= DEFERRABLE init_deferred_pred_opt",
 /*  62 */ "init_deferred_pred_opt ::=",
 /*  63 */ "init_deferred_pred_opt ::= INITIALLY DEFERRED",
 /*  64 */ "init_deferred_pred_opt ::= INITIALLY IMMEDIATE",
 /*  65 */ "conslist_opt ::=",
 /*  66 */ "tconscomma ::= COMMA",
 /*  67 */ "tcons ::= CONSTRAINT nm",
 /*  68 */ "tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf",
 /*  69 */ "tcons ::= UNIQUE LP sortlist RP onconf",
 /*  70 */ "tcons ::= CHECK LP expr RP onconf",
 /*  71 */ "tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt",
 /*  72 */ "defer_subclause_opt ::=",
 /*  73 */ "onconf ::=",
 /*  74 */ "onconf ::= ON CONFLICT resolvetype",
 /*  75 */ "orconf ::=",
 /*  76 */ "orconf ::= OR resolvetype",
 /*  77 */ "resolvetype ::= IGNORE",
 /*  78 */ "resolvetype ::= REPLACE",
 /*  79 */ "cmd ::= DROP TABLE ifexists fullname",
 /*  80 */ "ifexists ::= IF EXISTS",
 /*  81 */ "ifexists ::=",
 /*  82 */ "cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select",
 /*  83 */ "cmd ::= DROP VIEW ifexists fullname",
 /*  84 */ "cmd ::= select",
 /*  85 */ "select ::= WITH wqlist selectnowith",
 /*  86 */ "select ::= WITH RECURSIVE wqlist selectnowith",
 /*  87 */ "select ::= selectnowith",
 /*  88 */ "selectnowith ::= selectnowith multiselect_op oneselect",
 /*  89 */ "multiselect_op ::= UNION",
 /*  90 */ "multiselect_op ::= UNION ALL",
 /*  91 */ "multiselect_op ::= EXCEPT|INTERSECT",
 /*  92 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt",
 /*  93 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt",
 /*  94 */ "values ::= VALUES LP nexprlist RP",
 /*  95 */ "values ::= values COMMA LP nexprlist RP",
 /*  96 */ "distinct ::= DISTINCT",
 /*  97 */ "distinct ::= ALL",
 /*  98 */ "distinct ::=",
 /*  99 */ "sclp ::=",
 /* 100 */ "selcollist ::= sclp scanpt expr scanpt as",
 /* 101 */ "selcollist ::= sclp scanpt STAR",
 /* 102 */ "selcollist ::= sclp scanpt nm DOT STAR",
 /* 103 */ "as ::= AS nm",
 /* 104 */ "as ::=",
 /* 105 */ "from ::=",
 /* 106 */ "from ::= FROM seltablist",
 /* 107 */ "stl_prefix ::= seltablist joinop",
 /* 108 */ "stl_prefix ::=",
 /* 109 */ "seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt",
 /* 110 */ "seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt",
 /* 111 */ "seltablist ::= stl_prefix LP select RP as on_opt using_opt",
 /* 112 */ "seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt",
 /* 113 */ "dbnm ::=",
 /* 114 */ "dbnm ::= DOT nm",
 /* 115 */ "fullname ::= nm",
 /* 116 */ "fullname ::= nm DOT nm",
 /* 117 */ "xfullname ::= nm",
 /* 118 */ "xfullname ::= nm DOT nm",
 /* 119 */ "xfullname ::= nm DOT nm AS nm",
 /* 120 */ "xfullname ::= nm AS nm",
 /* 121 */ "joinop ::= COMMA|JOIN",
 /* 122 */ "joinop ::= JOIN_KW JOIN",
 /* 123 */ "joinop ::= JOIN_KW nm JOIN",
 /* 124 */ "joinop ::= JOIN_KW nm nm JOIN",
 /* 125 */ "on_opt ::= ON expr",
 /* 126 */ "on_opt ::=",
 /* 127 */ "indexed_opt ::=",
 /* 128 */ "indexed_opt ::= INDEXED BY nm",
 /* 129 */ "indexed_opt ::= NOT INDEXED",
 /* 130 */ "using_opt ::= USING LP idlist RP",
 /* 131 */ "using_opt ::=",
 /* 132 */ "orderby_opt ::=",
 /* 133 */ "orderby_opt ::= ORDER BY sortlist",
 /* 134 */ "sortlist ::= sortlist COMMA expr sortorder nulls",
 /* 135 */ "sortlist ::= expr sortorder nulls",
 /* 136 */ "sortorder ::= ASC",
 /* 137 */ "sortorder ::= DESC",
 /* 138 */ "sortorder ::=",


 /* 139 */ "nulls ::= NULLS FIRST",
 /* 140 */ "nulls ::= NULLS LAST",
 /* 141 */ "nulls ::=",
 /* 142 */ "groupby_opt ::=",
 /* 143 */ "groupby_opt ::= GROUP BY nexprlist",
 /* 144 */ "having_opt ::=",
 /* 145 */ "having_opt ::= HAVING expr",
 /* 146 */ "limit_opt ::=",
 /* 147 */ "limit_opt ::= LIMIT expr",
 /* 148 */ "limit_opt ::= LIMIT expr OFFSET expr",
 /* 149 */ "limit_opt ::= LIMIT expr COMMA expr",
 /* 150 */ "cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret",
 /* 151 */ "where_opt ::=",
 /* 152 */ "where_opt ::= WHERE expr",
 /* 153 */ "where_opt_ret ::=",
 /* 154 */ "where_opt_ret ::= WHERE expr",
 /* 155 */ "where_opt_ret ::= RETURNING selcollist",
 /* 156 */ "where_opt_ret ::= WHERE expr RETURNING selcollist",
 /* 157 */ "cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret",
 /* 158 */ "setlist ::= setlist COMMA nm EQ expr",
 /* 159 */ "setlist ::= setlist COMMA LP idlist RP EQ expr",
 /* 160 */ "setlist ::= nm EQ expr",
 /* 161 */ "setlist ::= LP idlist RP EQ expr",
 /* 162 */ "cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert",
 /* 163 */ "cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning",
 /* 164 */ "upsert ::=",
 /* 165 */ "upsert ::= RETURNING selcollist",
 /* 166 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert",
 /* 167 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert",
 /* 168 */ "upsert ::= ON CONFLICT DO NOTHING returning",
 /* 169 */ "upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning",
 /* 170 */ "returning ::= RETURNING selcollist",
 /* 171 */ "insert_cmd ::= INSERT orconf",
 /* 172 */ "insert_cmd ::= REPLACE",
 /* 173 */ "idlist_opt ::=",
 /* 174 */ "idlist_opt ::= LP idlist RP",
 /* 175 */ "idlist ::= idlist COMMA nm",
 /* 176 */ "idlist ::= nm",
 /* 177 */ "expr ::= LP expr RP",
 /* 178 */ "expr ::= ID|INDEXED",
 /* 179 */ "expr ::= JOIN_KW",
 /* 180 */ "expr ::= nm DOT nm",
 /* 181 */ "expr ::= nm DOT nm DOT nm",
 /* 182 */ "term ::= NULL|FLOAT|BLOB",
 /* 183 */ "term ::= STRING",
 /* 184 */ "term ::= INTEGER",
 /* 185 */ "expr ::= VARIABLE",
 /* 186 */ "expr ::= expr COLLATE ID|STRING",
 /* 187 */ "expr ::= CAST LP expr AS typetoken RP",
 /* 188 */ "expr ::= ID|INDEXED LP distinct exprlist RP",
 /* 189 */ "expr ::= ID|INDEXED LP STAR RP",
 /* 190 */ "expr ::= ID|INDEXED LP distinct exprlist RP filter_over",
 /* 191 */ "expr ::= ID|INDEXED LP STAR RP filter_over",
 /* 192 */ "term ::= CTIME_KW",
 /* 193 */ "expr ::= LP nexprlist COMMA expr RP",
 /* 194 */ "expr ::= expr AND expr",
 /* 195 */ "expr ::= expr OR expr",
 /* 196 */ "expr ::= expr LT|GT|GE|LE expr",
 /* 197 */ "expr ::= expr EQ|NE expr",
 /* 198 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr",
 /* 199 */ "expr ::= expr PLUS|MINUS expr",
 /* 200 */ "expr ::= expr STAR|SLASH|REM expr",
 /* 201 */ "expr ::= expr CONCAT expr",
 /* 202 */ "likeop ::= NOT LIKE_KW|MATCH",
 /* 203 */ "expr ::= expr likeop expr",
 /* 204 */ "expr ::= expr likeop expr ESCAPE expr",
 /* 205 */ "expr ::= expr ISNULL|NOTNULL",
 /* 206 */ "expr ::= expr NOT NULL",
 /* 207 */ "expr ::= expr IS expr",
 /* 208 */ "expr ::= expr IS NOT expr",
 /* 209 */ "expr ::= NOT expr",
 /* 210 */ "expr ::= BITNOT expr",
 /* 211 */ "expr ::= PLUS|MINUS expr",
 /* 212 */ "between_op ::= BETWEEN",
 /* 213 */ "between_op ::= NOT BETWEEN",
 /* 214 */ "expr ::= expr between_op expr AND expr",
 /* 215 */ "in_op ::= IN",
 /* 216 */ "in_op ::= NOT IN",
 /* 217 */ "expr ::= expr in_op LP exprlist RP",
 /* 218 */ "expr ::= LP select RP",
 /* 219 */ "expr ::= expr in_op LP select RP",
 /* 220 */ "expr ::= expr in_op nm dbnm paren_exprlist",
 /* 221 */ "expr ::= EXISTS LP select RP",
 /* 222 */ "expr ::= CASE case_operand case_exprlist case_else END",
 /* 223 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr",
 /* 224 */ "case_exprlist ::= WHEN expr THEN expr",
 /* 225 */ "case_else ::= ELSE expr",
 /* 226 */ "case_else ::=",
 /* 227 */ "case_operand ::= expr",
 /* 228 */ "case_operand ::=",
 /* 229 */ "exprlist ::=",
 /* 230 */ "nexprlist ::= nexprlist COMMA expr",
 /* 231 */ "nexprlist ::= expr",
 /* 232 */ "paren_exprlist ::=",
 /* 233 */ "paren_exprlist ::= LP exprlist RP",
 /* 234 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt",
 /* 235 */ "uniqueflag ::= UNIQUE",
 /* 236 */ "uniqueflag ::=",
 /* 237 */ "eidlist_opt ::=",
 /* 238 */ "eidlist_opt ::= LP eidlist RP",
 /* 239 */ "eidlist ::= eidlist COMMA nm collate sortorder",
 /* 240 */ "eidlist ::= nm collate sortorder",
 /* 241 */ "collate ::=",
 /* 242 */ "collate ::= COLLATE ID|STRING",
 /* 243 */ "cmd ::= DROP INDEX ifexists fullname",
 /* 244 */ "cmd ::= VACUUM vinto",
 /* 245 */ "cmd ::= VACUUM nm vinto",
 /* 246 */ "vinto ::= INTO expr",
 /* 247 */ "vinto ::=",
 /* 248 */ "cmd ::= PRAGMA nm dbnm",
 /* 249 */ "cmd ::= PRAGMA nm dbnm EQ nmnum",
 /* 250 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP",
 /* 251 */ "cmd ::= PRAGMA nm dbnm EQ minus_num",
 /* 252 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP",
 /* 253 */ "plus_num ::= PLUS INTEGER|FLOAT",
 /* 254 */ "minus_num ::= MINUS INTEGER|FLOAT",
 /* 255 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END",
 /* 256 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause",
 /* 257 */ "trigger_time ::= BEFORE|AFTER",
 /* 258 */ "trigger_time ::= INSTEAD OF",
 /* 259 */ "trigger_time ::=",
 /* 260 */ "trigger_event ::= DELETE|INSERT",
 /* 261 */ "trigger_event ::= UPDATE",
 /* 262 */ "trigger_event ::= UPDATE OF idlist",
 /* 263 */ "when_clause ::=",
 /* 264 */ "when_clause ::= WHEN expr",
 /* 265 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI",
 /* 266 */ "trigger_cmd_list ::= trigger_cmd SEMI",
 /* 267 */ "trnm ::= nm DOT nm",
 /* 268 */ "tridxby ::= INDEXED BY nm",
 /* 269 */ "tridxby ::= NOT INDEXED",
 /* 270 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt",
 /* 271 */ "trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt",
 /* 272 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt",
 /* 273 */ "trigger_cmd ::= scanpt select scanpt",
 /* 274 */ "expr ::= RAISE LP IGNORE RP",
 /* 275 */ "expr ::= RAISE LP raisetype COMMA nm RP",
 /* 276 */ "raisetype ::= ROLLBACK",
 /* 277 */ "raisetype ::= ABORT",
 /* 278 */ "raisetype ::= FAIL",
 /* 279 */ "cmd ::= DROP TRIGGER ifexists fullname",
 /* 280 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt",
 /* 281 */ "cmd ::= DETACH database_kw_opt expr",
 /* 282 */ "key_opt ::=",
 /* 283 */ "key_opt ::= KEY expr",
 /* 284 */ "cmd ::= REINDEX",
 /* 285 */ "cmd ::= REINDEX nm dbnm",
 /* 286 */ "cmd ::= ANALYZE",
 /* 287 */ "cmd ::= ANALYZE nm dbnm",
 /* 288 */ "cmd ::= ALTER TABLE fullname RENAME TO nm",
 /* 289 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist",
 /* 290 */ "cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm",
 /* 291 */ "add_column_fullname ::= fullname",
 /* 292 */ "cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm",
 /* 293 */ "cmd ::= create_vtab",
 /* 294 */ "cmd ::= create_vtab LP vtabarglist RP",
 /* 295 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm",
 /* 296 */ "vtabarg ::=",
 /* 297 */ "vtabargtoken ::= ANY",
 /* 298 */ "vtabargtoken ::= lp anylist RP",
 /* 299 */ "lp ::= LP",
 /* 300 */ "with ::= WITH wqlist",
 /* 301 */ "with ::= WITH RECURSIVE wqlist",
 /* 302 */ "wqas ::= AS",
 /* 303 */ "wqas ::= AS MATERIALIZED",
 /* 304 */ "wqas ::= AS NOT MATERIALIZED",
 /* 305 */ "wqitem ::= nm eidlist_opt wqas LP select RP",
 /* 306 */ "wqlist ::= wqitem",
 /* 307 */ "wqlist ::= wqlist COMMA wqitem",
 /* 308 */ "windowdefn_list ::= windowdefn",
 /* 309 */ "windowdefn_list ::= windowdefn_list COMMA windowdefn",
 /* 310 */ "windowdefn ::= nm AS LP window RP",
 /* 311 */ "window ::= PARTITION BY nexprlist orderby_opt frame_opt",
 /* 312 */ "window ::= nm PARTITION BY nexprlist orderby_opt frame_opt",
 /* 313 */ "window ::= ORDER BY sortlist frame_opt",
 /* 314 */ "window ::= nm ORDER BY sortlist frame_opt",
 /* 315 */ "window ::= frame_opt",
 /* 316 */ "window ::= nm frame_opt",
 /* 317 */ "frame_opt ::=",
 /* 318 */ "frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt",
 /* 319 */ "frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt",
 /* 320 */ "range_or_rows ::= RANGE|ROWS|GROUPS",
 /* 321 */ "frame_bound_s ::= frame_bound",
 /* 322 */ "frame_bound_s ::= UNBOUNDED PRECEDING",
 /* 323 */ "frame_bound_e ::= frame_bound",
 /* 324 */ "frame_bound_e ::= UNBOUNDED FOLLOWING",
 /* 325 */ "frame_bound ::= expr PRECEDING|FOLLOWING",
 /* 326 */ "frame_bound ::= CURRENT ROW",


 /* 327 */ "frame_exclude_opt ::=",
 /* 328 */ "frame_exclude_opt ::= EXCLUDE frame_exclude",
 /* 329 */ "frame_exclude ::= NO OTHERS",
 /* 330 */ "frame_exclude ::= CURRENT ROW",
 /* 331 */ "frame_exclude ::= GROUP|TIES",
 /* 332 */ "window_clause ::= WINDOW windowdefn_list",
 /* 333 */ "filter_over ::= filter_clause over_clause",
 /* 334 */ "filter_over ::= over_clause",
 /* 335 */ "filter_over ::= filter_clause",
 /* 336 */ "over_clause ::= OVER LP window RP",
 /* 337 */ "over_clause ::= OVER nm",
 /* 338 */ "filter_clause ::= FILTER LP WHERE expr RP",
 /* 339 */ "input ::= cmdlist",
 /* 340 */ "cmdlist ::= cmdlist ecmd",
 /* 341 */ "cmdlist ::= ecmd",
 /* 342 */ "ecmd ::= SEMI",
 /* 343 */ "ecmd ::= cmdx SEMI",
 /* 344 */ "ecmd ::= explain cmdx SEMI",
 /* 345 */ "trans_opt ::=",
 /* 346 */ "trans_opt ::= TRANSACTION",
 /* 347 */ "trans_opt ::= TRANSACTION nm",
 /* 348 */ "savepoint_opt ::= SAVEPOINT",
 /* 349 */ "savepoint_opt ::=",
 /* 350 */ "cmd ::= create_table create_table_args",
 /* 351 */ "table_option_set ::= table_option",
 /* 352 */ "columnlist ::= columnlist COMMA columnname carglist",
 /* 353 */ "columnlist ::= columnname carglist",
 /* 354 */ "nm ::= ID|INDEXED",
 /* 355 */ "nm ::= STRING",
 /* 356 */ "nm ::= JOIN_KW",
 /* 357 */ "typetoken ::= typename",
 /* 358 */ "typename ::= ID|STRING",
 /* 359 */ "signed ::= plus_num",
 /* 360 */ "signed ::= minus_num",
 /* 361 */ "carglist ::= carglist ccons",
 /* 362 */ "carglist ::=",
 /* 363 */ "ccons ::= NULL onconf",
 /* 364 */ "ccons ::= GENERATED ALWAYS AS generated",
 /* 365 */ "ccons ::= AS generated",
 /* 366 */ "conslist_opt ::= COMMA conslist",
 /* 367 */ "conslist ::= conslist tconscomma tcons",
 /* 368 */ "conslist ::= tcons",
 /* 369 */ "tconscomma ::=",
 /* 370 */ "defer_subclause_opt ::= defer_subclause",
 /* 371 */ "resolvetype ::= raisetype",
 /* 372 */ "selectnowith ::= oneselect",
 /* 373 */ "oneselect ::= values",
 /* 374 */ "sclp ::= selcollist COMMA",
 /* 375 */ "as ::= ID|STRING",
 /* 376 */ "returning ::=",
 /* 377 */ "expr ::= term",
 /* 378 */ "likeop ::= LIKE_KW|MATCH",
 /* 379 */ "exprlist ::= nexprlist",
 /* 380 */ "nmnum ::= plus_num",
 /* 381 */ "nmnum ::= nm",
 /* 382 */ "nmnum ::= ON",
 /* 383 */ "nmnum ::= DELETE",
 /* 384 */ "nmnum ::= DEFAULT",
 /* 385 */ "plus_num ::= INTEGER|FLOAT",
 /* 386 */ "foreach_clause ::=",
 /* 387 */ "foreach_clause ::= FOR EACH ROW",
 /* 388 */ "trnm ::= nm",
 /* 389 */ "tridxby ::=",
 /* 390 */ "database_kw_opt ::= DATABASE",
 /* 391 */ "database_kw_opt ::=",
 /* 392 */ "kwcolumn_opt ::=",
 /* 393 */ "kwcolumn_opt ::= COLUMNKW",
 /* 394 */ "vtabarglist ::= vtabarg",
 /* 395 */ "vtabarglist ::= vtabarglist COMMA vtabarg",
 /* 396 */ "vtabarg ::= vtabarg vtabargtoken",
 /* 397 */ "anylist ::=",
 /* 398 */ "anylist ::= anylist LP anylist RP",
 /* 399 */ "anylist ::= anylist ANY",
 /* 400 */ "with ::=",
};
#endif /* NDEBUG */


#if YYSTACKDEPTH<=0
/*
** Try to increase the size of the parser stack.  Return the number
160540
160541
160542
160543
160544
160545
160546
160547
160548
160549
160550
160551
160552
160553
160554
160555
160556
160557
160558
160559
160560
160561
160562
160563
160564
160565
160566
160567
160568
160569
160570
160571
160572
160573
160574
160575
160576
160577
160578
160579
160580
160581
160582
160583
160584
160585
160586
160587
160588
160589
160590
160591
160592
160593
160594
160595
160596
160597
160598
160599
160600
160601
160602
160603
160604
160605
160606
160607
160608
160609
160610
160611
160612
160613
160614
160615
160616
160617

160618
160619
160620
160621
160622
160623
160624
160625
160626
160627
160628
160629
160630
160631
160632
160633
160634
160635
160636
160637
160638
160639
160640
160641
160642
160643
160644
160645
    **
    ** Note: during a reduce, the only symbols destroyed are those
    ** which appear on the RHS of the rule, but which are *not* used
    ** inside the C code.
    */
/********* Begin destructor definitions ***************************************/
    case 203: /* select */
    case 237: /* selectnowith */
    case 238: /* oneselect */
    case 250: /* values */
{
sqlite3SelectDelete(pParse->db, (yypminor->yy81));
}
      break;
    case 214: /* term */
    case 215: /* expr */
    case 244: /* where_opt */
    case 246: /* having_opt */
    case 258: /* on_opt */
    case 265: /* where_opt_ret */
    case 276: /* case_operand */
    case 278: /* case_else */
    case 281: /* vinto */
    case 288: /* when_clause */
    case 293: /* key_opt */
    case 309: /* filter_clause */
{
sqlite3ExprDelete(pParse->db, (yypminor->yy404));
}
      break;
    case 219: /* eidlist_opt */
    case 229: /* sortlist */
    case 230: /* eidlist */
    case 242: /* selcollist */
    case 245: /* groupby_opt */
    case 247: /* orderby_opt */
    case 251: /* nexprlist */
    case 252: /* sclp */
    case 260: /* exprlist */
    case 266: /* setlist */
    case 275: /* paren_exprlist */
    case 277: /* case_exprlist */
    case 308: /* part_opt */
{
sqlite3ExprListDelete(pParse->db, (yypminor->yy70));
}
      break;
    case 236: /* fullname */
    case 243: /* from */
    case 254: /* seltablist */
    case 255: /* stl_prefix */
    case 261: /* xfullname */
{
sqlite3SrcListDelete(pParse->db, (yypminor->yy153));
}
      break;
    case 239: /* wqlist */
{
sqlite3WithDelete(pParse->db, (yypminor->yy103));
}
      break;
    case 249: /* window_clause */
    case 304: /* windowdefn_list */
{
sqlite3WindowListDelete(pParse->db, (yypminor->yy49));
}
      break;
    case 259: /* using_opt */
    case 262: /* idlist */
    case 268: /* idlist_opt */
{
sqlite3IdListDelete(pParse->db, (yypminor->yy436));
}
      break;
    case 271: /* filter_over */
    case 305: /* windowdefn */
    case 306: /* window */
    case 307: /* frame_opt */

    case 310: /* over_clause */
{
sqlite3WindowDelete(pParse->db, (yypminor->yy49));
}
      break;
    case 284: /* trigger_cmd_list */
    case 289: /* trigger_cmd */
{
sqlite3DeleteTriggerStep(pParse->db, (yypminor->yy157));
}
      break;
    case 286: /* trigger_event */
{
sqlite3IdListDelete(pParse->db, (yypminor->yy262).b);
}
      break;
    case 312: /* frame_bound */
    case 313: /* frame_bound_s */
    case 314: /* frame_bound_e */
{
sqlite3ExprDelete(pParse->db, (yypminor->yy117).pExpr);
}
      break;
/********* End destructor definitions *****************************************/
    default:  break;   /* If no destructor action specified: do nothing */
  }
}








|
|
|

|


|
|
|
|
|
|
|
|
|
|
|
|

|


|
|
|
|
|
|
|
|
|
|
|
|
|

|


|
|
|
|
|

|


|

|


|
|

|


|
|
|

|


|
<
|
|
>
|

|


|
|

|


|

|


|
|
|

|







161034
161035
161036
161037
161038
161039
161040
161041
161042
161043
161044
161045
161046
161047
161048
161049
161050
161051
161052
161053
161054
161055
161056
161057
161058
161059
161060
161061
161062
161063
161064
161065
161066
161067
161068
161069
161070
161071
161072
161073
161074
161075
161076
161077
161078
161079
161080
161081
161082
161083
161084
161085
161086
161087
161088
161089
161090
161091
161092
161093
161094
161095
161096
161097
161098
161099
161100
161101
161102
161103
161104
161105
161106
161107
161108

161109
161110
161111
161112
161113
161114
161115
161116
161117
161118
161119
161120
161121
161122
161123
161124
161125
161126
161127
161128
161129
161130
161131
161132
161133
161134
161135
161136
161137
161138
161139
    **
    ** Note: during a reduce, the only symbols destroyed are those
    ** which appear on the RHS of the rule, but which are *not* used
    ** inside the C code.
    */
/********* Begin destructor definitions ***************************************/
    case 203: /* select */
    case 238: /* selectnowith */
    case 239: /* oneselect */
    case 251: /* values */
{
sqlite3SelectDelete(pParse->db, (yypminor->yy303));
}
      break;
    case 215: /* term */
    case 216: /* expr */
    case 245: /* where_opt */
    case 247: /* having_opt */
    case 259: /* on_opt */
    case 266: /* where_opt_ret */
    case 277: /* case_operand */
    case 279: /* case_else */
    case 282: /* vinto */
    case 289: /* when_clause */
    case 294: /* key_opt */
    case 310: /* filter_clause */
{
sqlite3ExprDelete(pParse->db, (yypminor->yy626));
}
      break;
    case 220: /* eidlist_opt */
    case 230: /* sortlist */
    case 231: /* eidlist */
    case 243: /* selcollist */
    case 246: /* groupby_opt */
    case 248: /* orderby_opt */
    case 252: /* nexprlist */
    case 253: /* sclp */
    case 261: /* exprlist */
    case 267: /* setlist */
    case 276: /* paren_exprlist */
    case 278: /* case_exprlist */
    case 309: /* part_opt */
{
sqlite3ExprListDelete(pParse->db, (yypminor->yy562));
}
      break;
    case 237: /* fullname */
    case 244: /* from */
    case 255: /* seltablist */
    case 256: /* stl_prefix */
    case 262: /* xfullname */
{
sqlite3SrcListDelete(pParse->db, (yypminor->yy607));
}
      break;
    case 240: /* wqlist */
{
sqlite3WithDelete(pParse->db, (yypminor->yy43));
}
      break;
    case 250: /* window_clause */
    case 305: /* windowdefn_list */
{
sqlite3WindowListDelete(pParse->db, (yypminor->yy375));
}
      break;
    case 260: /* using_opt */
    case 263: /* idlist */
    case 269: /* idlist_opt */
{
sqlite3IdListDelete(pParse->db, (yypminor->yy240));
}
      break;
    case 272: /* filter_over */

    case 306: /* windowdefn */
    case 307: /* window */
    case 308: /* frame_opt */
    case 311: /* over_clause */
{
sqlite3WindowDelete(pParse->db, (yypminor->yy375));
}
      break;
    case 285: /* trigger_cmd_list */
    case 290: /* trigger_cmd */
{
sqlite3DeleteTriggerStep(pParse->db, (yypminor->yy95));
}
      break;
    case 287: /* trigger_event */
{
sqlite3IdListDelete(pParse->db, (yypminor->yy570).b);
}
      break;
    case 313: /* frame_bound */
    case 314: /* frame_bound_s */
    case 315: /* frame_bound_e */
{
sqlite3ExprDelete(pParse->db, (yypminor->yy81).pExpr);
}
      break;
/********* End destructor definitions *****************************************/
    default:  break;   /* If no destructor action specified: do nothing */
  }
}

160941
160942
160943
160944
160945
160946
160947
160948
160949
160950
160951


160952
160953
160954
160955
160956
160957
160958
160959
160960
160961
160962
160963
160964
160965
160966
160967
160968
160969
160970
160971
160972
160973
160974
160975
160976
160977
160978
160979
160980
160981
160982
160983
160984
160985
160986
160987
160988
160989
160990
160991
160992
160993
160994
160995
160996
160997
160998
160999
161000
161001
161002
161003
161004
161005
161006
161007
161008
161009
161010
161011
161012
161013
161014
161015
161016
161017
161018
161019
161020
161021
161022
161023
161024
161025
161026
161027
161028
161029
161030
161031
161032
161033
161034
161035
161036
161037
161038
161039
161040
161041
161042
161043
161044
161045
161046
161047
161048
161049
161050
161051
161052
161053
161054
161055
161056
161057
161058
161059
161060
161061
161062
161063
161064
161065
161066
161067
161068
161069
161070
161071
161072
161073
161074
161075
161076
161077
161078
161079
161080
161081
161082
161083
161084
161085
161086
161087
161088
161089
161090
161091
161092
161093
161094
161095
161096
161097
161098
161099
161100
161101
161102
161103
161104
161105
161106
161107
161108
161109
161110
161111
161112
161113
161114
161115
161116
161117
161118
161119
161120
161121
161122
161123
161124
161125
161126
161127
161128
161129
161130
161131
161132
161133
161134
161135
161136
161137
161138
161139
161140
161141
161142
161143
161144
161145
161146
161147
161148
161149
161150
161151
161152
161153
161154
161155
161156
161157
161158
161159
161160
161161
161162
161163
161164
161165
161166
161167
161168
161169
161170
161171
161172
161173
161174
161175
161176
161177
161178
161179
161180
161181
161182
161183
161184
161185
161186
161187
161188
161189
161190
161191
161192
161193
161194
161195
161196
161197
161198
161199
161200
161201
161202
161203
161204
161205
161206
161207
161208
161209
161210
161211
161212
161213
161214
161215
161216
161217
161218
161219
161220
161221
161222
161223
161224
161225
161226
161227
161228
161229
161230
161231
161232
161233
161234
161235
161236
161237
161238
161239
161240
161241
161242
161243
161244
161245
161246
161247
161248
161249
161250
161251
161252
161253
161254
161255
161256
161257
161258
161259
161260
161261
161262
161263
161264
161265
161266
161267
161268
161269
161270
161271
161272
161273
161274
161275
161276
161277

161278
161279
161280
161281
161282
161283
161284
161285
161286
161287
161288
161289
161290
161291
161292
161293
161294
161295
161296
161297
161298
161299
161300
161301
161302
161303
161304
161305
161306
161307
161308
161309
161310
161311
161312
161313
161314
161315
161316
161317
161318
161319
161320
161321
161322
161323
161324
161325
161326
161327
161328
161329
161330
161331
161332
161333
   189,  /* (12) cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */
   194,  /* (13) create_table ::= createkw temp TABLE ifnotexists nm dbnm */
   196,  /* (14) createkw ::= CREATE */
   198,  /* (15) ifnotexists ::= */
   198,  /* (16) ifnotexists ::= IF NOT EXISTS */
   197,  /* (17) temp ::= TEMP */
   197,  /* (18) temp ::= */
   195,  /* (19) create_table_args ::= LP columnlist conslist_opt RP table_options */
   195,  /* (20) create_table_args ::= AS select */
   202,  /* (21) table_options ::= */
   202,  /* (22) table_options ::= WITHOUT nm */


   204,  /* (23) columnname ::= nm typetoken */
   206,  /* (24) typetoken ::= */
   206,  /* (25) typetoken ::= typename LP signed RP */
   206,  /* (26) typetoken ::= typename LP signed COMMA signed RP */
   207,  /* (27) typename ::= typename ID|STRING */
   211,  /* (28) scanpt ::= */
   212,  /* (29) scantok ::= */
   213,  /* (30) ccons ::= CONSTRAINT nm */
   213,  /* (31) ccons ::= DEFAULT scantok term */
   213,  /* (32) ccons ::= DEFAULT LP expr RP */
   213,  /* (33) ccons ::= DEFAULT PLUS scantok term */
   213,  /* (34) ccons ::= DEFAULT MINUS scantok term */
   213,  /* (35) ccons ::= DEFAULT scantok ID|INDEXED */
   213,  /* (36) ccons ::= NOT NULL onconf */
   213,  /* (37) ccons ::= PRIMARY KEY sortorder onconf autoinc */
   213,  /* (38) ccons ::= UNIQUE onconf */
   213,  /* (39) ccons ::= CHECK LP expr RP */
   213,  /* (40) ccons ::= REFERENCES nm eidlist_opt refargs */
   213,  /* (41) ccons ::= defer_subclause */
   213,  /* (42) ccons ::= COLLATE ID|STRING */
   222,  /* (43) generated ::= LP expr RP */
   222,  /* (44) generated ::= LP expr RP ID */
   218,  /* (45) autoinc ::= */
   218,  /* (46) autoinc ::= AUTOINCR */
   220,  /* (47) refargs ::= */
   220,  /* (48) refargs ::= refargs refarg */
   223,  /* (49) refarg ::= MATCH nm */
   223,  /* (50) refarg ::= ON INSERT refact */
   223,  /* (51) refarg ::= ON DELETE refact */
   223,  /* (52) refarg ::= ON UPDATE refact */
   224,  /* (53) refact ::= SET NULL */
   224,  /* (54) refact ::= SET DEFAULT */
   224,  /* (55) refact ::= CASCADE */
   224,  /* (56) refact ::= RESTRICT */
   224,  /* (57) refact ::= NO ACTION */
   221,  /* (58) defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */
   221,  /* (59) defer_subclause ::= DEFERRABLE init_deferred_pred_opt */
   225,  /* (60) init_deferred_pred_opt ::= */
   225,  /* (61) init_deferred_pred_opt ::= INITIALLY DEFERRED */
   225,  /* (62) init_deferred_pred_opt ::= INITIALLY IMMEDIATE */
   201,  /* (63) conslist_opt ::= */
   227,  /* (64) tconscomma ::= COMMA */
   228,  /* (65) tcons ::= CONSTRAINT nm */
   228,  /* (66) tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */
   228,  /* (67) tcons ::= UNIQUE LP sortlist RP onconf */
   228,  /* (68) tcons ::= CHECK LP expr RP onconf */
   228,  /* (69) tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */
   231,  /* (70) defer_subclause_opt ::= */
   216,  /* (71) onconf ::= */
   216,  /* (72) onconf ::= ON CONFLICT resolvetype */
   232,  /* (73) orconf ::= */
   232,  /* (74) orconf ::= OR resolvetype */
   233,  /* (75) resolvetype ::= IGNORE */
   233,  /* (76) resolvetype ::= REPLACE */
   189,  /* (77) cmd ::= DROP TABLE ifexists fullname */
   235,  /* (78) ifexists ::= IF EXISTS */
   235,  /* (79) ifexists ::= */
   189,  /* (80) cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */
   189,  /* (81) cmd ::= DROP VIEW ifexists fullname */
   189,  /* (82) cmd ::= select */
   203,  /* (83) select ::= WITH wqlist selectnowith */
   203,  /* (84) select ::= WITH RECURSIVE wqlist selectnowith */
   203,  /* (85) select ::= selectnowith */
   237,  /* (86) selectnowith ::= selectnowith multiselect_op oneselect */
   240,  /* (87) multiselect_op ::= UNION */
   240,  /* (88) multiselect_op ::= UNION ALL */
   240,  /* (89) multiselect_op ::= EXCEPT|INTERSECT */
   238,  /* (90) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
   238,  /* (91) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */
   250,  /* (92) values ::= VALUES LP nexprlist RP */
   250,  /* (93) values ::= values COMMA LP nexprlist RP */
   241,  /* (94) distinct ::= DISTINCT */
   241,  /* (95) distinct ::= ALL */
   241,  /* (96) distinct ::= */
   252,  /* (97) sclp ::= */
   242,  /* (98) selcollist ::= sclp scanpt expr scanpt as */
   242,  /* (99) selcollist ::= sclp scanpt STAR */
   242,  /* (100) selcollist ::= sclp scanpt nm DOT STAR */
   253,  /* (101) as ::= AS nm */
   253,  /* (102) as ::= */
   243,  /* (103) from ::= */
   243,  /* (104) from ::= FROM seltablist */
   255,  /* (105) stl_prefix ::= seltablist joinop */
   255,  /* (106) stl_prefix ::= */
   254,  /* (107) seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */
   254,  /* (108) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt */
   254,  /* (109) seltablist ::= stl_prefix LP select RP as on_opt using_opt */
   254,  /* (110) seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */
   199,  /* (111) dbnm ::= */
   199,  /* (112) dbnm ::= DOT nm */
   236,  /* (113) fullname ::= nm */
   236,  /* (114) fullname ::= nm DOT nm */
   261,  /* (115) xfullname ::= nm */
   261,  /* (116) xfullname ::= nm DOT nm */
   261,  /* (117) xfullname ::= nm DOT nm AS nm */
   261,  /* (118) xfullname ::= nm AS nm */
   256,  /* (119) joinop ::= COMMA|JOIN */
   256,  /* (120) joinop ::= JOIN_KW JOIN */
   256,  /* (121) joinop ::= JOIN_KW nm JOIN */
   256,  /* (122) joinop ::= JOIN_KW nm nm JOIN */
   258,  /* (123) on_opt ::= ON expr */
   258,  /* (124) on_opt ::= */
   257,  /* (125) indexed_opt ::= */
   257,  /* (126) indexed_opt ::= INDEXED BY nm */
   257,  /* (127) indexed_opt ::= NOT INDEXED */
   259,  /* (128) using_opt ::= USING LP idlist RP */
   259,  /* (129) using_opt ::= */
   247,  /* (130) orderby_opt ::= */
   247,  /* (131) orderby_opt ::= ORDER BY sortlist */
   229,  /* (132) sortlist ::= sortlist COMMA expr sortorder nulls */
   229,  /* (133) sortlist ::= expr sortorder nulls */
   217,  /* (134) sortorder ::= ASC */
   217,  /* (135) sortorder ::= DESC */
   217,  /* (136) sortorder ::= */
   263,  /* (137) nulls ::= NULLS FIRST */
   263,  /* (138) nulls ::= NULLS LAST */
   263,  /* (139) nulls ::= */
   245,  /* (140) groupby_opt ::= */
   245,  /* (141) groupby_opt ::= GROUP BY nexprlist */
   246,  /* (142) having_opt ::= */
   246,  /* (143) having_opt ::= HAVING expr */
   248,  /* (144) limit_opt ::= */
   248,  /* (145) limit_opt ::= LIMIT expr */
   248,  /* (146) limit_opt ::= LIMIT expr OFFSET expr */
   248,  /* (147) limit_opt ::= LIMIT expr COMMA expr */
   189,  /* (148) cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret */
   244,  /* (149) where_opt ::= */
   244,  /* (150) where_opt ::= WHERE expr */
   265,  /* (151) where_opt_ret ::= */
   265,  /* (152) where_opt_ret ::= WHERE expr */
   265,  /* (153) where_opt_ret ::= RETURNING selcollist */
   265,  /* (154) where_opt_ret ::= WHERE expr RETURNING selcollist */
   189,  /* (155) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret */
   266,  /* (156) setlist ::= setlist COMMA nm EQ expr */
   266,  /* (157) setlist ::= setlist COMMA LP idlist RP EQ expr */
   266,  /* (158) setlist ::= nm EQ expr */
   266,  /* (159) setlist ::= LP idlist RP EQ expr */
   189,  /* (160) cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */
   189,  /* (161) cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */
   269,  /* (162) upsert ::= */
   269,  /* (163) upsert ::= RETURNING selcollist */
   269,  /* (164) upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */
   269,  /* (165) upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */
   269,  /* (166) upsert ::= ON CONFLICT DO NOTHING returning */
   269,  /* (167) upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */
   270,  /* (168) returning ::= RETURNING selcollist */
   267,  /* (169) insert_cmd ::= INSERT orconf */
   267,  /* (170) insert_cmd ::= REPLACE */
   268,  /* (171) idlist_opt ::= */
   268,  /* (172) idlist_opt ::= LP idlist RP */
   262,  /* (173) idlist ::= idlist COMMA nm */
   262,  /* (174) idlist ::= nm */
   215,  /* (175) expr ::= LP expr RP */
   215,  /* (176) expr ::= ID|INDEXED */
   215,  /* (177) expr ::= JOIN_KW */
   215,  /* (178) expr ::= nm DOT nm */
   215,  /* (179) expr ::= nm DOT nm DOT nm */
   214,  /* (180) term ::= NULL|FLOAT|BLOB */
   214,  /* (181) term ::= STRING */
   214,  /* (182) term ::= INTEGER */
   215,  /* (183) expr ::= VARIABLE */
   215,  /* (184) expr ::= expr COLLATE ID|STRING */
   215,  /* (185) expr ::= CAST LP expr AS typetoken RP */
   215,  /* (186) expr ::= ID|INDEXED LP distinct exprlist RP */
   215,  /* (187) expr ::= ID|INDEXED LP STAR RP */
   215,  /* (188) expr ::= ID|INDEXED LP distinct exprlist RP filter_over */
   215,  /* (189) expr ::= ID|INDEXED LP STAR RP filter_over */
   214,  /* (190) term ::= CTIME_KW */
   215,  /* (191) expr ::= LP nexprlist COMMA expr RP */
   215,  /* (192) expr ::= expr AND expr */
   215,  /* (193) expr ::= expr OR expr */
   215,  /* (194) expr ::= expr LT|GT|GE|LE expr */
   215,  /* (195) expr ::= expr EQ|NE expr */
   215,  /* (196) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */
   215,  /* (197) expr ::= expr PLUS|MINUS expr */
   215,  /* (198) expr ::= expr STAR|SLASH|REM expr */
   215,  /* (199) expr ::= expr CONCAT expr */
   272,  /* (200) likeop ::= NOT LIKE_KW|MATCH */
   215,  /* (201) expr ::= expr likeop expr */
   215,  /* (202) expr ::= expr likeop expr ESCAPE expr */
   215,  /* (203) expr ::= expr ISNULL|NOTNULL */
   215,  /* (204) expr ::= expr NOT NULL */
   215,  /* (205) expr ::= expr IS expr */
   215,  /* (206) expr ::= expr IS NOT expr */
   215,  /* (207) expr ::= NOT expr */
   215,  /* (208) expr ::= BITNOT expr */
   215,  /* (209) expr ::= PLUS|MINUS expr */
   273,  /* (210) between_op ::= BETWEEN */
   273,  /* (211) between_op ::= NOT BETWEEN */
   215,  /* (212) expr ::= expr between_op expr AND expr */
   274,  /* (213) in_op ::= IN */
   274,  /* (214) in_op ::= NOT IN */
   215,  /* (215) expr ::= expr in_op LP exprlist RP */
   215,  /* (216) expr ::= LP select RP */
   215,  /* (217) expr ::= expr in_op LP select RP */
   215,  /* (218) expr ::= expr in_op nm dbnm paren_exprlist */
   215,  /* (219) expr ::= EXISTS LP select RP */
   215,  /* (220) expr ::= CASE case_operand case_exprlist case_else END */
   277,  /* (221) case_exprlist ::= case_exprlist WHEN expr THEN expr */
   277,  /* (222) case_exprlist ::= WHEN expr THEN expr */
   278,  /* (223) case_else ::= ELSE expr */
   278,  /* (224) case_else ::= */
   276,  /* (225) case_operand ::= expr */
   276,  /* (226) case_operand ::= */
   260,  /* (227) exprlist ::= */
   251,  /* (228) nexprlist ::= nexprlist COMMA expr */
   251,  /* (229) nexprlist ::= expr */
   275,  /* (230) paren_exprlist ::= */
   275,  /* (231) paren_exprlist ::= LP exprlist RP */
   189,  /* (232) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
   279,  /* (233) uniqueflag ::= UNIQUE */
   279,  /* (234) uniqueflag ::= */
   219,  /* (235) eidlist_opt ::= */
   219,  /* (236) eidlist_opt ::= LP eidlist RP */
   230,  /* (237) eidlist ::= eidlist COMMA nm collate sortorder */
   230,  /* (238) eidlist ::= nm collate sortorder */
   280,  /* (239) collate ::= */
   280,  /* (240) collate ::= COLLATE ID|STRING */
   189,  /* (241) cmd ::= DROP INDEX ifexists fullname */
   189,  /* (242) cmd ::= VACUUM vinto */
   189,  /* (243) cmd ::= VACUUM nm vinto */
   281,  /* (244) vinto ::= INTO expr */
   281,  /* (245) vinto ::= */
   189,  /* (246) cmd ::= PRAGMA nm dbnm */
   189,  /* (247) cmd ::= PRAGMA nm dbnm EQ nmnum */
   189,  /* (248) cmd ::= PRAGMA nm dbnm LP nmnum RP */
   189,  /* (249) cmd ::= PRAGMA nm dbnm EQ minus_num */
   189,  /* (250) cmd ::= PRAGMA nm dbnm LP minus_num RP */
   209,  /* (251) plus_num ::= PLUS INTEGER|FLOAT */
   210,  /* (252) minus_num ::= MINUS INTEGER|FLOAT */
   189,  /* (253) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
   283,  /* (254) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
   285,  /* (255) trigger_time ::= BEFORE|AFTER */
   285,  /* (256) trigger_time ::= INSTEAD OF */
   285,  /* (257) trigger_time ::= */
   286,  /* (258) trigger_event ::= DELETE|INSERT */
   286,  /* (259) trigger_event ::= UPDATE */
   286,  /* (260) trigger_event ::= UPDATE OF idlist */
   288,  /* (261) when_clause ::= */
   288,  /* (262) when_clause ::= WHEN expr */
   284,  /* (263) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
   284,  /* (264) trigger_cmd_list ::= trigger_cmd SEMI */
   290,  /* (265) trnm ::= nm DOT nm */
   291,  /* (266) tridxby ::= INDEXED BY nm */
   291,  /* (267) tridxby ::= NOT INDEXED */
   289,  /* (268) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */
   289,  /* (269) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */
   289,  /* (270) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */
   289,  /* (271) trigger_cmd ::= scanpt select scanpt */
   215,  /* (272) expr ::= RAISE LP IGNORE RP */
   215,  /* (273) expr ::= RAISE LP raisetype COMMA nm RP */
   234,  /* (274) raisetype ::= ROLLBACK */
   234,  /* (275) raisetype ::= ABORT */
   234,  /* (276) raisetype ::= FAIL */
   189,  /* (277) cmd ::= DROP TRIGGER ifexists fullname */
   189,  /* (278) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
   189,  /* (279) cmd ::= DETACH database_kw_opt expr */
   293,  /* (280) key_opt ::= */
   293,  /* (281) key_opt ::= KEY expr */
   189,  /* (282) cmd ::= REINDEX */
   189,  /* (283) cmd ::= REINDEX nm dbnm */
   189,  /* (284) cmd ::= ANALYZE */
   189,  /* (285) cmd ::= ANALYZE nm dbnm */
   189,  /* (286) cmd ::= ALTER TABLE fullname RENAME TO nm */
   189,  /* (287) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */
   189,  /* (288) cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */
   294,  /* (289) add_column_fullname ::= fullname */
   189,  /* (290) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */
   189,  /* (291) cmd ::= create_vtab */
   189,  /* (292) cmd ::= create_vtab LP vtabarglist RP */
   296,  /* (293) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
   298,  /* (294) vtabarg ::= */
   299,  /* (295) vtabargtoken ::= ANY */
   299,  /* (296) vtabargtoken ::= lp anylist RP */
   300,  /* (297) lp ::= LP */
   264,  /* (298) with ::= WITH wqlist */
   264,  /* (299) with ::= WITH RECURSIVE wqlist */
   303,  /* (300) wqas ::= AS */
   303,  /* (301) wqas ::= AS MATERIALIZED */
   303,  /* (302) wqas ::= AS NOT MATERIALIZED */
   302,  /* (303) wqitem ::= nm eidlist_opt wqas LP select RP */
   239,  /* (304) wqlist ::= wqitem */
   239,  /* (305) wqlist ::= wqlist COMMA wqitem */
   304,  /* (306) windowdefn_list ::= windowdefn */
   304,  /* (307) windowdefn_list ::= windowdefn_list COMMA windowdefn */
   305,  /* (308) windowdefn ::= nm AS LP window RP */
   306,  /* (309) window ::= PARTITION BY nexprlist orderby_opt frame_opt */
   306,  /* (310) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */
   306,  /* (311) window ::= ORDER BY sortlist frame_opt */
   306,  /* (312) window ::= nm ORDER BY sortlist frame_opt */
   306,  /* (313) window ::= frame_opt */
   306,  /* (314) window ::= nm frame_opt */
   307,  /* (315) frame_opt ::= */
   307,  /* (316) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */
   307,  /* (317) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */
   311,  /* (318) range_or_rows ::= RANGE|ROWS|GROUPS */
   313,  /* (319) frame_bound_s ::= frame_bound */
   313,  /* (320) frame_bound_s ::= UNBOUNDED PRECEDING */
   314,  /* (321) frame_bound_e ::= frame_bound */
   314,  /* (322) frame_bound_e ::= UNBOUNDED FOLLOWING */
   312,  /* (323) frame_bound ::= expr PRECEDING|FOLLOWING */
   312,  /* (324) frame_bound ::= CURRENT ROW */
   315,  /* (325) frame_exclude_opt ::= */
   315,  /* (326) frame_exclude_opt ::= EXCLUDE frame_exclude */
   316,  /* (327) frame_exclude ::= NO OTHERS */
   316,  /* (328) frame_exclude ::= CURRENT ROW */
   316,  /* (329) frame_exclude ::= GROUP|TIES */
   249,  /* (330) window_clause ::= WINDOW windowdefn_list */
   271,  /* (331) filter_over ::= filter_clause over_clause */
   271,  /* (332) filter_over ::= over_clause */
   271,  /* (333) filter_over ::= filter_clause */
   310,  /* (334) over_clause ::= OVER LP window RP */
   310,  /* (335) over_clause ::= OVER nm */
   309,  /* (336) filter_clause ::= FILTER LP WHERE expr RP */
   184,  /* (337) input ::= cmdlist */
   185,  /* (338) cmdlist ::= cmdlist ecmd */
   185,  /* (339) cmdlist ::= ecmd */
   186,  /* (340) ecmd ::= SEMI */
   186,  /* (341) ecmd ::= cmdx SEMI */
   186,  /* (342) ecmd ::= explain cmdx SEMI */
   191,  /* (343) trans_opt ::= */
   191,  /* (344) trans_opt ::= TRANSACTION */
   191,  /* (345) trans_opt ::= TRANSACTION nm */
   193,  /* (346) savepoint_opt ::= SAVEPOINT */
   193,  /* (347) savepoint_opt ::= */
   189,  /* (348) cmd ::= create_table create_table_args */

   200,  /* (349) columnlist ::= columnlist COMMA columnname carglist */
   200,  /* (350) columnlist ::= columnname carglist */
   192,  /* (351) nm ::= ID|INDEXED */
   192,  /* (352) nm ::= STRING */
   192,  /* (353) nm ::= JOIN_KW */
   206,  /* (354) typetoken ::= typename */
   207,  /* (355) typename ::= ID|STRING */
   208,  /* (356) signed ::= plus_num */
   208,  /* (357) signed ::= minus_num */
   205,  /* (358) carglist ::= carglist ccons */
   205,  /* (359) carglist ::= */
   213,  /* (360) ccons ::= NULL onconf */
   213,  /* (361) ccons ::= GENERATED ALWAYS AS generated */
   213,  /* (362) ccons ::= AS generated */
   201,  /* (363) conslist_opt ::= COMMA conslist */
   226,  /* (364) conslist ::= conslist tconscomma tcons */
   226,  /* (365) conslist ::= tcons */
   227,  /* (366) tconscomma ::= */
   231,  /* (367) defer_subclause_opt ::= defer_subclause */
   233,  /* (368) resolvetype ::= raisetype */
   237,  /* (369) selectnowith ::= oneselect */
   238,  /* (370) oneselect ::= values */
   252,  /* (371) sclp ::= selcollist COMMA */
   253,  /* (372) as ::= ID|STRING */
   270,  /* (373) returning ::= */
   215,  /* (374) expr ::= term */
   272,  /* (375) likeop ::= LIKE_KW|MATCH */
   260,  /* (376) exprlist ::= nexprlist */
   282,  /* (377) nmnum ::= plus_num */
   282,  /* (378) nmnum ::= nm */
   282,  /* (379) nmnum ::= ON */
   282,  /* (380) nmnum ::= DELETE */
   282,  /* (381) nmnum ::= DEFAULT */
   209,  /* (382) plus_num ::= INTEGER|FLOAT */
   287,  /* (383) foreach_clause ::= */
   287,  /* (384) foreach_clause ::= FOR EACH ROW */
   290,  /* (385) trnm ::= nm */
   291,  /* (386) tridxby ::= */
   292,  /* (387) database_kw_opt ::= DATABASE */
   292,  /* (388) database_kw_opt ::= */
   295,  /* (389) kwcolumn_opt ::= */
   295,  /* (390) kwcolumn_opt ::= COLUMNKW */
   297,  /* (391) vtabarglist ::= vtabarg */
   297,  /* (392) vtabarglist ::= vtabarglist COMMA vtabarg */
   298,  /* (393) vtabarg ::= vtabarg vtabargtoken */
   301,  /* (394) anylist ::= */
   301,  /* (395) anylist ::= anylist LP anylist RP */
   301,  /* (396) anylist ::= anylist ANY */
   264,  /* (397) with ::= */
};

/* For rule J, yyRuleInfoNRhs[J] contains the negative of the number
** of symbols on the right-hand side of that rule. */
static const signed char yyRuleInfoNRhs[] = {
   -1,  /* (0) explain ::= EXPLAIN */
   -3,  /* (1) explain ::= EXPLAIN QUERY PLAN */







|

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







161435
161436
161437
161438
161439
161440
161441
161442
161443
161444
161445
161446
161447
161448
161449
161450
161451
161452
161453
161454
161455
161456
161457
161458
161459
161460
161461
161462
161463
161464
161465
161466
161467
161468
161469
161470
161471
161472
161473
161474
161475
161476
161477
161478
161479
161480
161481
161482
161483
161484
161485
161486
161487
161488
161489
161490
161491
161492
161493
161494
161495
161496
161497
161498
161499
161500
161501
161502
161503
161504
161505
161506
161507
161508
161509
161510
161511
161512
161513
161514
161515
161516
161517
161518
161519
161520
161521
161522
161523
161524
161525
161526
161527
161528
161529
161530
161531
161532
161533
161534
161535
161536
161537
161538
161539
161540
161541
161542
161543
161544
161545
161546
161547
161548
161549
161550
161551
161552
161553
161554
161555
161556
161557
161558
161559
161560
161561
161562
161563
161564
161565
161566
161567
161568
161569
161570
161571
161572
161573
161574
161575
161576
161577
161578
161579
161580
161581
161582
161583
161584
161585
161586
161587
161588
161589
161590
161591
161592
161593
161594
161595
161596
161597
161598
161599
161600
161601
161602
161603
161604
161605
161606
161607
161608
161609
161610
161611
161612
161613
161614
161615
161616
161617
161618
161619
161620
161621
161622
161623
161624
161625
161626
161627
161628
161629
161630
161631
161632
161633
161634
161635
161636
161637
161638
161639
161640
161641
161642
161643
161644
161645
161646
161647
161648
161649
161650
161651
161652
161653
161654
161655
161656
161657
161658
161659
161660
161661
161662
161663
161664
161665
161666
161667
161668
161669
161670
161671
161672
161673
161674
161675
161676
161677
161678
161679
161680
161681
161682
161683
161684
161685
161686
161687
161688
161689
161690
161691
161692
161693
161694
161695
161696
161697
161698
161699
161700
161701
161702
161703
161704
161705
161706
161707
161708
161709
161710
161711
161712
161713
161714
161715
161716
161717
161718
161719
161720
161721
161722
161723
161724
161725
161726
161727
161728
161729
161730
161731
161732
161733
161734
161735
161736
161737
161738
161739
161740
161741
161742
161743
161744
161745
161746
161747
161748
161749
161750
161751
161752
161753
161754
161755
161756
161757
161758
161759
161760
161761
161762
161763
161764
161765
161766
161767
161768
161769
161770
161771
161772
161773
161774
161775
161776
161777
161778
161779
161780
161781
161782
161783
161784
161785
161786
161787
161788
161789
161790
161791
161792
161793
161794
161795
161796
161797
161798
161799
161800
161801
161802
161803
161804
161805
161806
161807
161808
161809
161810
161811
161812
161813
161814
161815
161816
161817
161818
161819
161820
161821
161822
161823
161824
161825
161826
161827
161828
161829
161830
   189,  /* (12) cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */
   194,  /* (13) create_table ::= createkw temp TABLE ifnotexists nm dbnm */
   196,  /* (14) createkw ::= CREATE */
   198,  /* (15) ifnotexists ::= */
   198,  /* (16) ifnotexists ::= IF NOT EXISTS */
   197,  /* (17) temp ::= TEMP */
   197,  /* (18) temp ::= */
   195,  /* (19) create_table_args ::= LP columnlist conslist_opt RP table_option_set */
   195,  /* (20) create_table_args ::= AS select */
   202,  /* (21) table_option_set ::= */
   202,  /* (22) table_option_set ::= table_option_set COMMA table_option */
   204,  /* (23) table_option ::= WITHOUT nm */
   204,  /* (24) table_option ::= nm */
   205,  /* (25) columnname ::= nm typetoken */
   207,  /* (26) typetoken ::= */
   207,  /* (27) typetoken ::= typename LP signed RP */
   207,  /* (28) typetoken ::= typename LP signed COMMA signed RP */
   208,  /* (29) typename ::= typename ID|STRING */
   212,  /* (30) scanpt ::= */
   213,  /* (31) scantok ::= */
   214,  /* (32) ccons ::= CONSTRAINT nm */
   214,  /* (33) ccons ::= DEFAULT scantok term */
   214,  /* (34) ccons ::= DEFAULT LP expr RP */
   214,  /* (35) ccons ::= DEFAULT PLUS scantok term */
   214,  /* (36) ccons ::= DEFAULT MINUS scantok term */
   214,  /* (37) ccons ::= DEFAULT scantok ID|INDEXED */
   214,  /* (38) ccons ::= NOT NULL onconf */
   214,  /* (39) ccons ::= PRIMARY KEY sortorder onconf autoinc */
   214,  /* (40) ccons ::= UNIQUE onconf */
   214,  /* (41) ccons ::= CHECK LP expr RP */
   214,  /* (42) ccons ::= REFERENCES nm eidlist_opt refargs */
   214,  /* (43) ccons ::= defer_subclause */
   214,  /* (44) ccons ::= COLLATE ID|STRING */
   223,  /* (45) generated ::= LP expr RP */
   223,  /* (46) generated ::= LP expr RP ID */
   219,  /* (47) autoinc ::= */
   219,  /* (48) autoinc ::= AUTOINCR */
   221,  /* (49) refargs ::= */
   221,  /* (50) refargs ::= refargs refarg */
   224,  /* (51) refarg ::= MATCH nm */
   224,  /* (52) refarg ::= ON INSERT refact */
   224,  /* (53) refarg ::= ON DELETE refact */
   224,  /* (54) refarg ::= ON UPDATE refact */
   225,  /* (55) refact ::= SET NULL */
   225,  /* (56) refact ::= SET DEFAULT */
   225,  /* (57) refact ::= CASCADE */
   225,  /* (58) refact ::= RESTRICT */
   225,  /* (59) refact ::= NO ACTION */
   222,  /* (60) defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */
   222,  /* (61) defer_subclause ::= DEFERRABLE init_deferred_pred_opt */
   226,  /* (62) init_deferred_pred_opt ::= */
   226,  /* (63) init_deferred_pred_opt ::= INITIALLY DEFERRED */
   226,  /* (64) init_deferred_pred_opt ::= INITIALLY IMMEDIATE */
   201,  /* (65) conslist_opt ::= */
   228,  /* (66) tconscomma ::= COMMA */
   229,  /* (67) tcons ::= CONSTRAINT nm */
   229,  /* (68) tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */
   229,  /* (69) tcons ::= UNIQUE LP sortlist RP onconf */
   229,  /* (70) tcons ::= CHECK LP expr RP onconf */
   229,  /* (71) tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */
   232,  /* (72) defer_subclause_opt ::= */
   217,  /* (73) onconf ::= */
   217,  /* (74) onconf ::= ON CONFLICT resolvetype */
   233,  /* (75) orconf ::= */
   233,  /* (76) orconf ::= OR resolvetype */
   234,  /* (77) resolvetype ::= IGNORE */
   234,  /* (78) resolvetype ::= REPLACE */
   189,  /* (79) cmd ::= DROP TABLE ifexists fullname */
   236,  /* (80) ifexists ::= IF EXISTS */
   236,  /* (81) ifexists ::= */
   189,  /* (82) cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */
   189,  /* (83) cmd ::= DROP VIEW ifexists fullname */
   189,  /* (84) cmd ::= select */
   203,  /* (85) select ::= WITH wqlist selectnowith */
   203,  /* (86) select ::= WITH RECURSIVE wqlist selectnowith */
   203,  /* (87) select ::= selectnowith */
   238,  /* (88) selectnowith ::= selectnowith multiselect_op oneselect */
   241,  /* (89) multiselect_op ::= UNION */
   241,  /* (90) multiselect_op ::= UNION ALL */
   241,  /* (91) multiselect_op ::= EXCEPT|INTERSECT */
   239,  /* (92) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
   239,  /* (93) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */
   251,  /* (94) values ::= VALUES LP nexprlist RP */
   251,  /* (95) values ::= values COMMA LP nexprlist RP */
   242,  /* (96) distinct ::= DISTINCT */
   242,  /* (97) distinct ::= ALL */
   242,  /* (98) distinct ::= */
   253,  /* (99) sclp ::= */
   243,  /* (100) selcollist ::= sclp scanpt expr scanpt as */
   243,  /* (101) selcollist ::= sclp scanpt STAR */
   243,  /* (102) selcollist ::= sclp scanpt nm DOT STAR */
   254,  /* (103) as ::= AS nm */
   254,  /* (104) as ::= */
   244,  /* (105) from ::= */
   244,  /* (106) from ::= FROM seltablist */
   256,  /* (107) stl_prefix ::= seltablist joinop */
   256,  /* (108) stl_prefix ::= */
   255,  /* (109) seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */
   255,  /* (110) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt */
   255,  /* (111) seltablist ::= stl_prefix LP select RP as on_opt using_opt */
   255,  /* (112) seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */
   199,  /* (113) dbnm ::= */
   199,  /* (114) dbnm ::= DOT nm */
   237,  /* (115) fullname ::= nm */
   237,  /* (116) fullname ::= nm DOT nm */
   262,  /* (117) xfullname ::= nm */
   262,  /* (118) xfullname ::= nm DOT nm */
   262,  /* (119) xfullname ::= nm DOT nm AS nm */
   262,  /* (120) xfullname ::= nm AS nm */
   257,  /* (121) joinop ::= COMMA|JOIN */
   257,  /* (122) joinop ::= JOIN_KW JOIN */
   257,  /* (123) joinop ::= JOIN_KW nm JOIN */
   257,  /* (124) joinop ::= JOIN_KW nm nm JOIN */
   259,  /* (125) on_opt ::= ON expr */
   259,  /* (126) on_opt ::= */
   258,  /* (127) indexed_opt ::= */
   258,  /* (128) indexed_opt ::= INDEXED BY nm */
   258,  /* (129) indexed_opt ::= NOT INDEXED */
   260,  /* (130) using_opt ::= USING LP idlist RP */
   260,  /* (131) using_opt ::= */
   248,  /* (132) orderby_opt ::= */
   248,  /* (133) orderby_opt ::= ORDER BY sortlist */
   230,  /* (134) sortlist ::= sortlist COMMA expr sortorder nulls */
   230,  /* (135) sortlist ::= expr sortorder nulls */
   218,  /* (136) sortorder ::= ASC */
   218,  /* (137) sortorder ::= DESC */
   218,  /* (138) sortorder ::= */
   264,  /* (139) nulls ::= NULLS FIRST */
   264,  /* (140) nulls ::= NULLS LAST */
   264,  /* (141) nulls ::= */
   246,  /* (142) groupby_opt ::= */
   246,  /* (143) groupby_opt ::= GROUP BY nexprlist */
   247,  /* (144) having_opt ::= */
   247,  /* (145) having_opt ::= HAVING expr */
   249,  /* (146) limit_opt ::= */
   249,  /* (147) limit_opt ::= LIMIT expr */
   249,  /* (148) limit_opt ::= LIMIT expr OFFSET expr */
   249,  /* (149) limit_opt ::= LIMIT expr COMMA expr */
   189,  /* (150) cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret */
   245,  /* (151) where_opt ::= */
   245,  /* (152) where_opt ::= WHERE expr */
   266,  /* (153) where_opt_ret ::= */
   266,  /* (154) where_opt_ret ::= WHERE expr */
   266,  /* (155) where_opt_ret ::= RETURNING selcollist */
   266,  /* (156) where_opt_ret ::= WHERE expr RETURNING selcollist */
   189,  /* (157) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret */
   267,  /* (158) setlist ::= setlist COMMA nm EQ expr */
   267,  /* (159) setlist ::= setlist COMMA LP idlist RP EQ expr */
   267,  /* (160) setlist ::= nm EQ expr */
   267,  /* (161) setlist ::= LP idlist RP EQ expr */
   189,  /* (162) cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */
   189,  /* (163) cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */
   270,  /* (164) upsert ::= */
   270,  /* (165) upsert ::= RETURNING selcollist */
   270,  /* (166) upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */
   270,  /* (167) upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */
   270,  /* (168) upsert ::= ON CONFLICT DO NOTHING returning */
   270,  /* (169) upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */
   271,  /* (170) returning ::= RETURNING selcollist */
   268,  /* (171) insert_cmd ::= INSERT orconf */
   268,  /* (172) insert_cmd ::= REPLACE */
   269,  /* (173) idlist_opt ::= */
   269,  /* (174) idlist_opt ::= LP idlist RP */
   263,  /* (175) idlist ::= idlist COMMA nm */
   263,  /* (176) idlist ::= nm */
   216,  /* (177) expr ::= LP expr RP */
   216,  /* (178) expr ::= ID|INDEXED */
   216,  /* (179) expr ::= JOIN_KW */
   216,  /* (180) expr ::= nm DOT nm */
   216,  /* (181) expr ::= nm DOT nm DOT nm */
   215,  /* (182) term ::= NULL|FLOAT|BLOB */
   215,  /* (183) term ::= STRING */
   215,  /* (184) term ::= INTEGER */
   216,  /* (185) expr ::= VARIABLE */
   216,  /* (186) expr ::= expr COLLATE ID|STRING */
   216,  /* (187) expr ::= CAST LP expr AS typetoken RP */
   216,  /* (188) expr ::= ID|INDEXED LP distinct exprlist RP */
   216,  /* (189) expr ::= ID|INDEXED LP STAR RP */
   216,  /* (190) expr ::= ID|INDEXED LP distinct exprlist RP filter_over */
   216,  /* (191) expr ::= ID|INDEXED LP STAR RP filter_over */
   215,  /* (192) term ::= CTIME_KW */
   216,  /* (193) expr ::= LP nexprlist COMMA expr RP */
   216,  /* (194) expr ::= expr AND expr */
   216,  /* (195) expr ::= expr OR expr */
   216,  /* (196) expr ::= expr LT|GT|GE|LE expr */
   216,  /* (197) expr ::= expr EQ|NE expr */
   216,  /* (198) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */
   216,  /* (199) expr ::= expr PLUS|MINUS expr */
   216,  /* (200) expr ::= expr STAR|SLASH|REM expr */
   216,  /* (201) expr ::= expr CONCAT expr */
   273,  /* (202) likeop ::= NOT LIKE_KW|MATCH */
   216,  /* (203) expr ::= expr likeop expr */
   216,  /* (204) expr ::= expr likeop expr ESCAPE expr */
   216,  /* (205) expr ::= expr ISNULL|NOTNULL */
   216,  /* (206) expr ::= expr NOT NULL */
   216,  /* (207) expr ::= expr IS expr */
   216,  /* (208) expr ::= expr IS NOT expr */
   216,  /* (209) expr ::= NOT expr */
   216,  /* (210) expr ::= BITNOT expr */
   216,  /* (211) expr ::= PLUS|MINUS expr */
   274,  /* (212) between_op ::= BETWEEN */
   274,  /* (213) between_op ::= NOT BETWEEN */
   216,  /* (214) expr ::= expr between_op expr AND expr */
   275,  /* (215) in_op ::= IN */
   275,  /* (216) in_op ::= NOT IN */
   216,  /* (217) expr ::= expr in_op LP exprlist RP */
   216,  /* (218) expr ::= LP select RP */
   216,  /* (219) expr ::= expr in_op LP select RP */
   216,  /* (220) expr ::= expr in_op nm dbnm paren_exprlist */
   216,  /* (221) expr ::= EXISTS LP select RP */
   216,  /* (222) expr ::= CASE case_operand case_exprlist case_else END */
   278,  /* (223) case_exprlist ::= case_exprlist WHEN expr THEN expr */
   278,  /* (224) case_exprlist ::= WHEN expr THEN expr */
   279,  /* (225) case_else ::= ELSE expr */
   279,  /* (226) case_else ::= */
   277,  /* (227) case_operand ::= expr */
   277,  /* (228) case_operand ::= */
   261,  /* (229) exprlist ::= */
   252,  /* (230) nexprlist ::= nexprlist COMMA expr */
   252,  /* (231) nexprlist ::= expr */
   276,  /* (232) paren_exprlist ::= */
   276,  /* (233) paren_exprlist ::= LP exprlist RP */
   189,  /* (234) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
   280,  /* (235) uniqueflag ::= UNIQUE */
   280,  /* (236) uniqueflag ::= */
   220,  /* (237) eidlist_opt ::= */
   220,  /* (238) eidlist_opt ::= LP eidlist RP */
   231,  /* (239) eidlist ::= eidlist COMMA nm collate sortorder */
   231,  /* (240) eidlist ::= nm collate sortorder */
   281,  /* (241) collate ::= */
   281,  /* (242) collate ::= COLLATE ID|STRING */
   189,  /* (243) cmd ::= DROP INDEX ifexists fullname */
   189,  /* (244) cmd ::= VACUUM vinto */
   189,  /* (245) cmd ::= VACUUM nm vinto */
   282,  /* (246) vinto ::= INTO expr */
   282,  /* (247) vinto ::= */
   189,  /* (248) cmd ::= PRAGMA nm dbnm */
   189,  /* (249) cmd ::= PRAGMA nm dbnm EQ nmnum */
   189,  /* (250) cmd ::= PRAGMA nm dbnm LP nmnum RP */
   189,  /* (251) cmd ::= PRAGMA nm dbnm EQ minus_num */
   189,  /* (252) cmd ::= PRAGMA nm dbnm LP minus_num RP */
   210,  /* (253) plus_num ::= PLUS INTEGER|FLOAT */
   211,  /* (254) minus_num ::= MINUS INTEGER|FLOAT */
   189,  /* (255) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
   284,  /* (256) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
   286,  /* (257) trigger_time ::= BEFORE|AFTER */
   286,  /* (258) trigger_time ::= INSTEAD OF */
   286,  /* (259) trigger_time ::= */
   287,  /* (260) trigger_event ::= DELETE|INSERT */
   287,  /* (261) trigger_event ::= UPDATE */
   287,  /* (262) trigger_event ::= UPDATE OF idlist */
   289,  /* (263) when_clause ::= */
   289,  /* (264) when_clause ::= WHEN expr */
   285,  /* (265) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
   285,  /* (266) trigger_cmd_list ::= trigger_cmd SEMI */
   291,  /* (267) trnm ::= nm DOT nm */
   292,  /* (268) tridxby ::= INDEXED BY nm */
   292,  /* (269) tridxby ::= NOT INDEXED */
   290,  /* (270) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */
   290,  /* (271) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */
   290,  /* (272) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */
   290,  /* (273) trigger_cmd ::= scanpt select scanpt */
   216,  /* (274) expr ::= RAISE LP IGNORE RP */
   216,  /* (275) expr ::= RAISE LP raisetype COMMA nm RP */
   235,  /* (276) raisetype ::= ROLLBACK */
   235,  /* (277) raisetype ::= ABORT */
   235,  /* (278) raisetype ::= FAIL */
   189,  /* (279) cmd ::= DROP TRIGGER ifexists fullname */
   189,  /* (280) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
   189,  /* (281) cmd ::= DETACH database_kw_opt expr */
   294,  /* (282) key_opt ::= */
   294,  /* (283) key_opt ::= KEY expr */
   189,  /* (284) cmd ::= REINDEX */
   189,  /* (285) cmd ::= REINDEX nm dbnm */
   189,  /* (286) cmd ::= ANALYZE */
   189,  /* (287) cmd ::= ANALYZE nm dbnm */
   189,  /* (288) cmd ::= ALTER TABLE fullname RENAME TO nm */
   189,  /* (289) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */
   189,  /* (290) cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */
   295,  /* (291) add_column_fullname ::= fullname */
   189,  /* (292) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */
   189,  /* (293) cmd ::= create_vtab */
   189,  /* (294) cmd ::= create_vtab LP vtabarglist RP */
   297,  /* (295) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
   299,  /* (296) vtabarg ::= */
   300,  /* (297) vtabargtoken ::= ANY */
   300,  /* (298) vtabargtoken ::= lp anylist RP */
   301,  /* (299) lp ::= LP */
   265,  /* (300) with ::= WITH wqlist */
   265,  /* (301) with ::= WITH RECURSIVE wqlist */
   304,  /* (302) wqas ::= AS */
   304,  /* (303) wqas ::= AS MATERIALIZED */
   304,  /* (304) wqas ::= AS NOT MATERIALIZED */
   303,  /* (305) wqitem ::= nm eidlist_opt wqas LP select RP */
   240,  /* (306) wqlist ::= wqitem */
   240,  /* (307) wqlist ::= wqlist COMMA wqitem */
   305,  /* (308) windowdefn_list ::= windowdefn */
   305,  /* (309) windowdefn_list ::= windowdefn_list COMMA windowdefn */
   306,  /* (310) windowdefn ::= nm AS LP window RP */
   307,  /* (311) window ::= PARTITION BY nexprlist orderby_opt frame_opt */
   307,  /* (312) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */
   307,  /* (313) window ::= ORDER BY sortlist frame_opt */
   307,  /* (314) window ::= nm ORDER BY sortlist frame_opt */
   307,  /* (315) window ::= frame_opt */
   307,  /* (316) window ::= nm frame_opt */
   308,  /* (317) frame_opt ::= */
   308,  /* (318) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */
   308,  /* (319) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */
   312,  /* (320) range_or_rows ::= RANGE|ROWS|GROUPS */
   314,  /* (321) frame_bound_s ::= frame_bound */
   314,  /* (322) frame_bound_s ::= UNBOUNDED PRECEDING */
   315,  /* (323) frame_bound_e ::= frame_bound */
   315,  /* (324) frame_bound_e ::= UNBOUNDED FOLLOWING */
   313,  /* (325) frame_bound ::= expr PRECEDING|FOLLOWING */
   313,  /* (326) frame_bound ::= CURRENT ROW */
   316,  /* (327) frame_exclude_opt ::= */
   316,  /* (328) frame_exclude_opt ::= EXCLUDE frame_exclude */
   317,  /* (329) frame_exclude ::= NO OTHERS */
   317,  /* (330) frame_exclude ::= CURRENT ROW */
   317,  /* (331) frame_exclude ::= GROUP|TIES */
   250,  /* (332) window_clause ::= WINDOW windowdefn_list */
   272,  /* (333) filter_over ::= filter_clause over_clause */
   272,  /* (334) filter_over ::= over_clause */
   272,  /* (335) filter_over ::= filter_clause */
   311,  /* (336) over_clause ::= OVER LP window RP */
   311,  /* (337) over_clause ::= OVER nm */
   310,  /* (338) filter_clause ::= FILTER LP WHERE expr RP */
   184,  /* (339) input ::= cmdlist */
   185,  /* (340) cmdlist ::= cmdlist ecmd */
   185,  /* (341) cmdlist ::= ecmd */
   186,  /* (342) ecmd ::= SEMI */
   186,  /* (343) ecmd ::= cmdx SEMI */
   186,  /* (344) ecmd ::= explain cmdx SEMI */
   191,  /* (345) trans_opt ::= */
   191,  /* (346) trans_opt ::= TRANSACTION */
   191,  /* (347) trans_opt ::= TRANSACTION nm */
   193,  /* (348) savepoint_opt ::= SAVEPOINT */
   193,  /* (349) savepoint_opt ::= */
   189,  /* (350) cmd ::= create_table create_table_args */
   202,  /* (351) table_option_set ::= table_option */
   200,  /* (352) columnlist ::= columnlist COMMA columnname carglist */
   200,  /* (353) columnlist ::= columnname carglist */
   192,  /* (354) nm ::= ID|INDEXED */
   192,  /* (355) nm ::= STRING */
   192,  /* (356) nm ::= JOIN_KW */
   207,  /* (357) typetoken ::= typename */
   208,  /* (358) typename ::= ID|STRING */
   209,  /* (359) signed ::= plus_num */
   209,  /* (360) signed ::= minus_num */
   206,  /* (361) carglist ::= carglist ccons */
   206,  /* (362) carglist ::= */
   214,  /* (363) ccons ::= NULL onconf */
   214,  /* (364) ccons ::= GENERATED ALWAYS AS generated */
   214,  /* (365) ccons ::= AS generated */
   201,  /* (366) conslist_opt ::= COMMA conslist */
   227,  /* (367) conslist ::= conslist tconscomma tcons */
   227,  /* (368) conslist ::= tcons */
   228,  /* (369) tconscomma ::= */
   232,  /* (370) defer_subclause_opt ::= defer_subclause */
   234,  /* (371) resolvetype ::= raisetype */
   238,  /* (372) selectnowith ::= oneselect */
   239,  /* (373) oneselect ::= values */
   253,  /* (374) sclp ::= selcollist COMMA */
   254,  /* (375) as ::= ID|STRING */
   271,  /* (376) returning ::= */
   216,  /* (377) expr ::= term */
   273,  /* (378) likeop ::= LIKE_KW|MATCH */
   261,  /* (379) exprlist ::= nexprlist */
   283,  /* (380) nmnum ::= plus_num */
   283,  /* (381) nmnum ::= nm */
   283,  /* (382) nmnum ::= ON */
   283,  /* (383) nmnum ::= DELETE */
   283,  /* (384) nmnum ::= DEFAULT */
   210,  /* (385) plus_num ::= INTEGER|FLOAT */
   288,  /* (386) foreach_clause ::= */
   288,  /* (387) foreach_clause ::= FOR EACH ROW */
   291,  /* (388) trnm ::= nm */
   292,  /* (389) tridxby ::= */
   293,  /* (390) database_kw_opt ::= DATABASE */
   293,  /* (391) database_kw_opt ::= */
   296,  /* (392) kwcolumn_opt ::= */
   296,  /* (393) kwcolumn_opt ::= COLUMNKW */
   298,  /* (394) vtabarglist ::= vtabarg */
   298,  /* (395) vtabarglist ::= vtabarglist COMMA vtabarg */
   299,  /* (396) vtabarg ::= vtabarg vtabargtoken */
   302,  /* (397) anylist ::= */
   302,  /* (398) anylist ::= anylist LP anylist RP */
   302,  /* (399) anylist ::= anylist ANY */
   265,  /* (400) with ::= */
};

/* For rule J, yyRuleInfoNRhs[J] contains the negative of the number
** of symbols on the right-hand side of that rule. */
static const signed char yyRuleInfoNRhs[] = {
   -1,  /* (0) explain ::= EXPLAIN */
   -3,  /* (1) explain ::= EXPLAIN QUERY PLAN */
161344
161345
161346
161347
161348
161349
161350
161351
161352
161353
161354


161355
161356
161357
161358
161359
161360
161361
161362
161363
161364
161365
161366
161367
161368
161369
161370
161371
161372
161373
161374
161375
161376
161377
161378
161379
161380
161381
161382
161383
161384
161385
161386
161387
161388
161389
161390
161391
161392
161393
161394
161395
161396
161397
161398
161399
161400
161401
161402
161403
161404
161405
161406
161407
161408
161409
161410
161411
161412
161413
161414
161415
161416
161417
161418
161419
161420
161421
161422
161423
161424
161425
161426
161427
161428
161429
161430
161431
161432
161433
161434
161435
161436
161437
161438
161439
161440
161441
161442
161443
161444
161445
161446
161447
161448
161449
161450
161451
161452
161453
161454
161455
161456
161457
161458
161459
161460
161461
161462
161463
161464
161465
161466
161467
161468
161469
161470
161471
161472
161473
161474
161475
161476
161477
161478
161479
161480
161481
161482
161483
161484
161485
161486
161487
161488
161489
161490
161491
161492
161493
161494
161495
161496
161497
161498
161499
161500
161501
161502
161503
161504
161505
161506
161507
161508
161509
161510
161511
161512
161513
161514
161515
161516
161517
161518
161519
161520
161521
161522
161523
161524
161525
161526
161527
161528
161529
161530
161531
161532
161533
161534
161535
161536
161537
161538
161539
161540
161541
161542
161543
161544
161545
161546
161547
161548
161549
161550
161551
161552
161553
161554
161555
161556
161557
161558
161559
161560
161561
161562
161563
161564
161565
161566
161567
161568
161569
161570
161571
161572
161573
161574
161575
161576
161577
161578
161579
161580
161581
161582
161583
161584
161585
161586
161587
161588
161589
161590
161591
161592
161593
161594
161595
161596
161597
161598
161599
161600
161601
161602
161603
161604
161605
161606
161607
161608
161609
161610
161611
161612
161613
161614
161615
161616
161617
161618
161619
161620
161621
161622
161623
161624
161625
161626
161627
161628
161629
161630
161631
161632
161633
161634
161635
161636
161637
161638
161639
161640
161641
161642
161643
161644
161645
161646
161647
161648
161649
161650
161651
161652
161653
161654
161655
161656
161657
161658
161659
161660
161661
161662
161663
161664
161665
161666
161667
161668
161669
161670
161671
161672
161673
161674
161675
161676
161677
161678
161679
161680

161681
161682
161683
161684
161685
161686
161687
161688
161689
161690
161691
161692
161693
161694
161695
161696
161697
161698
161699
161700
161701
161702
161703
161704
161705
161706
161707
161708
161709
161710
161711
161712
161713
161714
161715
161716
161717
161718
161719
161720
161721
161722
161723
161724
161725
161726
161727
161728
161729
161730
161731
161732
161733
161734
161735
161736
   -5,  /* (12) cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */
   -6,  /* (13) create_table ::= createkw temp TABLE ifnotexists nm dbnm */
   -1,  /* (14) createkw ::= CREATE */
    0,  /* (15) ifnotexists ::= */
   -3,  /* (16) ifnotexists ::= IF NOT EXISTS */
   -1,  /* (17) temp ::= TEMP */
    0,  /* (18) temp ::= */
   -5,  /* (19) create_table_args ::= LP columnlist conslist_opt RP table_options */
   -2,  /* (20) create_table_args ::= AS select */
    0,  /* (21) table_options ::= */
   -2,  /* (22) table_options ::= WITHOUT nm */


   -2,  /* (23) columnname ::= nm typetoken */
    0,  /* (24) typetoken ::= */
   -4,  /* (25) typetoken ::= typename LP signed RP */
   -6,  /* (26) typetoken ::= typename LP signed COMMA signed RP */
   -2,  /* (27) typename ::= typename ID|STRING */
    0,  /* (28) scanpt ::= */
    0,  /* (29) scantok ::= */
   -2,  /* (30) ccons ::= CONSTRAINT nm */
   -3,  /* (31) ccons ::= DEFAULT scantok term */
   -4,  /* (32) ccons ::= DEFAULT LP expr RP */
   -4,  /* (33) ccons ::= DEFAULT PLUS scantok term */
   -4,  /* (34) ccons ::= DEFAULT MINUS scantok term */
   -3,  /* (35) ccons ::= DEFAULT scantok ID|INDEXED */
   -3,  /* (36) ccons ::= NOT NULL onconf */
   -5,  /* (37) ccons ::= PRIMARY KEY sortorder onconf autoinc */
   -2,  /* (38) ccons ::= UNIQUE onconf */
   -4,  /* (39) ccons ::= CHECK LP expr RP */
   -4,  /* (40) ccons ::= REFERENCES nm eidlist_opt refargs */
   -1,  /* (41) ccons ::= defer_subclause */
   -2,  /* (42) ccons ::= COLLATE ID|STRING */
   -3,  /* (43) generated ::= LP expr RP */
   -4,  /* (44) generated ::= LP expr RP ID */
    0,  /* (45) autoinc ::= */
   -1,  /* (46) autoinc ::= AUTOINCR */
    0,  /* (47) refargs ::= */
   -2,  /* (48) refargs ::= refargs refarg */
   -2,  /* (49) refarg ::= MATCH nm */
   -3,  /* (50) refarg ::= ON INSERT refact */
   -3,  /* (51) refarg ::= ON DELETE refact */
   -3,  /* (52) refarg ::= ON UPDATE refact */
   -2,  /* (53) refact ::= SET NULL */
   -2,  /* (54) refact ::= SET DEFAULT */
   -1,  /* (55) refact ::= CASCADE */
   -1,  /* (56) refact ::= RESTRICT */
   -2,  /* (57) refact ::= NO ACTION */
   -3,  /* (58) defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */
   -2,  /* (59) defer_subclause ::= DEFERRABLE init_deferred_pred_opt */
    0,  /* (60) init_deferred_pred_opt ::= */
   -2,  /* (61) init_deferred_pred_opt ::= INITIALLY DEFERRED */
   -2,  /* (62) init_deferred_pred_opt ::= INITIALLY IMMEDIATE */
    0,  /* (63) conslist_opt ::= */
   -1,  /* (64) tconscomma ::= COMMA */
   -2,  /* (65) tcons ::= CONSTRAINT nm */
   -7,  /* (66) tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */
   -5,  /* (67) tcons ::= UNIQUE LP sortlist RP onconf */
   -5,  /* (68) tcons ::= CHECK LP expr RP onconf */
  -10,  /* (69) tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */
    0,  /* (70) defer_subclause_opt ::= */
    0,  /* (71) onconf ::= */
   -3,  /* (72) onconf ::= ON CONFLICT resolvetype */
    0,  /* (73) orconf ::= */
   -2,  /* (74) orconf ::= OR resolvetype */
   -1,  /* (75) resolvetype ::= IGNORE */
   -1,  /* (76) resolvetype ::= REPLACE */
   -4,  /* (77) cmd ::= DROP TABLE ifexists fullname */
   -2,  /* (78) ifexists ::= IF EXISTS */
    0,  /* (79) ifexists ::= */
   -9,  /* (80) cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */
   -4,  /* (81) cmd ::= DROP VIEW ifexists fullname */
   -1,  /* (82) cmd ::= select */
   -3,  /* (83) select ::= WITH wqlist selectnowith */
   -4,  /* (84) select ::= WITH RECURSIVE wqlist selectnowith */
   -1,  /* (85) select ::= selectnowith */
   -3,  /* (86) selectnowith ::= selectnowith multiselect_op oneselect */
   -1,  /* (87) multiselect_op ::= UNION */
   -2,  /* (88) multiselect_op ::= UNION ALL */
   -1,  /* (89) multiselect_op ::= EXCEPT|INTERSECT */
   -9,  /* (90) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
  -10,  /* (91) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */
   -4,  /* (92) values ::= VALUES LP nexprlist RP */
   -5,  /* (93) values ::= values COMMA LP nexprlist RP */
   -1,  /* (94) distinct ::= DISTINCT */
   -1,  /* (95) distinct ::= ALL */
    0,  /* (96) distinct ::= */
    0,  /* (97) sclp ::= */
   -5,  /* (98) selcollist ::= sclp scanpt expr scanpt as */
   -3,  /* (99) selcollist ::= sclp scanpt STAR */
   -5,  /* (100) selcollist ::= sclp scanpt nm DOT STAR */
   -2,  /* (101) as ::= AS nm */
    0,  /* (102) as ::= */
    0,  /* (103) from ::= */
   -2,  /* (104) from ::= FROM seltablist */
   -2,  /* (105) stl_prefix ::= seltablist joinop */
    0,  /* (106) stl_prefix ::= */
   -7,  /* (107) seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */
   -9,  /* (108) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt */
   -7,  /* (109) seltablist ::= stl_prefix LP select RP as on_opt using_opt */
   -7,  /* (110) seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */
    0,  /* (111) dbnm ::= */
   -2,  /* (112) dbnm ::= DOT nm */
   -1,  /* (113) fullname ::= nm */
   -3,  /* (114) fullname ::= nm DOT nm */
   -1,  /* (115) xfullname ::= nm */
   -3,  /* (116) xfullname ::= nm DOT nm */
   -5,  /* (117) xfullname ::= nm DOT nm AS nm */
   -3,  /* (118) xfullname ::= nm AS nm */
   -1,  /* (119) joinop ::= COMMA|JOIN */
   -2,  /* (120) joinop ::= JOIN_KW JOIN */
   -3,  /* (121) joinop ::= JOIN_KW nm JOIN */
   -4,  /* (122) joinop ::= JOIN_KW nm nm JOIN */
   -2,  /* (123) on_opt ::= ON expr */
    0,  /* (124) on_opt ::= */
    0,  /* (125) indexed_opt ::= */
   -3,  /* (126) indexed_opt ::= INDEXED BY nm */
   -2,  /* (127) indexed_opt ::= NOT INDEXED */
   -4,  /* (128) using_opt ::= USING LP idlist RP */
    0,  /* (129) using_opt ::= */
    0,  /* (130) orderby_opt ::= */
   -3,  /* (131) orderby_opt ::= ORDER BY sortlist */
   -5,  /* (132) sortlist ::= sortlist COMMA expr sortorder nulls */
   -3,  /* (133) sortlist ::= expr sortorder nulls */
   -1,  /* (134) sortorder ::= ASC */
   -1,  /* (135) sortorder ::= DESC */
    0,  /* (136) sortorder ::= */
   -2,  /* (137) nulls ::= NULLS FIRST */
   -2,  /* (138) nulls ::= NULLS LAST */
    0,  /* (139) nulls ::= */
    0,  /* (140) groupby_opt ::= */
   -3,  /* (141) groupby_opt ::= GROUP BY nexprlist */
    0,  /* (142) having_opt ::= */
   -2,  /* (143) having_opt ::= HAVING expr */
    0,  /* (144) limit_opt ::= */
   -2,  /* (145) limit_opt ::= LIMIT expr */
   -4,  /* (146) limit_opt ::= LIMIT expr OFFSET expr */
   -4,  /* (147) limit_opt ::= LIMIT expr COMMA expr */
   -6,  /* (148) cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret */
    0,  /* (149) where_opt ::= */
   -2,  /* (150) where_opt ::= WHERE expr */
    0,  /* (151) where_opt_ret ::= */
   -2,  /* (152) where_opt_ret ::= WHERE expr */
   -2,  /* (153) where_opt_ret ::= RETURNING selcollist */
   -4,  /* (154) where_opt_ret ::= WHERE expr RETURNING selcollist */
   -9,  /* (155) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret */
   -5,  /* (156) setlist ::= setlist COMMA nm EQ expr */
   -7,  /* (157) setlist ::= setlist COMMA LP idlist RP EQ expr */
   -3,  /* (158) setlist ::= nm EQ expr */
   -5,  /* (159) setlist ::= LP idlist RP EQ expr */
   -7,  /* (160) cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */
   -8,  /* (161) cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */
    0,  /* (162) upsert ::= */
   -2,  /* (163) upsert ::= RETURNING selcollist */
  -12,  /* (164) upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */
   -9,  /* (165) upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */
   -5,  /* (166) upsert ::= ON CONFLICT DO NOTHING returning */
   -8,  /* (167) upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */
   -2,  /* (168) returning ::= RETURNING selcollist */
   -2,  /* (169) insert_cmd ::= INSERT orconf */
   -1,  /* (170) insert_cmd ::= REPLACE */
    0,  /* (171) idlist_opt ::= */
   -3,  /* (172) idlist_opt ::= LP idlist RP */
   -3,  /* (173) idlist ::= idlist COMMA nm */
   -1,  /* (174) idlist ::= nm */
   -3,  /* (175) expr ::= LP expr RP */
   -1,  /* (176) expr ::= ID|INDEXED */
   -1,  /* (177) expr ::= JOIN_KW */
   -3,  /* (178) expr ::= nm DOT nm */
   -5,  /* (179) expr ::= nm DOT nm DOT nm */
   -1,  /* (180) term ::= NULL|FLOAT|BLOB */
   -1,  /* (181) term ::= STRING */
   -1,  /* (182) term ::= INTEGER */
   -1,  /* (183) expr ::= VARIABLE */
   -3,  /* (184) expr ::= expr COLLATE ID|STRING */
   -6,  /* (185) expr ::= CAST LP expr AS typetoken RP */
   -5,  /* (186) expr ::= ID|INDEXED LP distinct exprlist RP */
   -4,  /* (187) expr ::= ID|INDEXED LP STAR RP */
   -6,  /* (188) expr ::= ID|INDEXED LP distinct exprlist RP filter_over */
   -5,  /* (189) expr ::= ID|INDEXED LP STAR RP filter_over */
   -1,  /* (190) term ::= CTIME_KW */
   -5,  /* (191) expr ::= LP nexprlist COMMA expr RP */
   -3,  /* (192) expr ::= expr AND expr */
   -3,  /* (193) expr ::= expr OR expr */
   -3,  /* (194) expr ::= expr LT|GT|GE|LE expr */
   -3,  /* (195) expr ::= expr EQ|NE expr */
   -3,  /* (196) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */
   -3,  /* (197) expr ::= expr PLUS|MINUS expr */
   -3,  /* (198) expr ::= expr STAR|SLASH|REM expr */
   -3,  /* (199) expr ::= expr CONCAT expr */
   -2,  /* (200) likeop ::= NOT LIKE_KW|MATCH */
   -3,  /* (201) expr ::= expr likeop expr */
   -5,  /* (202) expr ::= expr likeop expr ESCAPE expr */
   -2,  /* (203) expr ::= expr ISNULL|NOTNULL */
   -3,  /* (204) expr ::= expr NOT NULL */
   -3,  /* (205) expr ::= expr IS expr */
   -4,  /* (206) expr ::= expr IS NOT expr */
   -2,  /* (207) expr ::= NOT expr */
   -2,  /* (208) expr ::= BITNOT expr */
   -2,  /* (209) expr ::= PLUS|MINUS expr */
   -1,  /* (210) between_op ::= BETWEEN */
   -2,  /* (211) between_op ::= NOT BETWEEN */
   -5,  /* (212) expr ::= expr between_op expr AND expr */
   -1,  /* (213) in_op ::= IN */
   -2,  /* (214) in_op ::= NOT IN */
   -5,  /* (215) expr ::= expr in_op LP exprlist RP */
   -3,  /* (216) expr ::= LP select RP */
   -5,  /* (217) expr ::= expr in_op LP select RP */
   -5,  /* (218) expr ::= expr in_op nm dbnm paren_exprlist */
   -4,  /* (219) expr ::= EXISTS LP select RP */
   -5,  /* (220) expr ::= CASE case_operand case_exprlist case_else END */
   -5,  /* (221) case_exprlist ::= case_exprlist WHEN expr THEN expr */
   -4,  /* (222) case_exprlist ::= WHEN expr THEN expr */
   -2,  /* (223) case_else ::= ELSE expr */
    0,  /* (224) case_else ::= */
   -1,  /* (225) case_operand ::= expr */
    0,  /* (226) case_operand ::= */
    0,  /* (227) exprlist ::= */
   -3,  /* (228) nexprlist ::= nexprlist COMMA expr */
   -1,  /* (229) nexprlist ::= expr */
    0,  /* (230) paren_exprlist ::= */
   -3,  /* (231) paren_exprlist ::= LP exprlist RP */
  -12,  /* (232) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
   -1,  /* (233) uniqueflag ::= UNIQUE */
    0,  /* (234) uniqueflag ::= */
    0,  /* (235) eidlist_opt ::= */
   -3,  /* (236) eidlist_opt ::= LP eidlist RP */
   -5,  /* (237) eidlist ::= eidlist COMMA nm collate sortorder */
   -3,  /* (238) eidlist ::= nm collate sortorder */
    0,  /* (239) collate ::= */
   -2,  /* (240) collate ::= COLLATE ID|STRING */
   -4,  /* (241) cmd ::= DROP INDEX ifexists fullname */
   -2,  /* (242) cmd ::= VACUUM vinto */
   -3,  /* (243) cmd ::= VACUUM nm vinto */
   -2,  /* (244) vinto ::= INTO expr */
    0,  /* (245) vinto ::= */
   -3,  /* (246) cmd ::= PRAGMA nm dbnm */
   -5,  /* (247) cmd ::= PRAGMA nm dbnm EQ nmnum */
   -6,  /* (248) cmd ::= PRAGMA nm dbnm LP nmnum RP */
   -5,  /* (249) cmd ::= PRAGMA nm dbnm EQ minus_num */
   -6,  /* (250) cmd ::= PRAGMA nm dbnm LP minus_num RP */
   -2,  /* (251) plus_num ::= PLUS INTEGER|FLOAT */
   -2,  /* (252) minus_num ::= MINUS INTEGER|FLOAT */
   -5,  /* (253) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
  -11,  /* (254) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
   -1,  /* (255) trigger_time ::= BEFORE|AFTER */
   -2,  /* (256) trigger_time ::= INSTEAD OF */
    0,  /* (257) trigger_time ::= */
   -1,  /* (258) trigger_event ::= DELETE|INSERT */
   -1,  /* (259) trigger_event ::= UPDATE */
   -3,  /* (260) trigger_event ::= UPDATE OF idlist */
    0,  /* (261) when_clause ::= */
   -2,  /* (262) when_clause ::= WHEN expr */
   -3,  /* (263) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
   -2,  /* (264) trigger_cmd_list ::= trigger_cmd SEMI */
   -3,  /* (265) trnm ::= nm DOT nm */
   -3,  /* (266) tridxby ::= INDEXED BY nm */
   -2,  /* (267) tridxby ::= NOT INDEXED */
   -9,  /* (268) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */
   -8,  /* (269) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */
   -6,  /* (270) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */
   -3,  /* (271) trigger_cmd ::= scanpt select scanpt */
   -4,  /* (272) expr ::= RAISE LP IGNORE RP */
   -6,  /* (273) expr ::= RAISE LP raisetype COMMA nm RP */
   -1,  /* (274) raisetype ::= ROLLBACK */
   -1,  /* (275) raisetype ::= ABORT */
   -1,  /* (276) raisetype ::= FAIL */
   -4,  /* (277) cmd ::= DROP TRIGGER ifexists fullname */
   -6,  /* (278) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
   -3,  /* (279) cmd ::= DETACH database_kw_opt expr */
    0,  /* (280) key_opt ::= */
   -2,  /* (281) key_opt ::= KEY expr */
   -1,  /* (282) cmd ::= REINDEX */
   -3,  /* (283) cmd ::= REINDEX nm dbnm */
   -1,  /* (284) cmd ::= ANALYZE */
   -3,  /* (285) cmd ::= ANALYZE nm dbnm */
   -6,  /* (286) cmd ::= ALTER TABLE fullname RENAME TO nm */
   -7,  /* (287) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */
   -6,  /* (288) cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */
   -1,  /* (289) add_column_fullname ::= fullname */
   -8,  /* (290) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */
   -1,  /* (291) cmd ::= create_vtab */
   -4,  /* (292) cmd ::= create_vtab LP vtabarglist RP */
   -8,  /* (293) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
    0,  /* (294) vtabarg ::= */
   -1,  /* (295) vtabargtoken ::= ANY */
   -3,  /* (296) vtabargtoken ::= lp anylist RP */
   -1,  /* (297) lp ::= LP */
   -2,  /* (298) with ::= WITH wqlist */
   -3,  /* (299) with ::= WITH RECURSIVE wqlist */
   -1,  /* (300) wqas ::= AS */
   -2,  /* (301) wqas ::= AS MATERIALIZED */
   -3,  /* (302) wqas ::= AS NOT MATERIALIZED */
   -6,  /* (303) wqitem ::= nm eidlist_opt wqas LP select RP */
   -1,  /* (304) wqlist ::= wqitem */
   -3,  /* (305) wqlist ::= wqlist COMMA wqitem */
   -1,  /* (306) windowdefn_list ::= windowdefn */
   -3,  /* (307) windowdefn_list ::= windowdefn_list COMMA windowdefn */
   -5,  /* (308) windowdefn ::= nm AS LP window RP */
   -5,  /* (309) window ::= PARTITION BY nexprlist orderby_opt frame_opt */
   -6,  /* (310) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */
   -4,  /* (311) window ::= ORDER BY sortlist frame_opt */
   -5,  /* (312) window ::= nm ORDER BY sortlist frame_opt */
   -1,  /* (313) window ::= frame_opt */
   -2,  /* (314) window ::= nm frame_opt */
    0,  /* (315) frame_opt ::= */
   -3,  /* (316) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */
   -6,  /* (317) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */
   -1,  /* (318) range_or_rows ::= RANGE|ROWS|GROUPS */
   -1,  /* (319) frame_bound_s ::= frame_bound */
   -2,  /* (320) frame_bound_s ::= UNBOUNDED PRECEDING */
   -1,  /* (321) frame_bound_e ::= frame_bound */
   -2,  /* (322) frame_bound_e ::= UNBOUNDED FOLLOWING */
   -2,  /* (323) frame_bound ::= expr PRECEDING|FOLLOWING */
   -2,  /* (324) frame_bound ::= CURRENT ROW */
    0,  /* (325) frame_exclude_opt ::= */
   -2,  /* (326) frame_exclude_opt ::= EXCLUDE frame_exclude */
   -2,  /* (327) frame_exclude ::= NO OTHERS */
   -2,  /* (328) frame_exclude ::= CURRENT ROW */
   -1,  /* (329) frame_exclude ::= GROUP|TIES */
   -2,  /* (330) window_clause ::= WINDOW windowdefn_list */
   -2,  /* (331) filter_over ::= filter_clause over_clause */
   -1,  /* (332) filter_over ::= over_clause */
   -1,  /* (333) filter_over ::= filter_clause */
   -4,  /* (334) over_clause ::= OVER LP window RP */
   -2,  /* (335) over_clause ::= OVER nm */
   -5,  /* (336) filter_clause ::= FILTER LP WHERE expr RP */
   -1,  /* (337) input ::= cmdlist */
   -2,  /* (338) cmdlist ::= cmdlist ecmd */
   -1,  /* (339) cmdlist ::= ecmd */
   -1,  /* (340) ecmd ::= SEMI */
   -2,  /* (341) ecmd ::= cmdx SEMI */
   -3,  /* (342) ecmd ::= explain cmdx SEMI */
    0,  /* (343) trans_opt ::= */
   -1,  /* (344) trans_opt ::= TRANSACTION */
   -2,  /* (345) trans_opt ::= TRANSACTION nm */
   -1,  /* (346) savepoint_opt ::= SAVEPOINT */
    0,  /* (347) savepoint_opt ::= */
   -2,  /* (348) cmd ::= create_table create_table_args */

   -4,  /* (349) columnlist ::= columnlist COMMA columnname carglist */
   -2,  /* (350) columnlist ::= columnname carglist */
   -1,  /* (351) nm ::= ID|INDEXED */
   -1,  /* (352) nm ::= STRING */
   -1,  /* (353) nm ::= JOIN_KW */
   -1,  /* (354) typetoken ::= typename */
   -1,  /* (355) typename ::= ID|STRING */
   -1,  /* (356) signed ::= plus_num */
   -1,  /* (357) signed ::= minus_num */
   -2,  /* (358) carglist ::= carglist ccons */
    0,  /* (359) carglist ::= */
   -2,  /* (360) ccons ::= NULL onconf */
   -4,  /* (361) ccons ::= GENERATED ALWAYS AS generated */
   -2,  /* (362) ccons ::= AS generated */
   -2,  /* (363) conslist_opt ::= COMMA conslist */
   -3,  /* (364) conslist ::= conslist tconscomma tcons */
   -1,  /* (365) conslist ::= tcons */
    0,  /* (366) tconscomma ::= */
   -1,  /* (367) defer_subclause_opt ::= defer_subclause */
   -1,  /* (368) resolvetype ::= raisetype */
   -1,  /* (369) selectnowith ::= oneselect */
   -1,  /* (370) oneselect ::= values */
   -2,  /* (371) sclp ::= selcollist COMMA */
   -1,  /* (372) as ::= ID|STRING */
    0,  /* (373) returning ::= */
   -1,  /* (374) expr ::= term */
   -1,  /* (375) likeop ::= LIKE_KW|MATCH */
   -1,  /* (376) exprlist ::= nexprlist */
   -1,  /* (377) nmnum ::= plus_num */
   -1,  /* (378) nmnum ::= nm */
   -1,  /* (379) nmnum ::= ON */
   -1,  /* (380) nmnum ::= DELETE */
   -1,  /* (381) nmnum ::= DEFAULT */
   -1,  /* (382) plus_num ::= INTEGER|FLOAT */
    0,  /* (383) foreach_clause ::= */
   -3,  /* (384) foreach_clause ::= FOR EACH ROW */
   -1,  /* (385) trnm ::= nm */
    0,  /* (386) tridxby ::= */
   -1,  /* (387) database_kw_opt ::= DATABASE */
    0,  /* (388) database_kw_opt ::= */
    0,  /* (389) kwcolumn_opt ::= */
   -1,  /* (390) kwcolumn_opt ::= COLUMNKW */
   -1,  /* (391) vtabarglist ::= vtabarg */
   -3,  /* (392) vtabarglist ::= vtabarglist COMMA vtabarg */
   -2,  /* (393) vtabarg ::= vtabarg vtabargtoken */
    0,  /* (394) anylist ::= */
   -4,  /* (395) anylist ::= anylist LP anylist RP */
   -2,  /* (396) anylist ::= anylist ANY */
    0,  /* (397) with ::= */
};

static void yy_accept(yyParser*);  /* Forward Declaration */

/*
** Perform a reduce action and the shift that must immediately
** follow the reduce.







|

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







161841
161842
161843
161844
161845
161846
161847
161848
161849
161850
161851
161852
161853
161854
161855
161856
161857
161858
161859
161860
161861
161862
161863
161864
161865
161866
161867
161868
161869
161870
161871
161872
161873
161874
161875
161876
161877
161878
161879
161880
161881
161882
161883
161884
161885
161886
161887
161888
161889
161890
161891
161892
161893
161894
161895
161896
161897
161898
161899
161900
161901
161902
161903
161904
161905
161906
161907
161908
161909
161910
161911
161912
161913
161914
161915
161916
161917
161918
161919
161920
161921
161922
161923
161924
161925
161926
161927
161928
161929
161930
161931
161932
161933
161934
161935
161936
161937
161938
161939
161940
161941
161942
161943
161944
161945
161946
161947
161948
161949
161950
161951
161952
161953
161954
161955
161956
161957
161958
161959
161960
161961
161962
161963
161964
161965
161966
161967
161968
161969
161970
161971
161972
161973
161974
161975
161976
161977
161978
161979
161980
161981
161982
161983
161984
161985
161986
161987
161988
161989
161990
161991
161992
161993
161994
161995
161996
161997
161998
161999
162000
162001
162002
162003
162004
162005
162006
162007
162008
162009
162010
162011
162012
162013
162014
162015
162016
162017
162018
162019
162020
162021
162022
162023
162024
162025
162026
162027
162028
162029
162030
162031
162032
162033
162034
162035
162036
162037
162038
162039
162040
162041
162042
162043
162044
162045
162046
162047
162048
162049
162050
162051
162052
162053
162054
162055
162056
162057
162058
162059
162060
162061
162062
162063
162064
162065
162066
162067
162068
162069
162070
162071
162072
162073
162074
162075
162076
162077
162078
162079
162080
162081
162082
162083
162084
162085
162086
162087
162088
162089
162090
162091
162092
162093
162094
162095
162096
162097
162098
162099
162100
162101
162102
162103
162104
162105
162106
162107
162108
162109
162110
162111
162112
162113
162114
162115
162116
162117
162118
162119
162120
162121
162122
162123
162124
162125
162126
162127
162128
162129
162130
162131
162132
162133
162134
162135
162136
162137
162138
162139
162140
162141
162142
162143
162144
162145
162146
162147
162148
162149
162150
162151
162152
162153
162154
162155
162156
162157
162158
162159
162160
162161
162162
162163
162164
162165
162166
162167
162168
162169
162170
162171
162172
162173
162174
162175
162176
162177
162178
162179
162180
162181
162182
162183
162184
162185
162186
162187
162188
162189
162190
162191
162192
162193
162194
162195
162196
162197
162198
162199
162200
162201
162202
162203
162204
162205
162206
162207
162208
162209
162210
162211
162212
162213
162214
162215
162216
162217
162218
162219
162220
162221
162222
162223
162224
162225
162226
162227
162228
162229
162230
162231
162232
162233
162234
162235
162236
   -5,  /* (12) cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */
   -6,  /* (13) create_table ::= createkw temp TABLE ifnotexists nm dbnm */
   -1,  /* (14) createkw ::= CREATE */
    0,  /* (15) ifnotexists ::= */
   -3,  /* (16) ifnotexists ::= IF NOT EXISTS */
   -1,  /* (17) temp ::= TEMP */
    0,  /* (18) temp ::= */
   -5,  /* (19) create_table_args ::= LP columnlist conslist_opt RP table_option_set */
   -2,  /* (20) create_table_args ::= AS select */
    0,  /* (21) table_option_set ::= */
   -3,  /* (22) table_option_set ::= table_option_set COMMA table_option */
   -2,  /* (23) table_option ::= WITHOUT nm */
   -1,  /* (24) table_option ::= nm */
   -2,  /* (25) columnname ::= nm typetoken */
    0,  /* (26) typetoken ::= */
   -4,  /* (27) typetoken ::= typename LP signed RP */
   -6,  /* (28) typetoken ::= typename LP signed COMMA signed RP */
   -2,  /* (29) typename ::= typename ID|STRING */
    0,  /* (30) scanpt ::= */
    0,  /* (31) scantok ::= */
   -2,  /* (32) ccons ::= CONSTRAINT nm */
   -3,  /* (33) ccons ::= DEFAULT scantok term */
   -4,  /* (34) ccons ::= DEFAULT LP expr RP */
   -4,  /* (35) ccons ::= DEFAULT PLUS scantok term */
   -4,  /* (36) ccons ::= DEFAULT MINUS scantok term */
   -3,  /* (37) ccons ::= DEFAULT scantok ID|INDEXED */
   -3,  /* (38) ccons ::= NOT NULL onconf */
   -5,  /* (39) ccons ::= PRIMARY KEY sortorder onconf autoinc */
   -2,  /* (40) ccons ::= UNIQUE onconf */
   -4,  /* (41) ccons ::= CHECK LP expr RP */
   -4,  /* (42) ccons ::= REFERENCES nm eidlist_opt refargs */
   -1,  /* (43) ccons ::= defer_subclause */
   -2,  /* (44) ccons ::= COLLATE ID|STRING */
   -3,  /* (45) generated ::= LP expr RP */
   -4,  /* (46) generated ::= LP expr RP ID */
    0,  /* (47) autoinc ::= */
   -1,  /* (48) autoinc ::= AUTOINCR */
    0,  /* (49) refargs ::= */
   -2,  /* (50) refargs ::= refargs refarg */
   -2,  /* (51) refarg ::= MATCH nm */
   -3,  /* (52) refarg ::= ON INSERT refact */
   -3,  /* (53) refarg ::= ON DELETE refact */
   -3,  /* (54) refarg ::= ON UPDATE refact */
   -2,  /* (55) refact ::= SET NULL */
   -2,  /* (56) refact ::= SET DEFAULT */
   -1,  /* (57) refact ::= CASCADE */
   -1,  /* (58) refact ::= RESTRICT */
   -2,  /* (59) refact ::= NO ACTION */
   -3,  /* (60) defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */
   -2,  /* (61) defer_subclause ::= DEFERRABLE init_deferred_pred_opt */
    0,  /* (62) init_deferred_pred_opt ::= */
   -2,  /* (63) init_deferred_pred_opt ::= INITIALLY DEFERRED */
   -2,  /* (64) init_deferred_pred_opt ::= INITIALLY IMMEDIATE */
    0,  /* (65) conslist_opt ::= */
   -1,  /* (66) tconscomma ::= COMMA */
   -2,  /* (67) tcons ::= CONSTRAINT nm */
   -7,  /* (68) tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */
   -5,  /* (69) tcons ::= UNIQUE LP sortlist RP onconf */
   -5,  /* (70) tcons ::= CHECK LP expr RP onconf */
  -10,  /* (71) tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */
    0,  /* (72) defer_subclause_opt ::= */
    0,  /* (73) onconf ::= */
   -3,  /* (74) onconf ::= ON CONFLICT resolvetype */
    0,  /* (75) orconf ::= */
   -2,  /* (76) orconf ::= OR resolvetype */
   -1,  /* (77) resolvetype ::= IGNORE */
   -1,  /* (78) resolvetype ::= REPLACE */
   -4,  /* (79) cmd ::= DROP TABLE ifexists fullname */
   -2,  /* (80) ifexists ::= IF EXISTS */
    0,  /* (81) ifexists ::= */
   -9,  /* (82) cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */
   -4,  /* (83) cmd ::= DROP VIEW ifexists fullname */
   -1,  /* (84) cmd ::= select */
   -3,  /* (85) select ::= WITH wqlist selectnowith */
   -4,  /* (86) select ::= WITH RECURSIVE wqlist selectnowith */
   -1,  /* (87) select ::= selectnowith */
   -3,  /* (88) selectnowith ::= selectnowith multiselect_op oneselect */
   -1,  /* (89) multiselect_op ::= UNION */
   -2,  /* (90) multiselect_op ::= UNION ALL */
   -1,  /* (91) multiselect_op ::= EXCEPT|INTERSECT */
   -9,  /* (92) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
  -10,  /* (93) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */
   -4,  /* (94) values ::= VALUES LP nexprlist RP */
   -5,  /* (95) values ::= values COMMA LP nexprlist RP */
   -1,  /* (96) distinct ::= DISTINCT */
   -1,  /* (97) distinct ::= ALL */
    0,  /* (98) distinct ::= */
    0,  /* (99) sclp ::= */
   -5,  /* (100) selcollist ::= sclp scanpt expr scanpt as */
   -3,  /* (101) selcollist ::= sclp scanpt STAR */
   -5,  /* (102) selcollist ::= sclp scanpt nm DOT STAR */
   -2,  /* (103) as ::= AS nm */
    0,  /* (104) as ::= */
    0,  /* (105) from ::= */
   -2,  /* (106) from ::= FROM seltablist */
   -2,  /* (107) stl_prefix ::= seltablist joinop */
    0,  /* (108) stl_prefix ::= */
   -7,  /* (109) seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */
   -9,  /* (110) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt */
   -7,  /* (111) seltablist ::= stl_prefix LP select RP as on_opt using_opt */
   -7,  /* (112) seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */
    0,  /* (113) dbnm ::= */
   -2,  /* (114) dbnm ::= DOT nm */
   -1,  /* (115) fullname ::= nm */
   -3,  /* (116) fullname ::= nm DOT nm */
   -1,  /* (117) xfullname ::= nm */
   -3,  /* (118) xfullname ::= nm DOT nm */
   -5,  /* (119) xfullname ::= nm DOT nm AS nm */
   -3,  /* (120) xfullname ::= nm AS nm */
   -1,  /* (121) joinop ::= COMMA|JOIN */
   -2,  /* (122) joinop ::= JOIN_KW JOIN */
   -3,  /* (123) joinop ::= JOIN_KW nm JOIN */
   -4,  /* (124) joinop ::= JOIN_KW nm nm JOIN */
   -2,  /* (125) on_opt ::= ON expr */
    0,  /* (126) on_opt ::= */
    0,  /* (127) indexed_opt ::= */
   -3,  /* (128) indexed_opt ::= INDEXED BY nm */
   -2,  /* (129) indexed_opt ::= NOT INDEXED */
   -4,  /* (130) using_opt ::= USING LP idlist RP */
    0,  /* (131) using_opt ::= */
    0,  /* (132) orderby_opt ::= */
   -3,  /* (133) orderby_opt ::= ORDER BY sortlist */
   -5,  /* (134) sortlist ::= sortlist COMMA expr sortorder nulls */
   -3,  /* (135) sortlist ::= expr sortorder nulls */
   -1,  /* (136) sortorder ::= ASC */
   -1,  /* (137) sortorder ::= DESC */
    0,  /* (138) sortorder ::= */
   -2,  /* (139) nulls ::= NULLS FIRST */
   -2,  /* (140) nulls ::= NULLS LAST */
    0,  /* (141) nulls ::= */
    0,  /* (142) groupby_opt ::= */
   -3,  /* (143) groupby_opt ::= GROUP BY nexprlist */
    0,  /* (144) having_opt ::= */
   -2,  /* (145) having_opt ::= HAVING expr */
    0,  /* (146) limit_opt ::= */
   -2,  /* (147) limit_opt ::= LIMIT expr */
   -4,  /* (148) limit_opt ::= LIMIT expr OFFSET expr */
   -4,  /* (149) limit_opt ::= LIMIT expr COMMA expr */
   -6,  /* (150) cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret */
    0,  /* (151) where_opt ::= */
   -2,  /* (152) where_opt ::= WHERE expr */
    0,  /* (153) where_opt_ret ::= */
   -2,  /* (154) where_opt_ret ::= WHERE expr */
   -2,  /* (155) where_opt_ret ::= RETURNING selcollist */
   -4,  /* (156) where_opt_ret ::= WHERE expr RETURNING selcollist */
   -9,  /* (157) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret */
   -5,  /* (158) setlist ::= setlist COMMA nm EQ expr */
   -7,  /* (159) setlist ::= setlist COMMA LP idlist RP EQ expr */
   -3,  /* (160) setlist ::= nm EQ expr */
   -5,  /* (161) setlist ::= LP idlist RP EQ expr */
   -7,  /* (162) cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */
   -8,  /* (163) cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */
    0,  /* (164) upsert ::= */
   -2,  /* (165) upsert ::= RETURNING selcollist */
  -12,  /* (166) upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */
   -9,  /* (167) upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */
   -5,  /* (168) upsert ::= ON CONFLICT DO NOTHING returning */
   -8,  /* (169) upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */
   -2,  /* (170) returning ::= RETURNING selcollist */
   -2,  /* (171) insert_cmd ::= INSERT orconf */
   -1,  /* (172) insert_cmd ::= REPLACE */
    0,  /* (173) idlist_opt ::= */
   -3,  /* (174) idlist_opt ::= LP idlist RP */
   -3,  /* (175) idlist ::= idlist COMMA nm */
   -1,  /* (176) idlist ::= nm */
   -3,  /* (177) expr ::= LP expr RP */
   -1,  /* (178) expr ::= ID|INDEXED */
   -1,  /* (179) expr ::= JOIN_KW */
   -3,  /* (180) expr ::= nm DOT nm */
   -5,  /* (181) expr ::= nm DOT nm DOT nm */
   -1,  /* (182) term ::= NULL|FLOAT|BLOB */
   -1,  /* (183) term ::= STRING */
   -1,  /* (184) term ::= INTEGER */
   -1,  /* (185) expr ::= VARIABLE */
   -3,  /* (186) expr ::= expr COLLATE ID|STRING */
   -6,  /* (187) expr ::= CAST LP expr AS typetoken RP */
   -5,  /* (188) expr ::= ID|INDEXED LP distinct exprlist RP */
   -4,  /* (189) expr ::= ID|INDEXED LP STAR RP */
   -6,  /* (190) expr ::= ID|INDEXED LP distinct exprlist RP filter_over */
   -5,  /* (191) expr ::= ID|INDEXED LP STAR RP filter_over */
   -1,  /* (192) term ::= CTIME_KW */
   -5,  /* (193) expr ::= LP nexprlist COMMA expr RP */
   -3,  /* (194) expr ::= expr AND expr */
   -3,  /* (195) expr ::= expr OR expr */
   -3,  /* (196) expr ::= expr LT|GT|GE|LE expr */
   -3,  /* (197) expr ::= expr EQ|NE expr */
   -3,  /* (198) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */
   -3,  /* (199) expr ::= expr PLUS|MINUS expr */
   -3,  /* (200) expr ::= expr STAR|SLASH|REM expr */
   -3,  /* (201) expr ::= expr CONCAT expr */
   -2,  /* (202) likeop ::= NOT LIKE_KW|MATCH */
   -3,  /* (203) expr ::= expr likeop expr */
   -5,  /* (204) expr ::= expr likeop expr ESCAPE expr */
   -2,  /* (205) expr ::= expr ISNULL|NOTNULL */
   -3,  /* (206) expr ::= expr NOT NULL */
   -3,  /* (207) expr ::= expr IS expr */
   -4,  /* (208) expr ::= expr IS NOT expr */
   -2,  /* (209) expr ::= NOT expr */
   -2,  /* (210) expr ::= BITNOT expr */
   -2,  /* (211) expr ::= PLUS|MINUS expr */
   -1,  /* (212) between_op ::= BETWEEN */
   -2,  /* (213) between_op ::= NOT BETWEEN */
   -5,  /* (214) expr ::= expr between_op expr AND expr */
   -1,  /* (215) in_op ::= IN */
   -2,  /* (216) in_op ::= NOT IN */
   -5,  /* (217) expr ::= expr in_op LP exprlist RP */
   -3,  /* (218) expr ::= LP select RP */
   -5,  /* (219) expr ::= expr in_op LP select RP */
   -5,  /* (220) expr ::= expr in_op nm dbnm paren_exprlist */
   -4,  /* (221) expr ::= EXISTS LP select RP */
   -5,  /* (222) expr ::= CASE case_operand case_exprlist case_else END */
   -5,  /* (223) case_exprlist ::= case_exprlist WHEN expr THEN expr */
   -4,  /* (224) case_exprlist ::= WHEN expr THEN expr */
   -2,  /* (225) case_else ::= ELSE expr */
    0,  /* (226) case_else ::= */
   -1,  /* (227) case_operand ::= expr */
    0,  /* (228) case_operand ::= */
    0,  /* (229) exprlist ::= */
   -3,  /* (230) nexprlist ::= nexprlist COMMA expr */
   -1,  /* (231) nexprlist ::= expr */
    0,  /* (232) paren_exprlist ::= */
   -3,  /* (233) paren_exprlist ::= LP exprlist RP */
  -12,  /* (234) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
   -1,  /* (235) uniqueflag ::= UNIQUE */
    0,  /* (236) uniqueflag ::= */
    0,  /* (237) eidlist_opt ::= */
   -3,  /* (238) eidlist_opt ::= LP eidlist RP */
   -5,  /* (239) eidlist ::= eidlist COMMA nm collate sortorder */
   -3,  /* (240) eidlist ::= nm collate sortorder */
    0,  /* (241) collate ::= */
   -2,  /* (242) collate ::= COLLATE ID|STRING */
   -4,  /* (243) cmd ::= DROP INDEX ifexists fullname */
   -2,  /* (244) cmd ::= VACUUM vinto */
   -3,  /* (245) cmd ::= VACUUM nm vinto */
   -2,  /* (246) vinto ::= INTO expr */
    0,  /* (247) vinto ::= */
   -3,  /* (248) cmd ::= PRAGMA nm dbnm */
   -5,  /* (249) cmd ::= PRAGMA nm dbnm EQ nmnum */
   -6,  /* (250) cmd ::= PRAGMA nm dbnm LP nmnum RP */
   -5,  /* (251) cmd ::= PRAGMA nm dbnm EQ minus_num */
   -6,  /* (252) cmd ::= PRAGMA nm dbnm LP minus_num RP */
   -2,  /* (253) plus_num ::= PLUS INTEGER|FLOAT */
   -2,  /* (254) minus_num ::= MINUS INTEGER|FLOAT */
   -5,  /* (255) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
  -11,  /* (256) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
   -1,  /* (257) trigger_time ::= BEFORE|AFTER */
   -2,  /* (258) trigger_time ::= INSTEAD OF */
    0,  /* (259) trigger_time ::= */
   -1,  /* (260) trigger_event ::= DELETE|INSERT */
   -1,  /* (261) trigger_event ::= UPDATE */
   -3,  /* (262) trigger_event ::= UPDATE OF idlist */
    0,  /* (263) when_clause ::= */
   -2,  /* (264) when_clause ::= WHEN expr */
   -3,  /* (265) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
   -2,  /* (266) trigger_cmd_list ::= trigger_cmd SEMI */
   -3,  /* (267) trnm ::= nm DOT nm */
   -3,  /* (268) tridxby ::= INDEXED BY nm */
   -2,  /* (269) tridxby ::= NOT INDEXED */
   -9,  /* (270) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */
   -8,  /* (271) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */
   -6,  /* (272) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */
   -3,  /* (273) trigger_cmd ::= scanpt select scanpt */
   -4,  /* (274) expr ::= RAISE LP IGNORE RP */
   -6,  /* (275) expr ::= RAISE LP raisetype COMMA nm RP */
   -1,  /* (276) raisetype ::= ROLLBACK */
   -1,  /* (277) raisetype ::= ABORT */
   -1,  /* (278) raisetype ::= FAIL */
   -4,  /* (279) cmd ::= DROP TRIGGER ifexists fullname */
   -6,  /* (280) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
   -3,  /* (281) cmd ::= DETACH database_kw_opt expr */
    0,  /* (282) key_opt ::= */
   -2,  /* (283) key_opt ::= KEY expr */
   -1,  /* (284) cmd ::= REINDEX */
   -3,  /* (285) cmd ::= REINDEX nm dbnm */
   -1,  /* (286) cmd ::= ANALYZE */
   -3,  /* (287) cmd ::= ANALYZE nm dbnm */
   -6,  /* (288) cmd ::= ALTER TABLE fullname RENAME TO nm */
   -7,  /* (289) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */
   -6,  /* (290) cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */
   -1,  /* (291) add_column_fullname ::= fullname */
   -8,  /* (292) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */
   -1,  /* (293) cmd ::= create_vtab */
   -4,  /* (294) cmd ::= create_vtab LP vtabarglist RP */
   -8,  /* (295) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
    0,  /* (296) vtabarg ::= */
   -1,  /* (297) vtabargtoken ::= ANY */
   -3,  /* (298) vtabargtoken ::= lp anylist RP */
   -1,  /* (299) lp ::= LP */
   -2,  /* (300) with ::= WITH wqlist */
   -3,  /* (301) with ::= WITH RECURSIVE wqlist */
   -1,  /* (302) wqas ::= AS */
   -2,  /* (303) wqas ::= AS MATERIALIZED */
   -3,  /* (304) wqas ::= AS NOT MATERIALIZED */
   -6,  /* (305) wqitem ::= nm eidlist_opt wqas LP select RP */
   -1,  /* (306) wqlist ::= wqitem */
   -3,  /* (307) wqlist ::= wqlist COMMA wqitem */
   -1,  /* (308) windowdefn_list ::= windowdefn */
   -3,  /* (309) windowdefn_list ::= windowdefn_list COMMA windowdefn */
   -5,  /* (310) windowdefn ::= nm AS LP window RP */
   -5,  /* (311) window ::= PARTITION BY nexprlist orderby_opt frame_opt */
   -6,  /* (312) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */
   -4,  /* (313) window ::= ORDER BY sortlist frame_opt */
   -5,  /* (314) window ::= nm ORDER BY sortlist frame_opt */
   -1,  /* (315) window ::= frame_opt */
   -2,  /* (316) window ::= nm frame_opt */
    0,  /* (317) frame_opt ::= */
   -3,  /* (318) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */
   -6,  /* (319) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */
   -1,  /* (320) range_or_rows ::= RANGE|ROWS|GROUPS */
   -1,  /* (321) frame_bound_s ::= frame_bound */
   -2,  /* (322) frame_bound_s ::= UNBOUNDED PRECEDING */
   -1,  /* (323) frame_bound_e ::= frame_bound */
   -2,  /* (324) frame_bound_e ::= UNBOUNDED FOLLOWING */
   -2,  /* (325) frame_bound ::= expr PRECEDING|FOLLOWING */
   -2,  /* (326) frame_bound ::= CURRENT ROW */
    0,  /* (327) frame_exclude_opt ::= */
   -2,  /* (328) frame_exclude_opt ::= EXCLUDE frame_exclude */
   -2,  /* (329) frame_exclude ::= NO OTHERS */
   -2,  /* (330) frame_exclude ::= CURRENT ROW */
   -1,  /* (331) frame_exclude ::= GROUP|TIES */
   -2,  /* (332) window_clause ::= WINDOW windowdefn_list */
   -2,  /* (333) filter_over ::= filter_clause over_clause */
   -1,  /* (334) filter_over ::= over_clause */
   -1,  /* (335) filter_over ::= filter_clause */
   -4,  /* (336) over_clause ::= OVER LP window RP */
   -2,  /* (337) over_clause ::= OVER nm */
   -5,  /* (338) filter_clause ::= FILTER LP WHERE expr RP */
   -1,  /* (339) input ::= cmdlist */
   -2,  /* (340) cmdlist ::= cmdlist ecmd */
   -1,  /* (341) cmdlist ::= ecmd */
   -1,  /* (342) ecmd ::= SEMI */
   -2,  /* (343) ecmd ::= cmdx SEMI */
   -3,  /* (344) ecmd ::= explain cmdx SEMI */
    0,  /* (345) trans_opt ::= */
   -1,  /* (346) trans_opt ::= TRANSACTION */
   -2,  /* (347) trans_opt ::= TRANSACTION nm */
   -1,  /* (348) savepoint_opt ::= SAVEPOINT */
    0,  /* (349) savepoint_opt ::= */
   -2,  /* (350) cmd ::= create_table create_table_args */
   -1,  /* (351) table_option_set ::= table_option */
   -4,  /* (352) columnlist ::= columnlist COMMA columnname carglist */
   -2,  /* (353) columnlist ::= columnname carglist */
   -1,  /* (354) nm ::= ID|INDEXED */
   -1,  /* (355) nm ::= STRING */
   -1,  /* (356) nm ::= JOIN_KW */
   -1,  /* (357) typetoken ::= typename */
   -1,  /* (358) typename ::= ID|STRING */
   -1,  /* (359) signed ::= plus_num */
   -1,  /* (360) signed ::= minus_num */
   -2,  /* (361) carglist ::= carglist ccons */
    0,  /* (362) carglist ::= */
   -2,  /* (363) ccons ::= NULL onconf */
   -4,  /* (364) ccons ::= GENERATED ALWAYS AS generated */
   -2,  /* (365) ccons ::= AS generated */
   -2,  /* (366) conslist_opt ::= COMMA conslist */
   -3,  /* (367) conslist ::= conslist tconscomma tcons */
   -1,  /* (368) conslist ::= tcons */
    0,  /* (369) tconscomma ::= */
   -1,  /* (370) defer_subclause_opt ::= defer_subclause */
   -1,  /* (371) resolvetype ::= raisetype */
   -1,  /* (372) selectnowith ::= oneselect */
   -1,  /* (373) oneselect ::= values */
   -2,  /* (374) sclp ::= selcollist COMMA */
   -1,  /* (375) as ::= ID|STRING */
    0,  /* (376) returning ::= */
   -1,  /* (377) expr ::= term */
   -1,  /* (378) likeop ::= LIKE_KW|MATCH */
   -1,  /* (379) exprlist ::= nexprlist */
   -1,  /* (380) nmnum ::= plus_num */
   -1,  /* (381) nmnum ::= nm */
   -1,  /* (382) nmnum ::= ON */
   -1,  /* (383) nmnum ::= DELETE */
   -1,  /* (384) nmnum ::= DEFAULT */
   -1,  /* (385) plus_num ::= INTEGER|FLOAT */
    0,  /* (386) foreach_clause ::= */
   -3,  /* (387) foreach_clause ::= FOR EACH ROW */
   -1,  /* (388) trnm ::= nm */
    0,  /* (389) tridxby ::= */
   -1,  /* (390) database_kw_opt ::= DATABASE */
    0,  /* (391) database_kw_opt ::= */
    0,  /* (392) kwcolumn_opt ::= */
   -1,  /* (393) kwcolumn_opt ::= COLUMNKW */
   -1,  /* (394) vtabarglist ::= vtabarg */
   -3,  /* (395) vtabarglist ::= vtabarglist COMMA vtabarg */
   -2,  /* (396) vtabarg ::= vtabarg vtabargtoken */
    0,  /* (397) anylist ::= */
   -4,  /* (398) anylist ::= anylist LP anylist RP */
   -2,  /* (399) anylist ::= anylist ANY */
    0,  /* (400) with ::= */
};

static void yy_accept(yyParser*);  /* Forward Declaration */

/*
** Perform a reduce action and the shift that must immediately
** follow the reduce.
161774
161775
161776
161777
161778
161779
161780
161781
161782
161783
161784
161785
161786
161787
161788
161789
161790
161791
161792
161793
161794
161795
161796
161797
      case 1: /* explain ::= EXPLAIN QUERY PLAN */
{ pParse->explain = 2; }
        break;
      case 2: /* cmdx ::= cmd */
{ sqlite3FinishCoding(pParse); }
        break;
      case 3: /* cmd ::= BEGIN transtype trans_opt */
{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy376);}
        break;
      case 4: /* transtype ::= */
{yymsp[1].minor.yy376 = TK_DEFERRED;}
        break;
      case 5: /* transtype ::= DEFERRED */
      case 6: /* transtype ::= IMMEDIATE */ yytestcase(yyruleno==6);
      case 7: /* transtype ::= EXCLUSIVE */ yytestcase(yyruleno==7);
      case 318: /* range_or_rows ::= RANGE|ROWS|GROUPS */ yytestcase(yyruleno==318);
{yymsp[0].minor.yy376 = yymsp[0].major; /*A-overwrites-X*/}
        break;
      case 8: /* cmd ::= COMMIT|END trans_opt */
      case 9: /* cmd ::= ROLLBACK trans_opt */ yytestcase(yyruleno==9);
{sqlite3EndTransaction(pParse,yymsp[-1].major);}
        break;
      case 10: /* cmd ::= SAVEPOINT nm */
{







|


|




|
|







162274
162275
162276
162277
162278
162279
162280
162281
162282
162283
162284
162285
162286
162287
162288
162289
162290
162291
162292
162293
162294
162295
162296
162297
      case 1: /* explain ::= EXPLAIN QUERY PLAN */
{ pParse->explain = 2; }
        break;
      case 2: /* cmdx ::= cmd */
{ sqlite3FinishCoding(pParse); }
        break;
      case 3: /* cmd ::= BEGIN transtype trans_opt */
{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy64);}
        break;
      case 4: /* transtype ::= */
{yymsp[1].minor.yy64 = TK_DEFERRED;}
        break;
      case 5: /* transtype ::= DEFERRED */
      case 6: /* transtype ::= IMMEDIATE */ yytestcase(yyruleno==6);
      case 7: /* transtype ::= EXCLUSIVE */ yytestcase(yyruleno==7);
      case 320: /* range_or_rows ::= RANGE|ROWS|GROUPS */ yytestcase(yyruleno==320);
{yymsp[0].minor.yy64 = yymsp[0].major; /*A-overwrites-X*/}
        break;
      case 8: /* cmd ::= COMMIT|END trans_opt */
      case 9: /* cmd ::= ROLLBACK trans_opt */ yytestcase(yyruleno==9);
{sqlite3EndTransaction(pParse,yymsp[-1].major);}
        break;
      case 10: /* cmd ::= SAVEPOINT nm */
{
161806
161807
161808
161809
161810
161811
161812
161813
161814
161815
161816
161817
161818
161819
161820
161821
161822
161823
161824
161825
161826
161827
161828
161829
161830
161831
161832
161833
161834
161835
161836
161837
161838
161839
161840
161841
161842
161843
161844
161845
161846



161847




161848
161849
161850
161851
161852










161853
161854
161855

161856
161857
161858
161859
161860
161861
161862
161863
161864
161865
161866
161867
161868
161869
161870
161871
161872
161873
161874
161875
161876
161877
161878
161879
161880
161881
161882
161883
161884
161885
161886
161887
161888
161889
161890
161891
161892
161893
161894
161895
161896
161897
161898
161899
161900
161901
161902
161903
161904
161905
161906
161907
161908
161909
161910
161911
161912
161913
161914
161915
161916
161917
161918
161919
161920
161921
161922
161923
161924
161925
161926
161927
161928
161929
161930
161931
161932
161933
161934
161935
161936
161937
161938
161939
161940
161941
161942
161943
161944
161945
161946
161947
161948
161949
161950
161951
161952
161953
161954
161955
161956
161957
161958
161959
161960
161961
161962
161963
161964
161965
161966
161967
161968
161969
161970
161971
161972
161973
161974
161975
161976
161977
161978
161979
161980
161981
161982
161983
161984
161985
161986
161987
161988
161989
161990
161991
161992
161993
161994
161995
161996
161997
161998
161999
162000
162001
162002
162003
162004
162005
162006
162007
162008
162009
162010
162011
162012
162013
162014
162015
162016
162017
162018
162019
162020
162021
162022
162023
162024
162025
162026
162027
162028
162029
162030
162031
162032
162033
162034
162035
162036
162037
162038
162039
162040
162041
162042
162043
162044
162045
162046
162047
162048
162049
162050
162051
162052
162053
162054
162055
162056
162057
162058
162059
162060
162061
162062
162063
162064
162065
162066
162067
162068
162069
162070
162071
162072
162073
162074
162075
162076
162077
162078
162079
162080
162081
162082
162083
162084
162085
162086
162087
162088
162089
162090
162091
162092
162093
162094
162095
162096
162097
162098
162099
162100
162101
162102
162103
162104
162105
162106
162107
162108
162109
162110
162111
162112
162113
162114
162115
162116
162117
162118
162119
162120
162121
162122
162123
162124
162125
162126
162127
162128
162129
162130
162131
162132
162133
162134
162135
162136
162137
162138
162139
162140
162141
162142
162143
162144
162145
162146
162147
162148
162149
162150
162151
162152
162153
162154
162155
162156
162157
162158
162159
162160
162161
162162
162163
162164
162165
162166
162167
162168
162169
162170
162171
162172
162173
162174
162175
162176
162177
162178
162179
162180
162181
162182
162183
162184
162185
162186
162187
162188
162189
162190
162191
162192
162193
162194
162195
162196
162197
162198
162199
162200
162201
162202
162203
162204
162205
162206
162207
162208
162209
162210
162211
162212
162213
162214
162215
162216
162217
162218
162219
162220
162221
162222
162223
162224
162225
162226
162227
162228
162229
162230
162231
162232
162233
162234
162235
162236
162237
162238
162239
162240
162241
162242
162243
162244
162245
162246
162247
162248
162249
162250
162251
162252
162253
162254
162255
162256
162257
162258
162259
162260
162261
162262
162263
162264
162265
162266
162267
162268
162269
162270
162271
162272
162273
162274
162275
162276
162277
162278
162279
162280
162281
162282
162283
162284
162285
162286
162287
162288
162289
162290
162291
162292
162293
162294
162295
162296
162297
162298
162299
162300
162301
162302
162303
162304
162305
162306
162307
162308
162309
162310
162311
162312
162313
162314
162315
162316
162317
162318
162319
162320
162321
162322
162323
162324
162325
162326
162327
162328
162329
162330
162331
162332
162333
162334
162335
162336
162337
162338
162339
162340
162341
162342
162343
162344
162345
162346
162347
162348
162349
162350
162351
162352
162353
162354
162355
162356
162357
162358
162359
162360
162361
162362
162363
162364
162365
162366
162367
162368
162369
162370
162371
162372
162373
162374
162375
162376
162377
162378
162379
162380
162381
162382
162383
162384
162385
162386
162387
162388
162389
162390
162391
162392
162393
162394
162395
162396
162397
162398
162399
162400
162401
162402
162403
162404
162405
162406
162407
162408
162409
162410
162411
162412
162413
162414
162415
162416
162417
162418
162419
162420
162421
162422
162423
162424
162425
162426
162427
162428
162429
162430
162431
162432
162433
162434
162435
162436
162437
162438
162439
162440
162441
162442
162443
162444
162445
162446
162447
162448
162449
162450
162451
162452
162453
162454
162455
162456
162457
162458
162459
162460
162461
162462
162463
162464
162465
162466
162467
162468
162469
162470
162471
162472
162473
162474
162475
162476
162477
162478
162479
162480
162481
162482
162483
162484
162485
162486
162487
162488
162489
162490
162491
162492
162493
162494
162495
162496
162497
162498
162499
162500
162501
162502
162503
162504
162505
162506
162507
162508
162509
162510
162511
162512
162513
162514
162515
162516
162517
162518
162519
162520
162521
162522
162523
162524
162525
162526
162527
162528
162529
162530
162531
162532
162533
162534
162535
162536
162537
162538
162539
162540
162541
162542
162543
162544
162545
162546
162547
162548
162549
162550
162551
162552
162553
162554
162555
162556
162557
162558
162559
162560
162561
162562
162563
162564
162565
162566
162567
162568
162569
162570
162571
162572
162573
162574
162575
162576
162577
162578
162579
162580
162581
162582
162583
162584
162585
162586
162587
162588
162589
162590
162591
162592
162593
162594
162595
162596
162597
162598
162599
162600
162601
162602
162603
162604
162605
162606
162607
162608
162609
162610
162611
162612
162613
162614
162615
162616
162617
162618
162619
162620
162621
162622
162623
162624
162625
162626
162627
162628
162629
162630
162631
162632
162633
162634
162635
162636
162637
162638
162639
162640
162641
162642
162643
162644
162645
162646
162647
162648
162649
162650
162651
162652
162653
162654
162655
162656
162657
162658
162659
162660
162661
162662
162663
162664
162665
162666
162667
162668
162669
162670
162671
162672
162673
162674
162675
162676
162677
162678
162679
162680
162681
162682
162683
162684
162685
162686
162687
162688
162689
162690
162691
162692
162693
162694
162695
162696
162697
162698
162699
162700
162701
162702
162703
162704
162705
162706
162707
162708
162709
162710
162711
162712
162713
162714
162715
162716
162717
162718
162719
162720
162721
162722
162723
162724
162725
162726
162727
162728
162729
162730
162731
162732
162733
162734
162735
162736
162737
162738
162739
162740
162741
162742
162743
162744
162745
162746
162747
162748
162749
162750
162751
162752
162753
162754
162755
162756
162757
162758
162759
162760
162761
162762
162763
162764
162765
162766
162767
162768
162769
162770
162771
162772
162773
162774
162775
162776
162777
162778
162779
162780
162781
162782
162783
162784
162785
162786
162787
162788
162789
162790
162791
162792
162793
162794
162795
162796
162797
162798
162799
162800
162801
162802
162803
162804
162805
162806
162807
162808
162809
162810
162811
162812
162813
162814
162815
162816
162817
162818
162819
162820
162821
162822
162823
162824
162825
162826
162827
162828
162829
162830
162831
162832
162833
162834
162835
162836
162837
162838
162839
162840
162841
162842
162843
162844
162845
162846
162847
162848
162849
162850
162851
162852
162853
162854
162855
162856
162857
162858
162859
162860
162861
162862
162863
162864
162865
162866
162867
162868
162869
162870
162871
162872
162873
162874
162875
162876
162877
162878
162879
162880
162881
162882
162883
162884
162885
162886
162887
162888
162889
162890
162891
162892
162893
162894
162895
162896
162897
162898
162899
162900
162901
162902
162903
162904
162905
162906
162907
162908
162909
162910
162911
162912
162913
162914
162915
162916
162917
162918
162919
162920
162921
162922
162923
162924
162925
162926
162927
162928
162929
162930
162931
162932
162933
162934
162935
162936
162937
162938
162939
162940
162941
162942
162943
162944
162945
162946
162947
162948
162949
162950
162951
162952
162953
162954
162955
162956
162957
162958
162959
162960
162961
162962
162963
162964
162965
162966
162967
162968
162969
162970
162971
162972
162973
162974
162975
162976
162977
162978
162979
162980
162981
162982
162983
162984
162985
162986
162987
162988
162989
162990
162991
162992
162993
162994
162995
162996
162997
162998
162999
163000
163001
163002
163003
163004
163005
163006
163007
163008
163009
163010
163011
163012
163013
163014
163015
163016
163017
163018
163019
163020
163021
163022
163023
163024
163025
163026
163027
163028
163029
163030
163031
163032
163033
163034
163035
163036
163037
163038
163039
163040
163041
163042
163043
163044
163045
163046
163047
163048
163049
163050
163051
163052
163053
163054
163055
163056
163057
163058
163059
163060
163061
163062
163063
163064
163065
163066
163067
163068
163069
163070
163071
163072
163073
163074
163075
163076
163077
163078
163079
163080
163081
163082
163083
163084
163085
163086
163087
163088
163089
163090
163091
163092
163093
163094
163095
163096
163097
163098
163099
163100
163101
163102
163103
163104
163105
163106
163107
163108
163109
163110
163111
163112
163113
163114
163115
163116
163117
163118
163119
163120
163121
163122
163123
163124
163125
163126
163127
163128
163129
163130
163131
163132
163133
163134
163135
163136
163137
163138
163139
163140
163141
163142
163143
163144
163145
163146
163147
163148
163149
163150
163151
163152
163153
163154
163155
163156
163157
163158
163159
163160
163161
163162
163163
163164
163165
163166
163167
163168
163169
163170
163171
163172
163173
163174
163175
163176
163177
163178

163179
163180
163181
163182
163183
163184
163185
163186
163187
163188
163189
163190
163191
163192
163193
163194
163195
163196
163197
163198
163199
163200
163201
163202
163203
163204
163205
163206
163207
163208
163209
163210
163211
163212
163213
163214
163215
163216
163217
163218
163219
163220
163221
163222
163223
163224
163225
163226
163227
163228
163229
163230
163231
163232
163233
163234
      case 12: /* cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */
{
  sqlite3Savepoint(pParse, SAVEPOINT_ROLLBACK, &yymsp[0].minor.yy0);
}
        break;
      case 13: /* create_table ::= createkw temp TABLE ifnotexists nm dbnm */
{
   sqlite3StartTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,yymsp[-4].minor.yy376,0,0,yymsp[-2].minor.yy376);
}
        break;
      case 14: /* createkw ::= CREATE */
{disableLookaside(pParse);}
        break;
      case 15: /* ifnotexists ::= */
      case 18: /* temp ::= */ yytestcase(yyruleno==18);
      case 21: /* table_options ::= */ yytestcase(yyruleno==21);
      case 45: /* autoinc ::= */ yytestcase(yyruleno==45);
      case 60: /* init_deferred_pred_opt ::= */ yytestcase(yyruleno==60);
      case 70: /* defer_subclause_opt ::= */ yytestcase(yyruleno==70);
      case 79: /* ifexists ::= */ yytestcase(yyruleno==79);
      case 96: /* distinct ::= */ yytestcase(yyruleno==96);
      case 239: /* collate ::= */ yytestcase(yyruleno==239);
{yymsp[1].minor.yy376 = 0;}
        break;
      case 16: /* ifnotexists ::= IF NOT EXISTS */
{yymsp[-2].minor.yy376 = 1;}
        break;
      case 17: /* temp ::= TEMP */
{yymsp[0].minor.yy376 = pParse->db->init.busy==0;}
        break;
      case 19: /* create_table_args ::= LP columnlist conslist_opt RP table_options */
{
  sqlite3EndTable(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,yymsp[0].minor.yy376,0);
}
        break;
      case 20: /* create_table_args ::= AS select */
{
  sqlite3EndTable(pParse,0,0,0,yymsp[0].minor.yy81);
  sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy81);
}
        break;



      case 22: /* table_options ::= WITHOUT nm */




{
  if( yymsp[0].minor.yy0.n==5 && sqlite3_strnicmp(yymsp[0].minor.yy0.z,"rowid",5)==0 ){
    yymsp[-1].minor.yy376 = TF_WithoutRowid | TF_NoVisibleRowid;
  }else{
    yymsp[-1].minor.yy376 = 0;










    sqlite3ErrorMsg(pParse, "unknown table option: %.*s", yymsp[0].minor.yy0.n, yymsp[0].minor.yy0.z);
  }
}

        break;
      case 23: /* columnname ::= nm typetoken */
{sqlite3AddColumn(pParse,yymsp[-1].minor.yy0,yymsp[0].minor.yy0);}
        break;
      case 24: /* typetoken ::= */
      case 63: /* conslist_opt ::= */ yytestcase(yyruleno==63);
      case 102: /* as ::= */ yytestcase(yyruleno==102);
{yymsp[1].minor.yy0.n = 0; yymsp[1].minor.yy0.z = 0;}
        break;
      case 25: /* typetoken ::= typename LP signed RP */
{
  yymsp[-3].minor.yy0.n = (int)(&yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-3].minor.yy0.z);
}
        break;
      case 26: /* typetoken ::= typename LP signed COMMA signed RP */
{
  yymsp[-5].minor.yy0.n = (int)(&yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-5].minor.yy0.z);
}
        break;
      case 27: /* typename ::= typename ID|STRING */
{yymsp[-1].minor.yy0.n=yymsp[0].minor.yy0.n+(int)(yymsp[0].minor.yy0.z-yymsp[-1].minor.yy0.z);}
        break;
      case 28: /* scanpt ::= */
{
  assert( yyLookahead!=YYNOCODE );
  yymsp[1].minor.yy504 = yyLookaheadToken.z;
}
        break;
      case 29: /* scantok ::= */
{
  assert( yyLookahead!=YYNOCODE );
  yymsp[1].minor.yy0 = yyLookaheadToken;
}
        break;
      case 30: /* ccons ::= CONSTRAINT nm */
      case 65: /* tcons ::= CONSTRAINT nm */ yytestcase(yyruleno==65);
{pParse->constraintName = yymsp[0].minor.yy0;}
        break;
      case 31: /* ccons ::= DEFAULT scantok term */
{sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy404,yymsp[-1].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);}
        break;
      case 32: /* ccons ::= DEFAULT LP expr RP */
{sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy404,yymsp[-2].minor.yy0.z+1,yymsp[0].minor.yy0.z);}
        break;
      case 33: /* ccons ::= DEFAULT PLUS scantok term */
{sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy404,yymsp[-2].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);}
        break;
      case 34: /* ccons ::= DEFAULT MINUS scantok term */
{
  Expr *p = sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy404, 0);
  sqlite3AddDefaultValue(pParse,p,yymsp[-2].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);
}
        break;
      case 35: /* ccons ::= DEFAULT scantok ID|INDEXED */
{
  Expr *p = tokenExpr(pParse, TK_STRING, yymsp[0].minor.yy0);
  if( p ){
    sqlite3ExprIdToTrueFalse(p);
    testcase( p->op==TK_TRUEFALSE && sqlite3ExprTruthValue(p) );
  }
    sqlite3AddDefaultValue(pParse,p,yymsp[0].minor.yy0.z,yymsp[0].minor.yy0.z+yymsp[0].minor.yy0.n);
}
        break;
      case 36: /* ccons ::= NOT NULL onconf */
{sqlite3AddNotNull(pParse, yymsp[0].minor.yy376);}
        break;
      case 37: /* ccons ::= PRIMARY KEY sortorder onconf autoinc */
{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy376,yymsp[0].minor.yy376,yymsp[-2].minor.yy376);}
        break;
      case 38: /* ccons ::= UNIQUE onconf */
{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy376,0,0,0,0,
                                   SQLITE_IDXTYPE_UNIQUE);}
        break;
      case 39: /* ccons ::= CHECK LP expr RP */
{sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy404,yymsp[-2].minor.yy0.z,yymsp[0].minor.yy0.z);}
        break;
      case 40: /* ccons ::= REFERENCES nm eidlist_opt refargs */
{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy70,yymsp[0].minor.yy376);}
        break;
      case 41: /* ccons ::= defer_subclause */
{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy376);}
        break;
      case 42: /* ccons ::= COLLATE ID|STRING */
{sqlite3AddCollateType(pParse, &yymsp[0].minor.yy0);}
        break;
      case 43: /* generated ::= LP expr RP */
{sqlite3AddGenerated(pParse,yymsp[-1].minor.yy404,0);}
        break;
      case 44: /* generated ::= LP expr RP ID */
{sqlite3AddGenerated(pParse,yymsp[-2].minor.yy404,&yymsp[0].minor.yy0);}
        break;
      case 46: /* autoinc ::= AUTOINCR */
{yymsp[0].minor.yy376 = 1;}
        break;
      case 47: /* refargs ::= */
{ yymsp[1].minor.yy376 = OE_None*0x0101; /* EV: R-19803-45884 */}
        break;
      case 48: /* refargs ::= refargs refarg */
{ yymsp[-1].minor.yy376 = (yymsp[-1].minor.yy376 & ~yymsp[0].minor.yy139.mask) | yymsp[0].minor.yy139.value; }
        break;
      case 49: /* refarg ::= MATCH nm */
{ yymsp[-1].minor.yy139.value = 0;     yymsp[-1].minor.yy139.mask = 0x000000; }
        break;
      case 50: /* refarg ::= ON INSERT refact */
{ yymsp[-2].minor.yy139.value = 0;     yymsp[-2].minor.yy139.mask = 0x000000; }
        break;
      case 51: /* refarg ::= ON DELETE refact */
{ yymsp[-2].minor.yy139.value = yymsp[0].minor.yy376;     yymsp[-2].minor.yy139.mask = 0x0000ff; }
        break;
      case 52: /* refarg ::= ON UPDATE refact */
{ yymsp[-2].minor.yy139.value = yymsp[0].minor.yy376<<8;  yymsp[-2].minor.yy139.mask = 0x00ff00; }
        break;
      case 53: /* refact ::= SET NULL */
{ yymsp[-1].minor.yy376 = OE_SetNull;  /* EV: R-33326-45252 */}
        break;
      case 54: /* refact ::= SET DEFAULT */
{ yymsp[-1].minor.yy376 = OE_SetDflt;  /* EV: R-33326-45252 */}
        break;
      case 55: /* refact ::= CASCADE */
{ yymsp[0].minor.yy376 = OE_Cascade;  /* EV: R-33326-45252 */}
        break;
      case 56: /* refact ::= RESTRICT */
{ yymsp[0].minor.yy376 = OE_Restrict; /* EV: R-33326-45252 */}
        break;
      case 57: /* refact ::= NO ACTION */
{ yymsp[-1].minor.yy376 = OE_None;     /* EV: R-33326-45252 */}
        break;
      case 58: /* defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */
{yymsp[-2].minor.yy376 = 0;}
        break;
      case 59: /* defer_subclause ::= DEFERRABLE init_deferred_pred_opt */
      case 74: /* orconf ::= OR resolvetype */ yytestcase(yyruleno==74);
      case 169: /* insert_cmd ::= INSERT orconf */ yytestcase(yyruleno==169);
{yymsp[-1].minor.yy376 = yymsp[0].minor.yy376;}
        break;
      case 61: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */
      case 78: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==78);
      case 211: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==211);
      case 214: /* in_op ::= NOT IN */ yytestcase(yyruleno==214);
      case 240: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==240);
{yymsp[-1].minor.yy376 = 1;}
        break;
      case 62: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */
{yymsp[-1].minor.yy376 = 0;}
        break;
      case 64: /* tconscomma ::= COMMA */
{pParse->constraintName.n = 0;}
        break;
      case 66: /* tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */
{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy70,yymsp[0].minor.yy376,yymsp[-2].minor.yy376,0);}
        break;
      case 67: /* tcons ::= UNIQUE LP sortlist RP onconf */
{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy70,yymsp[0].minor.yy376,0,0,0,0,
                                       SQLITE_IDXTYPE_UNIQUE);}
        break;
      case 68: /* tcons ::= CHECK LP expr RP onconf */
{sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy404,yymsp[-3].minor.yy0.z,yymsp[-1].minor.yy0.z);}
        break;
      case 69: /* tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */
{
    sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy70, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy70, yymsp[-1].minor.yy376);
    sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy376);
}
        break;
      case 71: /* onconf ::= */
      case 73: /* orconf ::= */ yytestcase(yyruleno==73);
{yymsp[1].minor.yy376 = OE_Default;}
        break;
      case 72: /* onconf ::= ON CONFLICT resolvetype */
{yymsp[-2].minor.yy376 = yymsp[0].minor.yy376;}
        break;
      case 75: /* resolvetype ::= IGNORE */
{yymsp[0].minor.yy376 = OE_Ignore;}
        break;
      case 76: /* resolvetype ::= REPLACE */
      case 170: /* insert_cmd ::= REPLACE */ yytestcase(yyruleno==170);
{yymsp[0].minor.yy376 = OE_Replace;}
        break;
      case 77: /* cmd ::= DROP TABLE ifexists fullname */
{
  sqlite3DropTable(pParse, yymsp[0].minor.yy153, 0, yymsp[-1].minor.yy376);
}
        break;
      case 80: /* cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */
{
  sqlite3CreateView(pParse, &yymsp[-8].minor.yy0, &yymsp[-4].minor.yy0, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy70, yymsp[0].minor.yy81, yymsp[-7].minor.yy376, yymsp[-5].minor.yy376);
}
        break;
      case 81: /* cmd ::= DROP VIEW ifexists fullname */
{
  sqlite3DropTable(pParse, yymsp[0].minor.yy153, 1, yymsp[-1].minor.yy376);
}
        break;
      case 82: /* cmd ::= select */
{
  SelectDest dest = {SRT_Output, 0, 0, 0, 0, 0, 0};
  sqlite3Select(pParse, yymsp[0].minor.yy81, &dest);
  sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy81);
}
        break;
      case 83: /* select ::= WITH wqlist selectnowith */
{yymsp[-2].minor.yy81 = attachWithToSelect(pParse,yymsp[0].minor.yy81,yymsp[-1].minor.yy103);}
        break;
      case 84: /* select ::= WITH RECURSIVE wqlist selectnowith */
{yymsp[-3].minor.yy81 = attachWithToSelect(pParse,yymsp[0].minor.yy81,yymsp[-1].minor.yy103);}
        break;
      case 85: /* select ::= selectnowith */
{
  Select *p = yymsp[0].minor.yy81;
  if( p ){
    parserDoubleLinkSelect(pParse, p);
  }
  yymsp[0].minor.yy81 = p; /*A-overwrites-X*/
}
        break;
      case 86: /* selectnowith ::= selectnowith multiselect_op oneselect */
{
  Select *pRhs = yymsp[0].minor.yy81;
  Select *pLhs = yymsp[-2].minor.yy81;
  if( pRhs && pRhs->pPrior ){
    SrcList *pFrom;
    Token x;
    x.n = 0;
    parserDoubleLinkSelect(pParse, pRhs);
    pFrom = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&x,pRhs,0,0);
    pRhs = sqlite3SelectNew(pParse,0,pFrom,0,0,0,0,0,0);
  }
  if( pRhs ){
    pRhs->op = (u8)yymsp[-1].minor.yy376;
    pRhs->pPrior = pLhs;
    if( ALWAYS(pLhs) ) pLhs->selFlags &= ~SF_MultiValue;
    pRhs->selFlags &= ~SF_MultiValue;
    if( yymsp[-1].minor.yy376!=TK_ALL ) pParse->hasCompound = 1;
  }else{
    sqlite3SelectDelete(pParse->db, pLhs);
  }
  yymsp[-2].minor.yy81 = pRhs;
}
        break;
      case 87: /* multiselect_op ::= UNION */
      case 89: /* multiselect_op ::= EXCEPT|INTERSECT */ yytestcase(yyruleno==89);
{yymsp[0].minor.yy376 = yymsp[0].major; /*A-overwrites-OP*/}
        break;
      case 88: /* multiselect_op ::= UNION ALL */
{yymsp[-1].minor.yy376 = TK_ALL;}
        break;
      case 90: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
{
  yymsp[-8].minor.yy81 = sqlite3SelectNew(pParse,yymsp[-6].minor.yy70,yymsp[-5].minor.yy153,yymsp[-4].minor.yy404,yymsp[-3].minor.yy70,yymsp[-2].minor.yy404,yymsp[-1].minor.yy70,yymsp[-7].minor.yy376,yymsp[0].minor.yy404);
}
        break;
      case 91: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */
{
  yymsp[-9].minor.yy81 = sqlite3SelectNew(pParse,yymsp[-7].minor.yy70,yymsp[-6].minor.yy153,yymsp[-5].minor.yy404,yymsp[-4].minor.yy70,yymsp[-3].minor.yy404,yymsp[-1].minor.yy70,yymsp[-8].minor.yy376,yymsp[0].minor.yy404);
  if( yymsp[-9].minor.yy81 ){
    yymsp[-9].minor.yy81->pWinDefn = yymsp[-2].minor.yy49;
  }else{
    sqlite3WindowListDelete(pParse->db, yymsp[-2].minor.yy49);
  }
}
        break;
      case 92: /* values ::= VALUES LP nexprlist RP */
{
  yymsp[-3].minor.yy81 = sqlite3SelectNew(pParse,yymsp[-1].minor.yy70,0,0,0,0,0,SF_Values,0);
}
        break;
      case 93: /* values ::= values COMMA LP nexprlist RP */
{
  Select *pRight, *pLeft = yymsp[-4].minor.yy81;
  pRight = sqlite3SelectNew(pParse,yymsp[-1].minor.yy70,0,0,0,0,0,SF_Values|SF_MultiValue,0);
  if( ALWAYS(pLeft) ) pLeft->selFlags &= ~SF_MultiValue;
  if( pRight ){
    pRight->op = TK_ALL;
    pRight->pPrior = pLeft;
    yymsp[-4].minor.yy81 = pRight;
  }else{
    yymsp[-4].minor.yy81 = pLeft;
  }
}
        break;
      case 94: /* distinct ::= DISTINCT */
{yymsp[0].minor.yy376 = SF_Distinct;}
        break;
      case 95: /* distinct ::= ALL */
{yymsp[0].minor.yy376 = SF_All;}
        break;
      case 97: /* sclp ::= */
      case 130: /* orderby_opt ::= */ yytestcase(yyruleno==130);
      case 140: /* groupby_opt ::= */ yytestcase(yyruleno==140);
      case 227: /* exprlist ::= */ yytestcase(yyruleno==227);
      case 230: /* paren_exprlist ::= */ yytestcase(yyruleno==230);
      case 235: /* eidlist_opt ::= */ yytestcase(yyruleno==235);
{yymsp[1].minor.yy70 = 0;}
        break;
      case 98: /* selcollist ::= sclp scanpt expr scanpt as */
{
   yymsp[-4].minor.yy70 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy70, yymsp[-2].minor.yy404);
   if( yymsp[0].minor.yy0.n>0 ) sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy70, &yymsp[0].minor.yy0, 1);
   sqlite3ExprListSetSpan(pParse,yymsp[-4].minor.yy70,yymsp[-3].minor.yy504,yymsp[-1].minor.yy504);
}
        break;
      case 99: /* selcollist ::= sclp scanpt STAR */
{
  Expr *p = sqlite3Expr(pParse->db, TK_ASTERISK, 0);
  yymsp[-2].minor.yy70 = sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy70, p);
}
        break;
      case 100: /* selcollist ::= sclp scanpt nm DOT STAR */
{
  Expr *pRight = sqlite3PExpr(pParse, TK_ASTERISK, 0, 0);
  Expr *pLeft = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-2].minor.yy0, 1);
  Expr *pDot = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight);
  yymsp[-4].minor.yy70 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy70, pDot);
}
        break;
      case 101: /* as ::= AS nm */
      case 112: /* dbnm ::= DOT nm */ yytestcase(yyruleno==112);
      case 251: /* plus_num ::= PLUS INTEGER|FLOAT */ yytestcase(yyruleno==251);
      case 252: /* minus_num ::= MINUS INTEGER|FLOAT */ yytestcase(yyruleno==252);
{yymsp[-1].minor.yy0 = yymsp[0].minor.yy0;}
        break;
      case 103: /* from ::= */
      case 106: /* stl_prefix ::= */ yytestcase(yyruleno==106);
{yymsp[1].minor.yy153 = 0;}
        break;
      case 104: /* from ::= FROM seltablist */
{
  yymsp[-1].minor.yy153 = yymsp[0].minor.yy153;
  sqlite3SrcListShiftJoinType(yymsp[-1].minor.yy153);
}
        break;
      case 105: /* stl_prefix ::= seltablist joinop */
{
   if( ALWAYS(yymsp[-1].minor.yy153 && yymsp[-1].minor.yy153->nSrc>0) ) yymsp[-1].minor.yy153->a[yymsp[-1].minor.yy153->nSrc-1].fg.jointype = (u8)yymsp[0].minor.yy376;
}
        break;
      case 107: /* seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */
{
  yymsp[-6].minor.yy153 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy153,&yymsp[-5].minor.yy0,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,0,yymsp[-1].minor.yy404,yymsp[0].minor.yy436);
  sqlite3SrcListIndexedBy(pParse, yymsp[-6].minor.yy153, &yymsp[-2].minor.yy0);
}
        break;
      case 108: /* seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt */
{
  yymsp[-8].minor.yy153 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-8].minor.yy153,&yymsp[-7].minor.yy0,&yymsp[-6].minor.yy0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy404,yymsp[0].minor.yy436);
  sqlite3SrcListFuncArgs(pParse, yymsp[-8].minor.yy153, yymsp[-4].minor.yy70);
}
        break;
      case 109: /* seltablist ::= stl_prefix LP select RP as on_opt using_opt */
{
    yymsp[-6].minor.yy153 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy153,0,0,&yymsp[-2].minor.yy0,yymsp[-4].minor.yy81,yymsp[-1].minor.yy404,yymsp[0].minor.yy436);
  }
        break;
      case 110: /* seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */
{
    if( yymsp[-6].minor.yy153==0 && yymsp[-2].minor.yy0.n==0 && yymsp[-1].minor.yy404==0 && yymsp[0].minor.yy436==0 ){
      yymsp[-6].minor.yy153 = yymsp[-4].minor.yy153;
    }else if( yymsp[-4].minor.yy153->nSrc==1 ){
      yymsp[-6].minor.yy153 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy153,0,0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy404,yymsp[0].minor.yy436);
      if( yymsp[-6].minor.yy153 ){
        SrcItem *pNew = &yymsp[-6].minor.yy153->a[yymsp[-6].minor.yy153->nSrc-1];
        SrcItem *pOld = yymsp[-4].minor.yy153->a;
        pNew->zName = pOld->zName;
        pNew->zDatabase = pOld->zDatabase;
        pNew->pSelect = pOld->pSelect;
        if( pOld->fg.isTabFunc ){
          pNew->u1.pFuncArg = pOld->u1.pFuncArg;
          pOld->u1.pFuncArg = 0;
          pOld->fg.isTabFunc = 0;
          pNew->fg.isTabFunc = 1;
        }
        pOld->zName = pOld->zDatabase = 0;
        pOld->pSelect = 0;
      }
      sqlite3SrcListDelete(pParse->db, yymsp[-4].minor.yy153);
    }else{
      Select *pSubquery;
      sqlite3SrcListShiftJoinType(yymsp[-4].minor.yy153);
      pSubquery = sqlite3SelectNew(pParse,0,yymsp[-4].minor.yy153,0,0,0,0,SF_NestedFrom,0);
      yymsp[-6].minor.yy153 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy153,0,0,&yymsp[-2].minor.yy0,pSubquery,yymsp[-1].minor.yy404,yymsp[0].minor.yy436);
    }
  }
        break;
      case 111: /* dbnm ::= */
      case 125: /* indexed_opt ::= */ yytestcase(yyruleno==125);
{yymsp[1].minor.yy0.z=0; yymsp[1].minor.yy0.n=0;}
        break;
      case 113: /* fullname ::= nm */
{
  yylhsminor.yy153 = sqlite3SrcListAppend(pParse,0,&yymsp[0].minor.yy0,0);
  if( IN_RENAME_OBJECT && yylhsminor.yy153 ) sqlite3RenameTokenMap(pParse, yylhsminor.yy153->a[0].zName, &yymsp[0].minor.yy0);
}
  yymsp[0].minor.yy153 = yylhsminor.yy153;
        break;
      case 114: /* fullname ::= nm DOT nm */
{
  yylhsminor.yy153 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0);
  if( IN_RENAME_OBJECT && yylhsminor.yy153 ) sqlite3RenameTokenMap(pParse, yylhsminor.yy153->a[0].zName, &yymsp[0].minor.yy0);
}
  yymsp[-2].minor.yy153 = yylhsminor.yy153;
        break;
      case 115: /* xfullname ::= nm */
{yymsp[0].minor.yy153 = sqlite3SrcListAppend(pParse,0,&yymsp[0].minor.yy0,0); /*A-overwrites-X*/}
        break;
      case 116: /* xfullname ::= nm DOT nm */
{yymsp[-2].minor.yy153 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/}
        break;
      case 117: /* xfullname ::= nm DOT nm AS nm */
{
   yymsp[-4].minor.yy153 = sqlite3SrcListAppend(pParse,0,&yymsp[-4].minor.yy0,&yymsp[-2].minor.yy0); /*A-overwrites-X*/
   if( yymsp[-4].minor.yy153 ) yymsp[-4].minor.yy153->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0);
}
        break;
      case 118: /* xfullname ::= nm AS nm */
{
   yymsp[-2].minor.yy153 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,0); /*A-overwrites-X*/
   if( yymsp[-2].minor.yy153 ) yymsp[-2].minor.yy153->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0);
}
        break;
      case 119: /* joinop ::= COMMA|JOIN */
{ yymsp[0].minor.yy376 = JT_INNER; }
        break;
      case 120: /* joinop ::= JOIN_KW JOIN */
{yymsp[-1].minor.yy376 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0);  /*X-overwrites-A*/}
        break;
      case 121: /* joinop ::= JOIN_KW nm JOIN */
{yymsp[-2].minor.yy376 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); /*X-overwrites-A*/}
        break;
      case 122: /* joinop ::= JOIN_KW nm nm JOIN */
{yymsp[-3].minor.yy376 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);/*X-overwrites-A*/}
        break;
      case 123: /* on_opt ::= ON expr */
      case 143: /* having_opt ::= HAVING expr */ yytestcase(yyruleno==143);
      case 150: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==150);
      case 152: /* where_opt_ret ::= WHERE expr */ yytestcase(yyruleno==152);
      case 223: /* case_else ::= ELSE expr */ yytestcase(yyruleno==223);
      case 244: /* vinto ::= INTO expr */ yytestcase(yyruleno==244);
{yymsp[-1].minor.yy404 = yymsp[0].minor.yy404;}
        break;
      case 124: /* on_opt ::= */
      case 142: /* having_opt ::= */ yytestcase(yyruleno==142);
      case 144: /* limit_opt ::= */ yytestcase(yyruleno==144);
      case 149: /* where_opt ::= */ yytestcase(yyruleno==149);
      case 151: /* where_opt_ret ::= */ yytestcase(yyruleno==151);
      case 224: /* case_else ::= */ yytestcase(yyruleno==224);
      case 226: /* case_operand ::= */ yytestcase(yyruleno==226);
      case 245: /* vinto ::= */ yytestcase(yyruleno==245);
{yymsp[1].minor.yy404 = 0;}
        break;
      case 126: /* indexed_opt ::= INDEXED BY nm */
{yymsp[-2].minor.yy0 = yymsp[0].minor.yy0;}
        break;
      case 127: /* indexed_opt ::= NOT INDEXED */
{yymsp[-1].minor.yy0.z=0; yymsp[-1].minor.yy0.n=1;}
        break;
      case 128: /* using_opt ::= USING LP idlist RP */
{yymsp[-3].minor.yy436 = yymsp[-1].minor.yy436;}
        break;
      case 129: /* using_opt ::= */
      case 171: /* idlist_opt ::= */ yytestcase(yyruleno==171);
{yymsp[1].minor.yy436 = 0;}
        break;
      case 131: /* orderby_opt ::= ORDER BY sortlist */
      case 141: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==141);
{yymsp[-2].minor.yy70 = yymsp[0].minor.yy70;}
        break;
      case 132: /* sortlist ::= sortlist COMMA expr sortorder nulls */
{
  yymsp[-4].minor.yy70 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy70,yymsp[-2].minor.yy404);
  sqlite3ExprListSetSortOrder(yymsp[-4].minor.yy70,yymsp[-1].minor.yy376,yymsp[0].minor.yy376);
}
        break;
      case 133: /* sortlist ::= expr sortorder nulls */
{
  yymsp[-2].minor.yy70 = sqlite3ExprListAppend(pParse,0,yymsp[-2].minor.yy404); /*A-overwrites-Y*/
  sqlite3ExprListSetSortOrder(yymsp[-2].minor.yy70,yymsp[-1].minor.yy376,yymsp[0].minor.yy376);
}
        break;
      case 134: /* sortorder ::= ASC */
{yymsp[0].minor.yy376 = SQLITE_SO_ASC;}
        break;
      case 135: /* sortorder ::= DESC */
{yymsp[0].minor.yy376 = SQLITE_SO_DESC;}
        break;
      case 136: /* sortorder ::= */
      case 139: /* nulls ::= */ yytestcase(yyruleno==139);
{yymsp[1].minor.yy376 = SQLITE_SO_UNDEFINED;}
        break;
      case 137: /* nulls ::= NULLS FIRST */
{yymsp[-1].minor.yy376 = SQLITE_SO_ASC;}
        break;
      case 138: /* nulls ::= NULLS LAST */
{yymsp[-1].minor.yy376 = SQLITE_SO_DESC;}
        break;
      case 145: /* limit_opt ::= LIMIT expr */
{yymsp[-1].minor.yy404 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy404,0);}
        break;
      case 146: /* limit_opt ::= LIMIT expr OFFSET expr */
{yymsp[-3].minor.yy404 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[-2].minor.yy404,yymsp[0].minor.yy404);}
        break;
      case 147: /* limit_opt ::= LIMIT expr COMMA expr */
{yymsp[-3].minor.yy404 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy404,yymsp[-2].minor.yy404);}
        break;
      case 148: /* cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret */
{
  sqlite3SrcListIndexedBy(pParse, yymsp[-2].minor.yy153, &yymsp[-1].minor.yy0);
  sqlite3DeleteFrom(pParse,yymsp[-2].minor.yy153,yymsp[0].minor.yy404,0,0);
}
        break;
      case 153: /* where_opt_ret ::= RETURNING selcollist */
{sqlite3AddReturning(pParse,yymsp[0].minor.yy70); yymsp[-1].minor.yy404 = 0;}
        break;
      case 154: /* where_opt_ret ::= WHERE expr RETURNING selcollist */
{sqlite3AddReturning(pParse,yymsp[0].minor.yy70); yymsp[-3].minor.yy404 = yymsp[-2].minor.yy404;}
        break;
      case 155: /* cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret */
{
  sqlite3SrcListIndexedBy(pParse, yymsp[-5].minor.yy153, &yymsp[-4].minor.yy0);
  sqlite3ExprListCheckLength(pParse,yymsp[-2].minor.yy70,"set list");
  yymsp[-5].minor.yy153 = sqlite3SrcListAppendList(pParse, yymsp[-5].minor.yy153, yymsp[-1].minor.yy153);
  sqlite3Update(pParse,yymsp[-5].minor.yy153,yymsp[-2].minor.yy70,yymsp[0].minor.yy404,yymsp[-6].minor.yy376,0,0,0);
}
        break;
      case 156: /* setlist ::= setlist COMMA nm EQ expr */
{
  yymsp[-4].minor.yy70 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy70, yymsp[0].minor.yy404);
  sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy70, &yymsp[-2].minor.yy0, 1);
}
        break;
      case 157: /* setlist ::= setlist COMMA LP idlist RP EQ expr */
{
  yymsp[-6].minor.yy70 = sqlite3ExprListAppendVector(pParse, yymsp[-6].minor.yy70, yymsp[-3].minor.yy436, yymsp[0].minor.yy404);
}
        break;
      case 158: /* setlist ::= nm EQ expr */
{
  yylhsminor.yy70 = sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy404);
  sqlite3ExprListSetName(pParse, yylhsminor.yy70, &yymsp[-2].minor.yy0, 1);
}
  yymsp[-2].minor.yy70 = yylhsminor.yy70;
        break;
      case 159: /* setlist ::= LP idlist RP EQ expr */
{
  yymsp[-4].minor.yy70 = sqlite3ExprListAppendVector(pParse, 0, yymsp[-3].minor.yy436, yymsp[0].minor.yy404);
}
        break;
      case 160: /* cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */
{
  sqlite3Insert(pParse, yymsp[-3].minor.yy153, yymsp[-1].minor.yy81, yymsp[-2].minor.yy436, yymsp[-5].minor.yy376, yymsp[0].minor.yy190);
}
        break;
      case 161: /* cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */
{
  sqlite3Insert(pParse, yymsp[-4].minor.yy153, 0, yymsp[-3].minor.yy436, yymsp[-6].minor.yy376, 0);
}
        break;
      case 162: /* upsert ::= */
{ yymsp[1].minor.yy190 = 0; }
        break;
      case 163: /* upsert ::= RETURNING selcollist */
{ yymsp[-1].minor.yy190 = 0; sqlite3AddReturning(pParse,yymsp[0].minor.yy70); }
        break;
      case 164: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */
{ yymsp[-11].minor.yy190 = sqlite3UpsertNew(pParse->db,yymsp[-8].minor.yy70,yymsp[-6].minor.yy404,yymsp[-2].minor.yy70,yymsp[-1].minor.yy404,yymsp[0].minor.yy190);}
        break;
      case 165: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */
{ yymsp[-8].minor.yy190 = sqlite3UpsertNew(pParse->db,yymsp[-5].minor.yy70,yymsp[-3].minor.yy404,0,0,yymsp[0].minor.yy190); }
        break;
      case 166: /* upsert ::= ON CONFLICT DO NOTHING returning */
{ yymsp[-4].minor.yy190 = sqlite3UpsertNew(pParse->db,0,0,0,0,0); }
        break;
      case 167: /* upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */
{ yymsp[-7].minor.yy190 = sqlite3UpsertNew(pParse->db,0,0,yymsp[-2].minor.yy70,yymsp[-1].minor.yy404,0);}
        break;
      case 168: /* returning ::= RETURNING selcollist */
{sqlite3AddReturning(pParse,yymsp[0].minor.yy70);}
        break;
      case 172: /* idlist_opt ::= LP idlist RP */
{yymsp[-2].minor.yy436 = yymsp[-1].minor.yy436;}
        break;
      case 173: /* idlist ::= idlist COMMA nm */
{yymsp[-2].minor.yy436 = sqlite3IdListAppend(pParse,yymsp[-2].minor.yy436,&yymsp[0].minor.yy0);}
        break;
      case 174: /* idlist ::= nm */
{yymsp[0].minor.yy436 = sqlite3IdListAppend(pParse,0,&yymsp[0].minor.yy0); /*A-overwrites-Y*/}
        break;
      case 175: /* expr ::= LP expr RP */
{yymsp[-2].minor.yy404 = yymsp[-1].minor.yy404;}
        break;
      case 176: /* expr ::= ID|INDEXED */
      case 177: /* expr ::= JOIN_KW */ yytestcase(yyruleno==177);
{yymsp[0].minor.yy404=tokenExpr(pParse,TK_ID,yymsp[0].minor.yy0); /*A-overwrites-X*/}
        break;
      case 178: /* expr ::= nm DOT nm */
{
  Expr *temp1 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-2].minor.yy0, 1);
  Expr *temp2 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[0].minor.yy0, 1);
  if( IN_RENAME_OBJECT ){
    sqlite3RenameTokenMap(pParse, (void*)temp2, &yymsp[0].minor.yy0);
    sqlite3RenameTokenMap(pParse, (void*)temp1, &yymsp[-2].minor.yy0);
  }
  yylhsminor.yy404 = sqlite3PExpr(pParse, TK_DOT, temp1, temp2);
}
  yymsp[-2].minor.yy404 = yylhsminor.yy404;
        break;
      case 179: /* expr ::= nm DOT nm DOT nm */
{
  Expr *temp1 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-4].minor.yy0, 1);
  Expr *temp2 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-2].minor.yy0, 1);
  Expr *temp3 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[0].minor.yy0, 1);
  Expr *temp4 = sqlite3PExpr(pParse, TK_DOT, temp2, temp3);
  if( IN_RENAME_OBJECT ){
    sqlite3RenameTokenMap(pParse, (void*)temp3, &yymsp[0].minor.yy0);
    sqlite3RenameTokenMap(pParse, (void*)temp2, &yymsp[-2].minor.yy0);
  }
  yylhsminor.yy404 = sqlite3PExpr(pParse, TK_DOT, temp1, temp4);
}
  yymsp[-4].minor.yy404 = yylhsminor.yy404;
        break;
      case 180: /* term ::= NULL|FLOAT|BLOB */
      case 181: /* term ::= STRING */ yytestcase(yyruleno==181);
{yymsp[0].minor.yy404=tokenExpr(pParse,yymsp[0].major,yymsp[0].minor.yy0); /*A-overwrites-X*/}
        break;
      case 182: /* term ::= INTEGER */
{
  yylhsminor.yy404 = sqlite3ExprAlloc(pParse->db, TK_INTEGER, &yymsp[0].minor.yy0, 1);
}
  yymsp[0].minor.yy404 = yylhsminor.yy404;
        break;
      case 183: /* expr ::= VARIABLE */
{
  if( !(yymsp[0].minor.yy0.z[0]=='#' && sqlite3Isdigit(yymsp[0].minor.yy0.z[1])) ){
    u32 n = yymsp[0].minor.yy0.n;
    yymsp[0].minor.yy404 = tokenExpr(pParse, TK_VARIABLE, yymsp[0].minor.yy0);
    sqlite3ExprAssignVarNumber(pParse, yymsp[0].minor.yy404, n);
  }else{
    /* When doing a nested parse, one can include terms in an expression
    ** that look like this:   #1 #2 ...  These terms refer to registers
    ** in the virtual machine.  #N is the N-th register. */
    Token t = yymsp[0].minor.yy0; /*A-overwrites-X*/
    assert( t.n>=2 );
    if( pParse->nested==0 ){
      sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &t);
      yymsp[0].minor.yy404 = 0;
    }else{
      yymsp[0].minor.yy404 = sqlite3PExpr(pParse, TK_REGISTER, 0, 0);
      if( yymsp[0].minor.yy404 ) sqlite3GetInt32(&t.z[1], &yymsp[0].minor.yy404->iTable);
    }
  }
}
        break;
      case 184: /* expr ::= expr COLLATE ID|STRING */
{
  yymsp[-2].minor.yy404 = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy404, &yymsp[0].minor.yy0, 1);
}
        break;
      case 185: /* expr ::= CAST LP expr AS typetoken RP */
{
  yymsp[-5].minor.yy404 = sqlite3ExprAlloc(pParse->db, TK_CAST, &yymsp[-1].minor.yy0, 1);
  sqlite3ExprAttachSubtrees(pParse->db, yymsp[-5].minor.yy404, yymsp[-3].minor.yy404, 0);
}
        break;
      case 186: /* expr ::= ID|INDEXED LP distinct exprlist RP */
{
  yylhsminor.yy404 = sqlite3ExprFunction(pParse, yymsp[-1].minor.yy70, &yymsp[-4].minor.yy0, yymsp[-2].minor.yy376);
}
  yymsp[-4].minor.yy404 = yylhsminor.yy404;
        break;
      case 187: /* expr ::= ID|INDEXED LP STAR RP */
{
  yylhsminor.yy404 = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0, 0);
}
  yymsp[-3].minor.yy404 = yylhsminor.yy404;
        break;
      case 188: /* expr ::= ID|INDEXED LP distinct exprlist RP filter_over */
{
  yylhsminor.yy404 = sqlite3ExprFunction(pParse, yymsp[-2].minor.yy70, &yymsp[-5].minor.yy0, yymsp[-3].minor.yy376);
  sqlite3WindowAttach(pParse, yylhsminor.yy404, yymsp[0].minor.yy49);
}
  yymsp[-5].minor.yy404 = yylhsminor.yy404;
        break;
      case 189: /* expr ::= ID|INDEXED LP STAR RP filter_over */
{
  yylhsminor.yy404 = sqlite3ExprFunction(pParse, 0, &yymsp[-4].minor.yy0, 0);
  sqlite3WindowAttach(pParse, yylhsminor.yy404, yymsp[0].minor.yy49);
}
  yymsp[-4].minor.yy404 = yylhsminor.yy404;
        break;
      case 190: /* term ::= CTIME_KW */
{
  yylhsminor.yy404 = sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0, 0);
}
  yymsp[0].minor.yy404 = yylhsminor.yy404;
        break;
      case 191: /* expr ::= LP nexprlist COMMA expr RP */
{
  ExprList *pList = sqlite3ExprListAppend(pParse, yymsp[-3].minor.yy70, yymsp[-1].minor.yy404);
  yymsp[-4].minor.yy404 = sqlite3PExpr(pParse, TK_VECTOR, 0, 0);
  if( yymsp[-4].minor.yy404 ){
    yymsp[-4].minor.yy404->x.pList = pList;
    if( ALWAYS(pList->nExpr) ){
      yymsp[-4].minor.yy404->flags |= pList->a[0].pExpr->flags & EP_Propagate;
    }
  }else{
    sqlite3ExprListDelete(pParse->db, pList);
  }
}
        break;
      case 192: /* expr ::= expr AND expr */
{yymsp[-2].minor.yy404=sqlite3ExprAnd(pParse,yymsp[-2].minor.yy404,yymsp[0].minor.yy404);}
        break;
      case 193: /* expr ::= expr OR expr */
      case 194: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==194);
      case 195: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==195);
      case 196: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==196);
      case 197: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==197);
      case 198: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==198);
      case 199: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==199);
{yymsp[-2].minor.yy404=sqlite3PExpr(pParse,yymsp[-1].major,yymsp[-2].minor.yy404,yymsp[0].minor.yy404);}
        break;
      case 200: /* likeop ::= NOT LIKE_KW|MATCH */
{yymsp[-1].minor.yy0=yymsp[0].minor.yy0; yymsp[-1].minor.yy0.n|=0x80000000; /*yymsp[-1].minor.yy0-overwrite-yymsp[0].minor.yy0*/}
        break;
      case 201: /* expr ::= expr likeop expr */
{
  ExprList *pList;
  int bNot = yymsp[-1].minor.yy0.n & 0x80000000;
  yymsp[-1].minor.yy0.n &= 0x7fffffff;
  pList = sqlite3ExprListAppend(pParse,0, yymsp[0].minor.yy404);
  pList = sqlite3ExprListAppend(pParse,pList, yymsp[-2].minor.yy404);
  yymsp[-2].minor.yy404 = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0, 0);
  if( bNot ) yymsp[-2].minor.yy404 = sqlite3PExpr(pParse, TK_NOT, yymsp[-2].minor.yy404, 0);
  if( yymsp[-2].minor.yy404 ) yymsp[-2].minor.yy404->flags |= EP_InfixFunc;
}
        break;
      case 202: /* expr ::= expr likeop expr ESCAPE expr */
{
  ExprList *pList;
  int bNot = yymsp[-3].minor.yy0.n & 0x80000000;
  yymsp[-3].minor.yy0.n &= 0x7fffffff;
  pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy404);
  pList = sqlite3ExprListAppend(pParse,pList, yymsp[-4].minor.yy404);
  pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy404);
  yymsp[-4].minor.yy404 = sqlite3ExprFunction(pParse, pList, &yymsp[-3].minor.yy0, 0);
  if( bNot ) yymsp[-4].minor.yy404 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy404, 0);
  if( yymsp[-4].minor.yy404 ) yymsp[-4].minor.yy404->flags |= EP_InfixFunc;
}
        break;
      case 203: /* expr ::= expr ISNULL|NOTNULL */
{yymsp[-1].minor.yy404 = sqlite3PExpr(pParse,yymsp[0].major,yymsp[-1].minor.yy404,0);}
        break;
      case 204: /* expr ::= expr NOT NULL */
{yymsp[-2].minor.yy404 = sqlite3PExpr(pParse,TK_NOTNULL,yymsp[-2].minor.yy404,0);}
        break;
      case 205: /* expr ::= expr IS expr */
{
  yymsp[-2].minor.yy404 = sqlite3PExpr(pParse,TK_IS,yymsp[-2].minor.yy404,yymsp[0].minor.yy404);
  binaryToUnaryIfNull(pParse, yymsp[0].minor.yy404, yymsp[-2].minor.yy404, TK_ISNULL);
}
        break;
      case 206: /* expr ::= expr IS NOT expr */
{
  yymsp[-3].minor.yy404 = sqlite3PExpr(pParse,TK_ISNOT,yymsp[-3].minor.yy404,yymsp[0].minor.yy404);
  binaryToUnaryIfNull(pParse, yymsp[0].minor.yy404, yymsp[-3].minor.yy404, TK_NOTNULL);
}
        break;
      case 207: /* expr ::= NOT expr */
      case 208: /* expr ::= BITNOT expr */ yytestcase(yyruleno==208);
{yymsp[-1].minor.yy404 = sqlite3PExpr(pParse, yymsp[-1].major, yymsp[0].minor.yy404, 0);/*A-overwrites-B*/}
        break;
      case 209: /* expr ::= PLUS|MINUS expr */
{
  yymsp[-1].minor.yy404 = sqlite3PExpr(pParse, yymsp[-1].major==TK_PLUS ? TK_UPLUS : TK_UMINUS, yymsp[0].minor.yy404, 0);
  /*A-overwrites-B*/
}
        break;
      case 210: /* between_op ::= BETWEEN */
      case 213: /* in_op ::= IN */ yytestcase(yyruleno==213);
{yymsp[0].minor.yy376 = 0;}
        break;
      case 212: /* expr ::= expr between_op expr AND expr */
{
  ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy404);
  pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy404);
  yymsp[-4].minor.yy404 = sqlite3PExpr(pParse, TK_BETWEEN, yymsp[-4].minor.yy404, 0);
  if( yymsp[-4].minor.yy404 ){
    yymsp[-4].minor.yy404->x.pList = pList;
  }else{
    sqlite3ExprListDelete(pParse->db, pList);
  }
  if( yymsp[-3].minor.yy376 ) yymsp[-4].minor.yy404 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy404, 0);
}
        break;
      case 215: /* expr ::= expr in_op LP exprlist RP */
{
    if( yymsp[-1].minor.yy70==0 ){
      /* Expressions of the form
      **
      **      expr1 IN ()
      **      expr1 NOT IN ()
      **
      ** simplify to constants 0 (false) and 1 (true), respectively,
      ** regardless of the value of expr1.
      */
      sqlite3ExprUnmapAndDelete(pParse, yymsp[-4].minor.yy404);
      yymsp[-4].minor.yy404 = sqlite3Expr(pParse->db, TK_INTEGER, yymsp[-3].minor.yy376 ? "1" : "0");
    }else{
      Expr *pRHS = yymsp[-1].minor.yy70->a[0].pExpr;
      if( yymsp[-1].minor.yy70->nExpr==1 && sqlite3ExprIsConstant(pRHS) && yymsp[-4].minor.yy404->op!=TK_VECTOR ){
        yymsp[-1].minor.yy70->a[0].pExpr = 0;
        sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy70);
        pRHS = sqlite3PExpr(pParse, TK_UPLUS, pRHS, 0);
        yymsp[-4].minor.yy404 = sqlite3PExpr(pParse, TK_EQ, yymsp[-4].minor.yy404, pRHS);
      }else{
        yymsp[-4].minor.yy404 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy404, 0);
        if( yymsp[-4].minor.yy404==0 ){
          sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy70);
        }else if( yymsp[-4].minor.yy404->pLeft->op==TK_VECTOR ){
          int nExpr = yymsp[-4].minor.yy404->pLeft->x.pList->nExpr;
          Select *pSelectRHS = sqlite3ExprListToValues(pParse, nExpr, yymsp[-1].minor.yy70);
          if( pSelectRHS ){
            parserDoubleLinkSelect(pParse, pSelectRHS);
            sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy404, pSelectRHS);
          }
        }else{
          yymsp[-4].minor.yy404->x.pList = yymsp[-1].minor.yy70;
          sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy404);
        }
      }
      if( yymsp[-3].minor.yy376 ) yymsp[-4].minor.yy404 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy404, 0);
    }
  }
        break;
      case 216: /* expr ::= LP select RP */
{
    yymsp[-2].minor.yy404 = sqlite3PExpr(pParse, TK_SELECT, 0, 0);
    sqlite3PExprAddSelect(pParse, yymsp[-2].minor.yy404, yymsp[-1].minor.yy81);
  }
        break;
      case 217: /* expr ::= expr in_op LP select RP */
{
    yymsp[-4].minor.yy404 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy404, 0);
    sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy404, yymsp[-1].minor.yy81);
    if( yymsp[-3].minor.yy376 ) yymsp[-4].minor.yy404 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy404, 0);
  }
        break;
      case 218: /* expr ::= expr in_op nm dbnm paren_exprlist */
{
    SrcList *pSrc = sqlite3SrcListAppend(pParse, 0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);
    Select *pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0);
    if( yymsp[0].minor.yy70 )  sqlite3SrcListFuncArgs(pParse, pSelect ? pSrc : 0, yymsp[0].minor.yy70);
    yymsp[-4].minor.yy404 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy404, 0);
    sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy404, pSelect);
    if( yymsp[-3].minor.yy376 ) yymsp[-4].minor.yy404 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy404, 0);
  }
        break;
      case 219: /* expr ::= EXISTS LP select RP */
{
    Expr *p;
    p = yymsp[-3].minor.yy404 = sqlite3PExpr(pParse, TK_EXISTS, 0, 0);
    sqlite3PExprAddSelect(pParse, p, yymsp[-1].minor.yy81);
  }
        break;
      case 220: /* expr ::= CASE case_operand case_exprlist case_else END */
{
  yymsp[-4].minor.yy404 = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy404, 0);
  if( yymsp[-4].minor.yy404 ){
    yymsp[-4].minor.yy404->x.pList = yymsp[-1].minor.yy404 ? sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy70,yymsp[-1].minor.yy404) : yymsp[-2].minor.yy70;
    sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy404);
  }else{
    sqlite3ExprListDelete(pParse->db, yymsp[-2].minor.yy70);
    sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy404);
  }
}
        break;
      case 221: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */
{
  yymsp[-4].minor.yy70 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy70, yymsp[-2].minor.yy404);
  yymsp[-4].minor.yy70 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy70, yymsp[0].minor.yy404);
}
        break;
      case 222: /* case_exprlist ::= WHEN expr THEN expr */
{
  yymsp[-3].minor.yy70 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy404);
  yymsp[-3].minor.yy70 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy70, yymsp[0].minor.yy404);
}
        break;
      case 225: /* case_operand ::= expr */
{yymsp[0].minor.yy404 = yymsp[0].minor.yy404; /*A-overwrites-X*/}
        break;
      case 228: /* nexprlist ::= nexprlist COMMA expr */
{yymsp[-2].minor.yy70 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy70,yymsp[0].minor.yy404);}
        break;
      case 229: /* nexprlist ::= expr */
{yymsp[0].minor.yy70 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy404); /*A-overwrites-Y*/}
        break;
      case 231: /* paren_exprlist ::= LP exprlist RP */
      case 236: /* eidlist_opt ::= LP eidlist RP */ yytestcase(yyruleno==236);
{yymsp[-2].minor.yy70 = yymsp[-1].minor.yy70;}
        break;
      case 232: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
{
  sqlite3CreateIndex(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0,
                     sqlite3SrcListAppend(pParse,0,&yymsp[-4].minor.yy0,0), yymsp[-2].minor.yy70, yymsp[-10].minor.yy376,
                      &yymsp[-11].minor.yy0, yymsp[0].minor.yy404, SQLITE_SO_ASC, yymsp[-8].minor.yy376, SQLITE_IDXTYPE_APPDEF);
  if( IN_RENAME_OBJECT && pParse->pNewIndex ){
    sqlite3RenameTokenMap(pParse, pParse->pNewIndex->zName, &yymsp[-4].minor.yy0);
  }
}
        break;
      case 233: /* uniqueflag ::= UNIQUE */
      case 275: /* raisetype ::= ABORT */ yytestcase(yyruleno==275);
{yymsp[0].minor.yy376 = OE_Abort;}
        break;
      case 234: /* uniqueflag ::= */
{yymsp[1].minor.yy376 = OE_None;}
        break;
      case 237: /* eidlist ::= eidlist COMMA nm collate sortorder */
{
  yymsp[-4].minor.yy70 = parserAddExprIdListTerm(pParse, yymsp[-4].minor.yy70, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy376, yymsp[0].minor.yy376);
}
        break;
      case 238: /* eidlist ::= nm collate sortorder */
{
  yymsp[-2].minor.yy70 = parserAddExprIdListTerm(pParse, 0, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy376, yymsp[0].minor.yy376); /*A-overwrites-Y*/
}
        break;
      case 241: /* cmd ::= DROP INDEX ifexists fullname */
{sqlite3DropIndex(pParse, yymsp[0].minor.yy153, yymsp[-1].minor.yy376);}
        break;
      case 242: /* cmd ::= VACUUM vinto */
{sqlite3Vacuum(pParse,0,yymsp[0].minor.yy404);}
        break;
      case 243: /* cmd ::= VACUUM nm vinto */
{sqlite3Vacuum(pParse,&yymsp[-1].minor.yy0,yymsp[0].minor.yy404);}
        break;
      case 246: /* cmd ::= PRAGMA nm dbnm */
{sqlite3Pragma(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,0,0);}
        break;
      case 247: /* cmd ::= PRAGMA nm dbnm EQ nmnum */
{sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,0);}
        break;
      case 248: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */
{sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,0);}
        break;
      case 249: /* cmd ::= PRAGMA nm dbnm EQ minus_num */
{sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,1);}
        break;
      case 250: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */
{sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,1);}
        break;
      case 253: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
{
  Token all;
  all.z = yymsp[-3].minor.yy0.z;
  all.n = (int)(yymsp[0].minor.yy0.z - yymsp[-3].minor.yy0.z) + yymsp[0].minor.yy0.n;
  sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy157, &all);
}
        break;
      case 254: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
{
  sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, yymsp[-5].minor.yy376, yymsp[-4].minor.yy262.a, yymsp[-4].minor.yy262.b, yymsp[-2].minor.yy153, yymsp[0].minor.yy404, yymsp[-10].minor.yy376, yymsp[-8].minor.yy376);
  yymsp[-10].minor.yy0 = (yymsp[-6].minor.yy0.n==0?yymsp[-7].minor.yy0:yymsp[-6].minor.yy0); /*A-overwrites-T*/
}
        break;
      case 255: /* trigger_time ::= BEFORE|AFTER */
{ yymsp[0].minor.yy376 = yymsp[0].major; /*A-overwrites-X*/ }
        break;
      case 256: /* trigger_time ::= INSTEAD OF */
{ yymsp[-1].minor.yy376 = TK_INSTEAD;}
        break;
      case 257: /* trigger_time ::= */
{ yymsp[1].minor.yy376 = TK_BEFORE; }
        break;
      case 258: /* trigger_event ::= DELETE|INSERT */
      case 259: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==259);
{yymsp[0].minor.yy262.a = yymsp[0].major; /*A-overwrites-X*/ yymsp[0].minor.yy262.b = 0;}
        break;
      case 260: /* trigger_event ::= UPDATE OF idlist */
{yymsp[-2].minor.yy262.a = TK_UPDATE; yymsp[-2].minor.yy262.b = yymsp[0].minor.yy436;}
        break;
      case 261: /* when_clause ::= */
      case 280: /* key_opt ::= */ yytestcase(yyruleno==280);
{ yymsp[1].minor.yy404 = 0; }
        break;
      case 262: /* when_clause ::= WHEN expr */
      case 281: /* key_opt ::= KEY expr */ yytestcase(yyruleno==281);
{ yymsp[-1].minor.yy404 = yymsp[0].minor.yy404; }
        break;
      case 263: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
{
  assert( yymsp[-2].minor.yy157!=0 );
  yymsp[-2].minor.yy157->pLast->pNext = yymsp[-1].minor.yy157;
  yymsp[-2].minor.yy157->pLast = yymsp[-1].minor.yy157;
}
        break;
      case 264: /* trigger_cmd_list ::= trigger_cmd SEMI */
{
  assert( yymsp[-1].minor.yy157!=0 );
  yymsp[-1].minor.yy157->pLast = yymsp[-1].minor.yy157;
}
        break;
      case 265: /* trnm ::= nm DOT nm */
{
  yymsp[-2].minor.yy0 = yymsp[0].minor.yy0;
  sqlite3ErrorMsg(pParse,
        "qualified table names are not allowed on INSERT, UPDATE, and DELETE "
        "statements within triggers");
}
        break;
      case 266: /* tridxby ::= INDEXED BY nm */
{
  sqlite3ErrorMsg(pParse,
        "the INDEXED BY clause is not allowed on UPDATE or DELETE statements "
        "within triggers");
}
        break;
      case 267: /* tridxby ::= NOT INDEXED */
{
  sqlite3ErrorMsg(pParse,
        "the NOT INDEXED clause is not allowed on UPDATE or DELETE statements "
        "within triggers");
}
        break;
      case 268: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */
{yylhsminor.yy157 = sqlite3TriggerUpdateStep(pParse, &yymsp[-6].minor.yy0, yymsp[-2].minor.yy153, yymsp[-3].minor.yy70, yymsp[-1].minor.yy404, yymsp[-7].minor.yy376, yymsp[-8].minor.yy0.z, yymsp[0].minor.yy504);}
  yymsp[-8].minor.yy157 = yylhsminor.yy157;
        break;
      case 269: /* trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */
{
   yylhsminor.yy157 = sqlite3TriggerInsertStep(pParse,&yymsp[-4].minor.yy0,yymsp[-3].minor.yy436,yymsp[-2].minor.yy81,yymsp[-6].minor.yy376,yymsp[-1].minor.yy190,yymsp[-7].minor.yy504,yymsp[0].minor.yy504);/*yylhsminor.yy157-overwrites-yymsp[-6].minor.yy376*/
}
  yymsp[-7].minor.yy157 = yylhsminor.yy157;
        break;
      case 270: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */
{yylhsminor.yy157 = sqlite3TriggerDeleteStep(pParse, &yymsp[-3].minor.yy0, yymsp[-1].minor.yy404, yymsp[-5].minor.yy0.z, yymsp[0].minor.yy504);}
  yymsp[-5].minor.yy157 = yylhsminor.yy157;
        break;
      case 271: /* trigger_cmd ::= scanpt select scanpt */
{yylhsminor.yy157 = sqlite3TriggerSelectStep(pParse->db, yymsp[-1].minor.yy81, yymsp[-2].minor.yy504, yymsp[0].minor.yy504); /*yylhsminor.yy157-overwrites-yymsp[-1].minor.yy81*/}
  yymsp[-2].minor.yy157 = yylhsminor.yy157;
        break;
      case 272: /* expr ::= RAISE LP IGNORE RP */
{
  yymsp[-3].minor.yy404 = sqlite3PExpr(pParse, TK_RAISE, 0, 0);
  if( yymsp[-3].minor.yy404 ){
    yymsp[-3].minor.yy404->affExpr = OE_Ignore;
  }
}
        break;
      case 273: /* expr ::= RAISE LP raisetype COMMA nm RP */
{
  yymsp[-5].minor.yy404 = sqlite3ExprAlloc(pParse->db, TK_RAISE, &yymsp[-1].minor.yy0, 1);
  if( yymsp[-5].minor.yy404 ) {
    yymsp[-5].minor.yy404->affExpr = (char)yymsp[-3].minor.yy376;
  }
}
        break;
      case 274: /* raisetype ::= ROLLBACK */
{yymsp[0].minor.yy376 = OE_Rollback;}
        break;
      case 276: /* raisetype ::= FAIL */
{yymsp[0].minor.yy376 = OE_Fail;}
        break;
      case 277: /* cmd ::= DROP TRIGGER ifexists fullname */
{
  sqlite3DropTrigger(pParse,yymsp[0].minor.yy153,yymsp[-1].minor.yy376);
}
        break;
      case 278: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
{
  sqlite3Attach(pParse, yymsp[-3].minor.yy404, yymsp[-1].minor.yy404, yymsp[0].minor.yy404);
}
        break;
      case 279: /* cmd ::= DETACH database_kw_opt expr */
{
  sqlite3Detach(pParse, yymsp[0].minor.yy404);
}
        break;
      case 282: /* cmd ::= REINDEX */
{sqlite3Reindex(pParse, 0, 0);}
        break;
      case 283: /* cmd ::= REINDEX nm dbnm */
{sqlite3Reindex(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);}
        break;
      case 284: /* cmd ::= ANALYZE */
{sqlite3Analyze(pParse, 0, 0);}
        break;
      case 285: /* cmd ::= ANALYZE nm dbnm */
{sqlite3Analyze(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);}
        break;
      case 286: /* cmd ::= ALTER TABLE fullname RENAME TO nm */
{
  sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy153,&yymsp[0].minor.yy0);
}
        break;
      case 287: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */
{
  yymsp[-1].minor.yy0.n = (int)(pParse->sLastToken.z-yymsp[-1].minor.yy0.z) + pParse->sLastToken.n;
  sqlite3AlterFinishAddColumn(pParse, &yymsp[-1].minor.yy0);
}
        break;
      case 288: /* cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */
{
  sqlite3AlterDropColumn(pParse, yymsp[-3].minor.yy153, &yymsp[0].minor.yy0);
}
        break;
      case 289: /* add_column_fullname ::= fullname */
{
  disableLookaside(pParse);
  sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy153);
}
        break;
      case 290: /* cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */
{
  sqlite3AlterRenameColumn(pParse, yymsp[-5].minor.yy153, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0);
}
        break;
      case 291: /* cmd ::= create_vtab */
{sqlite3VtabFinishParse(pParse,0);}
        break;
      case 292: /* cmd ::= create_vtab LP vtabarglist RP */
{sqlite3VtabFinishParse(pParse,&yymsp[0].minor.yy0);}
        break;
      case 293: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
{
    sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, yymsp[-4].minor.yy376);
}
        break;
      case 294: /* vtabarg ::= */
{sqlite3VtabArgInit(pParse);}
        break;
      case 295: /* vtabargtoken ::= ANY */
      case 296: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==296);
      case 297: /* lp ::= LP */ yytestcase(yyruleno==297);
{sqlite3VtabArgExtend(pParse,&yymsp[0].minor.yy0);}
        break;
      case 298: /* with ::= WITH wqlist */
      case 299: /* with ::= WITH RECURSIVE wqlist */ yytestcase(yyruleno==299);
{ sqlite3WithPush(pParse, yymsp[0].minor.yy103, 1); }
        break;
      case 300: /* wqas ::= AS */
{yymsp[0].minor.yy552 = M10d_Any;}
        break;
      case 301: /* wqas ::= AS MATERIALIZED */
{yymsp[-1].minor.yy552 = M10d_Yes;}
        break;
      case 302: /* wqas ::= AS NOT MATERIALIZED */
{yymsp[-2].minor.yy552 = M10d_No;}
        break;
      case 303: /* wqitem ::= nm eidlist_opt wqas LP select RP */
{
  yymsp[-5].minor.yy329 = sqlite3CteNew(pParse, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy70, yymsp[-1].minor.yy81, yymsp[-3].minor.yy552); /*A-overwrites-X*/
}
        break;
      case 304: /* wqlist ::= wqitem */
{
  yymsp[0].minor.yy103 = sqlite3WithAdd(pParse, 0, yymsp[0].minor.yy329); /*A-overwrites-X*/
}
        break;
      case 305: /* wqlist ::= wqlist COMMA wqitem */
{
  yymsp[-2].minor.yy103 = sqlite3WithAdd(pParse, yymsp[-2].minor.yy103, yymsp[0].minor.yy329);
}
        break;
      case 306: /* windowdefn_list ::= windowdefn */
{ yylhsminor.yy49 = yymsp[0].minor.yy49; }
  yymsp[0].minor.yy49 = yylhsminor.yy49;
        break;
      case 307: /* windowdefn_list ::= windowdefn_list COMMA windowdefn */
{
  assert( yymsp[0].minor.yy49!=0 );
  sqlite3WindowChain(pParse, yymsp[0].minor.yy49, yymsp[-2].minor.yy49);
  yymsp[0].minor.yy49->pNextWin = yymsp[-2].minor.yy49;
  yylhsminor.yy49 = yymsp[0].minor.yy49;
}
  yymsp[-2].minor.yy49 = yylhsminor.yy49;
        break;
      case 308: /* windowdefn ::= nm AS LP window RP */
{
  if( ALWAYS(yymsp[-1].minor.yy49) ){
    yymsp[-1].minor.yy49->zName = sqlite3DbStrNDup(pParse->db, yymsp[-4].minor.yy0.z, yymsp[-4].minor.yy0.n);
  }
  yylhsminor.yy49 = yymsp[-1].minor.yy49;
}
  yymsp[-4].minor.yy49 = yylhsminor.yy49;
        break;
      case 309: /* window ::= PARTITION BY nexprlist orderby_opt frame_opt */
{
  yymsp[-4].minor.yy49 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy49, yymsp[-2].minor.yy70, yymsp[-1].minor.yy70, 0);
}
        break;
      case 310: /* window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */
{
  yylhsminor.yy49 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy49, yymsp[-2].minor.yy70, yymsp[-1].minor.yy70, &yymsp[-5].minor.yy0);
}
  yymsp[-5].minor.yy49 = yylhsminor.yy49;
        break;
      case 311: /* window ::= ORDER BY sortlist frame_opt */
{
  yymsp[-3].minor.yy49 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy49, 0, yymsp[-1].minor.yy70, 0);
}
        break;
      case 312: /* window ::= nm ORDER BY sortlist frame_opt */
{
  yylhsminor.yy49 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy49, 0, yymsp[-1].minor.yy70, &yymsp[-4].minor.yy0);
}
  yymsp[-4].minor.yy49 = yylhsminor.yy49;
        break;
      case 313: /* window ::= frame_opt */
      case 332: /* filter_over ::= over_clause */ yytestcase(yyruleno==332);
{
  yylhsminor.yy49 = yymsp[0].minor.yy49;
}
  yymsp[0].minor.yy49 = yylhsminor.yy49;
        break;
      case 314: /* window ::= nm frame_opt */
{
  yylhsminor.yy49 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy49, 0, 0, &yymsp[-1].minor.yy0);
}
  yymsp[-1].minor.yy49 = yylhsminor.yy49;
        break;
      case 315: /* frame_opt ::= */
{
  yymsp[1].minor.yy49 = sqlite3WindowAlloc(pParse, 0, TK_UNBOUNDED, 0, TK_CURRENT, 0, 0);
}
        break;
      case 316: /* frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */
{
  yylhsminor.yy49 = sqlite3WindowAlloc(pParse, yymsp[-2].minor.yy376, yymsp[-1].minor.yy117.eType, yymsp[-1].minor.yy117.pExpr, TK_CURRENT, 0, yymsp[0].minor.yy552);
}
  yymsp[-2].minor.yy49 = yylhsminor.yy49;
        break;
      case 317: /* frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */
{
  yylhsminor.yy49 = sqlite3WindowAlloc(pParse, yymsp[-5].minor.yy376, yymsp[-3].minor.yy117.eType, yymsp[-3].minor.yy117.pExpr, yymsp[-1].minor.yy117.eType, yymsp[-1].minor.yy117.pExpr, yymsp[0].minor.yy552);
}
  yymsp[-5].minor.yy49 = yylhsminor.yy49;
        break;
      case 319: /* frame_bound_s ::= frame_bound */
      case 321: /* frame_bound_e ::= frame_bound */ yytestcase(yyruleno==321);
{yylhsminor.yy117 = yymsp[0].minor.yy117;}
  yymsp[0].minor.yy117 = yylhsminor.yy117;
        break;
      case 320: /* frame_bound_s ::= UNBOUNDED PRECEDING */
      case 322: /* frame_bound_e ::= UNBOUNDED FOLLOWING */ yytestcase(yyruleno==322);
      case 324: /* frame_bound ::= CURRENT ROW */ yytestcase(yyruleno==324);
{yylhsminor.yy117.eType = yymsp[-1].major; yylhsminor.yy117.pExpr = 0;}
  yymsp[-1].minor.yy117 = yylhsminor.yy117;
        break;
      case 323: /* frame_bound ::= expr PRECEDING|FOLLOWING */
{yylhsminor.yy117.eType = yymsp[0].major; yylhsminor.yy117.pExpr = yymsp[-1].minor.yy404;}
  yymsp[-1].minor.yy117 = yylhsminor.yy117;
        break;
      case 325: /* frame_exclude_opt ::= */
{yymsp[1].minor.yy552 = 0;}
        break;
      case 326: /* frame_exclude_opt ::= EXCLUDE frame_exclude */
{yymsp[-1].minor.yy552 = yymsp[0].minor.yy552;}
        break;
      case 327: /* frame_exclude ::= NO OTHERS */
      case 328: /* frame_exclude ::= CURRENT ROW */ yytestcase(yyruleno==328);
{yymsp[-1].minor.yy552 = yymsp[-1].major; /*A-overwrites-X*/}
        break;
      case 329: /* frame_exclude ::= GROUP|TIES */
{yymsp[0].minor.yy552 = yymsp[0].major; /*A-overwrites-X*/}
        break;
      case 330: /* window_clause ::= WINDOW windowdefn_list */
{ yymsp[-1].minor.yy49 = yymsp[0].minor.yy49; }
        break;
      case 331: /* filter_over ::= filter_clause over_clause */
{
  if( yymsp[0].minor.yy49 ){
    yymsp[0].minor.yy49->pFilter = yymsp[-1].minor.yy404;
  }else{
    sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy404);
  }
  yylhsminor.yy49 = yymsp[0].minor.yy49;
}
  yymsp[-1].minor.yy49 = yylhsminor.yy49;
        break;
      case 333: /* filter_over ::= filter_clause */
{
  yylhsminor.yy49 = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window));
  if( yylhsminor.yy49 ){
    yylhsminor.yy49->eFrmType = TK_FILTER;
    yylhsminor.yy49->pFilter = yymsp[0].minor.yy404;
  }else{
    sqlite3ExprDelete(pParse->db, yymsp[0].minor.yy404);
  }
}
  yymsp[0].minor.yy49 = yylhsminor.yy49;
        break;
      case 334: /* over_clause ::= OVER LP window RP */
{
  yymsp[-3].minor.yy49 = yymsp[-1].minor.yy49;
  assert( yymsp[-3].minor.yy49!=0 );
}
        break;
      case 335: /* over_clause ::= OVER nm */
{
  yymsp[-1].minor.yy49 = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window));
  if( yymsp[-1].minor.yy49 ){
    yymsp[-1].minor.yy49->zName = sqlite3DbStrNDup(pParse->db, yymsp[0].minor.yy0.z, yymsp[0].minor.yy0.n);
  }
}
        break;
      case 336: /* filter_clause ::= FILTER LP WHERE expr RP */
{ yymsp[-4].minor.yy404 = yymsp[-1].minor.yy404; }
        break;
      default:
      /* (337) input ::= cmdlist */ yytestcase(yyruleno==337);
      /* (338) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==338);
      /* (339) cmdlist ::= ecmd (OPTIMIZED OUT) */ assert(yyruleno!=339);
      /* (340) ecmd ::= SEMI */ yytestcase(yyruleno==340);
      /* (341) ecmd ::= cmdx SEMI */ yytestcase(yyruleno==341);
      /* (342) ecmd ::= explain cmdx SEMI (NEVER REDUCES) */ assert(yyruleno!=342);
      /* (343) trans_opt ::= */ yytestcase(yyruleno==343);
      /* (344) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==344);
      /* (345) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==345);
      /* (346) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==346);
      /* (347) savepoint_opt ::= */ yytestcase(yyruleno==347);
      /* (348) cmd ::= create_table create_table_args */ yytestcase(yyruleno==348);

      /* (349) columnlist ::= columnlist COMMA columnname carglist */ yytestcase(yyruleno==349);
      /* (350) columnlist ::= columnname carglist */ yytestcase(yyruleno==350);
      /* (351) nm ::= ID|INDEXED */ yytestcase(yyruleno==351);
      /* (352) nm ::= STRING */ yytestcase(yyruleno==352);
      /* (353) nm ::= JOIN_KW */ yytestcase(yyruleno==353);
      /* (354) typetoken ::= typename */ yytestcase(yyruleno==354);
      /* (355) typename ::= ID|STRING */ yytestcase(yyruleno==355);
      /* (356) signed ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=356);
      /* (357) signed ::= minus_num (OPTIMIZED OUT) */ assert(yyruleno!=357);
      /* (358) carglist ::= carglist ccons */ yytestcase(yyruleno==358);
      /* (359) carglist ::= */ yytestcase(yyruleno==359);
      /* (360) ccons ::= NULL onconf */ yytestcase(yyruleno==360);
      /* (361) ccons ::= GENERATED ALWAYS AS generated */ yytestcase(yyruleno==361);
      /* (362) ccons ::= AS generated */ yytestcase(yyruleno==362);
      /* (363) conslist_opt ::= COMMA conslist */ yytestcase(yyruleno==363);
      /* (364) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==364);
      /* (365) conslist ::= tcons (OPTIMIZED OUT) */ assert(yyruleno!=365);
      /* (366) tconscomma ::= */ yytestcase(yyruleno==366);
      /* (367) defer_subclause_opt ::= defer_subclause (OPTIMIZED OUT) */ assert(yyruleno!=367);
      /* (368) resolvetype ::= raisetype (OPTIMIZED OUT) */ assert(yyruleno!=368);
      /* (369) selectnowith ::= oneselect (OPTIMIZED OUT) */ assert(yyruleno!=369);
      /* (370) oneselect ::= values */ yytestcase(yyruleno==370);
      /* (371) sclp ::= selcollist COMMA */ yytestcase(yyruleno==371);
      /* (372) as ::= ID|STRING */ yytestcase(yyruleno==372);
      /* (373) returning ::= */ yytestcase(yyruleno==373);
      /* (374) expr ::= term (OPTIMIZED OUT) */ assert(yyruleno!=374);
      /* (375) likeop ::= LIKE_KW|MATCH */ yytestcase(yyruleno==375);
      /* (376) exprlist ::= nexprlist */ yytestcase(yyruleno==376);
      /* (377) nmnum ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=377);
      /* (378) nmnum ::= nm (OPTIMIZED OUT) */ assert(yyruleno!=378);
      /* (379) nmnum ::= ON */ yytestcase(yyruleno==379);
      /* (380) nmnum ::= DELETE */ yytestcase(yyruleno==380);
      /* (381) nmnum ::= DEFAULT */ yytestcase(yyruleno==381);
      /* (382) plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==382);
      /* (383) foreach_clause ::= */ yytestcase(yyruleno==383);
      /* (384) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==384);
      /* (385) trnm ::= nm */ yytestcase(yyruleno==385);
      /* (386) tridxby ::= */ yytestcase(yyruleno==386);
      /* (387) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==387);
      /* (388) database_kw_opt ::= */ yytestcase(yyruleno==388);
      /* (389) kwcolumn_opt ::= */ yytestcase(yyruleno==389);
      /* (390) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==390);
      /* (391) vtabarglist ::= vtabarg */ yytestcase(yyruleno==391);
      /* (392) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==392);
      /* (393) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==393);
      /* (394) anylist ::= */ yytestcase(yyruleno==394);
      /* (395) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==395);
      /* (396) anylist ::= anylist ANY */ yytestcase(yyruleno==396);
      /* (397) with ::= */ yytestcase(yyruleno==397);
        break;
/********** End reduce actions ************************************************/
  };
  assert( yyruleno<sizeof(yyRuleInfoLhs)/sizeof(yyRuleInfoLhs[0]) );
  yygoto = yyRuleInfoLhs[yyruleno];
  yysize = yyRuleInfoNRhs[yyruleno];
  yyact = yy_find_reduce_action(yymsp[yysize].stateno,(YYCODETYPE)yygoto);







|







<
|
|
|
|
|
|
|


|


|

|

|




|
|


>
>
>
|
>
>
>
>


|

|
>
>
>
>
>
>
>
>
>
>



>

|


|
|
|


|




|




|


|


|


|





|
|


|
|

|
|

|
|

|

|



|









|
|

|
|

|
|


|
|

|
|

|
|

|


|
|

|
|

|
|

|
|

|
|

|
|

|
|

|
|

|
|

|
|

|
|

|
|

|
|

|
|

|
|

|
|
|
|

|
|
|
|
|
|

|
|

|


|
|

|
|


|
|

|

|
|


|
|
|

|
|

|
|

|
|
|

|

|


|

|


|

|


|


|
|


|
|

|
|

|

|



|


|

|
|









|



|



|


|
|
|

|
|

|

|


|

|
|
|

|



|

|


|

|
|




|

|



|
|

|
|

|
|
|
|
|
|
|

|

|
|
|


|


|


|




|


|
|
|
|


|
|
|

|

|
|


|

|


|

|
|


|

|
|


|

|


|

|
|
|
|
|
|
|












|


|
|
|



|
|


|

|
|

|

|

|
|

|

|
|

|
|

|

|
|


|

|
|


|
|

|
|

|
|

|
|

|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|

|


|


|
|

|
|
|

|
|
|

|

|
|


|

|
|


|
|

|
|

|
|
|

|
|

|
|

|
|

|
|

|
|

|

|
|


|
|

|
|

|

|
|
|
|


|

|
|


|

|


|

|
|

|

|

|


|

|


|

|


|
|

|
|

|
|

|
|

|
|

|
|

|
|

|
|

|
|

|
|

|
|

|
|
|

|







|

|

|









|

|

|
|
|

|

|

|

|



|
|








|

|
|




|

|


|

|
|


|

|

|

|

|

|

|

|
|

|

|

|
|

|

|

|

|

|

|
|
|
|

|






|
|

|
|
|
|
|
|
|
|

|


|




|
|
|
|
|


|




|
|
|
|
|
|


|
|

|
|

|

|
|


|

|
|


|
|
|

|

|



|
|
|

|

|
|
|
|
|



|


|

|








|
|

|
|
|
|

|

|
|
|
|
|
|


|


|
|


|



|

|
|


|

|
|
|


|



|
|
|
|


|


|
|


|

|
|
|
|

|
|



|

|
|


|

|
|


|
|

|
|

|
|

|
|
|

|


|
|





|
|
|

|
|

|

|


|

|


|
|

|
|

|
|

|


|


|


|


|


|




|


|

|



|
|

|
|

|
|

|
|
|

|
|

|
|
|

|
|
|

|

|
|
|


|

|
|


|







|






|






|
|
|

|

|

|

|
|
|

|
|
|

|

|
|
|



|

|
|
|



|
|

|
|

|

|


|

|


|

|


|


|


|


|


|

|


|





|

|


|


|


|

|


|


|


|

|


|


|
|
|


|
|
|

|
|

|
|

|
|

|

|


|

|


|

|


|
|
|

|

|
|
|
|

|

|

|
|

|

|

|

|


|

|

|

|

|


|

|

|

|
|

|

|

|

|

|

|

|


|

|

|

|

|

|

|
|
|
|

|
|
|
|
|

|
|
|

|
|

|
|

|
|
|

|
|

|
|

|

|
|

|

|

|

|

|
|
|
|

|


|

|

|
|


|

|
|
|



|
|


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







162306
162307
162308
162309
162310
162311
162312
162313
162314
162315
162316
162317
162318
162319
162320

162321
162322
162323
162324
162325
162326
162327
162328
162329
162330
162331
162332
162333
162334
162335
162336
162337
162338
162339
162340
162341
162342
162343
162344
162345
162346
162347
162348
162349
162350
162351
162352
162353
162354
162355
162356
162357
162358
162359
162360
162361
162362
162363
162364
162365
162366
162367
162368
162369
162370
162371
162372
162373
162374
162375
162376
162377
162378
162379
162380
162381
162382
162383
162384
162385
162386
162387
162388
162389
162390
162391
162392
162393
162394
162395
162396
162397
162398
162399
162400
162401
162402
162403
162404
162405
162406
162407
162408
162409
162410
162411
162412
162413
162414
162415
162416
162417
162418
162419
162420
162421
162422
162423
162424
162425
162426
162427
162428
162429
162430
162431
162432
162433
162434
162435
162436
162437
162438
162439
162440
162441
162442
162443
162444
162445
162446
162447
162448
162449
162450
162451
162452
162453
162454
162455
162456
162457
162458
162459
162460
162461
162462
162463
162464
162465
162466
162467
162468
162469
162470
162471
162472
162473
162474
162475
162476
162477
162478
162479
162480
162481
162482
162483
162484
162485
162486
162487
162488
162489
162490
162491
162492
162493
162494
162495
162496
162497
162498
162499
162500
162501
162502
162503
162504
162505
162506
162507
162508
162509
162510
162511
162512
162513
162514
162515
162516
162517
162518
162519
162520
162521
162522
162523
162524
162525
162526
162527
162528
162529
162530
162531
162532
162533
162534
162535
162536
162537
162538
162539
162540
162541
162542
162543
162544
162545
162546
162547
162548
162549
162550
162551
162552
162553
162554
162555
162556
162557
162558
162559
162560
162561
162562
162563
162564
162565
162566
162567
162568
162569
162570
162571
162572
162573
162574
162575
162576
162577
162578
162579
162580
162581
162582
162583
162584
162585
162586
162587
162588
162589
162590
162591
162592
162593
162594
162595
162596
162597
162598
162599
162600
162601
162602
162603
162604
162605
162606
162607
162608
162609
162610
162611
162612
162613
162614
162615
162616
162617
162618
162619
162620
162621
162622
162623
162624
162625
162626
162627
162628
162629
162630
162631
162632
162633
162634
162635
162636
162637
162638
162639
162640
162641
162642
162643
162644
162645
162646
162647
162648
162649
162650
162651
162652
162653
162654
162655
162656
162657
162658
162659
162660
162661
162662
162663
162664
162665
162666
162667
162668
162669
162670
162671
162672
162673
162674
162675
162676
162677
162678
162679
162680
162681
162682
162683
162684
162685
162686
162687
162688
162689
162690
162691
162692
162693
162694
162695
162696
162697
162698
162699
162700
162701
162702
162703
162704
162705
162706
162707
162708
162709
162710
162711
162712
162713
162714
162715
162716
162717
162718
162719
162720
162721
162722
162723
162724
162725
162726
162727
162728
162729
162730
162731
162732
162733
162734
162735
162736
162737
162738
162739
162740
162741
162742
162743
162744
162745
162746
162747
162748
162749
162750
162751
162752
162753
162754
162755
162756
162757
162758
162759
162760
162761
162762
162763
162764
162765
162766
162767
162768
162769
162770
162771
162772
162773
162774
162775
162776
162777
162778
162779
162780
162781
162782
162783
162784
162785
162786
162787
162788
162789
162790
162791
162792
162793
162794
162795
162796
162797
162798
162799
162800
162801
162802
162803
162804
162805
162806
162807
162808
162809
162810
162811
162812
162813
162814
162815
162816
162817
162818
162819
162820
162821
162822
162823
162824
162825
162826
162827
162828
162829
162830
162831
162832
162833
162834
162835
162836
162837
162838
162839
162840
162841
162842
162843
162844
162845
162846
162847
162848
162849
162850
162851
162852
162853
162854
162855
162856
162857
162858
162859
162860
162861
162862
162863
162864
162865
162866
162867
162868
162869
162870
162871
162872
162873
162874
162875
162876
162877
162878
162879
162880
162881
162882
162883
162884
162885
162886
162887
162888
162889
162890
162891
162892
162893
162894
162895
162896
162897
162898
162899
162900
162901
162902
162903
162904
162905
162906
162907
162908
162909
162910
162911
162912
162913
162914
162915
162916
162917
162918
162919
162920
162921
162922
162923
162924
162925
162926
162927
162928
162929
162930
162931
162932
162933
162934
162935
162936
162937
162938
162939
162940
162941
162942
162943
162944
162945
162946
162947
162948
162949
162950
162951
162952
162953
162954
162955
162956
162957
162958
162959
162960
162961
162962
162963
162964
162965
162966
162967
162968
162969
162970
162971
162972
162973
162974
162975
162976
162977
162978
162979
162980
162981
162982
162983
162984
162985
162986
162987
162988
162989
162990
162991
162992
162993
162994
162995
162996
162997
162998
162999
163000
163001
163002
163003
163004
163005
163006
163007
163008
163009
163010
163011
163012
163013
163014
163015
163016
163017
163018
163019
163020
163021
163022
163023
163024
163025
163026
163027
163028
163029
163030
163031
163032
163033
163034
163035
163036
163037
163038
163039
163040
163041
163042
163043
163044
163045
163046
163047
163048
163049
163050
163051
163052
163053
163054
163055
163056
163057
163058
163059
163060
163061
163062
163063
163064
163065
163066
163067
163068
163069
163070
163071
163072
163073
163074
163075
163076
163077
163078
163079
163080
163081
163082
163083
163084
163085
163086
163087
163088
163089
163090
163091
163092
163093
163094
163095
163096
163097
163098
163099
163100
163101
163102
163103
163104
163105
163106
163107
163108
163109
163110
163111
163112
163113
163114
163115
163116
163117
163118
163119
163120
163121
163122
163123
163124
163125
163126
163127
163128
163129
163130
163131
163132
163133
163134
163135
163136
163137
163138
163139
163140
163141
163142
163143
163144
163145
163146
163147
163148
163149
163150
163151
163152
163153
163154
163155
163156
163157
163158
163159
163160
163161
163162
163163
163164
163165
163166
163167
163168
163169
163170
163171
163172
163173
163174
163175
163176
163177
163178
163179
163180
163181
163182
163183
163184
163185
163186
163187
163188
163189
163190
163191
163192
163193
163194
163195
163196
163197
163198
163199
163200
163201
163202
163203
163204
163205
163206
163207
163208
163209
163210
163211
163212
163213
163214
163215
163216
163217
163218
163219
163220
163221
163222
163223
163224
163225
163226
163227
163228
163229
163230
163231
163232
163233
163234
163235
163236
163237
163238
163239
163240
163241
163242
163243
163244
163245
163246
163247
163248
163249
163250
163251
163252
163253
163254
163255
163256
163257
163258
163259
163260
163261
163262
163263
163264
163265
163266
163267
163268
163269
163270
163271
163272
163273
163274
163275
163276
163277
163278
163279
163280
163281
163282
163283
163284
163285
163286
163287
163288
163289
163290
163291
163292
163293
163294
163295
163296
163297
163298
163299
163300
163301
163302
163303
163304
163305
163306
163307
163308
163309
163310
163311
163312
163313
163314
163315
163316
163317
163318
163319
163320
163321
163322
163323
163324
163325
163326
163327
163328
163329
163330
163331
163332
163333
163334
163335
163336
163337
163338
163339
163340
163341
163342
163343
163344
163345
163346
163347
163348
163349
163350
163351
163352
163353
163354
163355
163356
163357
163358
163359
163360
163361
163362
163363
163364
163365
163366
163367
163368
163369
163370
163371
163372
163373
163374
163375
163376
163377
163378
163379
163380
163381
163382
163383
163384
163385
163386
163387
163388
163389
163390
163391
163392
163393
163394
163395
163396
163397
163398
163399
163400
163401
163402
163403
163404
163405
163406
163407
163408
163409
163410
163411
163412
163413
163414
163415
163416
163417
163418
163419
163420
163421
163422
163423
163424
163425
163426
163427
163428
163429
163430
163431
163432
163433
163434
163435
163436
163437
163438
163439
163440
163441
163442
163443
163444
163445
163446
163447
163448
163449
163450
163451
163452
163453
163454
163455
163456
163457
163458
163459
163460
163461
163462
163463
163464
163465
163466
163467
163468
163469
163470
163471
163472
163473
163474
163475
163476
163477
163478
163479
163480
163481
163482
163483
163484
163485
163486
163487
163488
163489
163490
163491
163492
163493
163494
163495
163496
163497
163498
163499
163500
163501
163502
163503
163504
163505
163506
163507
163508
163509
163510
163511
163512
163513
163514
163515
163516
163517
163518
163519
163520
163521
163522
163523
163524
163525
163526
163527
163528
163529
163530
163531
163532
163533
163534
163535
163536
163537
163538
163539
163540
163541
163542
163543
163544
163545
163546
163547
163548
163549
163550
163551
163552
163553
163554
163555
163556
163557
163558
163559
163560
163561
163562
163563
163564
163565
163566
163567
163568
163569
163570
163571
163572
163573
163574
163575
163576
163577
163578
163579
163580
163581
163582
163583
163584
163585
163586
163587
163588
163589
163590
163591
163592
163593
163594
163595
163596
163597
163598
163599
163600
163601
163602
163603
163604
163605
163606
163607
163608
163609
163610
163611
163612
163613
163614
163615
163616
163617
163618
163619
163620
163621
163622
163623
163624
163625
163626
163627
163628
163629
163630
163631
163632
163633
163634
163635
163636
163637
163638
163639
163640
163641
163642
163643
163644
163645
163646
163647
163648
163649
163650
163651
163652
163653
163654
163655
163656
163657
163658
163659
163660
163661
163662
163663
163664
163665
163666
163667
163668
163669
163670
163671
163672
163673
163674
163675
163676
163677
163678
163679
163680
163681
163682
163683
163684
163685
163686
163687
163688
163689
163690
163691
163692
163693
163694
163695
163696
163697
163698
163699
163700
163701
163702
163703
163704
163705
163706
163707
163708
163709
163710
163711
163712
163713
163714
163715
163716
163717
163718
163719
163720
163721
163722
163723
163724
163725
163726
163727
163728
163729
163730
163731
163732
163733
163734
163735
163736
163737
163738
163739
163740
163741
163742
163743
163744
163745
163746
163747
163748
163749
163750
163751
163752
      case 12: /* cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */
{
  sqlite3Savepoint(pParse, SAVEPOINT_ROLLBACK, &yymsp[0].minor.yy0);
}
        break;
      case 13: /* create_table ::= createkw temp TABLE ifnotexists nm dbnm */
{
   sqlite3StartTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,yymsp[-4].minor.yy64,0,0,yymsp[-2].minor.yy64);
}
        break;
      case 14: /* createkw ::= CREATE */
{disableLookaside(pParse);}
        break;
      case 15: /* ifnotexists ::= */
      case 18: /* temp ::= */ yytestcase(yyruleno==18);

      case 47: /* autoinc ::= */ yytestcase(yyruleno==47);
      case 62: /* init_deferred_pred_opt ::= */ yytestcase(yyruleno==62);
      case 72: /* defer_subclause_opt ::= */ yytestcase(yyruleno==72);
      case 81: /* ifexists ::= */ yytestcase(yyruleno==81);
      case 98: /* distinct ::= */ yytestcase(yyruleno==98);
      case 241: /* collate ::= */ yytestcase(yyruleno==241);
{yymsp[1].minor.yy64 = 0;}
        break;
      case 16: /* ifnotexists ::= IF NOT EXISTS */
{yymsp[-2].minor.yy64 = 1;}
        break;
      case 17: /* temp ::= TEMP */
{yymsp[0].minor.yy64 = pParse->db->init.busy==0;}
        break;
      case 19: /* create_table_args ::= LP columnlist conslist_opt RP table_option_set */
{
  sqlite3EndTable(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,yymsp[0].minor.yy51,0);
}
        break;
      case 20: /* create_table_args ::= AS select */
{
  sqlite3EndTable(pParse,0,0,0,yymsp[0].minor.yy303);
  sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy303);
}
        break;
      case 21: /* table_option_set ::= */
{yymsp[1].minor.yy51 = 0;}
        break;
      case 22: /* table_option_set ::= table_option_set COMMA table_option */
{yylhsminor.yy51 = yymsp[-2].minor.yy51|yymsp[0].minor.yy51;}
  yymsp[-2].minor.yy51 = yylhsminor.yy51;
        break;
      case 23: /* table_option ::= WITHOUT nm */
{
  if( yymsp[0].minor.yy0.n==5 && sqlite3_strnicmp(yymsp[0].minor.yy0.z,"rowid",5)==0 ){
    yymsp[-1].minor.yy51 = TF_WithoutRowid | TF_NoVisibleRowid;
  }else{
    yymsp[-1].minor.yy51 = 0;
    sqlite3ErrorMsg(pParse, "unknown table option: %.*s", yymsp[0].minor.yy0.n, yymsp[0].minor.yy0.z);
  }
}
        break;
      case 24: /* table_option ::= nm */
{
  if( yymsp[0].minor.yy0.n==6 && sqlite3_strnicmp(yymsp[0].minor.yy0.z,"strict",6)==0 ){
    yylhsminor.yy51 = TF_Strict;
  }else{
    yylhsminor.yy51 = 0;
    sqlite3ErrorMsg(pParse, "unknown table option: %.*s", yymsp[0].minor.yy0.n, yymsp[0].minor.yy0.z);
  }
}
  yymsp[0].minor.yy51 = yylhsminor.yy51;
        break;
      case 25: /* columnname ::= nm typetoken */
{sqlite3AddColumn(pParse,yymsp[-1].minor.yy0,yymsp[0].minor.yy0);}
        break;
      case 26: /* typetoken ::= */
      case 65: /* conslist_opt ::= */ yytestcase(yyruleno==65);
      case 104: /* as ::= */ yytestcase(yyruleno==104);
{yymsp[1].minor.yy0.n = 0; yymsp[1].minor.yy0.z = 0;}
        break;
      case 27: /* typetoken ::= typename LP signed RP */
{
  yymsp[-3].minor.yy0.n = (int)(&yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-3].minor.yy0.z);
}
        break;
      case 28: /* typetoken ::= typename LP signed COMMA signed RP */
{
  yymsp[-5].minor.yy0.n = (int)(&yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-5].minor.yy0.z);
}
        break;
      case 29: /* typename ::= typename ID|STRING */
{yymsp[-1].minor.yy0.n=yymsp[0].minor.yy0.n+(int)(yymsp[0].minor.yy0.z-yymsp[-1].minor.yy0.z);}
        break;
      case 30: /* scanpt ::= */
{
  assert( yyLookahead!=YYNOCODE );
  yymsp[1].minor.yy600 = yyLookaheadToken.z;
}
        break;
      case 31: /* scantok ::= */
{
  assert( yyLookahead!=YYNOCODE );
  yymsp[1].minor.yy0 = yyLookaheadToken;
}
        break;
      case 32: /* ccons ::= CONSTRAINT nm */
      case 67: /* tcons ::= CONSTRAINT nm */ yytestcase(yyruleno==67);
{pParse->constraintName = yymsp[0].minor.yy0;}
        break;
      case 33: /* ccons ::= DEFAULT scantok term */
{sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy626,yymsp[-1].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);}
        break;
      case 34: /* ccons ::= DEFAULT LP expr RP */
{sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy626,yymsp[-2].minor.yy0.z+1,yymsp[0].minor.yy0.z);}
        break;
      case 35: /* ccons ::= DEFAULT PLUS scantok term */
{sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy626,yymsp[-2].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);}
        break;
      case 36: /* ccons ::= DEFAULT MINUS scantok term */
{
  Expr *p = sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy626, 0);
  sqlite3AddDefaultValue(pParse,p,yymsp[-2].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);
}
        break;
      case 37: /* ccons ::= DEFAULT scantok ID|INDEXED */
{
  Expr *p = tokenExpr(pParse, TK_STRING, yymsp[0].minor.yy0);
  if( p ){
    sqlite3ExprIdToTrueFalse(p);
    testcase( p->op==TK_TRUEFALSE && sqlite3ExprTruthValue(p) );
  }
    sqlite3AddDefaultValue(pParse,p,yymsp[0].minor.yy0.z,yymsp[0].minor.yy0.z+yymsp[0].minor.yy0.n);
}
        break;
      case 38: /* ccons ::= NOT NULL onconf */
{sqlite3AddNotNull(pParse, yymsp[0].minor.yy64);}
        break;
      case 39: /* ccons ::= PRIMARY KEY sortorder onconf autoinc */
{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy64,yymsp[0].minor.yy64,yymsp[-2].minor.yy64);}
        break;
      case 40: /* ccons ::= UNIQUE onconf */
{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy64,0,0,0,0,
                                   SQLITE_IDXTYPE_UNIQUE);}
        break;
      case 41: /* ccons ::= CHECK LP expr RP */
{sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy626,yymsp[-2].minor.yy0.z,yymsp[0].minor.yy0.z);}
        break;
      case 42: /* ccons ::= REFERENCES nm eidlist_opt refargs */
{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy562,yymsp[0].minor.yy64);}
        break;
      case 43: /* ccons ::= defer_subclause */
{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy64);}
        break;
      case 44: /* ccons ::= COLLATE ID|STRING */
{sqlite3AddCollateType(pParse, &yymsp[0].minor.yy0);}
        break;
      case 45: /* generated ::= LP expr RP */
{sqlite3AddGenerated(pParse,yymsp[-1].minor.yy626,0);}
        break;
      case 46: /* generated ::= LP expr RP ID */
{sqlite3AddGenerated(pParse,yymsp[-2].minor.yy626,&yymsp[0].minor.yy0);}
        break;
      case 48: /* autoinc ::= AUTOINCR */
{yymsp[0].minor.yy64 = 1;}
        break;
      case 49: /* refargs ::= */
{ yymsp[1].minor.yy64 = OE_None*0x0101; /* EV: R-19803-45884 */}
        break;
      case 50: /* refargs ::= refargs refarg */
{ yymsp[-1].minor.yy64 = (yymsp[-1].minor.yy64 & ~yymsp[0].minor.yy83.mask) | yymsp[0].minor.yy83.value; }
        break;
      case 51: /* refarg ::= MATCH nm */
{ yymsp[-1].minor.yy83.value = 0;     yymsp[-1].minor.yy83.mask = 0x000000; }
        break;
      case 52: /* refarg ::= ON INSERT refact */
{ yymsp[-2].minor.yy83.value = 0;     yymsp[-2].minor.yy83.mask = 0x000000; }
        break;
      case 53: /* refarg ::= ON DELETE refact */
{ yymsp[-2].minor.yy83.value = yymsp[0].minor.yy64;     yymsp[-2].minor.yy83.mask = 0x0000ff; }
        break;
      case 54: /* refarg ::= ON UPDATE refact */
{ yymsp[-2].minor.yy83.value = yymsp[0].minor.yy64<<8;  yymsp[-2].minor.yy83.mask = 0x00ff00; }
        break;
      case 55: /* refact ::= SET NULL */
{ yymsp[-1].minor.yy64 = OE_SetNull;  /* EV: R-33326-45252 */}
        break;
      case 56: /* refact ::= SET DEFAULT */
{ yymsp[-1].minor.yy64 = OE_SetDflt;  /* EV: R-33326-45252 */}
        break;
      case 57: /* refact ::= CASCADE */
{ yymsp[0].minor.yy64 = OE_Cascade;  /* EV: R-33326-45252 */}
        break;
      case 58: /* refact ::= RESTRICT */
{ yymsp[0].minor.yy64 = OE_Restrict; /* EV: R-33326-45252 */}
        break;
      case 59: /* refact ::= NO ACTION */
{ yymsp[-1].minor.yy64 = OE_None;     /* EV: R-33326-45252 */}
        break;
      case 60: /* defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */
{yymsp[-2].minor.yy64 = 0;}
        break;
      case 61: /* defer_subclause ::= DEFERRABLE init_deferred_pred_opt */
      case 76: /* orconf ::= OR resolvetype */ yytestcase(yyruleno==76);
      case 171: /* insert_cmd ::= INSERT orconf */ yytestcase(yyruleno==171);
{yymsp[-1].minor.yy64 = yymsp[0].minor.yy64;}
        break;
      case 63: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */
      case 80: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==80);
      case 213: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==213);
      case 216: /* in_op ::= NOT IN */ yytestcase(yyruleno==216);
      case 242: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==242);
{yymsp[-1].minor.yy64 = 1;}
        break;
      case 64: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */
{yymsp[-1].minor.yy64 = 0;}
        break;
      case 66: /* tconscomma ::= COMMA */
{pParse->constraintName.n = 0;}
        break;
      case 68: /* tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */
{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy562,yymsp[0].minor.yy64,yymsp[-2].minor.yy64,0);}
        break;
      case 69: /* tcons ::= UNIQUE LP sortlist RP onconf */
{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy562,yymsp[0].minor.yy64,0,0,0,0,
                                       SQLITE_IDXTYPE_UNIQUE);}
        break;
      case 70: /* tcons ::= CHECK LP expr RP onconf */
{sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy626,yymsp[-3].minor.yy0.z,yymsp[-1].minor.yy0.z);}
        break;
      case 71: /* tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */
{
    sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy562, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy562, yymsp[-1].minor.yy64);
    sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy64);
}
        break;
      case 73: /* onconf ::= */
      case 75: /* orconf ::= */ yytestcase(yyruleno==75);
{yymsp[1].minor.yy64 = OE_Default;}
        break;
      case 74: /* onconf ::= ON CONFLICT resolvetype */
{yymsp[-2].minor.yy64 = yymsp[0].minor.yy64;}
        break;
      case 77: /* resolvetype ::= IGNORE */
{yymsp[0].minor.yy64 = OE_Ignore;}
        break;
      case 78: /* resolvetype ::= REPLACE */
      case 172: /* insert_cmd ::= REPLACE */ yytestcase(yyruleno==172);
{yymsp[0].minor.yy64 = OE_Replace;}
        break;
      case 79: /* cmd ::= DROP TABLE ifexists fullname */
{
  sqlite3DropTable(pParse, yymsp[0].minor.yy607, 0, yymsp[-1].minor.yy64);
}
        break;
      case 82: /* cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */
{
  sqlite3CreateView(pParse, &yymsp[-8].minor.yy0, &yymsp[-4].minor.yy0, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy562, yymsp[0].minor.yy303, yymsp[-7].minor.yy64, yymsp[-5].minor.yy64);
}
        break;
      case 83: /* cmd ::= DROP VIEW ifexists fullname */
{
  sqlite3DropTable(pParse, yymsp[0].minor.yy607, 1, yymsp[-1].minor.yy64);
}
        break;
      case 84: /* cmd ::= select */
{
  SelectDest dest = {SRT_Output, 0, 0, 0, 0, 0, 0};
  sqlite3Select(pParse, yymsp[0].minor.yy303, &dest);
  sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy303);
}
        break;
      case 85: /* select ::= WITH wqlist selectnowith */
{yymsp[-2].minor.yy303 = attachWithToSelect(pParse,yymsp[0].minor.yy303,yymsp[-1].minor.yy43);}
        break;
      case 86: /* select ::= WITH RECURSIVE wqlist selectnowith */
{yymsp[-3].minor.yy303 = attachWithToSelect(pParse,yymsp[0].minor.yy303,yymsp[-1].minor.yy43);}
        break;
      case 87: /* select ::= selectnowith */
{
  Select *p = yymsp[0].minor.yy303;
  if( p ){
    parserDoubleLinkSelect(pParse, p);
  }
  yymsp[0].minor.yy303 = p; /*A-overwrites-X*/
}
        break;
      case 88: /* selectnowith ::= selectnowith multiselect_op oneselect */
{
  Select *pRhs = yymsp[0].minor.yy303;
  Select *pLhs = yymsp[-2].minor.yy303;
  if( pRhs && pRhs->pPrior ){
    SrcList *pFrom;
    Token x;
    x.n = 0;
    parserDoubleLinkSelect(pParse, pRhs);
    pFrom = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&x,pRhs,0,0);
    pRhs = sqlite3SelectNew(pParse,0,pFrom,0,0,0,0,0,0);
  }
  if( pRhs ){
    pRhs->op = (u8)yymsp[-1].minor.yy64;
    pRhs->pPrior = pLhs;
    if( ALWAYS(pLhs) ) pLhs->selFlags &= ~SF_MultiValue;
    pRhs->selFlags &= ~SF_MultiValue;
    if( yymsp[-1].minor.yy64!=TK_ALL ) pParse->hasCompound = 1;
  }else{
    sqlite3SelectDelete(pParse->db, pLhs);
  }
  yymsp[-2].minor.yy303 = pRhs;
}
        break;
      case 89: /* multiselect_op ::= UNION */
      case 91: /* multiselect_op ::= EXCEPT|INTERSECT */ yytestcase(yyruleno==91);
{yymsp[0].minor.yy64 = yymsp[0].major; /*A-overwrites-OP*/}
        break;
      case 90: /* multiselect_op ::= UNION ALL */
{yymsp[-1].minor.yy64 = TK_ALL;}
        break;
      case 92: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
{
  yymsp[-8].minor.yy303 = sqlite3SelectNew(pParse,yymsp[-6].minor.yy562,yymsp[-5].minor.yy607,yymsp[-4].minor.yy626,yymsp[-3].minor.yy562,yymsp[-2].minor.yy626,yymsp[-1].minor.yy562,yymsp[-7].minor.yy64,yymsp[0].minor.yy626);
}
        break;
      case 93: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */
{
  yymsp[-9].minor.yy303 = sqlite3SelectNew(pParse,yymsp[-7].minor.yy562,yymsp[-6].minor.yy607,yymsp[-5].minor.yy626,yymsp[-4].minor.yy562,yymsp[-3].minor.yy626,yymsp[-1].minor.yy562,yymsp[-8].minor.yy64,yymsp[0].minor.yy626);
  if( yymsp[-9].minor.yy303 ){
    yymsp[-9].minor.yy303->pWinDefn = yymsp[-2].minor.yy375;
  }else{
    sqlite3WindowListDelete(pParse->db, yymsp[-2].minor.yy375);
  }
}
        break;
      case 94: /* values ::= VALUES LP nexprlist RP */
{
  yymsp[-3].minor.yy303 = sqlite3SelectNew(pParse,yymsp[-1].minor.yy562,0,0,0,0,0,SF_Values,0);
}
        break;
      case 95: /* values ::= values COMMA LP nexprlist RP */
{
  Select *pRight, *pLeft = yymsp[-4].minor.yy303;
  pRight = sqlite3SelectNew(pParse,yymsp[-1].minor.yy562,0,0,0,0,0,SF_Values|SF_MultiValue,0);
  if( ALWAYS(pLeft) ) pLeft->selFlags &= ~SF_MultiValue;
  if( pRight ){
    pRight->op = TK_ALL;
    pRight->pPrior = pLeft;
    yymsp[-4].minor.yy303 = pRight;
  }else{
    yymsp[-4].minor.yy303 = pLeft;
  }
}
        break;
      case 96: /* distinct ::= DISTINCT */
{yymsp[0].minor.yy64 = SF_Distinct;}
        break;
      case 97: /* distinct ::= ALL */
{yymsp[0].minor.yy64 = SF_All;}
        break;
      case 99: /* sclp ::= */
      case 132: /* orderby_opt ::= */ yytestcase(yyruleno==132);
      case 142: /* groupby_opt ::= */ yytestcase(yyruleno==142);
      case 229: /* exprlist ::= */ yytestcase(yyruleno==229);
      case 232: /* paren_exprlist ::= */ yytestcase(yyruleno==232);
      case 237: /* eidlist_opt ::= */ yytestcase(yyruleno==237);
{yymsp[1].minor.yy562 = 0;}
        break;
      case 100: /* selcollist ::= sclp scanpt expr scanpt as */
{
   yymsp[-4].minor.yy562 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy562, yymsp[-2].minor.yy626);
   if( yymsp[0].minor.yy0.n>0 ) sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy562, &yymsp[0].minor.yy0, 1);
   sqlite3ExprListSetSpan(pParse,yymsp[-4].minor.yy562,yymsp[-3].minor.yy600,yymsp[-1].minor.yy600);
}
        break;
      case 101: /* selcollist ::= sclp scanpt STAR */
{
  Expr *p = sqlite3Expr(pParse->db, TK_ASTERISK, 0);
  yymsp[-2].minor.yy562 = sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy562, p);
}
        break;
      case 102: /* selcollist ::= sclp scanpt nm DOT STAR */
{
  Expr *pRight = sqlite3PExpr(pParse, TK_ASTERISK, 0, 0);
  Expr *pLeft = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-2].minor.yy0, 1);
  Expr *pDot = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight);
  yymsp[-4].minor.yy562 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy562, pDot);
}
        break;
      case 103: /* as ::= AS nm */
      case 114: /* dbnm ::= DOT nm */ yytestcase(yyruleno==114);
      case 253: /* plus_num ::= PLUS INTEGER|FLOAT */ yytestcase(yyruleno==253);
      case 254: /* minus_num ::= MINUS INTEGER|FLOAT */ yytestcase(yyruleno==254);
{yymsp[-1].minor.yy0 = yymsp[0].minor.yy0;}
        break;
      case 105: /* from ::= */
      case 108: /* stl_prefix ::= */ yytestcase(yyruleno==108);
{yymsp[1].minor.yy607 = 0;}
        break;
      case 106: /* from ::= FROM seltablist */
{
  yymsp[-1].minor.yy607 = yymsp[0].minor.yy607;
  sqlite3SrcListShiftJoinType(yymsp[-1].minor.yy607);
}
        break;
      case 107: /* stl_prefix ::= seltablist joinop */
{
   if( ALWAYS(yymsp[-1].minor.yy607 && yymsp[-1].minor.yy607->nSrc>0) ) yymsp[-1].minor.yy607->a[yymsp[-1].minor.yy607->nSrc-1].fg.jointype = (u8)yymsp[0].minor.yy64;
}
        break;
      case 109: /* seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */
{
  yymsp[-6].minor.yy607 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy607,&yymsp[-5].minor.yy0,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,0,yymsp[-1].minor.yy626,yymsp[0].minor.yy240);
  sqlite3SrcListIndexedBy(pParse, yymsp[-6].minor.yy607, &yymsp[-2].minor.yy0);
}
        break;
      case 110: /* seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt */
{
  yymsp[-8].minor.yy607 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-8].minor.yy607,&yymsp[-7].minor.yy0,&yymsp[-6].minor.yy0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy626,yymsp[0].minor.yy240);
  sqlite3SrcListFuncArgs(pParse, yymsp[-8].minor.yy607, yymsp[-4].minor.yy562);
}
        break;
      case 111: /* seltablist ::= stl_prefix LP select RP as on_opt using_opt */
{
    yymsp[-6].minor.yy607 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy607,0,0,&yymsp[-2].minor.yy0,yymsp[-4].minor.yy303,yymsp[-1].minor.yy626,yymsp[0].minor.yy240);
  }
        break;
      case 112: /* seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */
{
    if( yymsp[-6].minor.yy607==0 && yymsp[-2].minor.yy0.n==0 && yymsp[-1].minor.yy626==0 && yymsp[0].minor.yy240==0 ){
      yymsp[-6].minor.yy607 = yymsp[-4].minor.yy607;
    }else if( yymsp[-4].minor.yy607->nSrc==1 ){
      yymsp[-6].minor.yy607 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy607,0,0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy626,yymsp[0].minor.yy240);
      if( yymsp[-6].minor.yy607 ){
        SrcItem *pNew = &yymsp[-6].minor.yy607->a[yymsp[-6].minor.yy607->nSrc-1];
        SrcItem *pOld = yymsp[-4].minor.yy607->a;
        pNew->zName = pOld->zName;
        pNew->zDatabase = pOld->zDatabase;
        pNew->pSelect = pOld->pSelect;
        if( pOld->fg.isTabFunc ){
          pNew->u1.pFuncArg = pOld->u1.pFuncArg;
          pOld->u1.pFuncArg = 0;
          pOld->fg.isTabFunc = 0;
          pNew->fg.isTabFunc = 1;
        }
        pOld->zName = pOld->zDatabase = 0;
        pOld->pSelect = 0;
      }
      sqlite3SrcListDelete(pParse->db, yymsp[-4].minor.yy607);
    }else{
      Select *pSubquery;
      sqlite3SrcListShiftJoinType(yymsp[-4].minor.yy607);
      pSubquery = sqlite3SelectNew(pParse,0,yymsp[-4].minor.yy607,0,0,0,0,SF_NestedFrom,0);
      yymsp[-6].minor.yy607 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy607,0,0,&yymsp[-2].minor.yy0,pSubquery,yymsp[-1].minor.yy626,yymsp[0].minor.yy240);
    }
  }
        break;
      case 113: /* dbnm ::= */
      case 127: /* indexed_opt ::= */ yytestcase(yyruleno==127);
{yymsp[1].minor.yy0.z=0; yymsp[1].minor.yy0.n=0;}
        break;
      case 115: /* fullname ::= nm */
{
  yylhsminor.yy607 = sqlite3SrcListAppend(pParse,0,&yymsp[0].minor.yy0,0);
  if( IN_RENAME_OBJECT && yylhsminor.yy607 ) sqlite3RenameTokenMap(pParse, yylhsminor.yy607->a[0].zName, &yymsp[0].minor.yy0);
}
  yymsp[0].minor.yy607 = yylhsminor.yy607;
        break;
      case 116: /* fullname ::= nm DOT nm */
{
  yylhsminor.yy607 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0);
  if( IN_RENAME_OBJECT && yylhsminor.yy607 ) sqlite3RenameTokenMap(pParse, yylhsminor.yy607->a[0].zName, &yymsp[0].minor.yy0);
}
  yymsp[-2].minor.yy607 = yylhsminor.yy607;
        break;
      case 117: /* xfullname ::= nm */
{yymsp[0].minor.yy607 = sqlite3SrcListAppend(pParse,0,&yymsp[0].minor.yy0,0); /*A-overwrites-X*/}
        break;
      case 118: /* xfullname ::= nm DOT nm */
{yymsp[-2].minor.yy607 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/}
        break;
      case 119: /* xfullname ::= nm DOT nm AS nm */
{
   yymsp[-4].minor.yy607 = sqlite3SrcListAppend(pParse,0,&yymsp[-4].minor.yy0,&yymsp[-2].minor.yy0); /*A-overwrites-X*/
   if( yymsp[-4].minor.yy607 ) yymsp[-4].minor.yy607->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0);
}
        break;
      case 120: /* xfullname ::= nm AS nm */
{
   yymsp[-2].minor.yy607 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,0); /*A-overwrites-X*/
   if( yymsp[-2].minor.yy607 ) yymsp[-2].minor.yy607->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0);
}
        break;
      case 121: /* joinop ::= COMMA|JOIN */
{ yymsp[0].minor.yy64 = JT_INNER; }
        break;
      case 122: /* joinop ::= JOIN_KW JOIN */
{yymsp[-1].minor.yy64 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0);  /*X-overwrites-A*/}
        break;
      case 123: /* joinop ::= JOIN_KW nm JOIN */
{yymsp[-2].minor.yy64 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); /*X-overwrites-A*/}
        break;
      case 124: /* joinop ::= JOIN_KW nm nm JOIN */
{yymsp[-3].minor.yy64 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);/*X-overwrites-A*/}
        break;
      case 125: /* on_opt ::= ON expr */
      case 145: /* having_opt ::= HAVING expr */ yytestcase(yyruleno==145);
      case 152: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==152);
      case 154: /* where_opt_ret ::= WHERE expr */ yytestcase(yyruleno==154);
      case 225: /* case_else ::= ELSE expr */ yytestcase(yyruleno==225);
      case 246: /* vinto ::= INTO expr */ yytestcase(yyruleno==246);
{yymsp[-1].minor.yy626 = yymsp[0].minor.yy626;}
        break;
      case 126: /* on_opt ::= */
      case 144: /* having_opt ::= */ yytestcase(yyruleno==144);
      case 146: /* limit_opt ::= */ yytestcase(yyruleno==146);
      case 151: /* where_opt ::= */ yytestcase(yyruleno==151);
      case 153: /* where_opt_ret ::= */ yytestcase(yyruleno==153);
      case 226: /* case_else ::= */ yytestcase(yyruleno==226);
      case 228: /* case_operand ::= */ yytestcase(yyruleno==228);
      case 247: /* vinto ::= */ yytestcase(yyruleno==247);
{yymsp[1].minor.yy626 = 0;}
        break;
      case 128: /* indexed_opt ::= INDEXED BY nm */
{yymsp[-2].minor.yy0 = yymsp[0].minor.yy0;}
        break;
      case 129: /* indexed_opt ::= NOT INDEXED */
{yymsp[-1].minor.yy0.z=0; yymsp[-1].minor.yy0.n=1;}
        break;
      case 130: /* using_opt ::= USING LP idlist RP */
{yymsp[-3].minor.yy240 = yymsp[-1].minor.yy240;}
        break;
      case 131: /* using_opt ::= */
      case 173: /* idlist_opt ::= */ yytestcase(yyruleno==173);
{yymsp[1].minor.yy240 = 0;}
        break;
      case 133: /* orderby_opt ::= ORDER BY sortlist */
      case 143: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==143);
{yymsp[-2].minor.yy562 = yymsp[0].minor.yy562;}
        break;
      case 134: /* sortlist ::= sortlist COMMA expr sortorder nulls */
{
  yymsp[-4].minor.yy562 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy562,yymsp[-2].minor.yy626);
  sqlite3ExprListSetSortOrder(yymsp[-4].minor.yy562,yymsp[-1].minor.yy64,yymsp[0].minor.yy64);
}
        break;
      case 135: /* sortlist ::= expr sortorder nulls */
{
  yymsp[-2].minor.yy562 = sqlite3ExprListAppend(pParse,0,yymsp[-2].minor.yy626); /*A-overwrites-Y*/
  sqlite3ExprListSetSortOrder(yymsp[-2].minor.yy562,yymsp[-1].minor.yy64,yymsp[0].minor.yy64);
}
        break;
      case 136: /* sortorder ::= ASC */
{yymsp[0].minor.yy64 = SQLITE_SO_ASC;}
        break;
      case 137: /* sortorder ::= DESC */
{yymsp[0].minor.yy64 = SQLITE_SO_DESC;}
        break;
      case 138: /* sortorder ::= */
      case 141: /* nulls ::= */ yytestcase(yyruleno==141);
{yymsp[1].minor.yy64 = SQLITE_SO_UNDEFINED;}
        break;
      case 139: /* nulls ::= NULLS FIRST */
{yymsp[-1].minor.yy64 = SQLITE_SO_ASC;}
        break;
      case 140: /* nulls ::= NULLS LAST */
{yymsp[-1].minor.yy64 = SQLITE_SO_DESC;}
        break;
      case 147: /* limit_opt ::= LIMIT expr */
{yymsp[-1].minor.yy626 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy626,0);}
        break;
      case 148: /* limit_opt ::= LIMIT expr OFFSET expr */
{yymsp[-3].minor.yy626 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[-2].minor.yy626,yymsp[0].minor.yy626);}
        break;
      case 149: /* limit_opt ::= LIMIT expr COMMA expr */
{yymsp[-3].minor.yy626 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy626,yymsp[-2].minor.yy626);}
        break;
      case 150: /* cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret */
{
  sqlite3SrcListIndexedBy(pParse, yymsp[-2].minor.yy607, &yymsp[-1].minor.yy0);
  sqlite3DeleteFrom(pParse,yymsp[-2].minor.yy607,yymsp[0].minor.yy626,0,0);
}
        break;
      case 155: /* where_opt_ret ::= RETURNING selcollist */
{sqlite3AddReturning(pParse,yymsp[0].minor.yy562); yymsp[-1].minor.yy626 = 0;}
        break;
      case 156: /* where_opt_ret ::= WHERE expr RETURNING selcollist */
{sqlite3AddReturning(pParse,yymsp[0].minor.yy562); yymsp[-3].minor.yy626 = yymsp[-2].minor.yy626;}
        break;
      case 157: /* cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret */
{
  sqlite3SrcListIndexedBy(pParse, yymsp[-5].minor.yy607, &yymsp[-4].minor.yy0);
  sqlite3ExprListCheckLength(pParse,yymsp[-2].minor.yy562,"set list");
  yymsp[-5].minor.yy607 = sqlite3SrcListAppendList(pParse, yymsp[-5].minor.yy607, yymsp[-1].minor.yy607);
  sqlite3Update(pParse,yymsp[-5].minor.yy607,yymsp[-2].minor.yy562,yymsp[0].minor.yy626,yymsp[-6].minor.yy64,0,0,0);
}
        break;
      case 158: /* setlist ::= setlist COMMA nm EQ expr */
{
  yymsp[-4].minor.yy562 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy562, yymsp[0].minor.yy626);
  sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy562, &yymsp[-2].minor.yy0, 1);
}
        break;
      case 159: /* setlist ::= setlist COMMA LP idlist RP EQ expr */
{
  yymsp[-6].minor.yy562 = sqlite3ExprListAppendVector(pParse, yymsp[-6].minor.yy562, yymsp[-3].minor.yy240, yymsp[0].minor.yy626);
}
        break;
      case 160: /* setlist ::= nm EQ expr */
{
  yylhsminor.yy562 = sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy626);
  sqlite3ExprListSetName(pParse, yylhsminor.yy562, &yymsp[-2].minor.yy0, 1);
}
  yymsp[-2].minor.yy562 = yylhsminor.yy562;
        break;
      case 161: /* setlist ::= LP idlist RP EQ expr */
{
  yymsp[-4].minor.yy562 = sqlite3ExprListAppendVector(pParse, 0, yymsp[-3].minor.yy240, yymsp[0].minor.yy626);
}
        break;
      case 162: /* cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */
{
  sqlite3Insert(pParse, yymsp[-3].minor.yy607, yymsp[-1].minor.yy303, yymsp[-2].minor.yy240, yymsp[-5].minor.yy64, yymsp[0].minor.yy138);
}
        break;
      case 163: /* cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */
{
  sqlite3Insert(pParse, yymsp[-4].minor.yy607, 0, yymsp[-3].minor.yy240, yymsp[-6].minor.yy64, 0);
}
        break;
      case 164: /* upsert ::= */
{ yymsp[1].minor.yy138 = 0; }
        break;
      case 165: /* upsert ::= RETURNING selcollist */
{ yymsp[-1].minor.yy138 = 0; sqlite3AddReturning(pParse,yymsp[0].minor.yy562); }
        break;
      case 166: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */
{ yymsp[-11].minor.yy138 = sqlite3UpsertNew(pParse->db,yymsp[-8].minor.yy562,yymsp[-6].minor.yy626,yymsp[-2].minor.yy562,yymsp[-1].minor.yy626,yymsp[0].minor.yy138);}
        break;
      case 167: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */
{ yymsp[-8].minor.yy138 = sqlite3UpsertNew(pParse->db,yymsp[-5].minor.yy562,yymsp[-3].minor.yy626,0,0,yymsp[0].minor.yy138); }
        break;
      case 168: /* upsert ::= ON CONFLICT DO NOTHING returning */
{ yymsp[-4].minor.yy138 = sqlite3UpsertNew(pParse->db,0,0,0,0,0); }
        break;
      case 169: /* upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */
{ yymsp[-7].minor.yy138 = sqlite3UpsertNew(pParse->db,0,0,yymsp[-2].minor.yy562,yymsp[-1].minor.yy626,0);}
        break;
      case 170: /* returning ::= RETURNING selcollist */
{sqlite3AddReturning(pParse,yymsp[0].minor.yy562);}
        break;
      case 174: /* idlist_opt ::= LP idlist RP */
{yymsp[-2].minor.yy240 = yymsp[-1].minor.yy240;}
        break;
      case 175: /* idlist ::= idlist COMMA nm */
{yymsp[-2].minor.yy240 = sqlite3IdListAppend(pParse,yymsp[-2].minor.yy240,&yymsp[0].minor.yy0);}
        break;
      case 176: /* idlist ::= nm */
{yymsp[0].minor.yy240 = sqlite3IdListAppend(pParse,0,&yymsp[0].minor.yy0); /*A-overwrites-Y*/}
        break;
      case 177: /* expr ::= LP expr RP */
{yymsp[-2].minor.yy626 = yymsp[-1].minor.yy626;}
        break;
      case 178: /* expr ::= ID|INDEXED */
      case 179: /* expr ::= JOIN_KW */ yytestcase(yyruleno==179);
{yymsp[0].minor.yy626=tokenExpr(pParse,TK_ID,yymsp[0].minor.yy0); /*A-overwrites-X*/}
        break;
      case 180: /* expr ::= nm DOT nm */
{
  Expr *temp1 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-2].minor.yy0, 1);
  Expr *temp2 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[0].minor.yy0, 1);
  if( IN_RENAME_OBJECT ){
    sqlite3RenameTokenMap(pParse, (void*)temp2, &yymsp[0].minor.yy0);
    sqlite3RenameTokenMap(pParse, (void*)temp1, &yymsp[-2].minor.yy0);
  }
  yylhsminor.yy626 = sqlite3PExpr(pParse, TK_DOT, temp1, temp2);
}
  yymsp[-2].minor.yy626 = yylhsminor.yy626;
        break;
      case 181: /* expr ::= nm DOT nm DOT nm */
{
  Expr *temp1 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-4].minor.yy0, 1);
  Expr *temp2 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-2].minor.yy0, 1);
  Expr *temp3 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[0].minor.yy0, 1);
  Expr *temp4 = sqlite3PExpr(pParse, TK_DOT, temp2, temp3);
  if( IN_RENAME_OBJECT ){
    sqlite3RenameTokenMap(pParse, (void*)temp3, &yymsp[0].minor.yy0);
    sqlite3RenameTokenMap(pParse, (void*)temp2, &yymsp[-2].minor.yy0);
  }
  yylhsminor.yy626 = sqlite3PExpr(pParse, TK_DOT, temp1, temp4);
}
  yymsp[-4].minor.yy626 = yylhsminor.yy626;
        break;
      case 182: /* term ::= NULL|FLOAT|BLOB */
      case 183: /* term ::= STRING */ yytestcase(yyruleno==183);
{yymsp[0].minor.yy626=tokenExpr(pParse,yymsp[0].major,yymsp[0].minor.yy0); /*A-overwrites-X*/}
        break;
      case 184: /* term ::= INTEGER */
{
  yylhsminor.yy626 = sqlite3ExprAlloc(pParse->db, TK_INTEGER, &yymsp[0].minor.yy0, 1);
}
  yymsp[0].minor.yy626 = yylhsminor.yy626;
        break;
      case 185: /* expr ::= VARIABLE */
{
  if( !(yymsp[0].minor.yy0.z[0]=='#' && sqlite3Isdigit(yymsp[0].minor.yy0.z[1])) ){
    u32 n = yymsp[0].minor.yy0.n;
    yymsp[0].minor.yy626 = tokenExpr(pParse, TK_VARIABLE, yymsp[0].minor.yy0);
    sqlite3ExprAssignVarNumber(pParse, yymsp[0].minor.yy626, n);
  }else{
    /* When doing a nested parse, one can include terms in an expression
    ** that look like this:   #1 #2 ...  These terms refer to registers
    ** in the virtual machine.  #N is the N-th register. */
    Token t = yymsp[0].minor.yy0; /*A-overwrites-X*/
    assert( t.n>=2 );
    if( pParse->nested==0 ){
      sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &t);
      yymsp[0].minor.yy626 = 0;
    }else{
      yymsp[0].minor.yy626 = sqlite3PExpr(pParse, TK_REGISTER, 0, 0);
      if( yymsp[0].minor.yy626 ) sqlite3GetInt32(&t.z[1], &yymsp[0].minor.yy626->iTable);
    }
  }
}
        break;
      case 186: /* expr ::= expr COLLATE ID|STRING */
{
  yymsp[-2].minor.yy626 = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy626, &yymsp[0].minor.yy0, 1);
}
        break;
      case 187: /* expr ::= CAST LP expr AS typetoken RP */
{
  yymsp[-5].minor.yy626 = sqlite3ExprAlloc(pParse->db, TK_CAST, &yymsp[-1].minor.yy0, 1);
  sqlite3ExprAttachSubtrees(pParse->db, yymsp[-5].minor.yy626, yymsp[-3].minor.yy626, 0);
}
        break;
      case 188: /* expr ::= ID|INDEXED LP distinct exprlist RP */
{
  yylhsminor.yy626 = sqlite3ExprFunction(pParse, yymsp[-1].minor.yy562, &yymsp[-4].minor.yy0, yymsp[-2].minor.yy64);
}
  yymsp[-4].minor.yy626 = yylhsminor.yy626;
        break;
      case 189: /* expr ::= ID|INDEXED LP STAR RP */
{
  yylhsminor.yy626 = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0, 0);
}
  yymsp[-3].minor.yy626 = yylhsminor.yy626;
        break;
      case 190: /* expr ::= ID|INDEXED LP distinct exprlist RP filter_over */
{
  yylhsminor.yy626 = sqlite3ExprFunction(pParse, yymsp[-2].minor.yy562, &yymsp[-5].minor.yy0, yymsp[-3].minor.yy64);
  sqlite3WindowAttach(pParse, yylhsminor.yy626, yymsp[0].minor.yy375);
}
  yymsp[-5].minor.yy626 = yylhsminor.yy626;
        break;
      case 191: /* expr ::= ID|INDEXED LP STAR RP filter_over */
{
  yylhsminor.yy626 = sqlite3ExprFunction(pParse, 0, &yymsp[-4].minor.yy0, 0);
  sqlite3WindowAttach(pParse, yylhsminor.yy626, yymsp[0].minor.yy375);
}
  yymsp[-4].minor.yy626 = yylhsminor.yy626;
        break;
      case 192: /* term ::= CTIME_KW */
{
  yylhsminor.yy626 = sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0, 0);
}
  yymsp[0].minor.yy626 = yylhsminor.yy626;
        break;
      case 193: /* expr ::= LP nexprlist COMMA expr RP */
{
  ExprList *pList = sqlite3ExprListAppend(pParse, yymsp[-3].minor.yy562, yymsp[-1].minor.yy626);
  yymsp[-4].minor.yy626 = sqlite3PExpr(pParse, TK_VECTOR, 0, 0);
  if( yymsp[-4].minor.yy626 ){
    yymsp[-4].minor.yy626->x.pList = pList;
    if( ALWAYS(pList->nExpr) ){
      yymsp[-4].minor.yy626->flags |= pList->a[0].pExpr->flags & EP_Propagate;
    }
  }else{
    sqlite3ExprListDelete(pParse->db, pList);
  }
}
        break;
      case 194: /* expr ::= expr AND expr */
{yymsp[-2].minor.yy626=sqlite3ExprAnd(pParse,yymsp[-2].minor.yy626,yymsp[0].minor.yy626);}
        break;
      case 195: /* expr ::= expr OR expr */
      case 196: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==196);
      case 197: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==197);
      case 198: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==198);
      case 199: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==199);
      case 200: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==200);
      case 201: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==201);
{yymsp[-2].minor.yy626=sqlite3PExpr(pParse,yymsp[-1].major,yymsp[-2].minor.yy626,yymsp[0].minor.yy626);}
        break;
      case 202: /* likeop ::= NOT LIKE_KW|MATCH */
{yymsp[-1].minor.yy0=yymsp[0].minor.yy0; yymsp[-1].minor.yy0.n|=0x80000000; /*yymsp[-1].minor.yy0-overwrite-yymsp[0].minor.yy0*/}
        break;
      case 203: /* expr ::= expr likeop expr */
{
  ExprList *pList;
  int bNot = yymsp[-1].minor.yy0.n & 0x80000000;
  yymsp[-1].minor.yy0.n &= 0x7fffffff;
  pList = sqlite3ExprListAppend(pParse,0, yymsp[0].minor.yy626);
  pList = sqlite3ExprListAppend(pParse,pList, yymsp[-2].minor.yy626);
  yymsp[-2].minor.yy626 = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0, 0);
  if( bNot ) yymsp[-2].minor.yy626 = sqlite3PExpr(pParse, TK_NOT, yymsp[-2].minor.yy626, 0);
  if( yymsp[-2].minor.yy626 ) yymsp[-2].minor.yy626->flags |= EP_InfixFunc;
}
        break;
      case 204: /* expr ::= expr likeop expr ESCAPE expr */
{
  ExprList *pList;
  int bNot = yymsp[-3].minor.yy0.n & 0x80000000;
  yymsp[-3].minor.yy0.n &= 0x7fffffff;
  pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy626);
  pList = sqlite3ExprListAppend(pParse,pList, yymsp[-4].minor.yy626);
  pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy626);
  yymsp[-4].minor.yy626 = sqlite3ExprFunction(pParse, pList, &yymsp[-3].minor.yy0, 0);
  if( bNot ) yymsp[-4].minor.yy626 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy626, 0);
  if( yymsp[-4].minor.yy626 ) yymsp[-4].minor.yy626->flags |= EP_InfixFunc;
}
        break;
      case 205: /* expr ::= expr ISNULL|NOTNULL */
{yymsp[-1].minor.yy626 = sqlite3PExpr(pParse,yymsp[0].major,yymsp[-1].minor.yy626,0);}
        break;
      case 206: /* expr ::= expr NOT NULL */
{yymsp[-2].minor.yy626 = sqlite3PExpr(pParse,TK_NOTNULL,yymsp[-2].minor.yy626,0);}
        break;
      case 207: /* expr ::= expr IS expr */
{
  yymsp[-2].minor.yy626 = sqlite3PExpr(pParse,TK_IS,yymsp[-2].minor.yy626,yymsp[0].minor.yy626);
  binaryToUnaryIfNull(pParse, yymsp[0].minor.yy626, yymsp[-2].minor.yy626, TK_ISNULL);
}
        break;
      case 208: /* expr ::= expr IS NOT expr */
{
  yymsp[-3].minor.yy626 = sqlite3PExpr(pParse,TK_ISNOT,yymsp[-3].minor.yy626,yymsp[0].minor.yy626);
  binaryToUnaryIfNull(pParse, yymsp[0].minor.yy626, yymsp[-3].minor.yy626, TK_NOTNULL);
}
        break;
      case 209: /* expr ::= NOT expr */
      case 210: /* expr ::= BITNOT expr */ yytestcase(yyruleno==210);
{yymsp[-1].minor.yy626 = sqlite3PExpr(pParse, yymsp[-1].major, yymsp[0].minor.yy626, 0);/*A-overwrites-B*/}
        break;
      case 211: /* expr ::= PLUS|MINUS expr */
{
  yymsp[-1].minor.yy626 = sqlite3PExpr(pParse, yymsp[-1].major==TK_PLUS ? TK_UPLUS : TK_UMINUS, yymsp[0].minor.yy626, 0);
  /*A-overwrites-B*/
}
        break;
      case 212: /* between_op ::= BETWEEN */
      case 215: /* in_op ::= IN */ yytestcase(yyruleno==215);
{yymsp[0].minor.yy64 = 0;}
        break;
      case 214: /* expr ::= expr between_op expr AND expr */
{
  ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy626);
  pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy626);
  yymsp[-4].minor.yy626 = sqlite3PExpr(pParse, TK_BETWEEN, yymsp[-4].minor.yy626, 0);
  if( yymsp[-4].minor.yy626 ){
    yymsp[-4].minor.yy626->x.pList = pList;
  }else{
    sqlite3ExprListDelete(pParse->db, pList);
  }
  if( yymsp[-3].minor.yy64 ) yymsp[-4].minor.yy626 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy626, 0);
}
        break;
      case 217: /* expr ::= expr in_op LP exprlist RP */
{
    if( yymsp[-1].minor.yy562==0 ){
      /* Expressions of the form
      **
      **      expr1 IN ()
      **      expr1 NOT IN ()
      **
      ** simplify to constants 0 (false) and 1 (true), respectively,
      ** regardless of the value of expr1.
      */
      sqlite3ExprUnmapAndDelete(pParse, yymsp[-4].minor.yy626);
      yymsp[-4].minor.yy626 = sqlite3Expr(pParse->db, TK_INTEGER, yymsp[-3].minor.yy64 ? "1" : "0");
    }else{
      Expr *pRHS = yymsp[-1].minor.yy562->a[0].pExpr;
      if( yymsp[-1].minor.yy562->nExpr==1 && sqlite3ExprIsConstant(pRHS) && yymsp[-4].minor.yy626->op!=TK_VECTOR ){
        yymsp[-1].minor.yy562->a[0].pExpr = 0;
        sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy562);
        pRHS = sqlite3PExpr(pParse, TK_UPLUS, pRHS, 0);
        yymsp[-4].minor.yy626 = sqlite3PExpr(pParse, TK_EQ, yymsp[-4].minor.yy626, pRHS);
      }else{
        yymsp[-4].minor.yy626 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy626, 0);
        if( yymsp[-4].minor.yy626==0 ){
          sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy562);
        }else if( yymsp[-4].minor.yy626->pLeft->op==TK_VECTOR ){
          int nExpr = yymsp[-4].minor.yy626->pLeft->x.pList->nExpr;
          Select *pSelectRHS = sqlite3ExprListToValues(pParse, nExpr, yymsp[-1].minor.yy562);
          if( pSelectRHS ){
            parserDoubleLinkSelect(pParse, pSelectRHS);
            sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy626, pSelectRHS);
          }
        }else{
          yymsp[-4].minor.yy626->x.pList = yymsp[-1].minor.yy562;
          sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy626);
        }
      }
      if( yymsp[-3].minor.yy64 ) yymsp[-4].minor.yy626 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy626, 0);
    }
  }
        break;
      case 218: /* expr ::= LP select RP */
{
    yymsp[-2].minor.yy626 = sqlite3PExpr(pParse, TK_SELECT, 0, 0);
    sqlite3PExprAddSelect(pParse, yymsp[-2].minor.yy626, yymsp[-1].minor.yy303);
  }
        break;
      case 219: /* expr ::= expr in_op LP select RP */
{
    yymsp[-4].minor.yy626 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy626, 0);
    sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy626, yymsp[-1].minor.yy303);
    if( yymsp[-3].minor.yy64 ) yymsp[-4].minor.yy626 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy626, 0);
  }
        break;
      case 220: /* expr ::= expr in_op nm dbnm paren_exprlist */
{
    SrcList *pSrc = sqlite3SrcListAppend(pParse, 0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);
    Select *pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0);
    if( yymsp[0].minor.yy562 )  sqlite3SrcListFuncArgs(pParse, pSelect ? pSrc : 0, yymsp[0].minor.yy562);
    yymsp[-4].minor.yy626 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy626, 0);
    sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy626, pSelect);
    if( yymsp[-3].minor.yy64 ) yymsp[-4].minor.yy626 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy626, 0);
  }
        break;
      case 221: /* expr ::= EXISTS LP select RP */
{
    Expr *p;
    p = yymsp[-3].minor.yy626 = sqlite3PExpr(pParse, TK_EXISTS, 0, 0);
    sqlite3PExprAddSelect(pParse, p, yymsp[-1].minor.yy303);
  }
        break;
      case 222: /* expr ::= CASE case_operand case_exprlist case_else END */
{
  yymsp[-4].minor.yy626 = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy626, 0);
  if( yymsp[-4].minor.yy626 ){
    yymsp[-4].minor.yy626->x.pList = yymsp[-1].minor.yy626 ? sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy562,yymsp[-1].minor.yy626) : yymsp[-2].minor.yy562;
    sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy626);
  }else{
    sqlite3ExprListDelete(pParse->db, yymsp[-2].minor.yy562);
    sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy626);
  }
}
        break;
      case 223: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */
{
  yymsp[-4].minor.yy562 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy562, yymsp[-2].minor.yy626);
  yymsp[-4].minor.yy562 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy562, yymsp[0].minor.yy626);
}
        break;
      case 224: /* case_exprlist ::= WHEN expr THEN expr */
{
  yymsp[-3].minor.yy562 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy626);
  yymsp[-3].minor.yy562 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy562, yymsp[0].minor.yy626);
}
        break;
      case 227: /* case_operand ::= expr */
{yymsp[0].minor.yy626 = yymsp[0].minor.yy626; /*A-overwrites-X*/}
        break;
      case 230: /* nexprlist ::= nexprlist COMMA expr */
{yymsp[-2].minor.yy562 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy562,yymsp[0].minor.yy626);}
        break;
      case 231: /* nexprlist ::= expr */
{yymsp[0].minor.yy562 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy626); /*A-overwrites-Y*/}
        break;
      case 233: /* paren_exprlist ::= LP exprlist RP */
      case 238: /* eidlist_opt ::= LP eidlist RP */ yytestcase(yyruleno==238);
{yymsp[-2].minor.yy562 = yymsp[-1].minor.yy562;}
        break;
      case 234: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
{
  sqlite3CreateIndex(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0,
                     sqlite3SrcListAppend(pParse,0,&yymsp[-4].minor.yy0,0), yymsp[-2].minor.yy562, yymsp[-10].minor.yy64,
                      &yymsp[-11].minor.yy0, yymsp[0].minor.yy626, SQLITE_SO_ASC, yymsp[-8].minor.yy64, SQLITE_IDXTYPE_APPDEF);
  if( IN_RENAME_OBJECT && pParse->pNewIndex ){
    sqlite3RenameTokenMap(pParse, pParse->pNewIndex->zName, &yymsp[-4].minor.yy0);
  }
}
        break;
      case 235: /* uniqueflag ::= UNIQUE */
      case 277: /* raisetype ::= ABORT */ yytestcase(yyruleno==277);
{yymsp[0].minor.yy64 = OE_Abort;}
        break;
      case 236: /* uniqueflag ::= */
{yymsp[1].minor.yy64 = OE_None;}
        break;
      case 239: /* eidlist ::= eidlist COMMA nm collate sortorder */
{
  yymsp[-4].minor.yy562 = parserAddExprIdListTerm(pParse, yymsp[-4].minor.yy562, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy64, yymsp[0].minor.yy64);
}
        break;
      case 240: /* eidlist ::= nm collate sortorder */
{
  yymsp[-2].minor.yy562 = parserAddExprIdListTerm(pParse, 0, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy64, yymsp[0].minor.yy64); /*A-overwrites-Y*/
}
        break;
      case 243: /* cmd ::= DROP INDEX ifexists fullname */
{sqlite3DropIndex(pParse, yymsp[0].minor.yy607, yymsp[-1].minor.yy64);}
        break;
      case 244: /* cmd ::= VACUUM vinto */
{sqlite3Vacuum(pParse,0,yymsp[0].minor.yy626);}
        break;
      case 245: /* cmd ::= VACUUM nm vinto */
{sqlite3Vacuum(pParse,&yymsp[-1].minor.yy0,yymsp[0].minor.yy626);}
        break;
      case 248: /* cmd ::= PRAGMA nm dbnm */
{sqlite3Pragma(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,0,0);}
        break;
      case 249: /* cmd ::= PRAGMA nm dbnm EQ nmnum */
{sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,0);}
        break;
      case 250: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */
{sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,0);}
        break;
      case 251: /* cmd ::= PRAGMA nm dbnm EQ minus_num */
{sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,1);}
        break;
      case 252: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */
{sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,1);}
        break;
      case 255: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
{
  Token all;
  all.z = yymsp[-3].minor.yy0.z;
  all.n = (int)(yymsp[0].minor.yy0.z - yymsp[-3].minor.yy0.z) + yymsp[0].minor.yy0.n;
  sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy95, &all);
}
        break;
      case 256: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
{
  sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, yymsp[-5].minor.yy64, yymsp[-4].minor.yy570.a, yymsp[-4].minor.yy570.b, yymsp[-2].minor.yy607, yymsp[0].minor.yy626, yymsp[-10].minor.yy64, yymsp[-8].minor.yy64);
  yymsp[-10].minor.yy0 = (yymsp[-6].minor.yy0.n==0?yymsp[-7].minor.yy0:yymsp[-6].minor.yy0); /*A-overwrites-T*/
}
        break;
      case 257: /* trigger_time ::= BEFORE|AFTER */
{ yymsp[0].minor.yy64 = yymsp[0].major; /*A-overwrites-X*/ }
        break;
      case 258: /* trigger_time ::= INSTEAD OF */
{ yymsp[-1].minor.yy64 = TK_INSTEAD;}
        break;
      case 259: /* trigger_time ::= */
{ yymsp[1].minor.yy64 = TK_BEFORE; }
        break;
      case 260: /* trigger_event ::= DELETE|INSERT */
      case 261: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==261);
{yymsp[0].minor.yy570.a = yymsp[0].major; /*A-overwrites-X*/ yymsp[0].minor.yy570.b = 0;}
        break;
      case 262: /* trigger_event ::= UPDATE OF idlist */
{yymsp[-2].minor.yy570.a = TK_UPDATE; yymsp[-2].minor.yy570.b = yymsp[0].minor.yy240;}
        break;
      case 263: /* when_clause ::= */
      case 282: /* key_opt ::= */ yytestcase(yyruleno==282);
{ yymsp[1].minor.yy626 = 0; }
        break;
      case 264: /* when_clause ::= WHEN expr */
      case 283: /* key_opt ::= KEY expr */ yytestcase(yyruleno==283);
{ yymsp[-1].minor.yy626 = yymsp[0].minor.yy626; }
        break;
      case 265: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
{
  assert( yymsp[-2].minor.yy95!=0 );
  yymsp[-2].minor.yy95->pLast->pNext = yymsp[-1].minor.yy95;
  yymsp[-2].minor.yy95->pLast = yymsp[-1].minor.yy95;
}
        break;
      case 266: /* trigger_cmd_list ::= trigger_cmd SEMI */
{
  assert( yymsp[-1].minor.yy95!=0 );
  yymsp[-1].minor.yy95->pLast = yymsp[-1].minor.yy95;
}
        break;
      case 267: /* trnm ::= nm DOT nm */
{
  yymsp[-2].minor.yy0 = yymsp[0].minor.yy0;
  sqlite3ErrorMsg(pParse,
        "qualified table names are not allowed on INSERT, UPDATE, and DELETE "
        "statements within triggers");
}
        break;
      case 268: /* tridxby ::= INDEXED BY nm */
{
  sqlite3ErrorMsg(pParse,
        "the INDEXED BY clause is not allowed on UPDATE or DELETE statements "
        "within triggers");
}
        break;
      case 269: /* tridxby ::= NOT INDEXED */
{
  sqlite3ErrorMsg(pParse,
        "the NOT INDEXED clause is not allowed on UPDATE or DELETE statements "
        "within triggers");
}
        break;
      case 270: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */
{yylhsminor.yy95 = sqlite3TriggerUpdateStep(pParse, &yymsp[-6].minor.yy0, yymsp[-2].minor.yy607, yymsp[-3].minor.yy562, yymsp[-1].minor.yy626, yymsp[-7].minor.yy64, yymsp[-8].minor.yy0.z, yymsp[0].minor.yy600);}
  yymsp[-8].minor.yy95 = yylhsminor.yy95;
        break;
      case 271: /* trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */
{
   yylhsminor.yy95 = sqlite3TriggerInsertStep(pParse,&yymsp[-4].minor.yy0,yymsp[-3].minor.yy240,yymsp[-2].minor.yy303,yymsp[-6].minor.yy64,yymsp[-1].minor.yy138,yymsp[-7].minor.yy600,yymsp[0].minor.yy600);/*yylhsminor.yy95-overwrites-yymsp[-6].minor.yy64*/
}
  yymsp[-7].minor.yy95 = yylhsminor.yy95;
        break;
      case 272: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */
{yylhsminor.yy95 = sqlite3TriggerDeleteStep(pParse, &yymsp[-3].minor.yy0, yymsp[-1].minor.yy626, yymsp[-5].minor.yy0.z, yymsp[0].minor.yy600);}
  yymsp[-5].minor.yy95 = yylhsminor.yy95;
        break;
      case 273: /* trigger_cmd ::= scanpt select scanpt */
{yylhsminor.yy95 = sqlite3TriggerSelectStep(pParse->db, yymsp[-1].minor.yy303, yymsp[-2].minor.yy600, yymsp[0].minor.yy600); /*yylhsminor.yy95-overwrites-yymsp[-1].minor.yy303*/}
  yymsp[-2].minor.yy95 = yylhsminor.yy95;
        break;
      case 274: /* expr ::= RAISE LP IGNORE RP */
{
  yymsp[-3].minor.yy626 = sqlite3PExpr(pParse, TK_RAISE, 0, 0);
  if( yymsp[-3].minor.yy626 ){
    yymsp[-3].minor.yy626->affExpr = OE_Ignore;
  }
}
        break;
      case 275: /* expr ::= RAISE LP raisetype COMMA nm RP */
{
  yymsp[-5].minor.yy626 = sqlite3ExprAlloc(pParse->db, TK_RAISE, &yymsp[-1].minor.yy0, 1);
  if( yymsp[-5].minor.yy626 ) {
    yymsp[-5].minor.yy626->affExpr = (char)yymsp[-3].minor.yy64;
  }
}
        break;
      case 276: /* raisetype ::= ROLLBACK */
{yymsp[0].minor.yy64 = OE_Rollback;}
        break;
      case 278: /* raisetype ::= FAIL */
{yymsp[0].minor.yy64 = OE_Fail;}
        break;
      case 279: /* cmd ::= DROP TRIGGER ifexists fullname */
{
  sqlite3DropTrigger(pParse,yymsp[0].minor.yy607,yymsp[-1].minor.yy64);
}
        break;
      case 280: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
{
  sqlite3Attach(pParse, yymsp[-3].minor.yy626, yymsp[-1].minor.yy626, yymsp[0].minor.yy626);
}
        break;
      case 281: /* cmd ::= DETACH database_kw_opt expr */
{
  sqlite3Detach(pParse, yymsp[0].minor.yy626);
}
        break;
      case 284: /* cmd ::= REINDEX */
{sqlite3Reindex(pParse, 0, 0);}
        break;
      case 285: /* cmd ::= REINDEX nm dbnm */
{sqlite3Reindex(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);}
        break;
      case 286: /* cmd ::= ANALYZE */
{sqlite3Analyze(pParse, 0, 0);}
        break;
      case 287: /* cmd ::= ANALYZE nm dbnm */
{sqlite3Analyze(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);}
        break;
      case 288: /* cmd ::= ALTER TABLE fullname RENAME TO nm */
{
  sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy607,&yymsp[0].minor.yy0);
}
        break;
      case 289: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */
{
  yymsp[-1].minor.yy0.n = (int)(pParse->sLastToken.z-yymsp[-1].minor.yy0.z) + pParse->sLastToken.n;
  sqlite3AlterFinishAddColumn(pParse, &yymsp[-1].minor.yy0);
}
        break;
      case 290: /* cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */
{
  sqlite3AlterDropColumn(pParse, yymsp[-3].minor.yy607, &yymsp[0].minor.yy0);
}
        break;
      case 291: /* add_column_fullname ::= fullname */
{
  disableLookaside(pParse);
  sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy607);
}
        break;
      case 292: /* cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */
{
  sqlite3AlterRenameColumn(pParse, yymsp[-5].minor.yy607, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0);
}
        break;
      case 293: /* cmd ::= create_vtab */
{sqlite3VtabFinishParse(pParse,0);}
        break;
      case 294: /* cmd ::= create_vtab LP vtabarglist RP */
{sqlite3VtabFinishParse(pParse,&yymsp[0].minor.yy0);}
        break;
      case 295: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
{
    sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, yymsp[-4].minor.yy64);
}
        break;
      case 296: /* vtabarg ::= */
{sqlite3VtabArgInit(pParse);}
        break;
      case 297: /* vtabargtoken ::= ANY */
      case 298: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==298);
      case 299: /* lp ::= LP */ yytestcase(yyruleno==299);
{sqlite3VtabArgExtend(pParse,&yymsp[0].minor.yy0);}
        break;
      case 300: /* with ::= WITH wqlist */
      case 301: /* with ::= WITH RECURSIVE wqlist */ yytestcase(yyruleno==301);
{ sqlite3WithPush(pParse, yymsp[0].minor.yy43, 1); }
        break;
      case 302: /* wqas ::= AS */
{yymsp[0].minor.yy534 = M10d_Any;}
        break;
      case 303: /* wqas ::= AS MATERIALIZED */
{yymsp[-1].minor.yy534 = M10d_Yes;}
        break;
      case 304: /* wqas ::= AS NOT MATERIALIZED */
{yymsp[-2].minor.yy534 = M10d_No;}
        break;
      case 305: /* wqitem ::= nm eidlist_opt wqas LP select RP */
{
  yymsp[-5].minor.yy255 = sqlite3CteNew(pParse, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy562, yymsp[-1].minor.yy303, yymsp[-3].minor.yy534); /*A-overwrites-X*/
}
        break;
      case 306: /* wqlist ::= wqitem */
{
  yymsp[0].minor.yy43 = sqlite3WithAdd(pParse, 0, yymsp[0].minor.yy255); /*A-overwrites-X*/
}
        break;
      case 307: /* wqlist ::= wqlist COMMA wqitem */
{
  yymsp[-2].minor.yy43 = sqlite3WithAdd(pParse, yymsp[-2].minor.yy43, yymsp[0].minor.yy255);
}
        break;
      case 308: /* windowdefn_list ::= windowdefn */
{ yylhsminor.yy375 = yymsp[0].minor.yy375; }
  yymsp[0].minor.yy375 = yylhsminor.yy375;
        break;
      case 309: /* windowdefn_list ::= windowdefn_list COMMA windowdefn */
{
  assert( yymsp[0].minor.yy375!=0 );
  sqlite3WindowChain(pParse, yymsp[0].minor.yy375, yymsp[-2].minor.yy375);
  yymsp[0].minor.yy375->pNextWin = yymsp[-2].minor.yy375;
  yylhsminor.yy375 = yymsp[0].minor.yy375;
}
  yymsp[-2].minor.yy375 = yylhsminor.yy375;
        break;
      case 310: /* windowdefn ::= nm AS LP window RP */
{
  if( ALWAYS(yymsp[-1].minor.yy375) ){
    yymsp[-1].minor.yy375->zName = sqlite3DbStrNDup(pParse->db, yymsp[-4].minor.yy0.z, yymsp[-4].minor.yy0.n);
  }
  yylhsminor.yy375 = yymsp[-1].minor.yy375;
}
  yymsp[-4].minor.yy375 = yylhsminor.yy375;
        break;
      case 311: /* window ::= PARTITION BY nexprlist orderby_opt frame_opt */
{
  yymsp[-4].minor.yy375 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy375, yymsp[-2].minor.yy562, yymsp[-1].minor.yy562, 0);
}
        break;
      case 312: /* window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */
{
  yylhsminor.yy375 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy375, yymsp[-2].minor.yy562, yymsp[-1].minor.yy562, &yymsp[-5].minor.yy0);
}
  yymsp[-5].minor.yy375 = yylhsminor.yy375;
        break;
      case 313: /* window ::= ORDER BY sortlist frame_opt */
{
  yymsp[-3].minor.yy375 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy375, 0, yymsp[-1].minor.yy562, 0);
}
        break;
      case 314: /* window ::= nm ORDER BY sortlist frame_opt */
{
  yylhsminor.yy375 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy375, 0, yymsp[-1].minor.yy562, &yymsp[-4].minor.yy0);
}
  yymsp[-4].minor.yy375 = yylhsminor.yy375;
        break;
      case 315: /* window ::= frame_opt */
      case 334: /* filter_over ::= over_clause */ yytestcase(yyruleno==334);
{
  yylhsminor.yy375 = yymsp[0].minor.yy375;
}
  yymsp[0].minor.yy375 = yylhsminor.yy375;
        break;
      case 316: /* window ::= nm frame_opt */
{
  yylhsminor.yy375 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy375, 0, 0, &yymsp[-1].minor.yy0);
}
  yymsp[-1].minor.yy375 = yylhsminor.yy375;
        break;
      case 317: /* frame_opt ::= */
{
  yymsp[1].minor.yy375 = sqlite3WindowAlloc(pParse, 0, TK_UNBOUNDED, 0, TK_CURRENT, 0, 0);
}
        break;
      case 318: /* frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */
{
  yylhsminor.yy375 = sqlite3WindowAlloc(pParse, yymsp[-2].minor.yy64, yymsp[-1].minor.yy81.eType, yymsp[-1].minor.yy81.pExpr, TK_CURRENT, 0, yymsp[0].minor.yy534);
}
  yymsp[-2].minor.yy375 = yylhsminor.yy375;
        break;
      case 319: /* frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */
{
  yylhsminor.yy375 = sqlite3WindowAlloc(pParse, yymsp[-5].minor.yy64, yymsp[-3].minor.yy81.eType, yymsp[-3].minor.yy81.pExpr, yymsp[-1].minor.yy81.eType, yymsp[-1].minor.yy81.pExpr, yymsp[0].minor.yy534);
}
  yymsp[-5].minor.yy375 = yylhsminor.yy375;
        break;
      case 321: /* frame_bound_s ::= frame_bound */
      case 323: /* frame_bound_e ::= frame_bound */ yytestcase(yyruleno==323);
{yylhsminor.yy81 = yymsp[0].minor.yy81;}
  yymsp[0].minor.yy81 = yylhsminor.yy81;
        break;
      case 322: /* frame_bound_s ::= UNBOUNDED PRECEDING */
      case 324: /* frame_bound_e ::= UNBOUNDED FOLLOWING */ yytestcase(yyruleno==324);
      case 326: /* frame_bound ::= CURRENT ROW */ yytestcase(yyruleno==326);
{yylhsminor.yy81.eType = yymsp[-1].major; yylhsminor.yy81.pExpr = 0;}
  yymsp[-1].minor.yy81 = yylhsminor.yy81;
        break;
      case 325: /* frame_bound ::= expr PRECEDING|FOLLOWING */
{yylhsminor.yy81.eType = yymsp[0].major; yylhsminor.yy81.pExpr = yymsp[-1].minor.yy626;}
  yymsp[-1].minor.yy81 = yylhsminor.yy81;
        break;
      case 327: /* frame_exclude_opt ::= */
{yymsp[1].minor.yy534 = 0;}
        break;
      case 328: /* frame_exclude_opt ::= EXCLUDE frame_exclude */
{yymsp[-1].minor.yy534 = yymsp[0].minor.yy534;}
        break;
      case 329: /* frame_exclude ::= NO OTHERS */
      case 330: /* frame_exclude ::= CURRENT ROW */ yytestcase(yyruleno==330);
{yymsp[-1].minor.yy534 = yymsp[-1].major; /*A-overwrites-X*/}
        break;
      case 331: /* frame_exclude ::= GROUP|TIES */
{yymsp[0].minor.yy534 = yymsp[0].major; /*A-overwrites-X*/}
        break;
      case 332: /* window_clause ::= WINDOW windowdefn_list */
{ yymsp[-1].minor.yy375 = yymsp[0].minor.yy375; }
        break;
      case 333: /* filter_over ::= filter_clause over_clause */
{
  if( yymsp[0].minor.yy375 ){
    yymsp[0].minor.yy375->pFilter = yymsp[-1].minor.yy626;
  }else{
    sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy626);
  }
  yylhsminor.yy375 = yymsp[0].minor.yy375;
}
  yymsp[-1].minor.yy375 = yylhsminor.yy375;
        break;
      case 335: /* filter_over ::= filter_clause */
{
  yylhsminor.yy375 = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window));
  if( yylhsminor.yy375 ){
    yylhsminor.yy375->eFrmType = TK_FILTER;
    yylhsminor.yy375->pFilter = yymsp[0].minor.yy626;
  }else{
    sqlite3ExprDelete(pParse->db, yymsp[0].minor.yy626);
  }
}
  yymsp[0].minor.yy375 = yylhsminor.yy375;
        break;
      case 336: /* over_clause ::= OVER LP window RP */
{
  yymsp[-3].minor.yy375 = yymsp[-1].minor.yy375;
  assert( yymsp[-3].minor.yy375!=0 );
}
        break;
      case 337: /* over_clause ::= OVER nm */
{
  yymsp[-1].minor.yy375 = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window));
  if( yymsp[-1].minor.yy375 ){
    yymsp[-1].minor.yy375->zName = sqlite3DbStrNDup(pParse->db, yymsp[0].minor.yy0.z, yymsp[0].minor.yy0.n);
  }
}
        break;
      case 338: /* filter_clause ::= FILTER LP WHERE expr RP */
{ yymsp[-4].minor.yy626 = yymsp[-1].minor.yy626; }
        break;
      default:
      /* (339) input ::= cmdlist */ yytestcase(yyruleno==339);
      /* (340) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==340);
      /* (341) cmdlist ::= ecmd (OPTIMIZED OUT) */ assert(yyruleno!=341);
      /* (342) ecmd ::= SEMI */ yytestcase(yyruleno==342);
      /* (343) ecmd ::= cmdx SEMI */ yytestcase(yyruleno==343);
      /* (344) ecmd ::= explain cmdx SEMI (NEVER REDUCES) */ assert(yyruleno!=344);
      /* (345) trans_opt ::= */ yytestcase(yyruleno==345);
      /* (346) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==346);
      /* (347) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==347);
      /* (348) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==348);
      /* (349) savepoint_opt ::= */ yytestcase(yyruleno==349);
      /* (350) cmd ::= create_table create_table_args */ yytestcase(yyruleno==350);
      /* (351) table_option_set ::= table_option (OPTIMIZED OUT) */ assert(yyruleno!=351);
      /* (352) columnlist ::= columnlist COMMA columnname carglist */ yytestcase(yyruleno==352);
      /* (353) columnlist ::= columnname carglist */ yytestcase(yyruleno==353);
      /* (354) nm ::= ID|INDEXED */ yytestcase(yyruleno==354);
      /* (355) nm ::= STRING */ yytestcase(yyruleno==355);
      /* (356) nm ::= JOIN_KW */ yytestcase(yyruleno==356);
      /* (357) typetoken ::= typename */ yytestcase(yyruleno==357);
      /* (358) typename ::= ID|STRING */ yytestcase(yyruleno==358);
      /* (359) signed ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=359);
      /* (360) signed ::= minus_num (OPTIMIZED OUT) */ assert(yyruleno!=360);
      /* (361) carglist ::= carglist ccons */ yytestcase(yyruleno==361);
      /* (362) carglist ::= */ yytestcase(yyruleno==362);
      /* (363) ccons ::= NULL onconf */ yytestcase(yyruleno==363);
      /* (364) ccons ::= GENERATED ALWAYS AS generated */ yytestcase(yyruleno==364);
      /* (365) ccons ::= AS generated */ yytestcase(yyruleno==365);
      /* (366) conslist_opt ::= COMMA conslist */ yytestcase(yyruleno==366);
      /* (367) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==367);
      /* (368) conslist ::= tcons (OPTIMIZED OUT) */ assert(yyruleno!=368);
      /* (369) tconscomma ::= */ yytestcase(yyruleno==369);
      /* (370) defer_subclause_opt ::= defer_subclause (OPTIMIZED OUT) */ assert(yyruleno!=370);
      /* (371) resolvetype ::= raisetype (OPTIMIZED OUT) */ assert(yyruleno!=371);
      /* (372) selectnowith ::= oneselect (OPTIMIZED OUT) */ assert(yyruleno!=372);
      /* (373) oneselect ::= values */ yytestcase(yyruleno==373);
      /* (374) sclp ::= selcollist COMMA */ yytestcase(yyruleno==374);
      /* (375) as ::= ID|STRING */ yytestcase(yyruleno==375);
      /* (376) returning ::= */ yytestcase(yyruleno==376);
      /* (377) expr ::= term (OPTIMIZED OUT) */ assert(yyruleno!=377);
      /* (378) likeop ::= LIKE_KW|MATCH */ yytestcase(yyruleno==378);
      /* (379) exprlist ::= nexprlist */ yytestcase(yyruleno==379);
      /* (380) nmnum ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=380);
      /* (381) nmnum ::= nm (OPTIMIZED OUT) */ assert(yyruleno!=381);
      /* (382) nmnum ::= ON */ yytestcase(yyruleno==382);
      /* (383) nmnum ::= DELETE */ yytestcase(yyruleno==383);
      /* (384) nmnum ::= DEFAULT */ yytestcase(yyruleno==384);
      /* (385) plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==385);
      /* (386) foreach_clause ::= */ yytestcase(yyruleno==386);
      /* (387) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==387);
      /* (388) trnm ::= nm */ yytestcase(yyruleno==388);
      /* (389) tridxby ::= */ yytestcase(yyruleno==389);
      /* (390) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==390);
      /* (391) database_kw_opt ::= */ yytestcase(yyruleno==391);
      /* (392) kwcolumn_opt ::= */ yytestcase(yyruleno==392);
      /* (393) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==393);
      /* (394) vtabarglist ::= vtabarg */ yytestcase(yyruleno==394);
      /* (395) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==395);
      /* (396) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==396);
      /* (397) anylist ::= */ yytestcase(yyruleno==397);
      /* (398) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==398);
      /* (399) anylist ::= anylist ANY */ yytestcase(yyruleno==399);
      /* (400) with ::= */ yytestcase(yyruleno==400);
        break;
/********** End reduce actions ************************************************/
  };
  assert( yyruleno<sizeof(yyRuleInfoLhs)/sizeof(yyRuleInfoLhs[0]) );
  yygoto = yyRuleInfoLhs[yyruleno];
  yysize = yyRuleInfoNRhs[yyruleno];
  yyact = yy_find_reduce_action(yymsp[yysize].stateno,(YYCODETYPE)yygoto);
163477
163478
163479
163480
163481
163482
163483
163484
163485
163486
163487
163488

163489
163490
163491
163492
163493
163494
163495
163496
163497
163498
          fprintf(yyTraceFILE,"%sDiscard input token %s\n",
             yyTracePrompt,yyTokenName[yymajor]);
        }
#endif
        yy_destructor(yypParser, (YYCODETYPE)yymajor, &yyminorunion);
        yymajor = YYNOCODE;
      }else{
        while( yypParser->yytos >= yypParser->yystack
            && (yyact = yy_find_reduce_action(
                        yypParser->yytos->stateno,
                        YYERRORSYMBOL)) > YY_MAX_SHIFTREDUCE
        ){

          yy_pop_parser_stack(yypParser);
        }
        if( yypParser->yytos < yypParser->yystack || yymajor==0 ){
          yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
          yy_parse_failed(yypParser);
#ifndef YYNOERRORRECOVERY
          yypParser->yyerrcnt = -1;
#endif
          yymajor = YYNOCODE;
        }else if( yymx!=YYERRORSYMBOL ){







|
|
<
|
<
>


|







163995
163996
163997
163998
163999
164000
164001
164002
164003

164004

164005
164006
164007
164008
164009
164010
164011
164012
164013
164014
164015
          fprintf(yyTraceFILE,"%sDiscard input token %s\n",
             yyTracePrompt,yyTokenName[yymajor]);
        }
#endif
        yy_destructor(yypParser, (YYCODETYPE)yymajor, &yyminorunion);
        yymajor = YYNOCODE;
      }else{
        while( yypParser->yytos > yypParser->yystack ){
          yyact = yy_find_reduce_action(yypParser->yytos->stateno,

                                        YYERRORSYMBOL);

          if( yyact<=YY_MAX_SHIFTREDUCE ) break;
          yy_pop_parser_stack(yypParser);
        }
        if( yypParser->yytos <= yypParser->yystack || yymajor==0 ){
          yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
          yy_parse_failed(yypParser);
#ifndef YYNOERRORRECOVERY
          yypParser->yyerrcnt = -1;
#endif
          yymajor = YYNOCODE;
        }else if( yymx!=YYERRORSYMBOL ){
166551
166552
166553
166554
166555
166556
166557
166558
166559
166560
166561
166562
166563
166564
166565
    /* Closing the handle. Fourth parameter is passed the value 2. */
    sqlite3GlobalConfig.xSqllog(sqlite3GlobalConfig.pSqllogArg, db, 0, 2);
  }
#endif

  /* Convert the connection into a zombie and then close it.
  */
  db->magic = SQLITE_MAGIC_ZOMBIE;
  sqlite3LeaveMutexAndCloseZombie(db);
  return SQLITE_OK;
}

/*
** Return the transaction state for a single databse, or the maximum
** transaction state over all attached databases if zSchema is null.







|







167068
167069
167070
167071
167072
167073
167074
167075
167076
167077
167078
167079
167080
167081
167082
    /* Closing the handle. Fourth parameter is passed the value 2. */
    sqlite3GlobalConfig.xSqllog(sqlite3GlobalConfig.pSqllogArg, db, 0, 2);
  }
#endif

  /* Convert the connection into a zombie and then close it.
  */
  db->eOpenState = SQLITE_STATE_ZOMBIE;
  sqlite3LeaveMutexAndCloseZombie(db);
  return SQLITE_OK;
}

/*
** Return the transaction state for a single databse, or the maximum
** transaction state over all attached databases if zSchema is null.
166615
166616
166617
166618
166619
166620
166621
166622
166623
166624
166625
166626
166627
166628
166629
  HashElem *i;                    /* Hash table iterator */
  int j;

  /* If there are outstanding sqlite3_stmt or sqlite3_backup objects
  ** or if the connection has not yet been closed by sqlite3_close_v2(),
  ** then just leave the mutex and return.
  */
  if( db->magic!=SQLITE_MAGIC_ZOMBIE || connectionIsBusy(db) ){
    sqlite3_mutex_leave(db->mutex);
    return;
  }

  /* If we reach this point, it means that the database connection has
  ** closed all sqlite3_stmt and sqlite3_backup objects and has been
  ** passed to sqlite3_close (meaning that it is a zombie).  Therefore,







|







167132
167133
167134
167135
167136
167137
167138
167139
167140
167141
167142
167143
167144
167145
167146
  HashElem *i;                    /* Hash table iterator */
  int j;

  /* If there are outstanding sqlite3_stmt or sqlite3_backup objects
  ** or if the connection has not yet been closed by sqlite3_close_v2(),
  ** then just leave the mutex and return.
  */
  if( db->eOpenState!=SQLITE_STATE_ZOMBIE || connectionIsBusy(db) ){
    sqlite3_mutex_leave(db->mutex);
    return;
  }

  /* If we reach this point, it means that the database connection has
  ** closed all sqlite3_stmt and sqlite3_backup objects and has been
  ** passed to sqlite3_close (meaning that it is a zombie).  Therefore,
166701
166702
166703
166704
166705
166706
166707
166708
166709
166710
166711
166712
166713
166714
166715
166716
166717
166718
166719
166720
166721
166722
166723
166724
166725
  sqlite3ValueFree(db->pErr);
  sqlite3CloseExtensions(db);
#if SQLITE_USER_AUTHENTICATION
  sqlite3_free(db->auth.zAuthUser);
  sqlite3_free(db->auth.zAuthPW);
#endif

  db->magic = SQLITE_MAGIC_ERROR;

  /* The temp-database schema is allocated differently from the other schema
  ** objects (using sqliteMalloc() directly, instead of sqlite3BtreeSchema()).
  ** So it needs to be freed here. Todo: Why not roll the temp schema into
  ** the same sqliteMalloc() as the one that allocates the database
  ** structure?
  */
  sqlite3DbFree(db, db->aDb[1].pSchema);
  sqlite3_mutex_leave(db->mutex);
  db->magic = SQLITE_MAGIC_CLOSED;
  sqlite3_mutex_free(db->mutex);
  assert( sqlite3LookasideUsed(db,0)==0 );
  if( db->lookaside.bMalloced ){
    sqlite3_free(db->lookaside.pStart);
  }
  sqlite3_free(db);
}







|









|







167218
167219
167220
167221
167222
167223
167224
167225
167226
167227
167228
167229
167230
167231
167232
167233
167234
167235
167236
167237
167238
167239
167240
167241
167242
  sqlite3ValueFree(db->pErr);
  sqlite3CloseExtensions(db);
#if SQLITE_USER_AUTHENTICATION
  sqlite3_free(db->auth.zAuthUser);
  sqlite3_free(db->auth.zAuthPW);
#endif

  db->eOpenState = SQLITE_STATE_ERROR;

  /* The temp-database schema is allocated differently from the other schema
  ** objects (using sqliteMalloc() directly, instead of sqlite3BtreeSchema()).
  ** So it needs to be freed here. Todo: Why not roll the temp schema into
  ** the same sqliteMalloc() as the one that allocates the database
  ** structure?
  */
  sqlite3DbFree(db, db->aDb[1].pSchema);
  sqlite3_mutex_leave(db->mutex);
  db->eOpenState = SQLITE_STATE_CLOSED;
  sqlite3_mutex_free(db->mutex);
  assert( sqlite3LookasideUsed(db,0)==0 );
  if( db->lookaside.bMalloced ){
    sqlite3_free(db->lookaside.pStart);
  }
  sqlite3_free(db);
}
167099
167100
167101
167102
167103
167104
167105
167106
167107
167108
167109
167110
167111
167112
167113
}

/*
** Cause any pending operation to stop at its earliest opportunity.
*/
SQLITE_API void sqlite3_interrupt(sqlite3 *db){
#ifdef SQLITE_ENABLE_API_ARMOR
  if( !sqlite3SafetyCheckOk(db) && (db==0 || db->magic!=SQLITE_MAGIC_ZOMBIE) ){
    (void)SQLITE_MISUSE_BKPT;
    return;
  }
#endif
  AtomicStore(&db->u1.isInterrupted, 1);
}








|







167616
167617
167618
167619
167620
167621
167622
167623
167624
167625
167626
167627
167628
167629
167630
}

/*
** Cause any pending operation to stop at its earliest opportunity.
*/
SQLITE_API void sqlite3_interrupt(sqlite3 *db){
#ifdef SQLITE_ENABLE_API_ARMOR
  if( !sqlite3SafetyCheckOk(db) && (db==0 || db->eOpenState!=SQLITE_STATE_ZOMBIE) ){
    (void)SQLITE_MISUSE_BKPT;
    return;
  }
#endif
  AtomicStore(&db->u1.isInterrupted, 1);
}

167128
167129
167130
167131
167132
167133
167134
167135
167136
167137
167138
167139
167140
167141
167142
167143
167144
167145
167146
167147
167148
167149
167150
167151
167152
  void (*xStep)(sqlite3_context*,int,sqlite3_value **),
  void (*xFinal)(sqlite3_context*),
  void (*xValue)(sqlite3_context*),
  void (*xInverse)(sqlite3_context*,int,sqlite3_value **),
  FuncDestructor *pDestructor
){
  FuncDef *p;
  int nName;
  int extraFlags;

  assert( sqlite3_mutex_held(db->mutex) );
  assert( xValue==0 || xSFunc==0 );
  if( zFunctionName==0                /* Must have a valid name */
   || (xSFunc!=0 && xFinal!=0)        /* Not both xSFunc and xFinal */
   || ((xFinal==0)!=(xStep==0))       /* Both or neither of xFinal and xStep */
   || ((xValue==0)!=(xInverse==0))    /* Both or neither of xValue, xInverse */
   || (nArg<-1 || nArg>SQLITE_MAX_FUNCTION_ARG)
   || (255<(nName = sqlite3Strlen30( zFunctionName)))
  ){
    return SQLITE_MISUSE_BKPT;
  }

  assert( SQLITE_FUNC_CONSTANT==SQLITE_DETERMINISTIC );
  assert( SQLITE_FUNC_DIRECT==SQLITE_DIRECTONLY );
  extraFlags = enc &  (SQLITE_DETERMINISTIC|SQLITE_DIRECTONLY|







<









|







167645
167646
167647
167648
167649
167650
167651

167652
167653
167654
167655
167656
167657
167658
167659
167660
167661
167662
167663
167664
167665
167666
167667
167668
  void (*xStep)(sqlite3_context*,int,sqlite3_value **),
  void (*xFinal)(sqlite3_context*),
  void (*xValue)(sqlite3_context*),
  void (*xInverse)(sqlite3_context*,int,sqlite3_value **),
  FuncDestructor *pDestructor
){
  FuncDef *p;

  int extraFlags;

  assert( sqlite3_mutex_held(db->mutex) );
  assert( xValue==0 || xSFunc==0 );
  if( zFunctionName==0                /* Must have a valid name */
   || (xSFunc!=0 && xFinal!=0)        /* Not both xSFunc and xFinal */
   || ((xFinal==0)!=(xStep==0))       /* Both or neither of xFinal and xStep */
   || ((xValue==0)!=(xInverse==0))    /* Both or neither of xValue, xInverse */
   || (nArg<-1 || nArg>SQLITE_MAX_FUNCTION_ARG)
   || (255<sqlite3Strlen30(zFunctionName))
  ){
    return SQLITE_MISUSE_BKPT;
  }

  assert( SQLITE_FUNC_CONSTANT==SQLITE_DETERMINISTIC );
  assert( SQLITE_FUNC_DIRECT==SQLITE_DIRECTONLY );
  extraFlags = enc &  (SQLITE_DETERMINISTIC|SQLITE_DIRECTONLY|
168405
168406
168407
168408
168409
168410
168411
168412
168413
168414
168415
168416
168417
168418
168419

/*
** This routine does the core work of extracting URI parameters from a
** database filename for the sqlite3_uri_parameter() interface.
*/
static const char *uriParameter(const char *zFilename, const char *zParam){
  zFilename += sqlite3Strlen30(zFilename) + 1;
  while( zFilename[0] ){
    int x = strcmp(zFilename, zParam);
    zFilename += sqlite3Strlen30(zFilename) + 1;
    if( x==0 ) return zFilename;
    zFilename += sqlite3Strlen30(zFilename) + 1;
  }
  return 0;
}







|







168921
168922
168923
168924
168925
168926
168927
168928
168929
168930
168931
168932
168933
168934
168935

/*
** This routine does the core work of extracting URI parameters from a
** database filename for the sqlite3_uri_parameter() interface.
*/
static const char *uriParameter(const char *zFilename, const char *zParam){
  zFilename += sqlite3Strlen30(zFilename) + 1;
  while( ALWAYS(zFilename!=0) && zFilename[0] ){
    int x = strcmp(zFilename, zParam);
    zFilename += sqlite3Strlen30(zFilename) + 1;
    if( x==0 ) return zFilename;
    zFilename += sqlite3Strlen30(zFilename) + 1;
  }
  return 0;
}
168502
168503
168504
168505
168506
168507
168508
168509
168510
168511
168512
168513
168514
168515
168516
168517
168518
168519
168520







168521

168522
168523
168524
168525
168526
168527
168528
    if( isThreadsafe==0 ){
      sqlite3MutexWarnOnContention(db->mutex);
    }
  }
  sqlite3_mutex_enter(db->mutex);
  db->errMask = 0xff;
  db->nDb = 2;
  db->magic = SQLITE_MAGIC_BUSY;
  db->aDb = db->aDbStatic;
  db->lookaside.bDisable = 1;
  db->lookaside.sz = 0;

  assert( sizeof(db->aLimit)==sizeof(aHardLimit) );
  memcpy(db->aLimit, aHardLimit, sizeof(db->aLimit));
  db->aLimit[SQLITE_LIMIT_WORKER_THREADS] = SQLITE_DEFAULT_WORKER_THREADS;
  db->autoCommit = 1;
  db->nextAutovac = -1;
  db->szMmap = sqlite3GlobalConfig.szMmap;
  db->nextPagesize = 0;







  db->nMaxSorterMmap = 0x7FFFFFFF;

  db->flags |= SQLITE_ShortColNames
                 | SQLITE_EnableTrigger
                 | SQLITE_EnableView
                 | SQLITE_CacheSpill
#if !defined(SQLITE_TRUSTED_SCHEMA) || SQLITE_TRUSTED_SCHEMA+0!=0
                 | SQLITE_TrustedSchema
#endif







|











>
>
>
>
>
>
>

>







169018
169019
169020
169021
169022
169023
169024
169025
169026
169027
169028
169029
169030
169031
169032
169033
169034
169035
169036
169037
169038
169039
169040
169041
169042
169043
169044
169045
169046
169047
169048
169049
169050
169051
169052
    if( isThreadsafe==0 ){
      sqlite3MutexWarnOnContention(db->mutex);
    }
  }
  sqlite3_mutex_enter(db->mutex);
  db->errMask = 0xff;
  db->nDb = 2;
  db->eOpenState = SQLITE_STATE_BUSY;
  db->aDb = db->aDbStatic;
  db->lookaside.bDisable = 1;
  db->lookaside.sz = 0;

  assert( sizeof(db->aLimit)==sizeof(aHardLimit) );
  memcpy(db->aLimit, aHardLimit, sizeof(db->aLimit));
  db->aLimit[SQLITE_LIMIT_WORKER_THREADS] = SQLITE_DEFAULT_WORKER_THREADS;
  db->autoCommit = 1;
  db->nextAutovac = -1;
  db->szMmap = sqlite3GlobalConfig.szMmap;
  db->nextPagesize = 0;
  db->init.azInit = sqlite3StdType; /* Any array of string ptrs will do */
#ifdef SQLITE_ENABLE_SORTER_MMAP
  /* Beginning with version 3.37.0, using the VFS xFetch() API to memory-map
  ** the temporary files used to do external sorts (see code in vdbesort.c)
  ** is disabled. It can still be used either by defining
  ** SQLITE_ENABLE_SORTER_MMAP at compile time or by using the
  ** SQLITE_TESTCTRL_SORTER_MMAP test-control at runtime. */
  db->nMaxSorterMmap = 0x7FFFFFFF;
#endif
  db->flags |= SQLITE_ShortColNames
                 | SQLITE_EnableTrigger
                 | SQLITE_EnableView
                 | SQLITE_CacheSpill
#if !defined(SQLITE_TRUSTED_SCHEMA) || SQLITE_TRUSTED_SCHEMA+0!=0
                 | SQLITE_TrustedSchema
#endif
168662
168663
168664
168665
168666
168667
168668
168669
168670
168671
168672
168673
168674
168675
168676
  ** database it is OFF. This matches the pager layer defaults.
  */
  db->aDb[0].zDbSName = "main";
  db->aDb[0].safety_level = SQLITE_DEFAULT_SYNCHRONOUS+1;
  db->aDb[1].zDbSName = "temp";
  db->aDb[1].safety_level = PAGER_SYNCHRONOUS_OFF;

  db->magic = SQLITE_MAGIC_OPEN;
  if( db->mallocFailed ){
    goto opendb_out;
  }

  /* Register all built-in functions, but do not attempt to read the
  ** database schema yet. This is delayed until the first time the database
  ** is accessed.







|







169186
169187
169188
169189
169190
169191
169192
169193
169194
169195
169196
169197
169198
169199
169200
  ** database it is OFF. This matches the pager layer defaults.
  */
  db->aDb[0].zDbSName = "main";
  db->aDb[0].safety_level = SQLITE_DEFAULT_SYNCHRONOUS+1;
  db->aDb[1].zDbSName = "temp";
  db->aDb[1].safety_level = PAGER_SYNCHRONOUS_OFF;

  db->eOpenState = SQLITE_STATE_OPEN;
  if( db->mallocFailed ){
    goto opendb_out;
  }

  /* Register all built-in functions, but do not attempt to read the
  ** database schema yet. This is delayed until the first time the database
  ** is accessed.
168729
168730
168731
168732
168733
168734
168735
168736
168737
168738
168739
168740
168741
168742
168743
  }
  rc = sqlite3_errcode(db);
  assert( db!=0 || rc==SQLITE_NOMEM );
  if( rc==SQLITE_NOMEM ){
    sqlite3_close(db);
    db = 0;
  }else if( rc!=SQLITE_OK ){
    db->magic = SQLITE_MAGIC_SICK;
  }
  *ppDb = db;
#ifdef SQLITE_ENABLE_SQLLOG
  if( sqlite3GlobalConfig.xSqllog ){
    /* Opening a db handle. Fourth parameter is passed 0. */
    void *pArg = sqlite3GlobalConfig.pSqllogArg;
    sqlite3GlobalConfig.xSqllog(pArg, db, zFilename, 0);







|







169253
169254
169255
169256
169257
169258
169259
169260
169261
169262
169263
169264
169265
169266
169267
  }
  rc = sqlite3_errcode(db);
  assert( db!=0 || rc==SQLITE_NOMEM );
  if( rc==SQLITE_NOMEM ){
    sqlite3_close(db);
    db = 0;
  }else if( rc!=SQLITE_OK ){
    db->eOpenState = SQLITE_STATE_SICK;
  }
  *ppDb = db;
#ifdef SQLITE_ENABLE_SQLLOG
  if( sqlite3GlobalConfig.xSqllog ){
    /* Opening a db handle. Fourth parameter is passed 0. */
    void *pArg = sqlite3GlobalConfig.pSqllogArg;
    sqlite3GlobalConfig.xSqllog(pArg, db, zFilename, 0);
169745
169746
169747
169748
169749
169750
169751
169752
169753
169754
169755
169756
169757
169758
169759
/*
** Return a pointer to the name of Nth query parameter of the filename.
*/
SQLITE_API const char *sqlite3_uri_key(const char *zFilename, int N){
  if( zFilename==0 || N<0 ) return 0;
  zFilename = databaseName(zFilename);
  zFilename += sqlite3Strlen30(zFilename) + 1;
  while( zFilename[0] && (N--)>0 ){
    zFilename += sqlite3Strlen30(zFilename) + 1;
    zFilename += sqlite3Strlen30(zFilename) + 1;
  }
  return zFilename[0] ? zFilename : 0;
}

/*







|







170269
170270
170271
170272
170273
170274
170275
170276
170277
170278
170279
170280
170281
170282
170283
/*
** Return a pointer to the name of Nth query parameter of the filename.
*/
SQLITE_API const char *sqlite3_uri_key(const char *zFilename, int N){
  if( zFilename==0 || N<0 ) return 0;
  zFilename = databaseName(zFilename);
  zFilename += sqlite3Strlen30(zFilename) + 1;
  while( ALWAYS(zFilename) && zFilename[0] && (N--)>0 ){
    zFilename += sqlite3Strlen30(zFilename) + 1;
    zFilename += sqlite3Strlen30(zFilename) + 1;
  }
  return zFilename[0] ? zFilename : 0;
}

/*
169788
169789
169790
169791
169792
169793
169794

169795
169796
169797

169798
169799
169800
169801
169802
169803
169804
169805
169806
169807
169808
169809
169810
169811
169812
169813
169814
169815
169816
169817
169818
** It is an error to pass this routine a filename string that was not
** passed into the VFS from the SQLite core.  Doing so is similar to
** passing free() a pointer that was not obtained from malloc() - it is
** an error that we cannot easily detect but that will likely cause memory
** corruption.
*/
SQLITE_API const char *sqlite3_filename_database(const char *zFilename){

  return databaseName(zFilename);
}
SQLITE_API const char *sqlite3_filename_journal(const char *zFilename){

  zFilename = databaseName(zFilename);
  zFilename += sqlite3Strlen30(zFilename) + 1;
  while( zFilename[0] ){
    zFilename += sqlite3Strlen30(zFilename) + 1;
    zFilename += sqlite3Strlen30(zFilename) + 1;
  }
  return zFilename + 1;
}
SQLITE_API const char *sqlite3_filename_wal(const char *zFilename){
#ifdef SQLITE_OMIT_WAL
  return 0;
#else
  zFilename = sqlite3_filename_journal(zFilename);
  zFilename += sqlite3Strlen30(zFilename) + 1;
  return zFilename;
#endif
}

/*
** Return the Btree pointer identified by zDbName.  Return NULL if not found.
*/







>



>


|










|







170312
170313
170314
170315
170316
170317
170318
170319
170320
170321
170322
170323
170324
170325
170326
170327
170328
170329
170330
170331
170332
170333
170334
170335
170336
170337
170338
170339
170340
170341
170342
170343
170344
** It is an error to pass this routine a filename string that was not
** passed into the VFS from the SQLite core.  Doing so is similar to
** passing free() a pointer that was not obtained from malloc() - it is
** an error that we cannot easily detect but that will likely cause memory
** corruption.
*/
SQLITE_API const char *sqlite3_filename_database(const char *zFilename){
  if( zFilename==0 ) return 0;
  return databaseName(zFilename);
}
SQLITE_API const char *sqlite3_filename_journal(const char *zFilename){
  if( zFilename==0 ) return 0;
  zFilename = databaseName(zFilename);
  zFilename += sqlite3Strlen30(zFilename) + 1;
  while( ALWAYS(zFilename) && zFilename[0] ){
    zFilename += sqlite3Strlen30(zFilename) + 1;
    zFilename += sqlite3Strlen30(zFilename) + 1;
  }
  return zFilename + 1;
}
SQLITE_API const char *sqlite3_filename_wal(const char *zFilename){
#ifdef SQLITE_OMIT_WAL
  return 0;
#else
  zFilename = sqlite3_filename_journal(zFilename);
  if( zFilename ) zFilename += sqlite3Strlen30(zFilename) + 1;
  return zFilename;
#endif
}

/*
** Return the Btree pointer identified by zDbName.  Return NULL if not found.
*/
171097
171098
171099
171100
171101
171102
171103
171104



171105
171106
171107
171108
171109
171110
171111
171112
171113
171114
171115
171116
171117
171118
171119
171120
171121
** amalgamation.
*/
#ifndef SQLITE_AMALGAMATION
/*
** Macros indicating that conditional expressions are always true or
** false.
*/
#ifdef SQLITE_COVERAGE_TEST



# define ALWAYS(x) (1)
# define NEVER(X)  (0)
#elif defined(SQLITE_DEBUG)
# define ALWAYS(x) sqlite3Fts3Always((x)!=0)
# define NEVER(x) sqlite3Fts3Never((x)!=0)
SQLITE_PRIVATE int sqlite3Fts3Always(int b);
SQLITE_PRIVATE int sqlite3Fts3Never(int b);
#else
# define ALWAYS(x) (x)
# define NEVER(x)  (x)
#endif

/*
** Internal types used by SQLite.
*/
typedef unsigned char u8;         /* 1-byte (or larger) unsigned integer */
typedef short int i16;            /* 2-byte (or larger) signed integer */







|
>
>
>
|
|
|
|
|
<
<

|
|







171623
171624
171625
171626
171627
171628
171629
171630
171631
171632
171633
171634
171635
171636
171637
171638


171639
171640
171641
171642
171643
171644
171645
171646
171647
171648
** amalgamation.
*/
#ifndef SQLITE_AMALGAMATION
/*
** Macros indicating that conditional expressions are always true or
** false.
*/
#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST)
# define SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS 1
#endif
#if defined(SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS)
# define ALWAYS(X)      (1)
# define NEVER(X)       (0)
#elif !defined(NDEBUG)
# define ALWAYS(X)      ((X)?1:(assert(0),0))
# define NEVER(X)       ((X)?(assert(0),1):0)


#else
# define ALWAYS(X)      (X)
# define NEVER(X)       (X)
#endif

/*
** Internal types used by SQLite.
*/
typedef unsigned char u8;         /* 1-byte (or larger) unsigned integer */
typedef short int i16;            /* 2-byte (or larger) signed integer */
171623
171624
171625
171626
171627
171628
171629
171630
171631
171632
171633
171634
171635
171636
171637
171638
171639
171640
171641
171642
171643
#endif

static int fts3EvalNext(Fts3Cursor *pCsr);
static int fts3EvalStart(Fts3Cursor *pCsr);
static int fts3TermSegReaderCursor(
    Fts3Cursor *, const char *, int, int, Fts3MultiSegReader **);

#ifndef SQLITE_AMALGAMATION
# if defined(SQLITE_DEBUG)
SQLITE_PRIVATE int sqlite3Fts3Always(int b) { assert( b ); return b; }
SQLITE_PRIVATE int sqlite3Fts3Never(int b)  { assert( !b ); return b; }
# endif
#endif

/*
** This variable is set to false when running tests for which the on disk
** structures should not be corrupt. Otherwise, true. If it is false, extra
** assert() conditions in the fts3 code are activated - conditions that are
** only true if it is guaranteed that the fts3 database is not corrupt.
*/
#ifdef SQLITE_DEBUG







<
<
<
<
<
<
<







172150
172151
172152
172153
172154
172155
172156







172157
172158
172159
172160
172161
172162
172163
#endif

static int fts3EvalNext(Fts3Cursor *pCsr);
static int fts3EvalStart(Fts3Cursor *pCsr);
static int fts3TermSegReaderCursor(
    Fts3Cursor *, const char *, int, int, Fts3MultiSegReader **);








/*
** This variable is set to false when running tests for which the on disk
** structures should not be corrupt. Otherwise, true. If it is false, extra
** assert() conditions in the fts3 code are activated - conditions that are
** only true if it is guaranteed that the fts3 database is not corrupt.
*/
#ifdef SQLITE_DEBUG
185322
185323
185324
185325
185326
185327
185328
185329
185330
185331
185332
185333
185334
185335
185336
    }
    p->iOff += fts3GetVarint32(&p->aNode[p->iOff], &nSuffix);

    if( nPrefix>p->term.n || nSuffix>p->nNode-p->iOff || nSuffix==0 ){
      return FTS_CORRUPT_VTAB;
    }
    blobGrowBuffer(&p->term, nPrefix+nSuffix, &rc);
    if( rc==SQLITE_OK ){
      memcpy(&p->term.a[nPrefix], &p->aNode[p->iOff], nSuffix);
      p->term.n = nPrefix+nSuffix;
      p->iOff += nSuffix;
      if( p->iChild==0 ){
        p->iOff += fts3GetVarint32(&p->aNode[p->iOff], &p->nDoclist);
        if( (p->nNode-p->iOff)<p->nDoclist ){
          return FTS_CORRUPT_VTAB;







|







185842
185843
185844
185845
185846
185847
185848
185849
185850
185851
185852
185853
185854
185855
185856
    }
    p->iOff += fts3GetVarint32(&p->aNode[p->iOff], &nSuffix);

    if( nPrefix>p->term.n || nSuffix>p->nNode-p->iOff || nSuffix==0 ){
      return FTS_CORRUPT_VTAB;
    }
    blobGrowBuffer(&p->term, nPrefix+nSuffix, &rc);
    if( rc==SQLITE_OK && ALWAYS(p->term.a!=0) ){
      memcpy(&p->term.a[nPrefix], &p->aNode[p->iOff], nSuffix);
      p->term.n = nPrefix+nSuffix;
      p->iOff += nSuffix;
      if( p->iChild==0 ){
        p->iOff += fts3GetVarint32(&p->aNode[p->iOff], &p->nDoclist);
        if( (p->nNode-p->iOff)<p->nDoclist ){
          return FTS_CORRUPT_VTAB;
185716
185717
185718
185719
185720
185721
185722

185723



185724
185725
185726
185727
185728
185729
185730
static int fts3TermCmp(
  const char *zLhs, int nLhs,     /* LHS of comparison */
  const char *zRhs, int nRhs      /* RHS of comparison */
){
  int nCmp = MIN(nLhs, nRhs);
  int res;


  res = (nCmp ? memcmp(zLhs, zRhs, nCmp) : 0);



  if( res==0 ) res = nLhs - nRhs;

  return res;
}


/*







>
|
>
>
>







186236
186237
186238
186239
186240
186241
186242
186243
186244
186245
186246
186247
186248
186249
186250
186251
186252
186253
186254
static int fts3TermCmp(
  const char *zLhs, int nLhs,     /* LHS of comparison */
  const char *zRhs, int nRhs      /* RHS of comparison */
){
  int nCmp = MIN(nLhs, nRhs);
  int res;

  if( nCmp && ALWAYS(zLhs) && ALWAYS(zRhs) ){
    res = memcmp(zLhs, zRhs, nCmp);
  }else{
    res = 0;
  }
  if( res==0 ) res = nLhs - nRhs;

  return res;
}


/*
186360
186361
186362
186363
186364
186365
186366
186367
186368
186369
186370
186371
186372
186373
186374
    sqlite3_bind_int(pSelect, 1, FTS_STAT_INCRMERGEHINT);
    if( SQLITE_ROW==sqlite3_step(pSelect) ){
      const char *aHint = sqlite3_column_blob(pSelect, 0);
      int nHint = sqlite3_column_bytes(pSelect, 0);
      if( aHint ){
        blobGrowBuffer(pHint, nHint, &rc);
        if( rc==SQLITE_OK ){
          memcpy(pHint->a, aHint, nHint);
          pHint->n = nHint;
        }
      }
    }
    rc2 = sqlite3_reset(pSelect);
    if( rc==SQLITE_OK ) rc = rc2;
  }







|







186884
186885
186886
186887
186888
186889
186890
186891
186892
186893
186894
186895
186896
186897
186898
    sqlite3_bind_int(pSelect, 1, FTS_STAT_INCRMERGEHINT);
    if( SQLITE_ROW==sqlite3_step(pSelect) ){
      const char *aHint = sqlite3_column_blob(pSelect, 0);
      int nHint = sqlite3_column_bytes(pSelect, 0);
      if( aHint ){
        blobGrowBuffer(pHint, nHint, &rc);
        if( rc==SQLITE_OK ){
          if( ALWAYS(pHint->a!=0) ) memcpy(pHint->a, aHint, nHint);
          pHint->n = nHint;
        }
      }
    }
    rc2 = sqlite3_reset(pSelect);
    if( rc==SQLITE_OK ) rc = rc2;
  }
188451
188452
188453
188454
188455
188456
188457
188458
188459
188460
188461


188462
188463
188464
188465
188466
188467
188468

/*
** Advance the iterator passed as an argument to the next position. Return
** 1 if the iterator is at EOF or if it now points to the start of the
** position list for the next column.
*/
static int fts3LcsIteratorAdvance(LcsIterator *pIter){
  char *pRead = pIter->pRead;
  sqlite3_int64 iRead;
  int rc = 0;



  pRead += sqlite3Fts3GetVarint(pRead, &iRead);
  if( iRead==0 || iRead==1 ){
    pRead = 0;
    rc = 1;
  }else{
    pIter->iPos += (int)(iRead-2);
  }







|



>
>







188975
188976
188977
188978
188979
188980
188981
188982
188983
188984
188985
188986
188987
188988
188989
188990
188991
188992
188993
188994

/*
** Advance the iterator passed as an argument to the next position. Return
** 1 if the iterator is at EOF or if it now points to the start of the
** position list for the next column.
*/
static int fts3LcsIteratorAdvance(LcsIterator *pIter){
  char *pRead;
  sqlite3_int64 iRead;
  int rc = 0;

  if( NEVER(pIter==0) ) return 1;
  pRead = pIter->pRead;
  pRead += sqlite3Fts3GetVarint(pRead, &iRead);
  if( iRead==0 || iRead==1 ){
    pRead = 0;
    rc = 1;
  }else{
    pIter->iPos += (int)(iRead-2);
  }
189976
189977
189978
189979
189980
189981
189982













189983
189984
189985
189986
189987
189988
189989
#ifndef SQLITE_AMALGAMATION
  /* Unsigned integer types.  These are already defined in the sqliteInt.h,
  ** but the definitions need to be repeated for separate compilation. */
  typedef sqlite3_uint64 u64;
  typedef unsigned int u32;
  typedef unsigned short int u16;
  typedef unsigned char u8;













#endif

/* Objects */
typedef struct JsonString JsonString;
typedef struct JsonNode JsonNode;
typedef struct JsonParse JsonParse;








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







190502
190503
190504
190505
190506
190507
190508
190509
190510
190511
190512
190513
190514
190515
190516
190517
190518
190519
190520
190521
190522
190523
190524
190525
190526
190527
190528
#ifndef SQLITE_AMALGAMATION
  /* Unsigned integer types.  These are already defined in the sqliteInt.h,
  ** but the definitions need to be repeated for separate compilation. */
  typedef sqlite3_uint64 u64;
  typedef unsigned int u32;
  typedef unsigned short int u16;
  typedef unsigned char u8;
# if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST)
#   define SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS 1
# endif
# if defined(SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS)
#   define ALWAYS(X)      (1)
#   define NEVER(X)       (0)
# elif !defined(NDEBUG)
#   define ALWAYS(X)      ((X)?1:(assert(0),0))
#   define NEVER(X)       ((X)?(assert(0),1):0)
# else
#   define ALWAYS(X)      (X)
#   define NEVER(X)       (X)
# endif
#endif

/* Objects */
typedef struct JsonString JsonString;
typedef struct JsonNode JsonNode;
typedef struct JsonParse JsonParse;

190318
190319
190320
190321
190322
190323
190324

190325
190326
190327
190328
190329
190330
190331
190332
190333
** the number of JsonNode objects that are encoded.
*/
static void jsonRenderNode(
  JsonNode *pNode,               /* The node to render */
  JsonString *pOut,              /* Write JSON here */
  sqlite3_value **aReplace       /* Replacement values */
){

  if( pNode->jnFlags & (JNODE_REPLACE|JNODE_PATCH) ){
    if( pNode->jnFlags & JNODE_REPLACE ){
      jsonAppendValue(pOut, aReplace[pNode->u.iReplace]);
      return;
    }
    pNode = pNode->u.pPatch;
  }
  switch( pNode->eType ){
    default: {







>

|







190857
190858
190859
190860
190861
190862
190863
190864
190865
190866
190867
190868
190869
190870
190871
190872
190873
** the number of JsonNode objects that are encoded.
*/
static void jsonRenderNode(
  JsonNode *pNode,               /* The node to render */
  JsonString *pOut,              /* Write JSON here */
  sqlite3_value **aReplace       /* Replacement values */
){
  assert( pNode!=0 );
  if( pNode->jnFlags & (JNODE_REPLACE|JNODE_PATCH) ){
    if( (pNode->jnFlags & JNODE_REPLACE)!=0 && ALWAYS(aReplace!=0) ){
      jsonAppendValue(pOut, aReplace[pNode->u.iReplace]);
      return;
    }
    pNode = pNode->u.pPatch;
  }
  switch( pNode->eType ){
    default: {
190485
190486
190487
190488
190489
190490
190491
190492
190493
190494
190495
190496
190497
190498
190499
        }
        i = i*10 + v;
      }
      if( pNode->u.zJContent[0]=='-' ){ i = -i; }
      sqlite3_result_int64(pCtx, i);
      int_done:
      break;
      int_as_real: i=0; /* no break */ deliberate_fall_through
    }
    case JSON_REAL: {
      double r;
#ifdef SQLITE_AMALGAMATION
      const char *z = pNode->u.zJContent;
      sqlite3AtoF(z, &r, sqlite3Strlen30(z), SQLITE_UTF8);
#else







|







191025
191026
191027
191028
191029
191030
191031
191032
191033
191034
191035
191036
191037
191038
191039
        }
        i = i*10 + v;
      }
      if( pNode->u.zJContent[0]=='-' ){ i = -i; }
      sqlite3_result_int64(pCtx, i);
      int_done:
      break;
      int_as_real: ; /* no break */ deliberate_fall_through
    }
    case JSON_REAL: {
      double r;
#ifdef SQLITE_AMALGAMATION
      const char *z = pNode->u.zJContent;
      sqlite3AtoF(z, &r, sqlite3Strlen30(z), SQLITE_UTF8);
#else
190639
190640
190641
190642
190643
190644
190645
190646
190647
190648
190649
190650
190651
190652
190653
static int jsonParseAddNode(
  JsonParse *pParse,        /* Append the node to this object */
  u32 eType,                /* Node type */
  u32 n,                    /* Content size or sub-node count */
  const char *zContent      /* Content */
){
  JsonNode *p;
  if( pParse->nNode>=pParse->nAlloc ){
    return jsonParseAddNodeExpand(pParse, eType, n, zContent);
  }
  p = &pParse->aNode[pParse->nNode];
  p->eType = (u8)eType;
  p->jnFlags = 0;
  p->n = n;
  p->u.zJContent = zContent;







|







191179
191180
191181
191182
191183
191184
191185
191186
191187
191188
191189
191190
191191
191192
191193
static int jsonParseAddNode(
  JsonParse *pParse,        /* Append the node to this object */
  u32 eType,                /* Node type */
  u32 n,                    /* Content size or sub-node count */
  const char *zContent      /* Content */
){
  JsonNode *p;
  if( pParse->aNode==0 || pParse->nNode>=pParse->nAlloc ){
    return jsonParseAddNodeExpand(pParse, eType, n, zContent);
  }
  p = &pParse->aNode[pParse->nNode];
  p->eType = (u8)eType;
  p->jnFlags = 0;
  p->n = n;
  p->u.zJContent = zContent;
192579
192580
192581
192582
192583
192584
192585




192586
192587
192588
192589
192590
192591
192592
192593
192594
192595
192596
192597
192598


192599











192600
192601
192602
192603
192604
192605
192606
/*   #include "sqlite3ext.h" */
  SQLITE_EXTENSION_INIT1
#else
/*   #include "sqlite3.h" */
#endif
SQLITE_PRIVATE int sqlite3GetToken(const unsigned char*,int*); /* In the SQLite core */





#ifndef SQLITE_AMALGAMATION
#include "sqlite3rtree.h"
typedef sqlite3_int64 i64;
typedef sqlite3_uint64 u64;
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
#if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
# define NDEBUG 1
#endif
#if defined(NDEBUG) && defined(SQLITE_DEBUG)
# undef NDEBUG
#endif


#endif












/* #include <string.h> */
/* #include <stdio.h> */
/* #include <assert.h> */
/* #include <stdlib.h> */

/*  The following macro is used to suppress compiler warnings.







>
>
>
>
|












>
>

>
>
>
>
>
>
>
>
>
>
>







193119
193120
193121
193122
193123
193124
193125
193126
193127
193128
193129
193130
193131
193132
193133
193134
193135
193136
193137
193138
193139
193140
193141
193142
193143
193144
193145
193146
193147
193148
193149
193150
193151
193152
193153
193154
193155
193156
193157
193158
193159
193160
193161
193162
193163
/*   #include "sqlite3ext.h" */
  SQLITE_EXTENSION_INIT1
#else
/*   #include "sqlite3.h" */
#endif
SQLITE_PRIVATE int sqlite3GetToken(const unsigned char*,int*); /* In the SQLite core */

/*
** If building separately, we will need some setup that is normally
** found in sqliteInt.h
*/
#if !defined(SQLITE_AMALGAMATION)
#include "sqlite3rtree.h"
typedef sqlite3_int64 i64;
typedef sqlite3_uint64 u64;
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
#if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
# define NDEBUG 1
#endif
#if defined(NDEBUG) && defined(SQLITE_DEBUG)
# undef NDEBUG
#endif
#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST)
# define SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS 1
#endif
#if defined(SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS)
# define ALWAYS(X)      (1)
# define NEVER(X)       (0)
#elif !defined(NDEBUG)
# define ALWAYS(X)      ((X)?1:(assert(0),0))
# define NEVER(X)       ((X)?(assert(0),1):0)
#else
# define ALWAYS(X)      (X)
# define NEVER(X)       (X)
#endif
#endif /* !defined(SQLITE_AMALGAMATION) */

/* #include <string.h> */
/* #include <stdio.h> */
/* #include <assert.h> */
/* #include <stdlib.h> */

/*  The following macro is used to suppress compiler warnings.
192650
192651
192652
192653
192654
192655
192656

192657

192658
192659
192660
192661
192662
192663
192664
  int iNodeSize;              /* Size in bytes of each node in the node table */
  u8 nDim;                    /* Number of dimensions */
  u8 nDim2;                   /* Twice the number of dimensions */
  u8 eCoordType;              /* RTREE_COORD_REAL32 or RTREE_COORD_INT32 */
  u8 nBytesPerCell;           /* Bytes consumed per cell */
  u8 inWrTrans;               /* True if inside write transaction */
  u8 nAux;                    /* # of auxiliary columns in %_rowid */

  u8 nAuxNotNull;             /* Number of initial not-null aux columns */

#ifdef SQLITE_DEBUG
  u8 bCorrupt;                /* Shadow table corruption detected */
#endif
  int iDepth;                 /* Current depth of the r-tree structure */
  char *zDb;                  /* Name of database containing r-tree table */
  char *zName;                /* Name of r-tree table */
  u32 nBusy;                  /* Current number of users of this structure */







>

>







193207
193208
193209
193210
193211
193212
193213
193214
193215
193216
193217
193218
193219
193220
193221
193222
193223
  int iNodeSize;              /* Size in bytes of each node in the node table */
  u8 nDim;                    /* Number of dimensions */
  u8 nDim2;                   /* Twice the number of dimensions */
  u8 eCoordType;              /* RTREE_COORD_REAL32 or RTREE_COORD_INT32 */
  u8 nBytesPerCell;           /* Bytes consumed per cell */
  u8 inWrTrans;               /* True if inside write transaction */
  u8 nAux;                    /* # of auxiliary columns in %_rowid */
#ifdef SQLITE_ENABLE_GEOPOLY
  u8 nAuxNotNull;             /* Number of initial not-null aux columns */
#endif
#ifdef SQLITE_DEBUG
  u8 bCorrupt;                /* Shadow table corruption detected */
#endif
  int iDepth;                 /* Current depth of the r-tree structure */
  char *zDb;                  /* Name of database containing r-tree table */
  char *zName;                /* Name of r-tree table */
  u32 nBusy;                  /* Current number of users of this structure */
192932
192933
192934
192935
192936
192937
192938




192939

192940
192941
192942
192943
192944
192945
192946
#endif
#endif

/* The testcase() macro should already be defined in the amalgamation.  If
** it is not, make it a no-op.
*/
#ifndef SQLITE_AMALGAMATION




# define testcase(X)

#endif

/*
** Make sure that the compiler intrinsics we desire are enabled when
** compiling with an appropriate version of MSVC unless prevented by
** the SQLITE_DISABLE_INTRINSIC define.
*/







>
>
>
>
|
>







193491
193492
193493
193494
193495
193496
193497
193498
193499
193500
193501
193502
193503
193504
193505
193506
193507
193508
193509
193510
#endif
#endif

/* The testcase() macro should already be defined in the amalgamation.  If
** it is not, make it a no-op.
*/
#ifndef SQLITE_AMALGAMATION
# ifdef SQLITE_COVERAGE_TEST
    unsigned int sqlite3RtreeTestcase = 0;
#   define testcase(X)  if( X ){ sqlite3RtreeTestcase += __LINE__; }
# else
#   define testcase(X)
# endif
#endif

/*
** Make sure that the compiler intrinsics we desire are enabled when
** compiling with an appropriate version of MSVC unless prevented by
** the SQLITE_DISABLE_INTRINSIC define.
*/
193181
193182
193183
193184
193185
193186
193187
193188
193189
193190
193191
193192
193193
193194
193195
193196
193197
193198
193199
193200
193201
193202
193203
193204
193205
193206
193207
193208
193209
193210
193211
193212
193213
193214
193215
193216
193217
193218
193219
193220
193221
193222
193223
193224
193225
193226
193227
193228
193229
193230
  if( pRtree->pNodeBlob && pRtree->inWrTrans==0 && pRtree->nCursor==0 ){
    sqlite3_blob *pBlob = pRtree->pNodeBlob;
    pRtree->pNodeBlob = 0;
    sqlite3_blob_close(pBlob);
  }
}

/*
** Check to see if pNode is the same as pParent or any of the parents
** of pParent.
*/
static int nodeInParentChain(const RtreeNode *pNode, const RtreeNode *pParent){
  do{
    if( pNode==pParent ) return 1;
    pParent = pParent->pParent;
  }while( pParent );
  return 0;
}

/*
** Obtain a reference to an r-tree node.
*/
static int nodeAcquire(
  Rtree *pRtree,             /* R-tree structure */
  i64 iNode,                 /* Node number to load */
  RtreeNode *pParent,        /* Either the parent node or NULL */
  RtreeNode **ppNode         /* OUT: Acquired node */
){
  int rc = SQLITE_OK;
  RtreeNode *pNode = 0;

  /* Check if the requested node is already in the hash table. If so,
  ** increase its reference count and return it.
  */
  if( (pNode = nodeHashLookup(pRtree, iNode))!=0 ){
    if( pParent && !pNode->pParent ){
      if( nodeInParentChain(pNode, pParent) ){
        RTREE_IS_CORRUPT(pRtree);
        return SQLITE_CORRUPT_VTAB;
      }
      pParent->nRef++;
      pNode->pParent = pParent;
    }else if( pParent && pNode->pParent && pParent!=pNode->pParent ){
      RTREE_IS_CORRUPT(pRtree);
      return SQLITE_CORRUPT_VTAB;
    }
    pNode->nRef++;
    *ppNode = pNode;
    return SQLITE_OK;
  }







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
















<
<
<
<
<
<
<
|







193745
193746
193747
193748
193749
193750
193751












193752
193753
193754
193755
193756
193757
193758
193759
193760
193761
193762
193763
193764
193765
193766
193767







193768
193769
193770
193771
193772
193773
193774
193775
  if( pRtree->pNodeBlob && pRtree->inWrTrans==0 && pRtree->nCursor==0 ){
    sqlite3_blob *pBlob = pRtree->pNodeBlob;
    pRtree->pNodeBlob = 0;
    sqlite3_blob_close(pBlob);
  }
}













/*
** Obtain a reference to an r-tree node.
*/
static int nodeAcquire(
  Rtree *pRtree,             /* R-tree structure */
  i64 iNode,                 /* Node number to load */
  RtreeNode *pParent,        /* Either the parent node or NULL */
  RtreeNode **ppNode         /* OUT: Acquired node */
){
  int rc = SQLITE_OK;
  RtreeNode *pNode = 0;

  /* Check if the requested node is already in the hash table. If so,
  ** increase its reference count and return it.
  */
  if( (pNode = nodeHashLookup(pRtree, iNode))!=0 ){







    if( pParent && pParent!=pNode->pParent ){
      RTREE_IS_CORRUPT(pRtree);
      return SQLITE_CORRUPT_VTAB;
    }
    pNode->nRef++;
    *ppNode = pNode;
    return SQLITE_OK;
  }
193274
193275
193276
193277
193278
193279
193280
193281
193282
193283
193284
193285
193286
193287
193288

  /* If the root node was just loaded, set pRtree->iDepth to the height
  ** of the r-tree structure. A height of zero means all data is stored on
  ** the root node. A height of one means the children of the root node
  ** are the leaves, and so on. If the depth as specified on the root node
  ** is greater than RTREE_MAX_DEPTH, the r-tree structure must be corrupt.
  */
  if( pNode && rc==SQLITE_OK && iNode==1 ){
    pRtree->iDepth = readInt16(pNode->zData);
    if( pRtree->iDepth>RTREE_MAX_DEPTH ){
      rc = SQLITE_CORRUPT_VTAB;
      RTREE_IS_CORRUPT(pRtree);
    }
  }








|







193819
193820
193821
193822
193823
193824
193825
193826
193827
193828
193829
193830
193831
193832
193833

  /* If the root node was just loaded, set pRtree->iDepth to the height
  ** of the r-tree structure. A height of zero means all data is stored on
  ** the root node. A height of one means the children of the root node
  ** are the leaves, and so on. If the depth as specified on the root node
  ** is greater than RTREE_MAX_DEPTH, the r-tree structure must be corrupt.
  */
  if( rc==SQLITE_OK && pNode && iNode==1 ){
    pRtree->iDepth = readInt16(pNode->zData);
    if( pRtree->iDepth>RTREE_MAX_DEPTH ){
      rc = SQLITE_CORRUPT_VTAB;
      RTREE_IS_CORRUPT(pRtree);
    }
  }

193880
193881
193882
193883
193884
193885
193886
193887
193888
193889
193890
193891

193892
193893
193894
193895
193896
193897
193898

/*
** Return the index of the cell containing a pointer to node pNode
** in its parent. If pNode is the root node, return -1.
*/
static int nodeParentIndex(Rtree *pRtree, RtreeNode *pNode, int *piIndex){
  RtreeNode *pParent = pNode->pParent;
  if( pParent ){
    return nodeRowidIndex(pRtree, pParent, pNode->iNode, piIndex);
  }
  *piIndex = -1;
  return SQLITE_OK;

}

/*
** Compare two search points.  Return negative, zero, or positive if the first
** is less than, equal to, or greater than the second.
**
** The rScore is the primary key.  Smaller rScore values come first.







|

|
|
|
>







194425
194426
194427
194428
194429
194430
194431
194432
194433
194434
194435
194436
194437
194438
194439
194440
194441
194442
194443
194444

/*
** Return the index of the cell containing a pointer to node pNode
** in its parent. If pNode is the root node, return -1.
*/
static int nodeParentIndex(Rtree *pRtree, RtreeNode *pNode, int *piIndex){
  RtreeNode *pParent = pNode->pParent;
  if( ALWAYS(pParent) ){
    return nodeRowidIndex(pRtree, pParent, pNode->iNode, piIndex);
  }else{
    *piIndex = -1;
    return SQLITE_OK;
  }
}

/*
** Compare two search points.  Return negative, zero, or positive if the first
** is less than, equal to, or greater than the second.
**
** The rScore is the primary key.  Smaller rScore values come first.
194007
194008
194009
194010
194011
194012
194013

194014
194015
194016
194017
194018
194019
194020
194021
   || (pFirst->rScore==rScore && pFirst->iLevel>iLevel)
  ){
    if( pCur->bPoint ){
      int ii;
      pNew = rtreeEnqueue(pCur, rScore, iLevel);
      if( pNew==0 ) return 0;
      ii = (int)(pNew - pCur->aPoint) + 1;

      if( ii<RTREE_CACHE_SZ ){
        assert( pCur->aNode[ii]==0 );
        pCur->aNode[ii] = pCur->aNode[0];
      }else{
        nodeRelease(RTREE_OF_CURSOR(pCur), pCur->aNode[0]);
      }
      pCur->aNode[0] = 0;
      *pNew = pCur->sPoint;







>
|







194553
194554
194555
194556
194557
194558
194559
194560
194561
194562
194563
194564
194565
194566
194567
194568
   || (pFirst->rScore==rScore && pFirst->iLevel>iLevel)
  ){
    if( pCur->bPoint ){
      int ii;
      pNew = rtreeEnqueue(pCur, rScore, iLevel);
      if( pNew==0 ) return 0;
      ii = (int)(pNew - pCur->aPoint) + 1;
      assert( ii==1 );
      if( ALWAYS(ii<RTREE_CACHE_SZ) ){
        assert( pCur->aNode[ii]==0 );
        pCur->aNode[ii] = pCur->aNode[0];
      }else{
        nodeRelease(RTREE_OF_CURSOR(pCur), pCur->aNode[0]);
      }
      pCur->aNode[0] = 0;
      *pNew = pCur->sPoint;
194068
194069
194070
194071
194072
194073
194074
194075
194076
194077
194078
194079
194080
194081
194082
  if( p->aNode[i] ){
    nodeRelease(RTREE_OF_CURSOR(p), p->aNode[i]);
    p->aNode[i] = 0;
  }
  if( p->bPoint ){
    p->anQueue[p->sPoint.iLevel]--;
    p->bPoint = 0;
  }else if( p->nPoint ){
    p->anQueue[p->aPoint[0].iLevel]--;
    n = --p->nPoint;
    p->aPoint[0] = p->aPoint[n];
    if( n<RTREE_CACHE_SZ-1 ){
      p->aNode[1] = p->aNode[n+1];
      p->aNode[n+1] = 0;
    }







|







194615
194616
194617
194618
194619
194620
194621
194622
194623
194624
194625
194626
194627
194628
194629
  if( p->aNode[i] ){
    nodeRelease(RTREE_OF_CURSOR(p), p->aNode[i]);
    p->aNode[i] = 0;
  }
  if( p->bPoint ){
    p->anQueue[p->sPoint.iLevel]--;
    p->bPoint = 0;
  }else if( ALWAYS(p->nPoint) ){
    p->anQueue[p->aPoint[0].iLevel]--;
    n = --p->nPoint;
    p->aPoint[0] = p->aPoint[n];
    if( n<RTREE_CACHE_SZ-1 ){
      p->aNode[1] = p->aNode[n+1];
      p->aNode[n+1] = 0;
    }
194209
194210
194211
194212
194213
194214
194215
194216
194217
194218
194219
194220
194221
194222
194223
194224
194225
194226
194227
194228
194229
194230
194231
194232
194233
194234
194235
194236
194237
194238
194239
194240
194241
** Rtree virtual table module xRowid method.
*/
static int rtreeRowid(sqlite3_vtab_cursor *pVtabCursor, sqlite_int64 *pRowid){
  RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor;
  RtreeSearchPoint *p = rtreeSearchPointFirst(pCsr);
  int rc = SQLITE_OK;
  RtreeNode *pNode = rtreeNodeOfFirstSearchPoint(pCsr, &rc);
  if( rc==SQLITE_OK && p ){
    *pRowid = nodeGetRowid(RTREE_OF_CURSOR(pCsr), pNode, p->iCell);
  }
  return rc;
}

/*
** Rtree virtual table module xColumn method.
*/
static int rtreeColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
  Rtree *pRtree = (Rtree *)cur->pVtab;
  RtreeCursor *pCsr = (RtreeCursor *)cur;
  RtreeSearchPoint *p = rtreeSearchPointFirst(pCsr);
  RtreeCoord c;
  int rc = SQLITE_OK;
  RtreeNode *pNode = rtreeNodeOfFirstSearchPoint(pCsr, &rc);

  if( rc ) return rc;
  if( p==0 ) return SQLITE_OK;
  if( i==0 ){
    sqlite3_result_int64(ctx, nodeGetRowid(pRtree, pNode, p->iCell));
  }else if( i<=pRtree->nDim2 ){
    nodeGetCoord(pRtree, pNode, p->iCell, i-1, &c);
#ifndef SQLITE_RTREE_INT_ONLY
    if( pRtree->eCoordType==RTREE_COORD_REAL32 ){
      sqlite3_result_double(ctx, c.f);







|

















|







194756
194757
194758
194759
194760
194761
194762
194763
194764
194765
194766
194767
194768
194769
194770
194771
194772
194773
194774
194775
194776
194777
194778
194779
194780
194781
194782
194783
194784
194785
194786
194787
194788
** Rtree virtual table module xRowid method.
*/
static int rtreeRowid(sqlite3_vtab_cursor *pVtabCursor, sqlite_int64 *pRowid){
  RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor;
  RtreeSearchPoint *p = rtreeSearchPointFirst(pCsr);
  int rc = SQLITE_OK;
  RtreeNode *pNode = rtreeNodeOfFirstSearchPoint(pCsr, &rc);
  if( rc==SQLITE_OK && ALWAYS(p) ){
    *pRowid = nodeGetRowid(RTREE_OF_CURSOR(pCsr), pNode, p->iCell);
  }
  return rc;
}

/*
** Rtree virtual table module xColumn method.
*/
static int rtreeColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
  Rtree *pRtree = (Rtree *)cur->pVtab;
  RtreeCursor *pCsr = (RtreeCursor *)cur;
  RtreeSearchPoint *p = rtreeSearchPointFirst(pCsr);
  RtreeCoord c;
  int rc = SQLITE_OK;
  RtreeNode *pNode = rtreeNodeOfFirstSearchPoint(pCsr, &rc);

  if( rc ) return rc;
  if( NEVER(p==0) ) return SQLITE_OK;
  if( i==0 ){
    sqlite3_result_int64(ctx, nodeGetRowid(pRtree, pNode, p->iCell));
  }else if( i<=pRtree->nDim2 ){
    nodeGetCoord(pRtree, pNode, p->iCell, i-1, &c);
#ifndef SQLITE_RTREE_INT_ONLY
    if( pRtree->eCoordType==RTREE_COORD_REAL32 ){
      sqlite3_result_double(ctx, c.f);
194426
194427
194428
194429
194430
194431
194432

194433

194434

194435
194436
194437
194438
194439
194440
194441
            }
          }
        }
      }
    }
    if( rc==SQLITE_OK ){
      RtreeSearchPoint *pNew;

      pNew = rtreeSearchPointNew(pCsr, RTREE_ZERO, (u8)(pRtree->iDepth+1));

      if( pNew==0 ) return SQLITE_NOMEM;

      pNew->id = 1;
      pNew->iCell = 0;
      pNew->eWithin = PARTLY_WITHIN;
      assert( pCsr->bPoint==1 );
      pCsr->aNode[0] = pRoot;
      pRoot = 0;
      RTREE_QUEUE_TRACE(pCsr, "PUSH-Fm:");







>

>
|
>







194973
194974
194975
194976
194977
194978
194979
194980
194981
194982
194983
194984
194985
194986
194987
194988
194989
194990
194991
            }
          }
        }
      }
    }
    if( rc==SQLITE_OK ){
      RtreeSearchPoint *pNew;
      assert( pCsr->bPoint==0 );  /* Due to the resetCursor() call above */
      pNew = rtreeSearchPointNew(pCsr, RTREE_ZERO, (u8)(pRtree->iDepth+1));
      if( NEVER(pNew==0) ){       /* Because pCsr->bPoint was FALSE */
        return SQLITE_NOMEM;
      }
      pNew->id = 1;
      pNew->iCell = 0;
      pNew->eWithin = PARTLY_WITHIN;
      assert( pCsr->bPoint==1 );
      pCsr->aNode[0] = pRoot;
      pRoot = 0;
      RTREE_QUEUE_TRACE(pCsr, "PUSH-Fm:");
194504
194505
194506
194507
194508
194509
194510
194511
194512
194513
194514
194515
194516
194517
194518
  }

  assert( pIdxInfo->idxStr==0 );
  for(ii=0; ii<pIdxInfo->nConstraint && iIdx<(int)(sizeof(zIdxStr)-1); ii++){
    struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[ii];

    if( bMatch==0 && p->usable
     && p->iColumn==0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ
    ){
      /* We have an equality constraint on the rowid. Use strategy 1. */
      int jj;
      for(jj=0; jj<ii; jj++){
        pIdxInfo->aConstraintUsage[jj].argvIndex = 0;
        pIdxInfo->aConstraintUsage[jj].omit = 0;
      }







|







195054
195055
195056
195057
195058
195059
195060
195061
195062
195063
195064
195065
195066
195067
195068
  }

  assert( pIdxInfo->idxStr==0 );
  for(ii=0; ii<pIdxInfo->nConstraint && iIdx<(int)(sizeof(zIdxStr)-1); ii++){
    struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[ii];

    if( bMatch==0 && p->usable
     && p->iColumn<=0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ
    ){
      /* We have an equality constraint on the rowid. Use strategy 1. */
      int jj;
      for(jj=0; jj<ii; jj++){
        pIdxInfo->aConstraintUsage[jj].argvIndex = 0;
        pIdxInfo->aConstraintUsage[jj].omit = 0;
      }
194710
194711
194712
194713
194714
194715
194716
194717
194718
194719
194720
194721
194722
194723
194724
    sqlite3_int64 iBest = 0;

    RtreeDValue fMinGrowth = RTREE_ZERO;
    RtreeDValue fMinArea = RTREE_ZERO;

    int nCell = NCELL(pNode);
    RtreeCell cell;
    RtreeNode *pChild;

    RtreeCell *aCell = 0;

    /* Select the child node which will be enlarged the least if pCell
    ** is inserted into it. Resolve ties by choosing the entry with
    ** the smallest area.
    */







|







195260
195261
195262
195263
195264
195265
195266
195267
195268
195269
195270
195271
195272
195273
195274
    sqlite3_int64 iBest = 0;

    RtreeDValue fMinGrowth = RTREE_ZERO;
    RtreeDValue fMinArea = RTREE_ZERO;

    int nCell = NCELL(pNode);
    RtreeCell cell;
    RtreeNode *pChild = 0;

    RtreeCell *aCell = 0;

    /* Select the child node which will be enlarged the least if pCell
    ** is inserted into it. Resolve ties by choosing the entry with
    ** the smallest area.
    */
194757
194758
194759
194760
194761
194762
194763

194764
194765
194766
194767
194768





194769

194770
194771
194772
194773
194774
194775
194776
static int AdjustTree(
  Rtree *pRtree,                    /* Rtree table */
  RtreeNode *pNode,                 /* Adjust ancestry of this node. */
  RtreeCell *pCell                  /* This cell was just inserted */
){
  RtreeNode *p = pNode;
  int cnt = 0;

  while( p->pParent ){
    RtreeNode *pParent = p->pParent;
    RtreeCell cell;
    int iCell;






    if( (++cnt)>1000 || nodeParentIndex(pRtree, p, &iCell)  ){

      RTREE_IS_CORRUPT(pRtree);
      return SQLITE_CORRUPT_VTAB;
    }

    nodeGetCell(pRtree, pParent, iCell, &cell);
    if( !cellContains(pRtree, &cell, pCell) ){
      cellUnion(pRtree, &cell, pCell);







>





>
>
>
>
>
|
>







195307
195308
195309
195310
195311
195312
195313
195314
195315
195316
195317
195318
195319
195320
195321
195322
195323
195324
195325
195326
195327
195328
195329
195330
195331
195332
195333
static int AdjustTree(
  Rtree *pRtree,                    /* Rtree table */
  RtreeNode *pNode,                 /* Adjust ancestry of this node. */
  RtreeCell *pCell                  /* This cell was just inserted */
){
  RtreeNode *p = pNode;
  int cnt = 0;
  int rc;
  while( p->pParent ){
    RtreeNode *pParent = p->pParent;
    RtreeCell cell;
    int iCell;

    cnt++;
    if( NEVER(cnt>100) ){
      RTREE_IS_CORRUPT(pRtree);
      return SQLITE_CORRUPT_VTAB;
    }
    rc = nodeParentIndex(pRtree, p, &iCell);
    if( NEVER(rc!=SQLITE_OK) ){
      RTREE_IS_CORRUPT(pRtree);
      return SQLITE_CORRUPT_VTAB;
    }

    nodeGetCell(pRtree, pParent, iCell, &cell);
    if( !cellContains(pRtree, &cell, pCell) ){
      cellUnion(pRtree, &cell, pCell);
195051
195052
195053
195054
195055
195056
195057




195058
195059
195060
195061
195062
195063

195064
195065
195066
195067
195068
195069
195070
  RtreeNode *pNode,
  int iHeight
){
  int (*xSetMapping)(Rtree *, sqlite3_int64, sqlite3_int64);
  xSetMapping = ((iHeight==0)?rowidWrite:parentWrite);
  if( iHeight>0 ){
    RtreeNode *pChild = nodeHashLookup(pRtree, iRowid);




    if( pChild ){
      nodeRelease(pRtree, pChild->pParent);
      nodeReference(pNode);
      pChild->pParent = pNode;
    }
  }

  return xSetMapping(pRtree, iRowid, pNode->iNode);
}

static int SplitNode(
  Rtree *pRtree,
  RtreeNode *pNode,
  RtreeCell *pCell,







>
>
>
>






>







195608
195609
195610
195611
195612
195613
195614
195615
195616
195617
195618
195619
195620
195621
195622
195623
195624
195625
195626
195627
195628
195629
195630
195631
195632
  RtreeNode *pNode,
  int iHeight
){
  int (*xSetMapping)(Rtree *, sqlite3_int64, sqlite3_int64);
  xSetMapping = ((iHeight==0)?rowidWrite:parentWrite);
  if( iHeight>0 ){
    RtreeNode *pChild = nodeHashLookup(pRtree, iRowid);
    RtreeNode *p;
    for(p=pNode; p; p=p->pParent){
      if( p==pChild ) return SQLITE_CORRUPT_VTAB;
    }
    if( pChild ){
      nodeRelease(pRtree, pChild->pParent);
      nodeReference(pNode);
      pChild->pParent = pNode;
    }
  }
  if( NEVER(pNode==0) ) return SQLITE_ERROR;
  return xSetMapping(pRtree, iRowid, pNode->iNode);
}

static int SplitNode(
  Rtree *pRtree,
  RtreeNode *pNode,
  RtreeCell *pCell,
195146
195147
195148
195149
195150
195151
195152
195153
195154
195155

195156
195157
195158
195159
195160
195161
195162
195163
195164
    if( rc!=SQLITE_OK ){
      goto splitnode_out;
    }
  }else{
    RtreeNode *pParent = pLeft->pParent;
    int iCell;
    rc = nodeParentIndex(pRtree, pLeft, &iCell);
    if( rc==SQLITE_OK ){
      nodeOverwriteCell(pRtree, pParent, &leftbbox, iCell);
      rc = AdjustTree(pRtree, pParent, &leftbbox);

    }
    if( rc!=SQLITE_OK ){
      goto splitnode_out;
    }
  }
  if( (rc = rtreeInsertCell(pRtree, pRight->pParent, &rightbbox, iHeight+1)) ){
    goto splitnode_out;
  }








|


>

|







195708
195709
195710
195711
195712
195713
195714
195715
195716
195717
195718
195719
195720
195721
195722
195723
195724
195725
195726
195727
    if( rc!=SQLITE_OK ){
      goto splitnode_out;
    }
  }else{
    RtreeNode *pParent = pLeft->pParent;
    int iCell;
    rc = nodeParentIndex(pRtree, pLeft, &iCell);
    if( ALWAYS(rc==SQLITE_OK) ){
      nodeOverwriteCell(pRtree, pParent, &leftbbox, iCell);
      rc = AdjustTree(pRtree, pParent, &leftbbox);
      assert( rc==SQLITE_OK );
    }
    if( NEVER(rc!=SQLITE_OK) ){
      goto splitnode_out;
    }
  }
  if( (rc = rtreeInsertCell(pRtree, pRight->pParent, &rightbbox, iHeight+1)) ){
    goto splitnode_out;
  }

195225
195226
195227
195228
195229
195230
195231
195232
195233
195234
195235
195236
195237
195238
195239
      /* Before setting pChild->pParent, test that we are not creating a
      ** loop of references (as we would if, say, pChild==pParent). We don't
      ** want to do this as it leads to a memory leak when trying to delete
      ** the referenced counted node structures.
      */
      iNode = sqlite3_column_int64(pRtree->pReadParent, 0);
      for(pTest=pLeaf; pTest && pTest->iNode!=iNode; pTest=pTest->pParent);
      if( !pTest ){
        rc2 = nodeAcquire(pRtree, iNode, 0, &pChild->pParent);
      }
    }
    rc = sqlite3_reset(pRtree->pReadParent);
    if( rc==SQLITE_OK ) rc = rc2;
    if( rc==SQLITE_OK && !pChild->pParent ){
      RTREE_IS_CORRUPT(pRtree);







|







195788
195789
195790
195791
195792
195793
195794
195795
195796
195797
195798
195799
195800
195801
195802
      /* Before setting pChild->pParent, test that we are not creating a
      ** loop of references (as we would if, say, pChild==pParent). We don't
      ** want to do this as it leads to a memory leak when trying to delete
      ** the referenced counted node structures.
      */
      iNode = sqlite3_column_int64(pRtree->pReadParent, 0);
      for(pTest=pLeaf; pTest && pTest->iNode!=iNode; pTest=pTest->pParent);
      if( pTest==0 ){
        rc2 = nodeAcquire(pRtree, iNode, 0, &pChild->pParent);
      }
    }
    rc = sqlite3_reset(pRtree->pReadParent);
    if( rc==SQLITE_OK ) rc = rc2;
    if( rc==SQLITE_OK && !pChild->pParent ){
      RTREE_IS_CORRUPT(pRtree);
195256
195257
195258
195259
195260
195261
195262

195263
195264
195265
195266
195267
195268
195269

  /* Remove the entry in the parent cell. */
  rc = nodeParentIndex(pRtree, pNode, &iCell);
  if( rc==SQLITE_OK ){
    pParent = pNode->pParent;
    pNode->pParent = 0;
    rc = deleteCell(pRtree, pParent, iCell, iHeight+1);

  }
  rc2 = nodeRelease(pRtree, pParent);
  if( rc==SQLITE_OK ){
    rc = rc2;
  }
  if( rc!=SQLITE_OK ){
    return rc;







>







195819
195820
195821
195822
195823
195824
195825
195826
195827
195828
195829
195830
195831
195832
195833

  /* Remove the entry in the parent cell. */
  rc = nodeParentIndex(pRtree, pNode, &iCell);
  if( rc==SQLITE_OK ){
    pParent = pNode->pParent;
    pNode->pParent = 0;
    rc = deleteCell(pRtree, pParent, iCell, iHeight+1);
    testcase( rc!=SQLITE_OK );
  }
  rc2 = nodeRelease(pRtree, pParent);
  if( rc==SQLITE_OK ){
    rc = rc2;
  }
  if( rc!=SQLITE_OK ){
    return rc;
195478
195479
195480
195481
195482
195483
195484
195485
195486
195487
195488
195489
195490
195491
195492
      rc = SplitNode(pRtree, pNode, pCell, iHeight);
    }else{
      pRtree->iReinsertHeight = iHeight;
      rc = Reinsert(pRtree, pNode, pCell, iHeight);
    }
  }else{
    rc = AdjustTree(pRtree, pNode, pCell);
    if( rc==SQLITE_OK ){
      if( iHeight==0 ){
        rc = rowidWrite(pRtree, pCell->iRowid, pNode->iNode);
      }else{
        rc = parentWrite(pRtree, pCell->iRowid, pNode->iNode);
      }
    }
  }







|







196042
196043
196044
196045
196046
196047
196048
196049
196050
196051
196052
196053
196054
196055
196056
      rc = SplitNode(pRtree, pNode, pCell, iHeight);
    }else{
      pRtree->iReinsertHeight = iHeight;
      rc = Reinsert(pRtree, pNode, pCell, iHeight);
    }
  }else{
    rc = AdjustTree(pRtree, pNode, pCell);
    if( ALWAYS(rc==SQLITE_OK) ){
      if( iHeight==0 ){
        rc = rowidWrite(pRtree, pCell->iRowid, pNode->iNode);
      }else{
        rc = parentWrite(pRtree, pCell->iRowid, pNode->iNode);
      }
    }
  }
195584
195585
195586
195587
195588
195589
195590
195591
195592
195593
195594
195595
195596
195597
195598
  ** the root node (the operation that Gutman's paper says to perform
  ** in this scenario).
  */
  if( rc==SQLITE_OK && pRtree->iDepth>0 && NCELL(pRoot)==1 ){
    int rc2;
    RtreeNode *pChild = 0;
    i64 iChild = nodeGetRowid(pRtree, pRoot, 0);
    rc = nodeAcquire(pRtree, iChild, pRoot, &pChild);
    if( rc==SQLITE_OK ){
      rc = removeNode(pRtree, pChild, pRtree->iDepth-1);
    }
    rc2 = nodeRelease(pRtree, pChild);
    if( rc==SQLITE_OK ) rc = rc2;
    if( rc==SQLITE_OK ){
      pRtree->iDepth--;







|







196148
196149
196150
196151
196152
196153
196154
196155
196156
196157
196158
196159
196160
196161
196162
  ** the root node (the operation that Gutman's paper says to perform
  ** in this scenario).
  */
  if( rc==SQLITE_OK && pRtree->iDepth>0 && NCELL(pRoot)==1 ){
    int rc2;
    RtreeNode *pChild = 0;
    i64 iChild = nodeGetRowid(pRtree, pRoot, 0);
    rc = nodeAcquire(pRtree, iChild, pRoot, &pChild);  /* tag-20210916a */
    if( rc==SQLITE_OK ){
      rc = removeNode(pRtree, pChild, pRtree->iDepth-1);
    }
    rc2 = nodeRelease(pRtree, pChild);
    if( rc==SQLITE_OK ) rc = rc2;
    if( rc==SQLITE_OK ){
      pRtree->iDepth--;
195919
195920
195921
195922
195923
195924
195925
195926
195927
195928
195929
195930
195931
195932
195933
195934
195935
195936
195937
195938
195939
195940
195941
195942
195943
195944
195945
195946
195947
195948
195949
195950
195951
195952
195953
195954
195955
195956
195957
195958
195959
195960
195961
195962
195963
** on sqlite_stat1 data. Otherwise, use RTREE_DEFAULT_ROWEST.
*/
static int rtreeQueryStat1(sqlite3 *db, Rtree *pRtree){
  const char *zFmt = "SELECT stat FROM %Q.sqlite_stat1 WHERE tbl = '%q_rowid'";
  char *zSql;
  sqlite3_stmt *p;
  int rc;
  i64 nRow = 0;

  rc = sqlite3_table_column_metadata(
      db, pRtree->zDb, "sqlite_stat1",0,0,0,0,0,0
  );
  if( rc!=SQLITE_OK ){
    pRtree->nRowEst = RTREE_DEFAULT_ROWEST;
    return rc==SQLITE_ERROR ? SQLITE_OK : rc;
  }
  zSql = sqlite3_mprintf(zFmt, pRtree->zDb, pRtree->zName);
  if( zSql==0 ){
    rc = SQLITE_NOMEM;
  }else{
    rc = sqlite3_prepare_v2(db, zSql, -1, &p, 0);
    if( rc==SQLITE_OK ){
      if( sqlite3_step(p)==SQLITE_ROW ) nRow = sqlite3_column_int64(p, 0);
      rc = sqlite3_finalize(p);
    }else if( rc!=SQLITE_NOMEM ){
      rc = SQLITE_OK;
    }

    if( rc==SQLITE_OK ){
      if( nRow==0 ){
        pRtree->nRowEst = RTREE_DEFAULT_ROWEST;
      }else{
        pRtree->nRowEst = MAX(nRow, RTREE_MIN_ROWEST);
      }
    }
    sqlite3_free(zSql);
  }

  return rc;
}


/*
** Return true if zName is the extension on one of the shadow tables used
** by this module.







|
















<
<
<
<
<
<
<
<
<
<



|







196483
196484
196485
196486
196487
196488
196489
196490
196491
196492
196493
196494
196495
196496
196497
196498
196499
196500
196501
196502
196503
196504
196505
196506










196507
196508
196509
196510
196511
196512
196513
196514
196515
196516
196517
** on sqlite_stat1 data. Otherwise, use RTREE_DEFAULT_ROWEST.
*/
static int rtreeQueryStat1(sqlite3 *db, Rtree *pRtree){
  const char *zFmt = "SELECT stat FROM %Q.sqlite_stat1 WHERE tbl = '%q_rowid'";
  char *zSql;
  sqlite3_stmt *p;
  int rc;
  i64 nRow = RTREE_MIN_ROWEST;

  rc = sqlite3_table_column_metadata(
      db, pRtree->zDb, "sqlite_stat1",0,0,0,0,0,0
  );
  if( rc!=SQLITE_OK ){
    pRtree->nRowEst = RTREE_DEFAULT_ROWEST;
    return rc==SQLITE_ERROR ? SQLITE_OK : rc;
  }
  zSql = sqlite3_mprintf(zFmt, pRtree->zDb, pRtree->zName);
  if( zSql==0 ){
    rc = SQLITE_NOMEM;
  }else{
    rc = sqlite3_prepare_v2(db, zSql, -1, &p, 0);
    if( rc==SQLITE_OK ){
      if( sqlite3_step(p)==SQLITE_ROW ) nRow = sqlite3_column_int64(p, 0);
      rc = sqlite3_finalize(p);










    }
    sqlite3_free(zSql);
  }
  pRtree->nRowEst = MAX(nRow, RTREE_MIN_ROWEST);
  return rc;
}


/*
** Return true if zName is the extension on one of the shadow tables used
** by this module.
196099
196100
196101
196102
196103
196104
196105

196106
196107
196108


196109
196110
196111
196112
196113
196114
196115
    }else{
      sqlite3_str *p = sqlite3_str_new(db);
      int ii;
      char *zSql;
      sqlite3_str_appendf(p, "UPDATE \"%w\".\"%w_rowid\"SET ", zDb, zPrefix);
      for(ii=0; ii<pRtree->nAux; ii++){
        if( ii ) sqlite3_str_append(p, ",", 1);

        if( ii<pRtree->nAuxNotNull ){
          sqlite3_str_appendf(p,"a%d=coalesce(?%d,a%d)",ii,ii+2,ii);
        }else{


          sqlite3_str_appendf(p,"a%d=?%d",ii,ii+2);
        }
      }
      sqlite3_str_appendf(p, " WHERE rowid=?1");
      zSql = sqlite3_str_finish(p);
      if( zSql==0 ){
        rc = SQLITE_NOMEM;







>


|
>
>







196653
196654
196655
196656
196657
196658
196659
196660
196661
196662
196663
196664
196665
196666
196667
196668
196669
196670
196671
196672
    }else{
      sqlite3_str *p = sqlite3_str_new(db);
      int ii;
      char *zSql;
      sqlite3_str_appendf(p, "UPDATE \"%w\".\"%w_rowid\"SET ", zDb, zPrefix);
      for(ii=0; ii<pRtree->nAux; ii++){
        if( ii ) sqlite3_str_append(p, ",", 1);
#ifdef SQLITE_ENABLE_GEOPOLY
        if( ii<pRtree->nAuxNotNull ){
          sqlite3_str_appendf(p,"a%d=coalesce(?%d,a%d)",ii,ii+2,ii);
        }else
#endif
        {
          sqlite3_str_appendf(p,"a%d=?%d",ii,ii+2);
        }
      }
      sqlite3_str_appendf(p, " WHERE rowid=?1");
      zSql = sqlite3_str_finish(p);
      if( zSql==0 ){
        rc = SQLITE_NOMEM;
196366
196367
196368
196369
196370
196371
196372

196373
196374
196375
196376
196377
196378
196379
  memset(&node, 0, sizeof(RtreeNode));
  memset(&tree, 0, sizeof(Rtree));
  tree.nDim = (u8)sqlite3_value_int(apArg[0]);
  if( tree.nDim<1 || tree.nDim>5 ) return;
  tree.nDim2 = tree.nDim*2;
  tree.nBytesPerCell = 8 + 8 * tree.nDim;
  node.zData = (u8 *)sqlite3_value_blob(apArg[1]);

  nData = sqlite3_value_bytes(apArg[1]);
  if( nData<4 ) return;
  if( nData<NCELL(&node)*tree.nBytesPerCell ) return;

  pOut = sqlite3_str_new(0);
  for(ii=0; ii<NCELL(&node); ii++){
    RtreeCell cell;







>







196923
196924
196925
196926
196927
196928
196929
196930
196931
196932
196933
196934
196935
196936
196937
  memset(&node, 0, sizeof(RtreeNode));
  memset(&tree, 0, sizeof(Rtree));
  tree.nDim = (u8)sqlite3_value_int(apArg[0]);
  if( tree.nDim<1 || tree.nDim>5 ) return;
  tree.nDim2 = tree.nDim*2;
  tree.nBytesPerCell = 8 + 8 * tree.nDim;
  node.zData = (u8 *)sqlite3_value_blob(apArg[1]);
  if( node.zData==0 ) return;
  nData = sqlite3_value_bytes(apArg[1]);
  if( nData<4 ) return;
  if( nData<NCELL(&node)*tree.nBytesPerCell ) return;

  pOut = sqlite3_str_new(0);
  for(ii=0; ii<NCELL(&node); ii++){
    RtreeCell cell;
196780
196781
196782
196783
196784
196785
196786
196787

196788

196789
196790
196791
196792
196793
196794
196795

  /* Find the number of auxiliary columns */
  if( check.rc==SQLITE_OK ){
    pStmt = rtreeCheckPrepare(&check, "SELECT * FROM %Q.'%q_rowid'", zDb, zTab);
    if( pStmt ){
      nAux = sqlite3_column_count(pStmt) - 2;
      sqlite3_finalize(pStmt);
    }

    check.rc = SQLITE_OK;

  }

  /* Find number of dimensions in the rtree table. */
  pStmt = rtreeCheckPrepare(&check, "SELECT * FROM %Q.%Q", zDb, zTab);
  if( pStmt ){
    int rc;
    check.nDim = (sqlite3_column_count(pStmt) - 1 - nAux) / 2;







|
>
|
>







197338
197339
197340
197341
197342
197343
197344
197345
197346
197347
197348
197349
197350
197351
197352
197353
197354
197355

  /* Find the number of auxiliary columns */
  if( check.rc==SQLITE_OK ){
    pStmt = rtreeCheckPrepare(&check, "SELECT * FROM %Q.'%q_rowid'", zDb, zTab);
    if( pStmt ){
      nAux = sqlite3_column_count(pStmt) - 2;
      sqlite3_finalize(pStmt);
    }else
    if( check.rc!=SQLITE_NOMEM ){
      check.rc = SQLITE_OK;
    }
  }

  /* Find number of dimensions in the rtree table. */
  pStmt = rtreeCheckPrepare(&check, "SELECT * FROM %Q.%Q", zDb, zTab);
  if( pStmt ){
    int rc;
    check.nDim = (sqlite3_column_count(pStmt) - 1 - nAux) / 2;
197195
197196
197197
197198
197199
197200
197201

197202
197203
197204
197205
197206
197207
197208
197209
197210
197211
197212
197213
197214
197215
static GeoPoly *geopolyFuncParam(
  sqlite3_context *pCtx,      /* Context for error messages */
  sqlite3_value *pVal,        /* The value to decode */
  int *pRc                    /* Write error here */
){
  GeoPoly *p = 0;
  int nByte;

  if( sqlite3_value_type(pVal)==SQLITE_BLOB
   && (nByte = sqlite3_value_bytes(pVal))>=(4+6*sizeof(GeoCoord))
  ){
    const unsigned char *a = sqlite3_value_blob(pVal);
    int nVertex;
    if( a==0 ){
      sqlite3_result_error_nomem(pCtx);
      return 0;
    }
    nVertex = (a[1]<<16) + (a[2]<<8) + a[3];
    if( (a[0]==0 || a[0]==1)
     && (nVertex*2*sizeof(GeoCoord) + 4)==(unsigned int)nByte
    ){
      p = sqlite3_malloc64( sizeof(*p) + (nVertex-1)*2*sizeof(GeoCoord) );







>






|







197755
197756
197757
197758
197759
197760
197761
197762
197763
197764
197765
197766
197767
197768
197769
197770
197771
197772
197773
197774
197775
197776
static GeoPoly *geopolyFuncParam(
  sqlite3_context *pCtx,      /* Context for error messages */
  sqlite3_value *pVal,        /* The value to decode */
  int *pRc                    /* Write error here */
){
  GeoPoly *p = 0;
  int nByte;
  testcase( pCtx==0 );
  if( sqlite3_value_type(pVal)==SQLITE_BLOB
   && (nByte = sqlite3_value_bytes(pVal))>=(4+6*sizeof(GeoCoord))
  ){
    const unsigned char *a = sqlite3_value_blob(pVal);
    int nVertex;
    if( a==0 ){
      if( pCtx ) sqlite3_result_error_nomem(pCtx);
      return 0;
    }
    nVertex = (a[1]<<16) + (a[2]<<8) + a[3];
    if( (a[0]==0 || a[0]==1)
     && (nVertex*2*sizeof(GeoCoord) + 4)==(unsigned int)nByte
    ){
      p = sqlite3_malloc64( sizeof(*p) + (nVertex-1)*2*sizeof(GeoCoord) );
198028
198029
198030
198031
198032
198033
198034
198035
198036
198037
198038
198039
198040
198041
198042
198043
198044
198045
198046
      pSeg->y = pSeg->y0;
      pSeg->pNext = pActive;
      pActive = pSeg;
      needSort = 1;
    }else{
      /* Remove a segment */
      if( pActive==pThisEvent->pSeg ){
        pActive = pActive->pNext;
      }else{
        for(pSeg=pActive; pSeg; pSeg=pSeg->pNext){
          if( pSeg->pNext==pThisEvent->pSeg ){
            pSeg->pNext = pSeg->pNext->pNext;
            break;
          }
        }
      }
    }
    pThisEvent = pThisEvent->pNext;
  }







|



|







198589
198590
198591
198592
198593
198594
198595
198596
198597
198598
198599
198600
198601
198602
198603
198604
198605
198606
198607
      pSeg->y = pSeg->y0;
      pSeg->pNext = pActive;
      pActive = pSeg;
      needSort = 1;
    }else{
      /* Remove a segment */
      if( pActive==pThisEvent->pSeg ){
        pActive = ALWAYS(pActive) ? pActive->pNext : 0;
      }else{
        for(pSeg=pActive; pSeg; pSeg=pSeg->pNext){
          if( pSeg->pNext==pThisEvent->pSeg ){
            pSeg->pNext = ALWAYS(pSeg->pNext) ? pSeg->pNext->pNext : 0;
            break;
          }
        }
      }
    }
    pThisEvent = pThisEvent->pNext;
  }
198276
198277
198278
198279
198280
198281
198282

198283
198284
198285
198286
198287
198288
198289
    ** with the configured constraints.
    */
    rc = nodeAcquire(pRtree, 1, 0, &pRoot);
    if( rc==SQLITE_OK && idxNum<=3 ){
      RtreeCoord bbox[4];
      RtreeConstraint *p;
      assert( argc==1 );

      geopolyBBox(0, argv[0], bbox, &rc);
      if( rc ){
        goto geopoly_filter_end;
      }
      pCsr->aConstraint = p = sqlite3_malloc(sizeof(RtreeConstraint)*4);
      pCsr->nConstraint = 4;
      if( p==0 ){







>







198837
198838
198839
198840
198841
198842
198843
198844
198845
198846
198847
198848
198849
198850
198851
    ** with the configured constraints.
    */
    rc = nodeAcquire(pRtree, 1, 0, &pRoot);
    if( rc==SQLITE_OK && idxNum<=3 ){
      RtreeCoord bbox[4];
      RtreeConstraint *p;
      assert( argc==1 );
      assert( argv[0]!=0 );
      geopolyBBox(0, argv[0], bbox, &rc);
      if( rc ){
        goto geopoly_filter_end;
      }
      pCsr->aConstraint = p = sqlite3_malloc(sizeof(RtreeConstraint)*4);
      pCsr->nConstraint = 4;
      if( p==0 ){
198503
198504
198505
198506
198507
198508
198509

198510
198511
198512
198513
198514
198515
198516
  cell.iRowid = newRowid;

  if( nData>1                                 /* not a DELETE */
   && (!oldRowidValid                         /* INSERT */
        || !sqlite3_value_nochange(aData[2])  /* UPDATE _shape */
        || oldRowid!=newRowid)                /* Rowid change */
  ){

    geopolyBBox(0, aData[2], cell.aCoord, &rc);
    if( rc ){
      if( rc==SQLITE_ERROR ){
        pVtab->zErrMsg =
          sqlite3_mprintf("_shape does not contain a valid polygon");
      }
      goto geopoly_update_end;







>







199065
199066
199067
199068
199069
199070
199071
199072
199073
199074
199075
199076
199077
199078
199079
  cell.iRowid = newRowid;

  if( nData>1                                 /* not a DELETE */
   && (!oldRowidValid                         /* INSERT */
        || !sqlite3_value_nochange(aData[2])  /* UPDATE _shape */
        || oldRowid!=newRowid)                /* Rowid change */
  ){
    assert( aData[2]!=0 );
    geopolyBBox(0, aData[2], cell.aCoord, &rc);
    if( rc ){
      if( rc==SQLITE_ERROR ){
        pVtab->zErrMsg =
          sqlite3_mprintf("_shape does not contain a valid polygon");
      }
      goto geopoly_update_end;
198856
198857
198858
198859
198860
198861
198862
198863



198864
198865
198866
198867
198868
198869
198870
  void *pContext,              /* Extra data passed into the callback */
  void (*xDestructor)(void*)   /* Destructor for the extra data */
){
  RtreeGeomCallback *pGeomCtx;      /* Context object for new user-function */

  /* Allocate and populate the context object. */
  pGeomCtx = (RtreeGeomCallback *)sqlite3_malloc(sizeof(RtreeGeomCallback));
  if( !pGeomCtx ) return SQLITE_NOMEM;



  pGeomCtx->xGeom = 0;
  pGeomCtx->xQueryFunc = xQueryFunc;
  pGeomCtx->xDestructor = xDestructor;
  pGeomCtx->pContext = pContext;
  return sqlite3_create_function_v2(db, zQueryFunc, -1, SQLITE_ANY,
      (void *)pGeomCtx, geomCallback, 0, 0, rtreeFreeCallback
  );







|
>
>
>







199419
199420
199421
199422
199423
199424
199425
199426
199427
199428
199429
199430
199431
199432
199433
199434
199435
199436
  void *pContext,              /* Extra data passed into the callback */
  void (*xDestructor)(void*)   /* Destructor for the extra data */
){
  RtreeGeomCallback *pGeomCtx;      /* Context object for new user-function */

  /* Allocate and populate the context object. */
  pGeomCtx = (RtreeGeomCallback *)sqlite3_malloc(sizeof(RtreeGeomCallback));
  if( !pGeomCtx ){
    if( xDestructor ) xDestructor(pContext);
    return SQLITE_NOMEM;
  }
  pGeomCtx->xGeom = 0;
  pGeomCtx->xQueryFunc = xQueryFunc;
  pGeomCtx->xDestructor = xDestructor;
  pGeomCtx->pContext = pContext;
  return sqlite3_create_function_v2(db, zQueryFunc, -1, SQLITE_ANY,
      (void *)pGeomCtx, geomCallback, 0, 0, rtreeFreeCallback
  );
205641
205642
205643
205644
205645
205646
205647









205648
205649
205650
205651
205652
205653
205654
** official SQLite documentation.
*/

/* #include "sqliteInt.h"   ** Requires access to internal data structures ** */
#if (defined(SQLITE_ENABLE_DBSTAT_VTAB) || defined(SQLITE_TEST)) \
    && !defined(SQLITE_OMIT_VIRTUALTABLE)










/*
** Page paths:
**
**   The value of the 'path' column describes the path taken from the
**   root-node of the b-tree structure to each page. The value of the
**   root-node path is '/'.
**







>
>
>
>
>
>
>
>
>







206207
206208
206209
206210
206211
206212
206213
206214
206215
206216
206217
206218
206219
206220
206221
206222
206223
206224
206225
206226
206227
206228
206229
** official SQLite documentation.
*/

/* #include "sqliteInt.h"   ** Requires access to internal data structures ** */
#if (defined(SQLITE_ENABLE_DBSTAT_VTAB) || defined(SQLITE_TEST)) \
    && !defined(SQLITE_OMIT_VIRTUALTABLE)

/*
** The pager and btree modules arrange objects in memory so that there are
** always approximately 200 bytes of addressable memory following each page
** buffer. This way small buffer overreads caused by corrupt database pages
** do not cause undefined behaviour. This module pads each page buffer
** by the following number of bytes for the same purpose.
*/
#define DBSTAT_PAGE_PADDING_BYTES 256

/*
** Page paths:
**
**   The value of the 'path' column describes the path taken from the
**   root-node of the b-tree structure to each page. The value of the
**   root-node path is '/'.
**
205708
205709
205710
205711
205712
205713
205714
205715
205716
205717
205718
205719
205720
205721
205722
205723
205724
  int nLastOvfl;                  /* Bytes of payload on final overflow page */
  int iOvfl;                      /* Iterates through aOvfl[] */
};

/* Size information for a single btree page */
struct StatPage {
  u32 iPgno;                      /* Page number */
  DbPage *pPg;                    /* Page content */
  int iCell;                      /* Current cell */

  char *zPath;                    /* Path to this page */

  /* Variables populated by statDecodePage(): */
  u8 flags;                       /* Copy of flags byte */
  int nCell;                      /* Number of cells on page */
  int nUnused;                    /* Number of unused bytes on page */
  StatCell *aCell;                /* Array of parsed cells */







|

<







206283
206284
206285
206286
206287
206288
206289
206290
206291

206292
206293
206294
206295
206296
206297
206298
  int nLastOvfl;                  /* Bytes of payload on final overflow page */
  int iOvfl;                      /* Iterates through aOvfl[] */
};

/* Size information for a single btree page */
struct StatPage {
  u32 iPgno;                      /* Page number */
  u8 *aPg;                        /* Page buffer from sqlite3_malloc() */
  int iCell;                      /* Current cell */

  char *zPath;                    /* Path to this page */

  /* Variables populated by statDecodePage(): */
  u8 flags;                       /* Copy of flags byte */
  int nCell;                      /* Number of cells on page */
  int nUnused;                    /* Number of unused bytes on page */
  StatCell *aCell;                /* Array of parsed cells */
205922
205923
205924
205925
205926
205927
205928

205929
205930
205931
205932

205933
205934
205935
205936

205937


205938
205939


205940

205941
205942
205943
205944
205945
205946
205947
    sqlite3_free(p->aCell);
  }
  p->nCell = 0;
  p->aCell = 0;
}

static void statClearPage(StatPage *p){

  statClearCells(p);
  sqlite3PagerUnref(p->pPg);
  sqlite3_free(p->zPath);
  memset(p, 0, sizeof(StatPage));

}

static void statResetCsr(StatCursor *pCsr){
  int i;

  sqlite3_reset(pCsr->pStmt);


  for(i=0; i<ArraySize(pCsr->aPage); i++){
    statClearPage(&pCsr->aPage[i]);


  }

  pCsr->iPage = 0;
  sqlite3_free(pCsr->zPath);
  pCsr->zPath = 0;
  pCsr->isEof = 0;
}

/* Resize the space-used counters inside of the cursor */







>

<


>




>
|
>
>


>
>

>







206496
206497
206498
206499
206500
206501
206502
206503
206504

206505
206506
206507
206508
206509
206510
206511
206512
206513
206514
206515
206516
206517
206518
206519
206520
206521
206522
206523
206524
206525
206526
206527
206528
    sqlite3_free(p->aCell);
  }
  p->nCell = 0;
  p->aCell = 0;
}

static void statClearPage(StatPage *p){
  u8 *aPg = p->aPg;
  statClearCells(p);

  sqlite3_free(p->zPath);
  memset(p, 0, sizeof(StatPage));
  p->aPg = aPg;
}

static void statResetCsr(StatCursor *pCsr){
  int i;
  /* In some circumstances, specifically if an OOM has occurred, the call
  ** to sqlite3_reset() may cause the pager to be reset (emptied). It is
  ** important that statClearPage() is called to free any page refs before
  ** this happens. dbsqlfuzz 9ed3e4e3816219d3509d711636c38542bf3f40b1. */
  for(i=0; i<ArraySize(pCsr->aPage); i++){
    statClearPage(&pCsr->aPage[i]);
    sqlite3_free(pCsr->aPage[i].aPg);
    pCsr->aPage[i].aPg = 0;
  }
  sqlite3_reset(pCsr->pStmt);
  pCsr->iPage = 0;
  sqlite3_free(pCsr->zPath);
  pCsr->zPath = 0;
  pCsr->isEof = 0;
}

/* Resize the space-used counters inside of the cursor */
205998
205999
206000
206001
206002
206003
206004
206005
206006
206007
206008
206009
206010
206011
206012
static int statDecodePage(Btree *pBt, StatPage *p){
  int nUnused;
  int iOff;
  int nHdr;
  int isLeaf;
  int szPage;

  u8 *aData = sqlite3PagerGetData(p->pPg);
  u8 *aHdr = &aData[p->iPgno==1 ? 100 : 0];

  p->flags = aHdr[0];
  if( p->flags==0x0A || p->flags==0x0D ){
    isLeaf = 1;
    nHdr = 8;
  }else if( p->flags==0x05 || p->flags==0x02 ){







|







206579
206580
206581
206582
206583
206584
206585
206586
206587
206588
206589
206590
206591
206592
206593
static int statDecodePage(Btree *pBt, StatPage *p){
  int nUnused;
  int iOff;
  int nHdr;
  int isLeaf;
  int szPage;

  u8 *aData = p->aPg;
  u8 *aHdr = &aData[p->iPgno==1 ? 100 : 0];

  p->flags = aHdr[0];
  if( p->flags==0x0A || p->flags==0x0D ){
    isLeaf = 1;
    nHdr = 8;
  }else if( p->flags==0x05 || p->flags==0x02 ){
206069
206070
206071
206072
206073
206074
206075
206076
206077
206078
206079
206080
206081
206082
206083
        if( nLocal<0 ) goto statPageIsCorrupt;
        pCell->nLocal = nLocal;
        assert( nPayload>=(u32)nLocal );
        assert( nLocal<=(nUsable-35) );
        if( nPayload>(u32)nLocal ){
          int j;
          int nOvfl = ((nPayload - nLocal) + nUsable-4 - 1) / (nUsable - 4);
          if( iOff+nLocal>nUsable || nPayload>0x7fffffff ){
            goto statPageIsCorrupt;
          }
          pCell->nLastOvfl = (nPayload-nLocal) - (nOvfl-1) * (nUsable-4);
          pCell->nOvfl = nOvfl;
          pCell->aOvfl = sqlite3_malloc64(sizeof(u32)*nOvfl);
          if( pCell->aOvfl==0 ) return SQLITE_NOMEM_BKPT;
          pCell->aOvfl[0] = sqlite3Get4byte(&aData[iOff+nLocal]);







|







206650
206651
206652
206653
206654
206655
206656
206657
206658
206659
206660
206661
206662
206663
206664
        if( nLocal<0 ) goto statPageIsCorrupt;
        pCell->nLocal = nLocal;
        assert( nPayload>=(u32)nLocal );
        assert( nLocal<=(nUsable-35) );
        if( nPayload>(u32)nLocal ){
          int j;
          int nOvfl = ((nPayload - nLocal) + nUsable-4 - 1) / (nUsable - 4);
          if( iOff+nLocal+4>nUsable || nPayload>0x7fffffff ){
            goto statPageIsCorrupt;
          }
          pCell->nLastOvfl = (nPayload-nLocal) - (nOvfl-1) * (nUsable-4);
          pCell->nOvfl = nOvfl;
          pCell->aOvfl = sqlite3_malloc64(sizeof(u32)*nOvfl);
          if( pCell->aOvfl==0 ) return SQLITE_NOMEM_BKPT;
          pCell->aOvfl[0] = sqlite3Get4byte(&aData[iOff+nLocal]);
206127
206128
206129
206130
206131
206132
206133
































206134
206135
206136
206137
206138
206139
206140
206141
206142
206143
206144
206145
206146
206147
206148
206149
206150
206151
206152
206153
206154
206155
206156
206157
206158
206159
206160
206161
206162
206163
206164
206165
206166
206167
206168
206169
206170
206171
206172
    pCsr->szPage += x[1];
  }else{
    /* Not ZIPVFS: The default page size and offset */
    pCsr->szPage += sqlite3BtreeGetPageSize(pBt);
    pCsr->iOffset = (i64)pCsr->szPage * (pCsr->iPageno - 1);
  }
}

































/*
** Move a DBSTAT cursor to the next entry.  Normally, the next
** entry will be the next page, but in aggregated mode (pCsr->isAgg!=0),
** the next entry is the next btree.
*/
static int statNext(sqlite3_vtab_cursor *pCursor){
  int rc;
  int nPayload;
  char *z;
  StatCursor *pCsr = (StatCursor *)pCursor;
  StatTable *pTab = (StatTable *)pCursor->pVtab;
  Btree *pBt = pTab->db->aDb[pCsr->iDb].pBt;
  Pager *pPager = sqlite3BtreePager(pBt);

  sqlite3_free(pCsr->zPath);
  pCsr->zPath = 0;

statNextRestart:
  if( pCsr->aPage[0].pPg==0 ){
    /* Start measuring space on the next btree */
    statResetCounts(pCsr);
    rc = sqlite3_step(pCsr->pStmt);
    if( rc==SQLITE_ROW ){
      int nPage;
      u32 iRoot = (u32)sqlite3_column_int64(pCsr->pStmt, 1);
      sqlite3PagerPagecount(pPager, &nPage);
      if( nPage==0 ){
        pCsr->isEof = 1;
        return sqlite3_reset(pCsr->pStmt);
      }
      rc = sqlite3PagerGet(pPager, iRoot, &pCsr->aPage[0].pPg, 0);
      pCsr->aPage[0].iPgno = iRoot;
      pCsr->aPage[0].iCell = 0;
      if( !pCsr->isAgg ){
        pCsr->aPage[0].zPath = z = sqlite3_mprintf("/");
        if( z==0 ) rc = SQLITE_NOMEM_BKPT;
      }
      pCsr->iPage = 0;







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



















|











|







206708
206709
206710
206711
206712
206713
206714
206715
206716
206717
206718
206719
206720
206721
206722
206723
206724
206725
206726
206727
206728
206729
206730
206731
206732
206733
206734
206735
206736
206737
206738
206739
206740
206741
206742
206743
206744
206745
206746
206747
206748
206749
206750
206751
206752
206753
206754
206755
206756
206757
206758
206759
206760
206761
206762
206763
206764
206765
206766
206767
206768
206769
206770
206771
206772
206773
206774
206775
206776
206777
206778
206779
206780
206781
206782
206783
206784
206785
    pCsr->szPage += x[1];
  }else{
    /* Not ZIPVFS: The default page size and offset */
    pCsr->szPage += sqlite3BtreeGetPageSize(pBt);
    pCsr->iOffset = (i64)pCsr->szPage * (pCsr->iPageno - 1);
  }
}

/*
** Load a copy of the page data for page iPg into the buffer belonging
** to page object pPg. Allocate the buffer if necessary. Return SQLITE_OK
** if successful, or an SQLite error code otherwise.
*/
static int statGetPage(
  Btree *pBt,                     /* Load page from this b-tree */
  u32 iPg,                        /* Page number to load */
  StatPage *pPg                   /* Load page into this object */
){
  int pgsz = sqlite3BtreeGetPageSize(pBt);
  DbPage *pDbPage = 0;
  int rc;

  if( pPg->aPg==0 ){
    pPg->aPg = (u8*)sqlite3_malloc(pgsz + DBSTAT_PAGE_PADDING_BYTES);
    if( pPg->aPg==0 ){
      return SQLITE_NOMEM_BKPT;
    }
    memset(&pPg->aPg[pgsz], 0, DBSTAT_PAGE_PADDING_BYTES);
  }

  rc = sqlite3PagerGet(sqlite3BtreePager(pBt), iPg, &pDbPage, 0);
  if( rc==SQLITE_OK ){
    const u8 *a = sqlite3PagerGetData(pDbPage);
    memcpy(pPg->aPg, a, pgsz);
    sqlite3PagerUnref(pDbPage);
  }

  return rc;
}

/*
** Move a DBSTAT cursor to the next entry.  Normally, the next
** entry will be the next page, but in aggregated mode (pCsr->isAgg!=0),
** the next entry is the next btree.
*/
static int statNext(sqlite3_vtab_cursor *pCursor){
  int rc;
  int nPayload;
  char *z;
  StatCursor *pCsr = (StatCursor *)pCursor;
  StatTable *pTab = (StatTable *)pCursor->pVtab;
  Btree *pBt = pTab->db->aDb[pCsr->iDb].pBt;
  Pager *pPager = sqlite3BtreePager(pBt);

  sqlite3_free(pCsr->zPath);
  pCsr->zPath = 0;

statNextRestart:
  if( pCsr->iPage<0 ){
    /* Start measuring space on the next btree */
    statResetCounts(pCsr);
    rc = sqlite3_step(pCsr->pStmt);
    if( rc==SQLITE_ROW ){
      int nPage;
      u32 iRoot = (u32)sqlite3_column_int64(pCsr->pStmt, 1);
      sqlite3PagerPagecount(pPager, &nPage);
      if( nPage==0 ){
        pCsr->isEof = 1;
        return sqlite3_reset(pCsr->pStmt);
      }
      rc = statGetPage(pBt, iRoot, &pCsr->aPage[0]);
      pCsr->aPage[0].iPgno = iRoot;
      pCsr->aPage[0].iCell = 0;
      if( !pCsr->isAgg ){
        pCsr->aPage[0].zPath = z = sqlite3_mprintf("/");
        if( z==0 ) rc = SQLITE_NOMEM_BKPT;
      }
      pCsr->iPage = 0;
206209
206210
206211
206212
206213
206214
206215
206216
206217
206218
206219
206220
206221
206222
206223
206224
206225
206226
206227
206228
206229
206230
206231
206232
206233
206234
206235
206236
206237
206238
206239
206240
206241
206242
206243
206244
      }
      if( p->iRightChildPg ) break;
      p->iCell++;
    }

    if( !p->iRightChildPg || p->iCell>p->nCell ){
      statClearPage(p);
      if( pCsr->iPage>0 ){
        pCsr->iPage--;
      }else if( pCsr->isAgg ){
        /* label-statNext-done:  When computing aggregate space usage over
        ** an entire btree, this is the exit point from this function */
        return SQLITE_OK;
      }
      goto statNextRestart; /* Tail recursion */
    }
    pCsr->iPage++;
    if( pCsr->iPage>=ArraySize(pCsr->aPage) ){
      statResetCsr(pCsr);
      return SQLITE_CORRUPT_BKPT;
    }
    assert( p==&pCsr->aPage[pCsr->iPage-1] );

    if( p->iCell==p->nCell ){
      p[1].iPgno = p->iRightChildPg;
    }else{
      p[1].iPgno = p->aCell[p->iCell].iChildPg;
    }
    rc = sqlite3PagerGet(pPager, p[1].iPgno, &p[1].pPg, 0);
    pCsr->nPage++;
    p[1].iCell = 0;
    if( !pCsr->isAgg ){
      p[1].zPath = z = sqlite3_mprintf("%s%.3x/", p->zPath, p->iCell);
      if( z==0 ) rc = SQLITE_NOMEM_BKPT;
    }
    p->iCell++;







<
|
|


















|







206822
206823
206824
206825
206826
206827
206828

206829
206830
206831
206832
206833
206834
206835
206836
206837
206838
206839
206840
206841
206842
206843
206844
206845
206846
206847
206848
206849
206850
206851
206852
206853
206854
206855
206856
      }
      if( p->iRightChildPg ) break;
      p->iCell++;
    }

    if( !p->iRightChildPg || p->iCell>p->nCell ){
      statClearPage(p);

      pCsr->iPage--;
      if( pCsr->isAgg && pCsr->iPage<0 ){
        /* label-statNext-done:  When computing aggregate space usage over
        ** an entire btree, this is the exit point from this function */
        return SQLITE_OK;
      }
      goto statNextRestart; /* Tail recursion */
    }
    pCsr->iPage++;
    if( pCsr->iPage>=ArraySize(pCsr->aPage) ){
      statResetCsr(pCsr);
      return SQLITE_CORRUPT_BKPT;
    }
    assert( p==&pCsr->aPage[pCsr->iPage-1] );

    if( p->iCell==p->nCell ){
      p[1].iPgno = p->iRightChildPg;
    }else{
      p[1].iPgno = p->aCell[p->iCell].iChildPg;
    }
    rc = statGetPage(pBt, p[1].iPgno, &p[1]);
    pCsr->nPage++;
    p[1].iCell = 0;
    if( !pCsr->isAgg ){
      p[1].zPath = z = sqlite3_mprintf("%s%.3x/", p->zPath, p->iCell);
      if( z==0 ) rc = SQLITE_NOMEM_BKPT;
    }
    p->iCell++;
206360
206361
206362
206363
206364
206365
206366

206367
206368
206369
206370
206371
206372
206373
    return SQLITE_NOMEM_BKPT;
  }else{
    rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pCsr->pStmt, 0);
    sqlite3_free(zSql);
  }

  if( rc==SQLITE_OK ){

    rc = statNext(pCursor);
  }
  return rc;
}

static int statColumn(
  sqlite3_vtab_cursor *pCursor,







>







206972
206973
206974
206975
206976
206977
206978
206979
206980
206981
206982
206983
206984
206985
206986
    return SQLITE_NOMEM_BKPT;
  }else{
    rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pCsr->pStmt, 0);
    sqlite3_free(zSql);
  }

  if( rc==SQLITE_OK ){
    pCsr->iPage = -1;
    rc = statNext(pCursor);
  }
  return rc;
}

static int statColumn(
  sqlite3_vtab_cursor *pCursor,
207311
207312
207313
207314
207315
207316
207317
207318
207319
207320
207321
207322
207323
207324
207325
        }
        n = sqlite3_value_bytes(pValue);
        if( z==0 && (eType!=SQLITE_BLOB || n>0) ) return SQLITE_NOMEM;
        nVarint = sessionVarintLen(n);

        if( aBuf ){
          sessionVarintPut(&aBuf[1], n);
          if( n ) memcpy(&aBuf[nVarint + 1], z, n);
        }

        nByte = 1 + nVarint + n;
        break;
      }
    }
  }else{







|







207924
207925
207926
207927
207928
207929
207930
207931
207932
207933
207934
207935
207936
207937
207938
        }
        n = sqlite3_value_bytes(pValue);
        if( z==0 && (eType!=SQLITE_BLOB || n>0) ) return SQLITE_NOMEM;
        nVarint = sessionVarintLen(n);

        if( aBuf ){
          sessionVarintPut(&aBuf[1], n);
          if( n>0 ) memcpy(&aBuf[nVarint + 1], z, n);
        }

        nByte = 1 + nVarint + n;
        break;
      }
    }
  }else{
207916
207917
207918
207919
207920
207921
207922




207923
207924
207925
207926
207927
207928






207929
207930
207931
207932






207933
207934
207935
207936
207937
207938
207939
          "SELECT 0, 'tbl',  '', 0, '', 1     UNION ALL "
          "SELECT 1, 'idx',  '', 0, '', 2     UNION ALL "
          "SELECT 2, 'stat', '', 0, '', 0"
      );
    }else if( rc==SQLITE_ERROR ){
      zPragma = sqlite3_mprintf("");
    }else{




      return rc;
    }
  }else{
    zPragma = sqlite3_mprintf("PRAGMA '%q'.table_info('%q')", zDb, zThis);
  }
  if( !zPragma ) return SQLITE_NOMEM;







  rc = sqlite3_prepare_v2(db, zPragma, -1, &pStmt, 0);
  sqlite3_free(zPragma);
  if( rc!=SQLITE_OK ) return rc;







  nByte = nThis + 1;
  while( SQLITE_ROW==sqlite3_step(pStmt) ){
    nByte += sqlite3_column_bytes(pStmt, 1);
    nDbCol++;
  }
  rc = sqlite3_reset(pStmt);







>
>
>
>





|
>
>
>
>
>
>



|
>
>
>
>
>
>







208529
208530
208531
208532
208533
208534
208535
208536
208537
208538
208539
208540
208541
208542
208543
208544
208545
208546
208547
208548
208549
208550
208551
208552
208553
208554
208555
208556
208557
208558
208559
208560
208561
208562
208563
208564
208565
208566
208567
208568
          "SELECT 0, 'tbl',  '', 0, '', 1     UNION ALL "
          "SELECT 1, 'idx',  '', 0, '', 2     UNION ALL "
          "SELECT 2, 'stat', '', 0, '', 0"
      );
    }else if( rc==SQLITE_ERROR ){
      zPragma = sqlite3_mprintf("");
    }else{
      *pazCol = 0;
      *pabPK = 0;
      *pnCol = 0;
      if( pzTab ) *pzTab = 0;
      return rc;
    }
  }else{
    zPragma = sqlite3_mprintf("PRAGMA '%q'.table_info('%q')", zDb, zThis);
  }
  if( !zPragma ){
    *pazCol = 0;
    *pabPK = 0;
    *pnCol = 0;
    if( pzTab ) *pzTab = 0;
    return SQLITE_NOMEM;
  }

  rc = sqlite3_prepare_v2(db, zPragma, -1, &pStmt, 0);
  sqlite3_free(zPragma);
  if( rc!=SQLITE_OK ){
    *pazCol = 0;
    *pabPK = 0;
    *pnCol = 0;
    if( pzTab ) *pzTab = 0;
    return rc;
  }

  nByte = nThis + 1;
  while( SQLITE_ROW==sqlite3_step(pStmt) ){
    nByte += sqlite3_column_bytes(pStmt, 1);
    nDbCol++;
  }
  rc = sqlite3_reset(pStmt);
208343
208344
208345
208346
208347
208348
208349
208350




208351
208352
208353
208354
208355
208356
208357
    /* If there is a table-filter configured, invoke it. If it returns 0,
    ** do not automatically add the new table. */
    if( pSession->xTableFilter==0
     || pSession->xTableFilter(pSession->pFilterCtx, zName)
    ){
      rc = sqlite3session_attach(pSession, zName);
      if( rc==SQLITE_OK ){
        for(pRet=pSession->pTable; pRet->pNext; pRet=pRet->pNext);




        assert( 0==sqlite3_strnicmp(pRet->zName, zName, nName+1) );
      }
    }
  }

  assert( rc==SQLITE_OK || pRet==0 );
  *ppTab = pRet;







|
>
>
>
>







208972
208973
208974
208975
208976
208977
208978
208979
208980
208981
208982
208983
208984
208985
208986
208987
208988
208989
208990
    /* If there is a table-filter configured, invoke it. If it returns 0,
    ** do not automatically add the new table. */
    if( pSession->xTableFilter==0
     || pSession->xTableFilter(pSession->pFilterCtx, zName)
    ){
      rc = sqlite3session_attach(pSession, zName);
      if( rc==SQLITE_OK ){
        pRet = pSession->pTable;
        while( ALWAYS(pRet) && pRet->pNext ){
          pRet = pRet->pNext;
        }
        assert( pRet!=0 );
        assert( 0==sqlite3_strnicmp(pRet->zName, zName, nName+1) );
      }
    }
  }

  assert( rc==SQLITE_OK || pRet==0 );
  *ppTab = pRet;
209116
209117
209118
209119
209120
209121
209122

209123
209124
209125
209126
209127
209128
209129
  int rc = SQLITE_OK;
  SessionBuffer buf2 = {0,0,0}; /* Buffer to accumulate new.* record in */
  int bNoop = 1;                /* Set to zero if any values are modified */
  int nRewind = pBuf->nBuf;     /* Set to zero if any values are modified */
  int i;                        /* Used to iterate through columns */
  u8 *pCsr = p->aRecord;        /* Used to iterate through old.* values */


  sessionAppendByte(pBuf, SQLITE_UPDATE, &rc);
  sessionAppendByte(pBuf, p->bIndirect, &rc);
  for(i=0; i<sqlite3_column_count(pStmt); i++){
    int bChanged = 0;
    int nAdvance;
    int eType = *pCsr;
    switch( eType ){







>







209749
209750
209751
209752
209753
209754
209755
209756
209757
209758
209759
209760
209761
209762
209763
  int rc = SQLITE_OK;
  SessionBuffer buf2 = {0,0,0}; /* Buffer to accumulate new.* record in */
  int bNoop = 1;                /* Set to zero if any values are modified */
  int nRewind = pBuf->nBuf;     /* Set to zero if any values are modified */
  int i;                        /* Used to iterate through columns */
  u8 *pCsr = p->aRecord;        /* Used to iterate through old.* values */

  assert( abPK!=0 );
  sessionAppendByte(pBuf, SQLITE_UPDATE, &rc);
  sessionAppendByte(pBuf, p->bIndirect, &rc);
  for(i=0; i<sqlite3_column_count(pStmt); i++){
    int bChanged = 0;
    int nAdvance;
    int eType = *pCsr;
    switch( eType ){
209420
209421
209422
209423
209424
209425
209426
209427

209428
209429
209430
209431
209432

209433
209434
209435
209436
209437
209438
209439
209440
209441
209442
209443
209444
209445
209446
209447
209448
209449
209450
209451
209452
209453
209454
  void **ppChangeset              /* OUT: Buffer containing changeset */
){
  sqlite3 *db = pSession->db;     /* Source database handle */
  SessionTable *pTab;             /* Used to iterate through attached tables */
  SessionBuffer buf = {0,0,0};    /* Buffer in which to accumlate changeset */
  int rc;                         /* Return code */

  assert( xOutput==0 || (pnChangeset==0 && ppChangeset==0 ) );


  /* Zero the output variables in case an error occurs. If this session
  ** object is already in the error state (sqlite3_session.rc != SQLITE_OK),
  ** this call will be a no-op.  */
  if( xOutput==0 ){

    *pnChangeset = 0;
    *ppChangeset = 0;
  }

  if( pSession->rc ) return pSession->rc;
  rc = sqlite3_exec(pSession->db, "SAVEPOINT changeset", 0, 0, 0);
  if( rc!=SQLITE_OK ) return rc;

  sqlite3_mutex_enter(sqlite3_db_mutex(db));

  for(pTab=pSession->pTable; rc==SQLITE_OK && pTab; pTab=pTab->pNext){
    if( pTab->nEntry ){
      const char *zName = pTab->zName;
      int nCol;                   /* Number of columns in table */
      u8 *abPK;                   /* Primary key array */
      const char **azCol = 0;     /* Table columns */
      int i;                      /* Used to iterate through hash buckets */
      sqlite3_stmt *pSel = 0;     /* SELECT statement to query table pTab */
      int nRewind = buf.nBuf;     /* Initial size of write buffer */
      int nNoop;                  /* Size of buffer after writing tbl header */

      /* Check the table schema is still Ok. */







|
>





>













|
|







210054
210055
210056
210057
210058
210059
210060
210061
210062
210063
210064
210065
210066
210067
210068
210069
210070
210071
210072
210073
210074
210075
210076
210077
210078
210079
210080
210081
210082
210083
210084
210085
210086
210087
210088
210089
210090
  void **ppChangeset              /* OUT: Buffer containing changeset */
){
  sqlite3 *db = pSession->db;     /* Source database handle */
  SessionTable *pTab;             /* Used to iterate through attached tables */
  SessionBuffer buf = {0,0,0};    /* Buffer in which to accumlate changeset */
  int rc;                         /* Return code */

  assert( xOutput==0 || (pnChangeset==0 && ppChangeset==0) );
  assert( xOutput!=0 || (pnChangeset!=0 && ppChangeset!=0) );

  /* Zero the output variables in case an error occurs. If this session
  ** object is already in the error state (sqlite3_session.rc != SQLITE_OK),
  ** this call will be a no-op.  */
  if( xOutput==0 ){
    assert( pnChangeset!=0  && ppChangeset!=0 );
    *pnChangeset = 0;
    *ppChangeset = 0;
  }

  if( pSession->rc ) return pSession->rc;
  rc = sqlite3_exec(pSession->db, "SAVEPOINT changeset", 0, 0, 0);
  if( rc!=SQLITE_OK ) return rc;

  sqlite3_mutex_enter(sqlite3_db_mutex(db));

  for(pTab=pSession->pTable; rc==SQLITE_OK && pTab; pTab=pTab->pNext){
    if( pTab->nEntry ){
      const char *zName = pTab->zName;
      int nCol = 0;               /* Number of columns in table */
      u8 *abPK = 0;               /* Primary key array */
      const char **azCol = 0;     /* Table columns */
      int i;                      /* Used to iterate through hash buckets */
      sqlite3_stmt *pSel = 0;     /* SELECT statement to query table pTab */
      int nRewind = buf.nBuf;     /* Initial size of write buffer */
      int nNoop;                  /* Size of buffer after writing tbl header */

      /* Check the table schema is still Ok. */
209478
209479
209480
209481
209482
209483
209484

209485
209486
209487
209488
209489
209490
209491
              int iCol;
              sessionAppendByte(&buf, SQLITE_INSERT, &rc);
              sessionAppendByte(&buf, p->bIndirect, &rc);
              for(iCol=0; iCol<nCol; iCol++){
                sessionAppendCol(&buf, pSel, iCol, &rc);
              }
            }else{

              rc = sessionAppendUpdate(&buf, bPatchset, pSel, p, abPK);
            }
          }else if( p->op!=SQLITE_INSERT ){
            rc = sessionAppendDelete(&buf, bPatchset, p, nCol, abPK);
          }
          if( rc==SQLITE_OK ){
            rc = sqlite3_reset(pSel);







>







210114
210115
210116
210117
210118
210119
210120
210121
210122
210123
210124
210125
210126
210127
210128
              int iCol;
              sessionAppendByte(&buf, SQLITE_INSERT, &rc);
              sessionAppendByte(&buf, p->bIndirect, &rc);
              for(iCol=0; iCol<nCol; iCol++){
                sessionAppendCol(&buf, pSel, iCol, &rc);
              }
            }else{
              assert( abPK!=0 );  /* Because sessionSelectStmt() returned ok */
              rc = sessionAppendUpdate(&buf, bPatchset, pSel, p, abPK);
            }
          }else if( p->op!=SQLITE_INSERT ){
            rc = sessionAppendDelete(&buf, bPatchset, p, nCol, abPK);
          }
          if( rc==SQLITE_OK ){
            rc = sqlite3_reset(pSel);
209538
209539
209540
209541
209542
209543
209544



209545
209546
209547
209548
209549
209550
209551
209552
209553
209554
209555
209556
209557
209558
209559

209560
209561
209562
209563
209564
209565
209566
209567
209568
209569
209570

209571
209572
209573
209574
209575
209576
209577
209578
209579
209580
209581
209582
209583
209584
209585

209586
209587
209588
209589
209590
209591
209592
** using sqlite3_free().
*/
SQLITE_API int sqlite3session_changeset(
  sqlite3_session *pSession,      /* Session object */
  int *pnChangeset,               /* OUT: Size of buffer at *ppChangeset */
  void **ppChangeset              /* OUT: Buffer containing changeset */
){



  int rc = sessionGenerateChangeset(pSession, 0, 0, 0, pnChangeset,ppChangeset);
  assert( rc || pnChangeset==0
       || pSession->bEnableSize==0 || *pnChangeset<=pSession->nMaxChangesetSize
  );
  return rc;
}

/*
** Streaming version of sqlite3session_changeset().
*/
SQLITE_API int sqlite3session_changeset_strm(
  sqlite3_session *pSession,
  int (*xOutput)(void *pOut, const void *pData, int nData),
  void *pOut
){

  return sessionGenerateChangeset(pSession, 0, xOutput, pOut, 0, 0);
}

/*
** Streaming version of sqlite3session_patchset().
*/
SQLITE_API int sqlite3session_patchset_strm(
  sqlite3_session *pSession,
  int (*xOutput)(void *pOut, const void *pData, int nData),
  void *pOut
){

  return sessionGenerateChangeset(pSession, 1, xOutput, pOut, 0, 0);
}

/*
** Obtain a patchset object containing all changes recorded by the
** session object passed as the first argument.
**
** It is the responsibility of the caller to eventually free the buffer
** using sqlite3_free().
*/
SQLITE_API int sqlite3session_patchset(
  sqlite3_session *pSession,      /* Session object */
  int *pnPatchset,                /* OUT: Size of buffer at *ppChangeset */
  void **ppPatchset               /* OUT: Buffer containing changeset */
){

  return sessionGenerateChangeset(pSession, 1, 0, 0, pnPatchset, ppPatchset);
}

/*
** Enable or disable the session object passed as the first argument.
*/
SQLITE_API int sqlite3session_enable(sqlite3_session *pSession, int bEnable){







>
>
>
|














>











>















>







210175
210176
210177
210178
210179
210180
210181
210182
210183
210184
210185
210186
210187
210188
210189
210190
210191
210192
210193
210194
210195
210196
210197
210198
210199
210200
210201
210202
210203
210204
210205
210206
210207
210208
210209
210210
210211
210212
210213
210214
210215
210216
210217
210218
210219
210220
210221
210222
210223
210224
210225
210226
210227
210228
210229
210230
210231
210232
210233
210234
210235
** using sqlite3_free().
*/
SQLITE_API int sqlite3session_changeset(
  sqlite3_session *pSession,      /* Session object */
  int *pnChangeset,               /* OUT: Size of buffer at *ppChangeset */
  void **ppChangeset              /* OUT: Buffer containing changeset */
){
  int rc;

  if( pnChangeset==0 || ppChangeset==0 ) return SQLITE_MISUSE;
  rc = sessionGenerateChangeset(pSession, 0, 0, 0, pnChangeset,ppChangeset);
  assert( rc || pnChangeset==0
       || pSession->bEnableSize==0 || *pnChangeset<=pSession->nMaxChangesetSize
  );
  return rc;
}

/*
** Streaming version of sqlite3session_changeset().
*/
SQLITE_API int sqlite3session_changeset_strm(
  sqlite3_session *pSession,
  int (*xOutput)(void *pOut, const void *pData, int nData),
  void *pOut
){
  if( xOutput==0 ) return SQLITE_MISUSE;
  return sessionGenerateChangeset(pSession, 0, xOutput, pOut, 0, 0);
}

/*
** Streaming version of sqlite3session_patchset().
*/
SQLITE_API int sqlite3session_patchset_strm(
  sqlite3_session *pSession,
  int (*xOutput)(void *pOut, const void *pData, int nData),
  void *pOut
){
  if( xOutput==0 ) return SQLITE_MISUSE;
  return sessionGenerateChangeset(pSession, 1, xOutput, pOut, 0, 0);
}

/*
** Obtain a patchset object containing all changes recorded by the
** session object passed as the first argument.
**
** It is the responsibility of the caller to eventually free the buffer
** using sqlite3_free().
*/
SQLITE_API int sqlite3session_patchset(
  sqlite3_session *pSession,      /* Session object */
  int *pnPatchset,                /* OUT: Size of buffer at *ppChangeset */
  void **ppPatchset               /* OUT: Buffer containing changeset */
){
  if( pnPatchset==0 || ppPatchset==0 ) return SQLITE_MISUSE;
  return sessionGenerateChangeset(pSession, 1, 0, 0, pnPatchset, ppPatchset);
}

/*
** Enable or disable the session object passed as the first argument.
*/
SQLITE_API int sqlite3session_enable(sqlite3_session *pSession, int bEnable){
210542
210543
210544
210545
210546
210547
210548
210549
210550
210551
210552
210553
210554
210555
210556
210557
210558
210559
210560
      rc = xOutput(pOut, sOut.aBuf, sOut.nBuf);
      sOut.nBuf = 0;
      if( rc!=SQLITE_OK ) goto finished_invert;
    }
  }

  assert( rc==SQLITE_OK );
  if( pnInverted ){
    *pnInverted = sOut.nBuf;
    *ppInverted = sOut.aBuf;
    sOut.aBuf = 0;
  }else if( sOut.nBuf>0 ){
    rc = xOutput(pOut, sOut.aBuf, sOut.nBuf);
  }

 finished_invert:
  sqlite3_free(sOut.aBuf);
  sqlite3_free(apVal);
  sqlite3_free(sPK.aBuf);







|



|







211185
211186
211187
211188
211189
211190
211191
211192
211193
211194
211195
211196
211197
211198
211199
211200
211201
211202
211203
      rc = xOutput(pOut, sOut.aBuf, sOut.nBuf);
      sOut.nBuf = 0;
      if( rc!=SQLITE_OK ) goto finished_invert;
    }
  }

  assert( rc==SQLITE_OK );
  if( pnInverted && ALWAYS(ppInverted) ){
    *pnInverted = sOut.nBuf;
    *ppInverted = sOut.aBuf;
    sOut.aBuf = 0;
  }else if( sOut.nBuf>0 && ALWAYS(xOutput!=0) ){
    rc = xOutput(pOut, sOut.aBuf, sOut.nBuf);
  }

 finished_invert:
  sqlite3_free(sOut.aBuf);
  sqlite3_free(apVal);
  sqlite3_free(sPK.aBuf);
211002
211003
211004
211005
211006
211007
211008
211009
211010
211011
211012
211013
211014
211015
211016
  ** argument iterator points to a suitable entry. Make sure that xValue
  ** is one of these to guarantee that it is safe to ignore the return
  ** in the code below. */
  assert( xValue==sqlite3changeset_old || xValue==sqlite3changeset_new );

  for(i=0; rc==SQLITE_OK && i<nCol; i++){
    if( !abPK || abPK[i] ){
      sqlite3_value *pVal;
      (void)xValue(pIter, i, &pVal);
      if( pVal==0 ){
        /* The value in the changeset was "undefined". This indicates a
        ** corrupt changeset blob.  */
        rc = SQLITE_CORRUPT_BKPT;
      }else{
        rc = sessionBindValue(pStmt, i+1, pVal);







|







211645
211646
211647
211648
211649
211650
211651
211652
211653
211654
211655
211656
211657
211658
211659
  ** argument iterator points to a suitable entry. Make sure that xValue
  ** is one of these to guarantee that it is safe to ignore the return
  ** in the code below. */
  assert( xValue==sqlite3changeset_old || xValue==sqlite3changeset_new );

  for(i=0; rc==SQLITE_OK && i<nCol; i++){
    if( !abPK || abPK[i] ){
      sqlite3_value *pVal = 0;
      (void)xValue(pIter, i, &pVal);
      if( pVal==0 ){
        /* The value in the changeset was "undefined". This indicates a
        ** corrupt changeset blob.  */
        rc = SQLITE_CORRUPT_BKPT;
      }else{
        rc = sessionBindValue(pStmt, i+1, pVal);
212145
212146
212147
212148
212149
212150
212151
212152
212153
212154
212155
212156
212157
212158
212159
212160
212161
      }
    }
  }

  if( rc==SQLITE_OK ){
    if( xOutput ){
      if( buf.nBuf>0 ) rc = xOutput(pOut, buf.aBuf, buf.nBuf);
    }else{
      *ppOut = buf.aBuf;
      *pnOut = buf.nBuf;
      buf.aBuf = 0;
    }
  }
  sqlite3_free(buf.aBuf);

  return rc;
}







|

|







212788
212789
212790
212791
212792
212793
212794
212795
212796
212797
212798
212799
212800
212801
212802
212803
212804
      }
    }
  }

  if( rc==SQLITE_OK ){
    if( xOutput ){
      if( buf.nBuf>0 ) rc = xOutput(pOut, buf.aBuf, buf.nBuf);
    }else if( ppOut ){
      *ppOut = buf.aBuf;
      if( pnOut ) *pnOut = buf.nBuf;
      buf.aBuf = 0;
    }
  }
  sqlite3_free(buf.aBuf);

  return rc;
}
212547
212548
212549
212550
212551
212552
212553
212554
212555
212556
212557
212558
212559
212560
212561
  }

  if( rc==SQLITE_OK ){
    if( xOutput ){
      if( sOut.nBuf>0 ){
        rc = xOutput(pOut, sOut.aBuf, sOut.nBuf);
      }
    }else{
      *ppOut = (void*)sOut.aBuf;
      *pnOut = sOut.nBuf;
      sOut.aBuf = 0;
    }
  }
  sqlite3_free(sOut.aBuf);
  return rc;







|







213190
213191
213192
213193
213194
213195
213196
213197
213198
213199
213200
213201
213202
213203
213204
  }

  if( rc==SQLITE_OK ){
    if( xOutput ){
      if( sOut.nBuf>0 ){
        rc = xOutput(pOut, sOut.aBuf, sOut.nBuf);
      }
    }else if( ppOut ){
      *ppOut = (void*)sOut.aBuf;
      *pnOut = sOut.nBuf;
      sOut.aBuf = 0;
    }
  }
  sqlite3_free(sOut.aBuf);
  return rc;
213290
213291
213292
213293
213294
213295
213296





213297
213298







213299
213300
213301
213302
213303
213304
213305
typedef sqlite3_uint64 u64;

#ifndef ArraySize
# define ArraySize(x) ((int)(sizeof(x) / sizeof(x[0])))
#endif

#define testcase(x)





#define ALWAYS(x) 1
#define NEVER(x) 0








#define MIN(x,y) (((x) < (y)) ? (x) : (y))
#define MAX(x,y) (((x) > (y)) ? (x) : (y))

/*
** Constants for the largest and smallest possible 64-bit signed integers.
*/







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







213933
213934
213935
213936
213937
213938
213939
213940
213941
213942
213943
213944
213945
213946
213947
213948
213949
213950
213951
213952
213953
213954
213955
213956
213957
213958
213959
213960
typedef sqlite3_uint64 u64;

#ifndef ArraySize
# define ArraySize(x) ((int)(sizeof(x) / sizeof(x[0])))
#endif

#define testcase(x)

#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST)
# define SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS 1
#endif
#if defined(SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS)
# define ALWAYS(X)      (1)
# define NEVER(X)       (0)
#elif !defined(NDEBUG)
# define ALWAYS(X)      ((X)?1:(assert(0),0))
# define NEVER(X)       ((X)?(assert(0),1):0)
#else
# define ALWAYS(X)      (X)
# define NEVER(X)       (X)
#endif

#define MIN(x,y) (((x) < (y)) ? (x) : (y))
#define MAX(x,y) (((x) > (y)) ? (x) : (y))

/*
** Constants for the largest and smallest possible 64-bit signed integers.
*/
215508
215509
215510
215511
215512
215513
215514
215515
215516
215517
215518
215519

215520
215521
215522
215523
215524
215525
215526
215527
215528
215529
          fprintf(fts5yyTraceFILE,"%sDiscard input token %s\n",
             fts5yyTracePrompt,fts5yyTokenName[fts5yymajor]);
        }
#endif
        fts5yy_destructor(fts5yypParser, (fts5YYCODETYPE)fts5yymajor, &fts5yyminorunion);
        fts5yymajor = fts5YYNOCODE;
      }else{
        while( fts5yypParser->fts5yytos >= fts5yypParser->fts5yystack
            && (fts5yyact = fts5yy_find_reduce_action(
                        fts5yypParser->fts5yytos->stateno,
                        fts5YYERRORSYMBOL)) > fts5YY_MAX_SHIFTREDUCE
        ){

          fts5yy_pop_parser_stack(fts5yypParser);
        }
        if( fts5yypParser->fts5yytos < fts5yypParser->fts5yystack || fts5yymajor==0 ){
          fts5yy_destructor(fts5yypParser,(fts5YYCODETYPE)fts5yymajor,&fts5yyminorunion);
          fts5yy_parse_failed(fts5yypParser);
#ifndef fts5YYNOERRORRECOVERY
          fts5yypParser->fts5yyerrcnt = -1;
#endif
          fts5yymajor = fts5YYNOCODE;
        }else if( fts5yymx!=fts5YYERRORSYMBOL ){







|
|
<
|
<
>


|







216163
216164
216165
216166
216167
216168
216169
216170
216171

216172

216173
216174
216175
216176
216177
216178
216179
216180
216181
216182
216183
          fprintf(fts5yyTraceFILE,"%sDiscard input token %s\n",
             fts5yyTracePrompt,fts5yyTokenName[fts5yymajor]);
        }
#endif
        fts5yy_destructor(fts5yypParser, (fts5YYCODETYPE)fts5yymajor, &fts5yyminorunion);
        fts5yymajor = fts5YYNOCODE;
      }else{
        while( fts5yypParser->fts5yytos > fts5yypParser->fts5yystack ){
          fts5yyact = fts5yy_find_reduce_action(fts5yypParser->fts5yytos->stateno,

                                        fts5YYERRORSYMBOL);

          if( fts5yyact<=fts5YY_MAX_SHIFTREDUCE ) break;
          fts5yy_pop_parser_stack(fts5yypParser);
        }
        if( fts5yypParser->fts5yytos <= fts5yypParser->fts5yystack || fts5yymajor==0 ){
          fts5yy_destructor(fts5yypParser,(fts5YYCODETYPE)fts5yymajor,&fts5yyminorunion);
          fts5yy_parse_failed(fts5yypParser);
#ifndef fts5YYNOERRORRECOVERY
          fts5yypParser->fts5yyerrcnt = -1;
#endif
          fts5yymajor = fts5YYNOCODE;
        }else if( fts5yymx!=fts5YYERRORSYMBOL ){
217285
217286
217287
217288
217289
217290
217291

217292
217293
217294
217295
217296
217297
217298
217299
217300
217301
217302
217303
217304
217305
217306
217307
217308




217309
217310
217311
217312
217313
217314
217315
    int bOption = 0;
    int bMustBeCol = 0;

    z = fts5ConfigGobbleWord(&rc, zOrig, &zOne, &bMustBeCol);
    z = fts5ConfigSkipWhitespace(z);
    if( z && *z=='=' ){
      bOption = 1;

      z++;
      if( bMustBeCol ) z = 0;
    }
    z = fts5ConfigSkipWhitespace(z);
    if( z && z[0] ){
      int bDummy;
      z = fts5ConfigGobbleWord(&rc, z, &zTwo, &bDummy);
      if( z && z[0] ) z = 0;
    }

    if( rc==SQLITE_OK ){
      if( z==0 ){
        *pzErr = sqlite3_mprintf("parse error in \"%s\"", zOrig);
        rc = SQLITE_ERROR;
      }else{
        if( bOption ){
          rc = fts5ConfigParseSpecial(pGlobal, pRet, zOne, zTwo?zTwo:"", pzErr);




        }else{
          rc = fts5ConfigParseColumn(pRet, zOne, zTwo, pzErr);
          zOne = 0;
        }
      }
    }








>
















|
>
>
>
>







217939
217940
217941
217942
217943
217944
217945
217946
217947
217948
217949
217950
217951
217952
217953
217954
217955
217956
217957
217958
217959
217960
217961
217962
217963
217964
217965
217966
217967
217968
217969
217970
217971
217972
217973
217974
    int bOption = 0;
    int bMustBeCol = 0;

    z = fts5ConfigGobbleWord(&rc, zOrig, &zOne, &bMustBeCol);
    z = fts5ConfigSkipWhitespace(z);
    if( z && *z=='=' ){
      bOption = 1;
      assert( zOne!=0 );
      z++;
      if( bMustBeCol ) z = 0;
    }
    z = fts5ConfigSkipWhitespace(z);
    if( z && z[0] ){
      int bDummy;
      z = fts5ConfigGobbleWord(&rc, z, &zTwo, &bDummy);
      if( z && z[0] ) z = 0;
    }

    if( rc==SQLITE_OK ){
      if( z==0 ){
        *pzErr = sqlite3_mprintf("parse error in \"%s\"", zOrig);
        rc = SQLITE_ERROR;
      }else{
        if( bOption ){
          rc = fts5ConfigParseSpecial(pGlobal, pRet,
            ALWAYS(zOne)?zOne:"",
            zTwo?zTwo:"",
            pzErr
          );
        }else{
          rc = fts5ConfigParseColumn(pRet, zOne, zTwo, pzErr);
          zOne = 0;
        }
      }
    }

218118
218119
218120
218121
218122
218123
218124

218125
218126
218127
218128
218129
218130
218131
** that it points to.
*/
static i64 fts5ExprSynonymRowid(Fts5ExprTerm *pTerm, int bDesc, int *pbEof){
  i64 iRet = 0;
  int bRetValid = 0;
  Fts5ExprTerm *p;


  assert( pTerm->pSynonym );
  assert( bDesc==0 || bDesc==1 );
  for(p=pTerm; p; p=p->pSynonym){
    if( 0==sqlite3Fts5IterEof(p->pIter) ){
      i64 iRowid = p->pIter->iRowid;
      if( bRetValid==0 || (bDesc!=(iRowid<iRet)) ){
        iRet = iRowid;







>







218777
218778
218779
218780
218781
218782
218783
218784
218785
218786
218787
218788
218789
218790
218791
** that it points to.
*/
static i64 fts5ExprSynonymRowid(Fts5ExprTerm *pTerm, int bDesc, int *pbEof){
  i64 iRet = 0;
  int bRetValid = 0;
  Fts5ExprTerm *p;

  assert( pTerm );
  assert( pTerm->pSynonym );
  assert( bDesc==0 || bDesc==1 );
  for(p=pTerm; p; p=p->pSynonym){
    if( 0==sqlite3Fts5IterEof(p->pIter) ){
      i64 iRowid = p->pIter->iRowid;
      if( bRetValid==0 || (bDesc!=(iRowid<iRet)) ){
        iRet = iRowid;
219558
219559
219560
219561
219562
219563
219564
219565
219566
219567
219568
219569
219570
219571
219572
    }
  }else{
    /* This happens when parsing a token or quoted phrase that contains
    ** no token characters at all. (e.g ... MATCH '""'). */
    sCtx.pPhrase = sqlite3Fts5MallocZero(&rc, sizeof(Fts5ExprPhrase));
  }

  if( rc==SQLITE_OK ){
    /* All the allocations succeeded. Put the expression object together. */
    pNew->pIndex = pExpr->pIndex;
    pNew->pConfig = pExpr->pConfig;
    pNew->nPhrase = 1;
    pNew->apExprPhrase[0] = sCtx.pPhrase;
    pNew->pRoot->pNear->apPhrase[0] = sCtx.pPhrase;
    pNew->pRoot->pNear->nPhrase = 1;







|







220218
220219
220220
220221
220222
220223
220224
220225
220226
220227
220228
220229
220230
220231
220232
    }
  }else{
    /* This happens when parsing a token or quoted phrase that contains
    ** no token characters at all. (e.g ... MATCH '""'). */
    sCtx.pPhrase = sqlite3Fts5MallocZero(&rc, sizeof(Fts5ExprPhrase));
  }

  if( rc==SQLITE_OK && ALWAYS(sCtx.pPhrase) ){
    /* All the allocations succeeded. Put the expression object together. */
    pNew->pIndex = pExpr->pIndex;
    pNew->pConfig = pExpr->pConfig;
    pNew->nPhrase = 1;
    pNew->apExprPhrase[0] = sCtx.pPhrase;
    pNew->pRoot->pNear->apPhrase[0] = sCtx.pPhrase;
    pNew->pRoot->pNear->nPhrase = 1;
222000
222001
222002
222003
222004
222005
222006

222007
222008
222009
222010
222011
222012
222013
    p->rc = rc;
    p->nRead++;
  }

  assert( (pRet==0)==(p->rc!=SQLITE_OK) );
  return pRet;
}


/*
** Release a reference to data record returned by an earlier call to
** fts5DataRead().
*/
static void fts5DataRelease(Fts5Data *pData){
  sqlite3_free(pData);







>







222660
222661
222662
222663
222664
222665
222666
222667
222668
222669
222670
222671
222672
222673
222674
    p->rc = rc;
    p->nRead++;
  }

  assert( (pRet==0)==(p->rc!=SQLITE_OK) );
  return pRet;
}


/*
** Release a reference to data record returned by an earlier call to
** fts5DataRead().
*/
static void fts5DataRelease(Fts5Data *pData){
  sqlite3_free(pData);
222140
222141
222142
222143
222144
222145
222146




































222147
222148
222149
222150
222151
222152
222153
}
static int sqlite3Fts5StructureTest(Fts5Index *p, void *pStruct){
  if( p->pStruct!=(Fts5Structure*)pStruct ){
    return SQLITE_ABORT;
  }
  return SQLITE_OK;
}





































/*
** Deserialize and return the structure record currently stored in serialized
** form within buffer pData/nData.
**
** The Fts5Structure.aLevel[] and each Fts5StructureLevel.aSeg[] array
** are over-allocated by one slot. This allows the structure contents







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







222801
222802
222803
222804
222805
222806
222807
222808
222809
222810
222811
222812
222813
222814
222815
222816
222817
222818
222819
222820
222821
222822
222823
222824
222825
222826
222827
222828
222829
222830
222831
222832
222833
222834
222835
222836
222837
222838
222839
222840
222841
222842
222843
222844
222845
222846
222847
222848
222849
222850
}
static int sqlite3Fts5StructureTest(Fts5Index *p, void *pStruct){
  if( p->pStruct!=(Fts5Structure*)pStruct ){
    return SQLITE_ABORT;
  }
  return SQLITE_OK;
}

/*
** Ensure that structure object (*pp) is writable.
**
** This function is a no-op if (*pRc) is not SQLITE_OK when it is called. If
** an error occurs, (*pRc) is set to an SQLite error code before returning.
*/
static void fts5StructureMakeWritable(int *pRc, Fts5Structure **pp){
  Fts5Structure *p = *pp;
  if( *pRc==SQLITE_OK && p->nRef>1 ){
    int nByte = sizeof(Fts5Structure)+(p->nLevel-1)*sizeof(Fts5StructureLevel);
    Fts5Structure *pNew;
    pNew = (Fts5Structure*)sqlite3Fts5MallocZero(pRc, nByte);
    if( pNew ){
      int i;
      memcpy(pNew, p, nByte);
      for(i=0; i<p->nLevel; i++) pNew->aLevel[i].aSeg = 0;
      for(i=0; i<p->nLevel; i++){
        Fts5StructureLevel *pLvl = &pNew->aLevel[i];
        nByte = sizeof(Fts5StructureSegment) * pNew->aLevel[i].nSeg;
        pLvl->aSeg = (Fts5StructureSegment*)sqlite3Fts5MallocZero(pRc, nByte);
        if( pLvl->aSeg==0 ){
          for(i=0; i<p->nLevel; i++){
            sqlite3_free(pNew->aLevel[i].aSeg);
          }
          sqlite3_free(pNew);
          return;
        }
        memcpy(pLvl->aSeg, p->aLevel[i].aSeg, nByte);
      }
      p->nRef--;
      pNew->nRef = 1;
    }
    *pp = pNew;
  }
}

/*
** Deserialize and return the structure record currently stored in serialized
** form within buffer pData/nData.
**
** The Fts5Structure.aLevel[] and each Fts5StructureLevel.aSeg[] array
** are over-allocated by one slot. This allows the structure contents
222242
222243
222244
222245
222246
222247
222248

222249
222250
222251

222252
222253
222254
222255
222256
222257
222258
  }

  *ppOut = pRet;
  return rc;
}

/*

**
*/
static void fts5StructureAddLevel(int *pRc, Fts5Structure **ppStruct){

  if( *pRc==SQLITE_OK ){
    Fts5Structure *pStruct = *ppStruct;
    int nLevel = pStruct->nLevel;
    sqlite3_int64 nByte = (
        sizeof(Fts5Structure) +                  /* Main structure */
        sizeof(Fts5StructureLevel) * (nLevel+1)  /* aLevel[] array */
    );







>
|


>







222939
222940
222941
222942
222943
222944
222945
222946
222947
222948
222949
222950
222951
222952
222953
222954
222955
222956
222957
  }

  *ppOut = pRet;
  return rc;
}

/*
** Add a level to the Fts5Structure.aLevel[] array of structure object
** (*ppStruct).
*/
static void fts5StructureAddLevel(int *pRc, Fts5Structure **ppStruct){
  fts5StructureMakeWritable(pRc, ppStruct);
  if( *pRc==SQLITE_OK ){
    Fts5Structure *pStruct = *ppStruct;
    int nLevel = pStruct->nLevel;
    sqlite3_int64 nByte = (
        sizeof(Fts5Structure) +                  /* Main structure */
        sizeof(Fts5StructureLevel) * (nLevel+1)  /* aLevel[] array */
    );
223038
223039
223040
223041
223042
223043
223044

223045
223046
223047
223048
223049
223050
223051
    pIter->pSeg = pSeg;
    pIter->iLeafPgno = pSeg->pgnoFirst-1;
    fts5SegIterNextPage(p, pIter);
  }

  if( p->rc==SQLITE_OK ){
    pIter->iLeafOffset = 4;

    assert_nc( pIter->pLeaf->nn>4 );
    assert_nc( fts5LeafFirstTermOff(pIter->pLeaf)==4 );
    pIter->iPgidxOff = pIter->pLeaf->szLeaf+1;
    fts5SegIterLoadTerm(p, pIter, 0);
    fts5SegIterLoadNPos(p, pIter);
  }
}







>







223737
223738
223739
223740
223741
223742
223743
223744
223745
223746
223747
223748
223749
223750
223751
    pIter->pSeg = pSeg;
    pIter->iLeafPgno = pSeg->pgnoFirst-1;
    fts5SegIterNextPage(p, pIter);
  }

  if( p->rc==SQLITE_OK ){
    pIter->iLeafOffset = 4;
    assert( pIter->pLeaf!=0 );
    assert_nc( pIter->pLeaf->nn>4 );
    assert_nc( fts5LeafFirstTermOff(pIter->pLeaf)==4 );
    pIter->iPgidxOff = pIter->pLeaf->szLeaf+1;
    fts5SegIterLoadTerm(p, pIter, 0);
    fts5SegIterLoadNPos(p, pIter);
  }
}
223421
223422
223423
223424
223425
223426
223427
223428
223429
223430
223431
223432
223433
223434
223435
  Fts5DlidxIter *pDlidx = pIter->pDlidx;
  Fts5Data *pLast = 0;
  int pgnoLast = 0;

  if( pDlidx ){
    int iSegid = pIter->pSeg->iSegid;
    pgnoLast = fts5DlidxIterPgno(pDlidx);
    pLast = fts5DataRead(p, FTS5_SEGMENT_ROWID(iSegid, pgnoLast));
  }else{
    Fts5Data *pLeaf = pIter->pLeaf;         /* Current leaf data */

    /* Currently, Fts5SegIter.iLeafOffset points to the first byte of
    ** position-list content for the current rowid. Back it up so that it
    ** points to the start of the position-list size field. */
    int iPoslist;







|







224121
224122
224123
224124
224125
224126
224127
224128
224129
224130
224131
224132
224133
224134
224135
  Fts5DlidxIter *pDlidx = pIter->pDlidx;
  Fts5Data *pLast = 0;
  int pgnoLast = 0;

  if( pDlidx ){
    int iSegid = pIter->pSeg->iSegid;
    pgnoLast = fts5DlidxIterPgno(pDlidx);
    pLast = fts5LeafRead(p, FTS5_SEGMENT_ROWID(iSegid, pgnoLast));
  }else{
    Fts5Data *pLeaf = pIter->pLeaf;         /* Current leaf data */

    /* Currently, Fts5SegIter.iLeafOffset points to the first byte of
    ** position-list content for the current rowid. Back it up so that it
    ** points to the start of the position-list size field. */
    int iPoslist;
223448
223449
223450
223451
223452
223453
223454
223455
223456
223457
223458
223459
223460
223461
223462
      int pgno;
      Fts5StructureSegment *pSeg = pIter->pSeg;

      /* The last rowid in the doclist may not be on the current page. Search
      ** forward to find the page containing the last rowid.  */
      for(pgno=pIter->iLeafPgno+1; !p->rc && pgno<=pSeg->pgnoLast; pgno++){
        i64 iAbs = FTS5_SEGMENT_ROWID(pSeg->iSegid, pgno);
        Fts5Data *pNew = fts5DataRead(p, iAbs);
        if( pNew ){
          int iRowid, bTermless;
          iRowid = fts5LeafFirstRowidOff(pNew);
          bTermless = fts5LeafIsTermless(pNew);
          if( iRowid ){
            SWAPVAL(Fts5Data*, pNew, pLast);
            pgnoLast = pgno;







|







224148
224149
224150
224151
224152
224153
224154
224155
224156
224157
224158
224159
224160
224161
224162
      int pgno;
      Fts5StructureSegment *pSeg = pIter->pSeg;

      /* The last rowid in the doclist may not be on the current page. Search
      ** forward to find the page containing the last rowid.  */
      for(pgno=pIter->iLeafPgno+1; !p->rc && pgno<=pSeg->pgnoLast; pgno++){
        i64 iAbs = FTS5_SEGMENT_ROWID(pSeg->iSegid, pgno);
        Fts5Data *pNew = fts5LeafRead(p, iAbs);
        if( pNew ){
          int iRowid, bTermless;
          iRowid = fts5LeafFirstRowidOff(pNew);
          bTermless = fts5LeafIsTermless(pNew);
          if( iRowid ){
            SWAPVAL(Fts5Data*, pNew, pLast);
            pgnoLast = pgno;
223479
223480
223481
223482
223483
223484
223485




223486
223487
223488
223489
223490
223491
223492
223493
223494
223495
223496
223497
223498
223499
223500
223501
  */
  if( pLast ){
    int iOff;
    fts5DataRelease(pIter->pLeaf);
    pIter->pLeaf = pLast;
    pIter->iLeafPgno = pgnoLast;
    iOff = fts5LeafFirstRowidOff(pLast);




    iOff += fts5GetVarint(&pLast->p[iOff], (u64*)&pIter->iRowid);
    pIter->iLeafOffset = iOff;

    if( fts5LeafIsTermless(pLast) ){
      pIter->iEndofDoclist = pLast->nn+1;
    }else{
      pIter->iEndofDoclist = fts5LeafFirstTermOff(pLast);
    }

  }

  fts5SegIterReverseInitPage(p, pIter);
}

/*
** Iterator pIter currently points to the first rowid of a doclist.







>
>
>
>








<







224179
224180
224181
224182
224183
224184
224185
224186
224187
224188
224189
224190
224191
224192
224193
224194
224195
224196
224197

224198
224199
224200
224201
224202
224203
224204
  */
  if( pLast ){
    int iOff;
    fts5DataRelease(pIter->pLeaf);
    pIter->pLeaf = pLast;
    pIter->iLeafPgno = pgnoLast;
    iOff = fts5LeafFirstRowidOff(pLast);
    if( iOff>pLast->szLeaf ){
      p->rc = FTS5_CORRUPT;
      return;
    }
    iOff += fts5GetVarint(&pLast->p[iOff], (u64*)&pIter->iRowid);
    pIter->iLeafOffset = iOff;

    if( fts5LeafIsTermless(pLast) ){
      pIter->iEndofDoclist = pLast->nn+1;
    }else{
      pIter->iEndofDoclist = fts5LeafFirstTermOff(pLast);
    }

  }

  fts5SegIterReverseInitPage(p, pIter);
}

/*
** Iterator pIter currently points to the first rowid of a doclist.
223995
223996
223997
223998
223999
224000
224001
224002
224003
224004
224005
224006
224007
224008
224009
  }else{
    fts5DataRelease(pIter->pNextLeaf);
    pIter->pNextLeaf = 0;
    pIter->iLeafPgno = iLeafPgno-1;
    fts5SegIterNextPage(p, pIter);
    assert( p->rc!=SQLITE_OK || pIter->iLeafPgno==iLeafPgno );

    if( p->rc==SQLITE_OK ){
      int iOff;
      u8 *a = pIter->pLeaf->p;
      int n = pIter->pLeaf->szLeaf;

      iOff = fts5LeafFirstRowidOff(pIter->pLeaf);
      if( iOff<4 || iOff>=n ){
        p->rc = FTS5_CORRUPT;







|







224698
224699
224700
224701
224702
224703
224704
224705
224706
224707
224708
224709
224710
224711
224712
  }else{
    fts5DataRelease(pIter->pNextLeaf);
    pIter->pNextLeaf = 0;
    pIter->iLeafPgno = iLeafPgno-1;
    fts5SegIterNextPage(p, pIter);
    assert( p->rc!=SQLITE_OK || pIter->iLeafPgno==iLeafPgno );

    if( p->rc==SQLITE_OK && ALWAYS(pIter->pLeaf!=0) ){
      int iOff;
      u8 *a = pIter->pLeaf->p;
      int n = pIter->pLeaf->szLeaf;

      iOff = fts5LeafFirstRowidOff(pIter->pLeaf);
      if( iOff<4 || iOff>=n ){
        p->rc = FTS5_CORRUPT;
224427
224428
224429
224430
224431
224432
224433


224434


224435
224436
224437
224438
224439
224440
224441
*/
static void fts5SegiterPoslist(
  Fts5Index *p,
  Fts5SegIter *pSeg,
  Fts5Colset *pColset,
  Fts5Buffer *pBuf
){


  if( 0==fts5BufferGrow(&p->rc, pBuf, pSeg->nPos+FTS5_DATA_ZERO_PADDING) ){


    memset(&pBuf->p[pBuf->n+pSeg->nPos], 0, FTS5_DATA_ZERO_PADDING);
    if( pColset==0 ){
      fts5ChunkIterate(p, pSeg, (void*)pBuf, fts5PoslistCallback);
    }else{
      if( p->pConfig->eDetail==FTS5_DETAIL_FULL ){
        PoslistCallbackCtx sCtx;
        sCtx.pBuf = pBuf;







>
>

>
>







225130
225131
225132
225133
225134
225135
225136
225137
225138
225139
225140
225141
225142
225143
225144
225145
225146
225147
225148
*/
static void fts5SegiterPoslist(
  Fts5Index *p,
  Fts5SegIter *pSeg,
  Fts5Colset *pColset,
  Fts5Buffer *pBuf
){
  assert( pBuf!=0 );
  assert( pSeg!=0 );
  if( 0==fts5BufferGrow(&p->rc, pBuf, pSeg->nPos+FTS5_DATA_ZERO_PADDING) ){
    assert( pBuf->p!=0 );
    assert( pBuf->nSpace >= pBuf->n+pSeg->nPos+FTS5_DATA_ZERO_PADDING );
    memset(&pBuf->p[pBuf->n+pSeg->nPos], 0, FTS5_DATA_ZERO_PADDING);
    if( pColset==0 ){
      fts5ChunkIterate(p, pSeg, (void*)pBuf, fts5PoslistCallback);
    }else{
      if( p->pConfig->eDetail==FTS5_DETAIL_FULL ){
        PoslistCallbackCtx sCtx;
        sCtx.pBuf = pBuf;
224651
224652
224653
224654
224655
224656
224657

224658
224659
224660
224661
224662
224663
224664
    fts5SegiterPoslist(pIter->pIndex, pSeg, pColset, &pIter->poslist);
    pIter->base.pData = pIter->poslist.p;
    pIter->base.nData = pIter->poslist.n;
  }
}

static void fts5IterSetOutputCb(int *pRc, Fts5Iter *pIter){

  if( *pRc==SQLITE_OK ){
    Fts5Config *pConfig = pIter->pIndex->pConfig;
    if( pConfig->eDetail==FTS5_DETAIL_NONE ){
      pIter->xSetOutputs = fts5IterSetOutputs_None;
    }

    else if( pIter->pColset==0 ){







>







225358
225359
225360
225361
225362
225363
225364
225365
225366
225367
225368
225369
225370
225371
225372
    fts5SegiterPoslist(pIter->pIndex, pSeg, pColset, &pIter->poslist);
    pIter->base.pData = pIter->poslist.p;
    pIter->base.nData = pIter->poslist.n;
  }
}

static void fts5IterSetOutputCb(int *pRc, Fts5Iter *pIter){
  assert( pIter!=0 || (*pRc)!=SQLITE_OK );
  if( *pRc==SQLITE_OK ){
    Fts5Config *pConfig = pIter->pIndex->pConfig;
    if( pConfig->eDetail==FTS5_DETAIL_NONE ){
      pIter->xSetOutputs = fts5IterSetOutputs_None;
    }

    else if( pIter->pColset==0 ){
224722
224723
224724
224725
224726
224727
224728
224729



224730
224731
224732
224733
224734
224735
224736
      nSeg = pStruct->nSegment;
      nSeg += (p->pHash ? 1 : 0);
    }else{
      nSeg = MIN(pStruct->aLevel[iLevel].nSeg, nSegment);
    }
  }
  *ppOut = pNew = fts5MultiIterAlloc(p, nSeg);
  if( pNew==0 ) return;



  pNew->bRev = (0!=(flags & FTS5INDEX_QUERY_DESC));
  pNew->bSkipEmpty = (0!=(flags & FTS5INDEX_QUERY_SKIPEMPTY));
  pNew->pColset = pColset;
  if( (flags & FTS5INDEX_QUERY_NOOUTPUT)==0 ){
    fts5IterSetOutputCb(&p->rc, pNew);
  }








|
>
>
>







225430
225431
225432
225433
225434
225435
225436
225437
225438
225439
225440
225441
225442
225443
225444
225445
225446
225447
      nSeg = pStruct->nSegment;
      nSeg += (p->pHash ? 1 : 0);
    }else{
      nSeg = MIN(pStruct->aLevel[iLevel].nSeg, nSegment);
    }
  }
  *ppOut = pNew = fts5MultiIterAlloc(p, nSeg);
  if( pNew==0 ){
    assert( p->rc!=SQLITE_OK );
    goto fts5MultiIterNew_post_check;
  }
  pNew->bRev = (0!=(flags & FTS5INDEX_QUERY_DESC));
  pNew->bSkipEmpty = (0!=(flags & FTS5INDEX_QUERY_SKIPEMPTY));
  pNew->pColset = pColset;
  if( (flags & FTS5INDEX_QUERY_NOOUTPUT)==0 ){
    fts5IterSetOutputCb(&p->rc, pNew);
  }

224786
224787
224788
224789
224790
224791
224792




224793
224794
224795
224796
224797
224798
224799
      pNew->xSetOutputs(pNew, pSeg);
    }

  }else{
    fts5MultiIterFree(pNew);
    *ppOut = 0;
  }




}

/*
** Create an Fts5Iter that iterates through the doclist provided
** as the second argument.
*/
static void fts5MultiIterNew2(







>
>
>
>







225497
225498
225499
225500
225501
225502
225503
225504
225505
225506
225507
225508
225509
225510
225511
225512
225513
225514
      pNew->xSetOutputs(pNew, pSeg);
    }

  }else{
    fts5MultiIterFree(pNew);
    *ppOut = 0;
  }

fts5MultiIterNew_post_check:
  assert( (*ppOut)!=0 || p->rc!=SQLITE_OK );
  return;
}

/*
** Create an Fts5Iter that iterates through the doclist provided
** as the second argument.
*/
static void fts5MultiIterNew2(
224833
224834
224835
224836
224837
224838
224839

224840
224841
224842
224843
224844
224845
224846
224847
}

/*
** Return true if the iterator is at EOF or if an error has occurred.
** False otherwise.
*/
static int fts5MultiIterEof(Fts5Index *p, Fts5Iter *pIter){

  assert( p->rc
      || (pIter->aSeg[ pIter->aFirst[1].iFirst ].pLeaf==0)==pIter->base.bEof
  );
  return (p->rc || pIter->base.bEof);
}

/*
** Return the rowid of the entry that the iterator currently points







>
|







225548
225549
225550
225551
225552
225553
225554
225555
225556
225557
225558
225559
225560
225561
225562
225563
}

/*
** Return true if the iterator is at EOF or if an error has occurred.
** False otherwise.
*/
static int fts5MultiIterEof(Fts5Index *p, Fts5Iter *pIter){
  assert( pIter!=0 || p->rc!=SQLITE_OK );
  assert( p->rc!=SQLITE_OK
      || (pIter->aSeg[ pIter->aFirst[1].iFirst ].pLeaf==0)==pIter->base.bEof
  );
  return (p->rc || pIter->base.bEof);
}

/*
** Return the rowid of the entry that the iterator currently points
225637
225638
225639
225640
225641
225642
225643

225644
225645
225646
225647
225648
225649
225650
    }
  }

  /* Flush the last leaf page to disk. Set the output segment b-tree height
  ** and last leaf page number at the same time.  */
  fts5WriteFinish(p, &writer, &pSeg->pgnoLast);


  if( fts5MultiIterEof(p, pIter) ){
    int i;

    /* Remove the redundant segments from the %_data table */
    for(i=0; i<nInput; i++){
      fts5DataRemoveSegment(p, pLvl->aSeg[i].iSegid);
    }







>







226353
226354
226355
226356
226357
226358
226359
226360
226361
226362
226363
226364
226365
226366
226367
    }
  }

  /* Flush the last leaf page to disk. Set the output segment b-tree height
  ** and last leaf page number at the same time.  */
  fts5WriteFinish(p, &writer, &pSeg->pgnoLast);

  assert( pIter!=0 || p->rc!=SQLITE_OK );
  if( fts5MultiIterEof(p, pIter) ){
    int i;

    /* Remove the redundant segments from the %_data table */
    for(i=0; i<nInput; i++){
      fts5DataRemoveSegment(p, pLvl->aSeg[i].iSegid);
    }
225737
225738
225739
225740
225741
225742
225743
225744
225745
225746
225747
225748
225749
225750
225751
** already occurred, this function is a no-op.
*/
static void fts5IndexAutomerge(
  Fts5Index *p,                   /* FTS5 backend object */
  Fts5Structure **ppStruct,       /* IN/OUT: Current structure of index */
  int nLeaf                       /* Number of output leaves just written */
){
  if( p->rc==SQLITE_OK && p->pConfig->nAutomerge>0 ){
    Fts5Structure *pStruct = *ppStruct;
    u64 nWrite;                   /* Initial value of write-counter */
    int nWork;                    /* Number of work-quanta to perform */
    int nRem;                     /* Number of leaf pages left to write */

    /* Update the write-counter. While doing so, set nWork. */
    nWrite = pStruct->nWriteCounter;







|







226454
226455
226456
226457
226458
226459
226460
226461
226462
226463
226464
226465
226466
226467
226468
** already occurred, this function is a no-op.
*/
static void fts5IndexAutomerge(
  Fts5Index *p,                   /* FTS5 backend object */
  Fts5Structure **ppStruct,       /* IN/OUT: Current structure of index */
  int nLeaf                       /* Number of output leaves just written */
){
  if( p->rc==SQLITE_OK && p->pConfig->nAutomerge>0 && ALWAYS((*ppStruct)!=0) ){
    Fts5Structure *pStruct = *ppStruct;
    u64 nWrite;                   /* Initial value of write-counter */
    int nWork;                    /* Number of work-quanta to perform */
    int nRem;                     /* Number of leaf pages left to write */

    /* Update the write-counter. While doing so, set nWork. */
    nWrite = pStruct->nWriteCounter;
226847
226848
226849
226850
226851
226852
226853

226854


226855
226856
226857
226858

226859
226860
226861
226862
226863
226864
226865
        );
        fts5StructureRelease(pStruct);
      }
    }else{
      /* Scan multiple terms in the main index */
      int bDesc = (flags & FTS5INDEX_QUERY_DESC)!=0;
      fts5SetupPrefixIter(p, bDesc, iPrefixIdx, buf.p, nToken+1, pColset,&pRet);

      assert( p->rc!=SQLITE_OK || pRet->pColset==0 );


      fts5IterSetOutputCb(&p->rc, pRet);
      if( p->rc==SQLITE_OK ){
        Fts5SegIter *pSeg = &pRet->aSeg[pRet->aFirst[1].iFirst];
        if( pSeg->pLeaf ) pRet->xSetOutputs(pRet, pSeg);

      }
    }

    if( p->rc ){
      sqlite3Fts5IterClose((Fts5IndexIter*)pRet);
      pRet = 0;
      sqlite3Fts5IndexCloseReader(p);







>
|
>
>
|
|
|
|
>







227564
227565
227566
227567
227568
227569
227570
227571
227572
227573
227574
227575
227576
227577
227578
227579
227580
227581
227582
227583
227584
227585
227586
        );
        fts5StructureRelease(pStruct);
      }
    }else{
      /* Scan multiple terms in the main index */
      int bDesc = (flags & FTS5INDEX_QUERY_DESC)!=0;
      fts5SetupPrefixIter(p, bDesc, iPrefixIdx, buf.p, nToken+1, pColset,&pRet);
      if( pRet==0 ){
        assert( p->rc!=SQLITE_OK );
      }else{
        assert( pRet->pColset==0 );
        fts5IterSetOutputCb(&p->rc, pRet);
        if( p->rc==SQLITE_OK ){
          Fts5SegIter *pSeg = &pRet->aSeg[pRet->aFirst[1].iFirst];
          if( pSeg->pLeaf ) pRet->xSetOutputs(pRet, pSeg);
        }
      }
    }

    if( p->rc ){
      sqlite3Fts5IterClose((Fts5IndexIter*)pRet);
      pRet = 0;
      sqlite3Fts5IndexCloseReader(p);
227099
227100
227101
227102
227103
227104
227105
227106
227107
227108
227109
227110
227111
227112
227113
  u64 *pCksum                     /* IN/OUT: Checksum value */
){
  int eDetail = p->pConfig->eDetail;
  u64 cksum = *pCksum;
  Fts5IndexIter *pIter = 0;
  int rc = sqlite3Fts5IndexQuery(p, z, n, flags, 0, &pIter);

  while( rc==SQLITE_OK && 0==sqlite3Fts5IterEof(pIter) ){
    i64 rowid = pIter->iRowid;

    if( eDetail==FTS5_DETAIL_NONE ){
      cksum ^= sqlite3Fts5IndexEntryCksum(rowid, 0, 0, iIdx, z, n);
    }else{
      Fts5PoslistReader sReader;
      for(sqlite3Fts5PoslistReaderInit(pIter->pData, pIter->nData, &sReader);







|







227820
227821
227822
227823
227824
227825
227826
227827
227828
227829
227830
227831
227832
227833
227834
  u64 *pCksum                     /* IN/OUT: Checksum value */
){
  int eDetail = p->pConfig->eDetail;
  u64 cksum = *pCksum;
  Fts5IndexIter *pIter = 0;
  int rc = sqlite3Fts5IndexQuery(p, z, n, flags, 0, &pIter);

  while( rc==SQLITE_OK && ALWAYS(pIter!=0) && 0==sqlite3Fts5IterEof(pIter) ){
    i64 rowid = pIter->iRowid;

    if( eDetail==FTS5_DETAIL_NONE ){
      cksum ^= sqlite3Fts5IndexEntryCksum(rowid, 0, 0, iIdx, z, n);
    }else{
      Fts5PoslistReader sReader;
      for(sqlite3Fts5PoslistReaderInit(pIter->pData, pIter->nData, &sReader);
227464
227465
227466
227467
227468
227469
227470

227471
227472
227473
227474
227475
227476
227477
227478
227479
227480



227481

227482
227483
227484
227485
227486
227487
227488
227489
227490
227491
227492
227493
227494
227495
227496
*/
static int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum, int bUseCksum){
  int eDetail = p->pConfig->eDetail;
  u64 cksum2 = 0;                 /* Checksum based on contents of indexes */
  Fts5Buffer poslist = {0,0,0};   /* Buffer used to hold a poslist */
  Fts5Iter *pIter;                /* Used to iterate through entire index */
  Fts5Structure *pStruct;         /* Index structure */


#ifdef SQLITE_DEBUG
  /* Used by extra internal tests only run if NDEBUG is not defined */
  u64 cksum3 = 0;                 /* Checksum based on contents of indexes */
  Fts5Buffer term = {0,0,0};      /* Buffer used to hold most recent term */
#endif
  const int flags = FTS5INDEX_QUERY_NOOUTPUT;

  /* Load the FTS index structure */
  pStruct = fts5StructureRead(p);





  /* Check that the internal nodes of each segment match the leaves */
  if( pStruct ){
    int iLvl, iSeg;
    for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){
      for(iSeg=0; iSeg<pStruct->aLevel[iLvl].nSeg; iSeg++){
        Fts5StructureSegment *pSeg = &pStruct->aLevel[iLvl].aSeg[iSeg];
        fts5IndexIntegrityCheckSegment(p, pSeg);
      }
    }
  }

  /* The cksum argument passed to this function is a checksum calculated
  ** based on all expected entries in the FTS index (including prefix index
  ** entries). This block checks that a checksum calculated based on the
  ** actual contents of FTS index is identical.







>










>
>
>
|
>

<
<
|
|
|
|
<







228185
228186
228187
228188
228189
228190
228191
228192
228193
228194
228195
228196
228197
228198
228199
228200
228201
228202
228203
228204
228205
228206
228207
228208


228209
228210
228211
228212

228213
228214
228215
228216
228217
228218
228219
*/
static int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum, int bUseCksum){
  int eDetail = p->pConfig->eDetail;
  u64 cksum2 = 0;                 /* Checksum based on contents of indexes */
  Fts5Buffer poslist = {0,0,0};   /* Buffer used to hold a poslist */
  Fts5Iter *pIter;                /* Used to iterate through entire index */
  Fts5Structure *pStruct;         /* Index structure */
  int iLvl, iSeg;

#ifdef SQLITE_DEBUG
  /* Used by extra internal tests only run if NDEBUG is not defined */
  u64 cksum3 = 0;                 /* Checksum based on contents of indexes */
  Fts5Buffer term = {0,0,0};      /* Buffer used to hold most recent term */
#endif
  const int flags = FTS5INDEX_QUERY_NOOUTPUT;

  /* Load the FTS index structure */
  pStruct = fts5StructureRead(p);
  if( pStruct==0 ){
    assert( p->rc!=SQLITE_OK );
    return fts5IndexReturn(p);
  }

  /* Check that the internal nodes of each segment match the leaves */


  for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){
    for(iSeg=0; iSeg<pStruct->aLevel[iLvl].nSeg; iSeg++){
      Fts5StructureSegment *pSeg = &pStruct->aLevel[iLvl].aSeg[iSeg];
      fts5IndexIntegrityCheckSegment(p, pSeg);

    }
  }

  /* The cksum argument passed to this function is a checksum calculated
  ** based on all expected entries in the FTS index (including prefix index
  ** entries). This block checks that a checksum calculated based on the
  ** actual contents of FTS index is identical.
229429
229430
229431
229432
229433
229434
229435

229436
229437
229438
229439
229440
229441
229442
229443
    /* This is either a full-table scan (ePlan==FTS5_PLAN_SCAN) or a lookup
    ** by rowid (ePlan==FTS5_PLAN_ROWID).  */
    pCsr->ePlan = (pRowidEq ? FTS5_PLAN_ROWID : FTS5_PLAN_SCAN);
    rc = sqlite3Fts5StorageStmt(
        pTab->pStorage, fts5StmtType(pCsr), &pCsr->pStmt, &pTab->p.base.zErrMsg
    );
    if( rc==SQLITE_OK ){

      if( pCsr->ePlan==FTS5_PLAN_ROWID ){
        sqlite3_bind_value(pCsr->pStmt, 1, pRowidEq);
      }else{
        sqlite3_bind_int64(pCsr->pStmt, 1, pCsr->iFirstRowid);
        sqlite3_bind_int64(pCsr->pStmt, 2, pCsr->iLastRowid);
      }
      rc = fts5NextMethod(pCursor);
    }







>
|







230152
230153
230154
230155
230156
230157
230158
230159
230160
230161
230162
230163
230164
230165
230166
230167
    /* This is either a full-table scan (ePlan==FTS5_PLAN_SCAN) or a lookup
    ** by rowid (ePlan==FTS5_PLAN_ROWID).  */
    pCsr->ePlan = (pRowidEq ? FTS5_PLAN_ROWID : FTS5_PLAN_SCAN);
    rc = sqlite3Fts5StorageStmt(
        pTab->pStorage, fts5StmtType(pCsr), &pCsr->pStmt, &pTab->p.base.zErrMsg
    );
    if( rc==SQLITE_OK ){
      if( pRowidEq!=0 ){
        assert( pCsr->ePlan==FTS5_PLAN_ROWID );
        sqlite3_bind_value(pCsr->pStmt, 1, pRowidEq);
      }else{
        sqlite3_bind_int64(pCsr->pStmt, 1, pCsr->iFirstRowid);
        sqlite3_bind_int64(pCsr->pStmt, 2, pCsr->iLastRowid);
      }
      rc = fts5NextMethod(pCursor);
    }
230847
230848
230849
230850
230851
230852
230853
230854
230855
230856
230857
230858
230859
230860
230861
static void fts5SourceIdFunc(
  sqlite3_context *pCtx,          /* Function call context */
  int nArg,                       /* Number of args */
  sqlite3_value **apUnused        /* Function arguments */
){
  assert( nArg==0 );
  UNUSED_PARAM2(nArg, apUnused);
  sqlite3_result_text(pCtx, "fts5: 2021-08-06 20:17:39 087b8b41c6ed76b55c11315e7e95679d67590be20ae21108b593d00bb7d1c57a", -1, SQLITE_TRANSIENT);
}

/*
** Return true if zName is the extension on one of the shadow tables used
** by this module.
*/
static int fts5ShadowName(const char *zName){







|







231571
231572
231573
231574
231575
231576
231577
231578
231579
231580
231581
231582
231583
231584
231585
static void fts5SourceIdFunc(
  sqlite3_context *pCtx,          /* Function call context */
  int nArg,                       /* Number of args */
  sqlite3_value **apUnused        /* Function arguments */
){
  assert( nArg==0 );
  UNUSED_PARAM2(nArg, apUnused);
  sqlite3_result_text(pCtx, "fts5: 2021-10-05 18:33:38 a7835bead85b1b18a8affd9835240b0baf9c7af887196bbdcc3f5d58055042fc", -1, SQLITE_TRANSIENT);
}

/*
** Return true if zName is the extension on one of the shadow tables used
** by this module.
*/
static int fts5ShadowName(const char *zName){
231398
231399
231400
231401
231402
231403
231404


231405
231406
231407
231408
231409
231410


231411
231412
231413
231414
231415
231416
231417
  ctx.pStorage = p;
  ctx.iCol = -1;
  rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 1, iDel);
  for(iCol=1; rc==SQLITE_OK && iCol<=pConfig->nCol; iCol++){
    if( pConfig->abUnindexed[iCol-1]==0 ){
      const char *zText;
      int nText;


      if( pSeek ){
        zText = (const char*)sqlite3_column_text(pSeek, iCol);
        nText = sqlite3_column_bytes(pSeek, iCol);
      }else{
        zText = (const char*)sqlite3_value_text(apVal[iCol-1]);
        nText = sqlite3_value_bytes(apVal[iCol-1]);


      }
      ctx.szCol = 0;
      rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT,
          zText, nText, (void*)&ctx, fts5StorageInsertCallback
      );
      p->aTotalSize[iCol-1] -= (i64)ctx.szCol;
      if( p->aTotalSize[iCol-1]<0 ){







>
>



|


>
>







232122
232123
232124
232125
232126
232127
232128
232129
232130
232131
232132
232133
232134
232135
232136
232137
232138
232139
232140
232141
232142
232143
232144
232145
  ctx.pStorage = p;
  ctx.iCol = -1;
  rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 1, iDel);
  for(iCol=1; rc==SQLITE_OK && iCol<=pConfig->nCol; iCol++){
    if( pConfig->abUnindexed[iCol-1]==0 ){
      const char *zText;
      int nText;
      assert( pSeek==0 || apVal==0 );
      assert( pSeek!=0 || apVal!=0 );
      if( pSeek ){
        zText = (const char*)sqlite3_column_text(pSeek, iCol);
        nText = sqlite3_column_bytes(pSeek, iCol);
      }else if( ALWAYS(apVal) ){
        zText = (const char*)sqlite3_value_text(apVal[iCol-1]);
        nText = sqlite3_value_bytes(apVal[iCol-1]);
      }else{
        continue;
      }
      ctx.szCol = 0;
      rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT,
          zText, nText, (void*)&ctx, fts5StorageInsertCallback
      );
      p->aTotalSize[iCol-1] -= (i64)ctx.szCol;
      if( p->aTotalSize[iCol-1]<0 ){
232039
232040
232041
232042
232043
232044
232045
232046
232047

232048
232049
232050
232051
232052
232053
232054
232055
232056
232057
232058
232059


232060
232061
232062
232063
232064
232065
232066
static int sqlite3Fts5StorageDocsize(Fts5Storage *p, i64 iRowid, int *aCol){
  int nCol = p->pConfig->nCol;    /* Number of user columns in table */
  sqlite3_stmt *pLookup = 0;      /* Statement to query %_docsize */
  int rc;                         /* Return Code */

  assert( p->pConfig->bColumnsize );
  rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP_DOCSIZE, &pLookup, 0);
  if( rc==SQLITE_OK ){
    int bCorrupt = 1;

    sqlite3_bind_int64(pLookup, 1, iRowid);
    if( SQLITE_ROW==sqlite3_step(pLookup) ){
      const u8 *aBlob = sqlite3_column_blob(pLookup, 0);
      int nBlob = sqlite3_column_bytes(pLookup, 0);
      if( 0==fts5StorageDecodeSizeArray(aCol, nCol, aBlob, nBlob) ){
        bCorrupt = 0;
      }
    }
    rc = sqlite3_reset(pLookup);
    if( bCorrupt && rc==SQLITE_OK ){
      rc = FTS5_CORRUPT;
    }


  }

  return rc;
}

static int sqlite3Fts5StorageSize(Fts5Storage *p, int iCol, i64 *pnToken){
  int rc = fts5StorageLoadTotals(p, 0);







|

>












>
>







232767
232768
232769
232770
232771
232772
232773
232774
232775
232776
232777
232778
232779
232780
232781
232782
232783
232784
232785
232786
232787
232788
232789
232790
232791
232792
232793
232794
232795
232796
232797
static int sqlite3Fts5StorageDocsize(Fts5Storage *p, i64 iRowid, int *aCol){
  int nCol = p->pConfig->nCol;    /* Number of user columns in table */
  sqlite3_stmt *pLookup = 0;      /* Statement to query %_docsize */
  int rc;                         /* Return Code */

  assert( p->pConfig->bColumnsize );
  rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP_DOCSIZE, &pLookup, 0);
  if( pLookup ){
    int bCorrupt = 1;
    assert( rc==SQLITE_OK );
    sqlite3_bind_int64(pLookup, 1, iRowid);
    if( SQLITE_ROW==sqlite3_step(pLookup) ){
      const u8 *aBlob = sqlite3_column_blob(pLookup, 0);
      int nBlob = sqlite3_column_bytes(pLookup, 0);
      if( 0==fts5StorageDecodeSizeArray(aCol, nCol, aBlob, nBlob) ){
        bCorrupt = 0;
      }
    }
    rc = sqlite3_reset(pLookup);
    if( bCorrupt && rc==SQLITE_OK ){
      rc = FTS5_CORRUPT;
    }
  }else{
    assert( rc!=SQLITE_OK );
  }

  return rc;
}

static int sqlite3Fts5StorageSize(Fts5Storage *p, int iCol, i64 *pnToken){
  int rc = fts5StorageLoadTotals(p, 0);
Changes to src/sqlite3.h.
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
**
** See also: [sqlite3_libversion()],
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
#define SQLITE_VERSION        "3.37.0"
#define SQLITE_VERSION_NUMBER 3037000
#define SQLITE_SOURCE_ID      "2021-08-06 20:17:39 087b8b41c6ed76b55c11315e7e95679d67590be20ae21108b593d00bb7d1c57a"

/*
** CAPI3REF: Run-Time Library Version Numbers
** KEYWORDS: sqlite3_version sqlite3_sourceid
**
** These interfaces provide the same information as the [SQLITE_VERSION],
** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros







|







144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
**
** See also: [sqlite3_libversion()],
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
#define SQLITE_VERSION        "3.37.0"
#define SQLITE_VERSION_NUMBER 3037000
#define SQLITE_SOURCE_ID      "2021-10-06 10:36:56 566e6974892ebd3d3de8d77b24655257a5efe14434c553e1a25fc680b201b336"

/*
** CAPI3REF: Run-Time Library Version Numbers
** KEYWORDS: sqlite3_version sqlite3_sourceid
**
** These interfaces provide the same information as the [SQLITE_VERSION],
** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros
557
558
559
560
561
562
563

564
565
566
567
568
569
570
#define SQLITE_CONSTRAINT_NOTNULL      (SQLITE_CONSTRAINT | (5<<8))
#define SQLITE_CONSTRAINT_PRIMARYKEY   (SQLITE_CONSTRAINT | (6<<8))
#define SQLITE_CONSTRAINT_TRIGGER      (SQLITE_CONSTRAINT | (7<<8))
#define SQLITE_CONSTRAINT_UNIQUE       (SQLITE_CONSTRAINT | (8<<8))
#define SQLITE_CONSTRAINT_VTAB         (SQLITE_CONSTRAINT | (9<<8))
#define SQLITE_CONSTRAINT_ROWID        (SQLITE_CONSTRAINT |(10<<8))
#define SQLITE_CONSTRAINT_PINNED       (SQLITE_CONSTRAINT |(11<<8))

#define SQLITE_NOTICE_RECOVER_WAL      (SQLITE_NOTICE | (1<<8))
#define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8))
#define SQLITE_WARNING_AUTOINDEX       (SQLITE_WARNING | (1<<8))
#define SQLITE_AUTH_USER               (SQLITE_AUTH | (1<<8))
#define SQLITE_OK_LOAD_PERMANENTLY     (SQLITE_OK | (1<<8))
#define SQLITE_OK_SYMLINK              (SQLITE_OK | (2<<8))








>







557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
#define SQLITE_CONSTRAINT_NOTNULL      (SQLITE_CONSTRAINT | (5<<8))
#define SQLITE_CONSTRAINT_PRIMARYKEY   (SQLITE_CONSTRAINT | (6<<8))
#define SQLITE_CONSTRAINT_TRIGGER      (SQLITE_CONSTRAINT | (7<<8))
#define SQLITE_CONSTRAINT_UNIQUE       (SQLITE_CONSTRAINT | (8<<8))
#define SQLITE_CONSTRAINT_VTAB         (SQLITE_CONSTRAINT | (9<<8))
#define SQLITE_CONSTRAINT_ROWID        (SQLITE_CONSTRAINT |(10<<8))
#define SQLITE_CONSTRAINT_PINNED       (SQLITE_CONSTRAINT |(11<<8))
#define SQLITE_CONSTRAINT_DATATYPE     (SQLITE_CONSTRAINT |(12<<8))
#define SQLITE_NOTICE_RECOVER_WAL      (SQLITE_NOTICE | (1<<8))
#define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8))
#define SQLITE_WARNING_AUTOINDEX       (SQLITE_WARNING | (1<<8))
#define SQLITE_AUTH_USER               (SQLITE_AUTH | (1<<8))
#define SQLITE_OK_LOAD_PERMANENTLY     (SQLITE_OK | (1<<8))
#define SQLITE_OK_SYMLINK              (SQLITE_OK | (2<<8))

Changes to src/stash.c.
400
401
402
403
404
405
406
407
408
409
410
411

412
413
414

415

416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467

468
469
470
471
472
473
474
475
476
477

478
479
480
481
482
483
484
}

/*
** Show the diffs associate with a single stash.
*/
static void stash_diff(
  int stashid,             /* The stash entry to diff */
  const char *zDiffCmd,    /* Command used for diffing */
  const char *zBinGlob,    /* GLOB pattern to determine binary files */
  int fBaseline,           /* Diff against original baseline check-in if true */
  int fIncludeBinary,      /* Do diffs against binary files */
  u64 diffFlags            /* Other diff flags */

){
  Stmt q;
  Blob empty;

  blob_zero(&empty);

  db_prepare(&q,
     "SELECT blob.rid, isRemoved, isExec, isLink, origname, newname, delta"
     "  FROM stashfile, blob WHERE stashid=%d AND blob.uuid=stashfile.hash",
     stashid
  );
  while( db_step(&q)==SQLITE_ROW ){
    int rid = db_column_int(&q, 0);
    int isRemoved = db_column_int(&q, 1);
    int isLink = db_column_int(&q, 3);
    int isBin1, isBin2;
    const char *zOrig = db_column_text(&q, 4);
    const char *zNew = db_column_text(&q, 5);
    char *zOPath = mprintf("%s%s", g.zLocalRoot, zOrig);
    Blob a, b;
    if( rid==0 ){
      db_ephemeral_blob(&q, 6, &a);
      fossil_print("ADDED %s\n", zNew);
      diff_print_index(zNew, diffFlags, 0);
      isBin1 = 0;
      isBin2 = fIncludeBinary ? 0 : looks_like_binary(&a);
      diff_file_mem(&empty, &a, isBin1, isBin2, zNew, zDiffCmd,
                    zBinGlob, fIncludeBinary, diffFlags);
    }else if( isRemoved ){
      fossil_print("DELETE %s\n", zOrig);
      diff_print_index(zNew, diffFlags, 0);
      isBin2 = 0;
      if( fBaseline ){
        content_get(rid, &a);
        isBin1 = fIncludeBinary ? 0 : looks_like_binary(&a);
        diff_file_mem(&a, &empty, isBin1, isBin2, zOrig, zDiffCmd,
                      zBinGlob, fIncludeBinary, diffFlags);
      }
    }else{
      Blob delta;
      int isOrigLink = file_islink(zOPath);
      db_ephemeral_blob(&q, 6, &delta);
      fossil_print("CHANGED %s\n", zNew);
      if( !isOrigLink != !isLink ){
        diff_print_index(zNew, diffFlags, 0);
        diff_print_filenames(zOrig, zNew, diffFlags, 0);
        printf(DIFF_CANNOT_COMPUTE_SYMLINK);
      }else{
        content_get(rid, &a);
        blob_delta_apply(&a, &delta, &b);
        isBin1 = fIncludeBinary ? 0 : looks_like_binary(&a);
        isBin2 = fIncludeBinary ? 0 : looks_like_binary(&b);
        if( fBaseline ){
          diff_file_mem(&a, &b, isBin1, isBin2, zNew,
                        zDiffCmd, zBinGlob, fIncludeBinary, diffFlags);
        }else{
          /*Diff with file on disk using fSwapDiff=1 to show the diff in the
            same direction as if fBaseline=1.*/

          diff_file(&b, isBin2, zOPath, zNew, zDiffCmd,
              zBinGlob, fIncludeBinary, diffFlags, 1, 0);
        }
        blob_reset(&a);
        blob_reset(&b);
      }
      blob_reset(&delta);
    }
  }
  db_finalize(&q);

}

/*
** Drop the indicated stash
*/
static void stash_drop(int stashid){
  db_multi_exec(







<
<

<
<
>



>

>









<






|
|
<
<
|
<

|
|
<


<
|
<





|

|
|




<
<

|
<

<
<
>
|
|








>







400
401
402
403
404
405
406


407


408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423

424
425
426
427
428
429
430
431


432

433
434
435

436
437

438

439
440
441
442
443
444
445
446
447
448
449
450
451


452
453

454


455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
}

/*
** Show the diffs associate with a single stash.
*/
static void stash_diff(
  int stashid,             /* The stash entry to diff */


  int fBaseline,           /* Diff against original baseline check-in if true */


  DiffConfig *pCfg         /* Diff formatting options */
){
  Stmt q;
  Blob empty;
  int bWebpage = (pCfg->diffFlags & (DIFF_WEBPAGE|DIFF_JSON|DIFF_TCL))!=0;
  blob_zero(&empty);
  diff_begin(pCfg);
  db_prepare(&q,
     "SELECT blob.rid, isRemoved, isExec, isLink, origname, newname, delta"
     "  FROM stashfile, blob WHERE stashid=%d AND blob.uuid=stashfile.hash",
     stashid
  );
  while( db_step(&q)==SQLITE_ROW ){
    int rid = db_column_int(&q, 0);
    int isRemoved = db_column_int(&q, 1);
    int isLink = db_column_int(&q, 3);

    const char *zOrig = db_column_text(&q, 4);
    const char *zNew = db_column_text(&q, 5);
    char *zOPath = mprintf("%s%s", g.zLocalRoot, zOrig);
    Blob a, b;
    if( rid==0 ){
      db_ephemeral_blob(&q, 6, &a);
      if( !bWebpage ) fossil_print("ADDED %s\n", zNew);
      diff_print_index(zNew, pCfg, 0);


      diff_file_mem(&empty, &a, zNew, pCfg);

    }else if( isRemoved ){
      if( !bWebpage) fossil_print("DELETE %s\n", zOrig);
      diff_print_index(zNew, pCfg, 0);

      if( fBaseline ){
        content_get(rid, &a);

        diff_file_mem(&a, &empty, zOrig, pCfg);

      }
    }else{
      Blob delta;
      int isOrigLink = file_islink(zOPath);
      db_ephemeral_blob(&q, 6, &delta);
      if( !bWebpage ) fossil_print("CHANGED %s\n", zNew);
      if( !isOrigLink != !isLink ){
        diff_print_index(zNew, pCfg, 0);
        diff_print_filenames(zOrig, zNew, pCfg, 0);
        printf(DIFF_CANNOT_COMPUTE_SYMLINK);
      }else{
        content_get(rid, &a);
        blob_delta_apply(&a, &delta, &b);


        if( fBaseline ){
          diff_file_mem(&a, &b, zNew, pCfg);

        }else{


          pCfg->diffFlags ^= DIFF_INVERT;
          diff_file(&b, zOPath, zNew, pCfg, 0);
          pCfg->diffFlags ^= DIFF_INVERT;
        }
        blob_reset(&a);
        blob_reset(&b);
      }
      blob_reset(&delta);
    }
  }
  db_finalize(&q);
  diff_end(pCfg, 0);
}

/*
** Drop the indicated stash
*/
static void stash_drop(int stashid){
  db_multi_exec(
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
  if( memcmp(zCmd, "diff", nCmd)==0
   || memcmp(zCmd, "gdiff", nCmd)==0
   || memcmp(zCmd, "show", nCmd)==0
   || memcmp(zCmd, "gshow", nCmd)==0
   || memcmp(zCmd, "cat", nCmd)==0
   || memcmp(zCmd, "gcat", nCmd)==0
  ){
    const char *zDiffCmd = 0;
    const char *zBinGlob = 0;
    int fIncludeBinary = 0;
    int fBaseline = 0;
    u64 diffFlags;

    if( strstr(zCmd,"show")!=0 || strstr(zCmd,"cat")!=0 ){
      fBaseline = 1;
    }
    if( find_option("tk",0,0)!=0 ){
      db_close(0);
      diff_tk(fBaseline ? "stash show" : "stash diff", 3);
      return;
    }
    if( find_option("internal","i",0)==0 ){
      zDiffCmd = diff_command_external(zCmd[0]=='g');
    }
    diffFlags = diff_options();
    if( find_option("verbose","v",0)!=0 ) diffFlags |= DIFF_VERBOSE;
    if( g.argc>4 ) usage(mprintf("%s ?STASHID? ?DIFF-OPTIONS?", zCmd));
    if( zDiffCmd ){
      zBinGlob = diff_get_binary_glob();
      fIncludeBinary = diff_include_binary_files();
    }
    stashid = stash_get_id(g.argc==4 ? g.argv[3] : 0);
    stash_diff(stashid, zDiffCmd, zBinGlob, fBaseline, fIncludeBinary,
               diffFlags);
  }else
  if( memcmp(zCmd, "help", nCmd)==0 ){
    g.argv[1] = "help";
    g.argv[2] = "stash";
    g.argc = 3;
    help_cmd();
  }else
  {
    usage("SUBCOMMAND ARGS...");
  }
  db_end_transaction(0);
}







<
<
<

|









<
<
<
|
<
<
<
<
<
<

|
<












724
725
726
727
728
729
730



731
732
733
734
735
736
737
738
739
740
741



742






743
744

745
746
747
748
749
750
751
752
753
754
755
756
  if( memcmp(zCmd, "diff", nCmd)==0
   || memcmp(zCmd, "gdiff", nCmd)==0
   || memcmp(zCmd, "show", nCmd)==0
   || memcmp(zCmd, "gshow", nCmd)==0
   || memcmp(zCmd, "cat", nCmd)==0
   || memcmp(zCmd, "gcat", nCmd)==0
  ){



    int fBaseline = 0;
    DiffConfig DCfg;

    if( strstr(zCmd,"show")!=0 || strstr(zCmd,"cat")!=0 ){
      fBaseline = 1;
    }
    if( find_option("tk",0,0)!=0 ){
      db_close(0);
      diff_tk(fBaseline ? "stash show" : "stash diff", 3);
      return;
    }



    diff_options(&DCfg, zCmd[0]=='g', 0);






    stashid = stash_get_id(g.argc==4 ? g.argv[3] : 0);
    stash_diff(stashid, fBaseline, &DCfg);

  }else
  if( memcmp(zCmd, "help", nCmd)==0 ){
    g.argv[1] = "help";
    g.argv[2] = "stash";
    g.argc = 3;
    help_cmd();
  }else
  {
    usage("SUBCOMMAND ARGS...");
  }
  db_end_transaction(0);
}
Changes to src/stat.c.
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502

  style_set_current_feature("stat");
  style_header("URLs and Checkouts");
  style_adunit_config(ADUNIT_RIGHT_OK);
  style_submenu_element("Stat", "stat");
  style_submenu_element("Schema", "repo_schema");
  iNow = db_int64(0, "SELECT strftime('%%s','now')");
  @ <div class="section">URLs used to access</div>
  @ <table border="0" width='100%%'>
  db_prepare(&q, "SELECT substr(name,9), datetime(mtime,'unixepoch'), mtime"
                 "  FROM config WHERE name GLOB 'baseurl:*' ORDER BY 3 DESC");
  cnt = 0;
  nOmitted = 0;
  while( db_step(&q)==SQLITE_ROW ){
    if( !showAll && db_column_int64(&q,2)<(iNow - 3600*24*30) && cnt>8 ){







|







488
489
490
491
492
493
494
495
496
497
498
499
500
501
502

  style_set_current_feature("stat");
  style_header("URLs and Checkouts");
  style_adunit_config(ADUNIT_RIGHT_OK);
  style_submenu_element("Stat", "stat");
  style_submenu_element("Schema", "repo_schema");
  iNow = db_int64(0, "SELECT strftime('%%s','now')");
  @ <div class="section">URLs used to access this repository</div>
  @ <table border="0" width='100%%'>
  db_prepare(&q, "SELECT substr(name,9), datetime(mtime,'unixepoch'), mtime"
                 "  FROM config WHERE name GLOB 'baseurl:*' ORDER BY 3 DESC");
  cnt = 0;
  nOmitted = 0;
  while( db_step(&q)==SQLITE_ROW ){
    if( !showAll && db_column_int64(&q,2)<(iNow - 3600*24*30) && cnt>8 ){
530
531
532
533
534
535
536

537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555


556
557
558
559
560
561
562

563
564
565
566

567
568
569
570
571
572
573
    }
  }
  db_finalize(&q);
  if( cnt ){
    @ </table>
  }
  cnt = 0;

  db_prepare(&q, "SELECT substr(name,10), datetime(mtime,'unixepoch')"
                 "  FROM config WHERE name GLOB 'syncwith:*' ORDER BY 2 DESC");
  while( db_step(&q)==SQLITE_ROW ){
    const char *zURL = db_column_text(&q,0);
    if( cnt==0 ){
      @ <div class="section">Sync to these URLs</div>
      @ <table border='0' width='100%%'>
    }
    @ <tr><td width='100%%'><a href='%h(zURL)'>%h(zURL)</a>
    @ <td><nobr>%h(db_column_text(&q,1))</nobr></td></tr>
    cnt++;
  }
  db_finalize(&q);
  if( cnt ){
    @ </table>
  }
  cnt = 0;
  db_prepare(&q, "SELECT substr(name,9), datetime(mtime,'unixepoch')"
                 "  FROM config WHERE name GLOB 'gitpush:*' ORDER BY 2 DESC");


  while( db_step(&q)==SQLITE_ROW ){
    const char *zURL = db_column_text(&q,0);
    UrlData x;
    if( cnt==0 ){
      @ <div class="section">Git Mirrors</div>
      @ <table border='0' width='100%%'>
    }

    url_parse_local(zURL, URL_OMIT_USER, &x);
    @ <tr><td width='100%%'><a href='%h(x.canonical)'>%h(x.canonical)</a>
    @ <td><nobr>%h(db_column_text(&q,1))</nobr></td></tr>
    cnt++;

  }
  db_finalize(&q);
  if( cnt ){
    @ </table>
  }
  style_finish_page();
}







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




|


>




>







530
531
532
533
534
535
536
537
538
539

540
541
542










543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
    }
  }
  db_finalize(&q);
  if( cnt ){
    @ </table>
  }
  cnt = 0;
  db_prepare(&q,
    "SELECT substr(name,10), datetime(mtime,'unixepoch')"
    "  FROM config WHERE name GLOB 'syncwith:*'"

    "UNION ALL "
    "SELECT substr(name,10), datetime(mtime,'unixepoch')"
    "  FROM config WHERE name GLOB 'syncfrom:*'"










    "UNION ALL "
    "SELECT substr(name,9), datetime(mtime,'unixepoch')"
    "  FROM config WHERE name GLOB 'gitpush:*'"
    "ORDER BY 2 DESC"
  );
  while( db_step(&q)==SQLITE_ROW ){
    const char *zURL = db_column_text(&q,0);
    UrlData x;
    if( cnt==0 ){
      @ <div class="section">Sync with these URLs</div>
      @ <table border='0' width='100%%'>
    }
    memset(&x, 0, sizeof(x));
    url_parse_local(zURL, URL_OMIT_USER, &x);
    @ <tr><td width='100%%'><a href='%h(x.canonical)'>%h(x.canonical)</a>
    @ <td><nobr>%h(db_column_text(&q,1))</nobr></td></tr>
    cnt++;
    url_unparse(&x);
  }
  db_finalize(&q);
  if( cnt ){
    @ </table>
  }
  style_finish_page();
}
Added src/style.chat.css.
































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
/* Chat-related */
body.chat span.at-name { /* for @USERNAME references */
  text-decoration: underline;
  font-weight: bold;
}
/* A wrapper for a single single chat message (one row of the UI) */
body.chat .message-widget {
  margin-bottom: 0.75em;
  border: none;
  display: flex;
  flex-direction: column;
  border: none;
  align-items: flex-start;
}
body.chat button,
body.chat input[type=button] {
  line-height: inherit/*undo skin-specific funkiness*/;
}
body.chat .message-widget:last-of-type {
  /* Latest message: reduce bottom gap */
  margin-bottom: 0.1em;
}
body.chat.my-messages-right .message-widget.mine {
  /* Right-aligns a user's own chat messages, similar to how
     most/some mobile messaging apps do it. */
  align-items: flex-end;
}
body.chat.my-messages-right .message-widget.notification {
  /* Center-aligns a system-level notification message. */
  align-items: center;
}
/* The content area of a message. */
body.chat .message-widget-content {
  display: inline-block;
  border-radius: 0.25em;
  border: 1px solid rgba(0,0,0,0.2);
  box-shadow: 0.2em 0.2em 0.2em rgba(0, 0, 0, 0.29);
  padding: 0.25em 0.5em;
  margin-top: 0;
  min-width: 9em /*avoid unsightly "underlap" with the neighboring
                   .message-widget-tab element*/;
  white-space: normal;
}
body.chat.monospace-messages .message-widget-content,
/*body.chat.monospace-messages textarea,*/
/*body.chat.monospace-messages input[type=text],*/
body.chat.monospace-messages #chat-input-field{
  font-family: monospace;  
}
body.chat .message-widget-content > * {
  margin: 0;
  padding: 0;
}
body.chat .message-widget-content > pre {
  white-space: pre-wrap;
}
body.chat .message-widget-content > .markdown > *:first-child {
  margin-top: 0;
}
body.chat .message-widget-content > .markdown > *:last-child {
  margin-bottom: 0;
}
/* User name and timestamp (a LEGEND-like element) */
body.chat .message-widget .message-widget-tab {
  border-radius: 0.25em 0.25em 0 0;
  margin: 0 0.25em 0em 0.15em;
  padding: 0 0.5em 0.15em 0.5em;
  cursor: pointer;
  white-space: nowrap;
}
body.chat .fossil-tooltip.help-buttonlet-content {
  font-size: 80%;
}
body.chat .message-widget .message-widget-tab .xfrom {
  /* Element which holds the "this message is from user X" part
     of the message banner. */
  font-style: italic;
  font-weight: bold;
}
/* The popup element for displaying message timestamps
   and deletion controls. */
body.chat .chat-message-popup {
  font-family: monospace;
  font-size: 0.9em;
  text-align: left;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  padding: 0.25em;
  margin-top: 0.25em;
  border: 1px outset;
  border-radius: 0.5em;
}
/* Full message timestamps. */
body.chat .chat-message-popup > span { white-space: nowrap; }
/* Container for the message deletion buttons. */
body.chat .chat-message-popup > .toolbar {
  padding: 0;
  margin: 0;
  border: 2px inset rgba(0,0,0,0.3);
  border-radius: 0.25em;
  display: flex;
  flex-direction: row;
  justify-content: stretch;
  flex-wrap: wrap;
  align-items: center;
}
body.chat .chat-message-popup > .toolbar > * {
  margin: 0.35em;
}
body.chat .chat-message-popup > .toolbar > button {
  flex: 1 1 auto;
}
/* The widget for loading more/older chat messages. */
body.chat #load-msg-toolbar  {
  border-radius: 0.25em;
  padding: 0.1em 0.2em;
  margin-bottom: 1em;
}
/* .all-done is set when chat has loaded all of the available
   historical messages */
body.chat #load-msg-toolbar.all-done {
  opacity: 0.5;
}
body.chat #load-msg-toolbar > div {
  display: flex;
  flex-direction: row;
  justify-content: stretch;
  flex-wrap: wrap;
}
body.chat #load-msg-toolbar > div > button {
  flex: 1 1 auto;
}
/* "Chat-only mode" hides the site header/footer, showing only
   the chat app. */
body.chat.chat-only-mode{}
body.chat #chat-button-settings {}
/** Popup widget for the /chat settings. */
body.chat .chat-settings-popup {
  font-size: 0.8em;
  text-align: left;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  padding: 0.25em;
  z-index: 200;
}

/** Container for the list of /chat messages. */
body.chat #chat-messages-wrapper {
  overflow: auto;
  padding: 0 0.25em;
}
body.chat #chat-messages-wrapper.loading > * {
  /* An attempt at reducing flicker when loading lots of messages. */
  visibility: hidden;
}
body.chat div.content {
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column-reverse;
  /* ^^^^ In order to get good automatic scrolling of new messages on
     the BOTTOM in bottom-up chat mode, such that they scroll up
     instead of down, we have to use column-reverse layout, which
     changes #chat-messages-wrapper's "gravity" for purposes of
     scrolling! If we instead use flex-direction:column then each new
     message pushes #chat-input-area down further off the screen!
 */
  align-items: stretch;
}
/* Wrapper for /chat user input controls */
body.chat #chat-input-area {
  display: flex;
  flex-direction: column;
  padding: 0;
  margin: 0;
  flex: 0 1 auto;
}
body.chat:not(.chat-only-mode) #chat-input-area{
  /* Safari user reports that 2em is necessary to keep the file selection
     widget from overlapping the page footer, whereas a margin of 0 is fine
     for FF/Chrome (and 2em is a *huge* waste of space for those). */
  margin-bottom: 0;
}
#chat-input-field {
  display: inline-block/*supposed workaround for Chrome weirdness*/;
  padding: 0.2em;
  flex: 10 1 auto;
  background-color: rgba(156,156,156,0.3);
  overflow: auto;
  resize: vertical;
  white-space: pre-wrap;
  /* ^^^ Firefox, when pasting plain text into a contenteditable field,
     loses all newlines unless we explicitly set this. Chrome does not. */
  cursor: text;
  /* ^^^ In some browsers the cursor may not change for a contenteditable
     element until it has focus, causing potential confusion. */
}
#chat-input-field:empty::before {
  content: attr(data-placeholder);
  opacity: 0.6;
}
#chat-input-field:not(:focus){
  border-width: 1px;
  border-style: solid;
  border-radius: 0.25em;
}
#chat-input-field:focus{
  /* This transparent border helps avoid the text shifting around
     when the contenteditable attribute causes a border (which we
     apparently cannot style) to be added. */
  border-width: 1px;
  border-style: solid;
  border-color: transparent;
  border-radius: 0.25em;
}
/* Widget holding the chat message input field, send button, and
   settings button. */
body.chat #chat-input-line {
  display: flex;
  flex-direction: row;
  align-items: stretch;
  flex-wrap: nowrap;
}
/*body.chat #chat-input-line:not(.compact) {
  flex-wrap: nowrap;
}*/
body.chat #chat-input-line.compact {
  /* "The problem" with wrapping, together with a contenteditable input
     field, is that the latter grows as the user types, so causes
     wrapping to happen while they type, then to unwrap as soon as the
     input field is cleared (when the message is sent). When we stay
     wrapped in compact mode, the wrapped buttons simply take up too
     much space. */
  /*flex-wrap: wrap;
  justify-content: flex-end;*/
  flex-direction: column;
  /**
     We "really do" need column orientation here because it's the
     only way to eliminate the possibility that (A) the buttons
     get truncated in very narrow windows and (B) that they keep
     stable positions.
 */
}
body.chat #chat-input-line.compact #chat-input-field {
}

body.chat #chat-buttons-wrapper {
  flex: 0 1 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  min-width: 4em;
  min-height: 1.5em;
  align-self: flex-end
  /*keep buttons stable at bottom/right even when input field
    resizes */;
}
body.chat #chat-input-line.compact #chat-buttons-wrapper {
  flex-direction: row;
  flex: 1 1 auto;
  align-self: stretch;
  justify-content: flex-end;
  /*flex-wrap: wrap;*/
  /* Wrapping would be ideal except that the edit widget
     grows in width as the user types, moving the buttons
     around */
}
body.chat #chat-buttons-wrapper > .cbutton {
  padding: 0;
  display: inline-block;
  border-width: 1px;
  border-style: solid;
  border-radius: 0.25em;
  min-width: 4ex;
  max-width: 4ex;
  min-height: 4ex;
  max-height: 4ex;
  margin: 0.125em;
  display: inline-flex;
  justify-content: center;
  align-items: center;
  cursor: pointer;
  font-size: 130%;
}
body.chat #chat-buttons-wrapper > .cbutton:hover {
  background-color: rgba(200,200,200,0.3);
}
body.chat #chat-input-line.compact #chat-buttons-wrapper > .cbutton {
  margin: 2px 0.125em 0 0.125em;
  min-width: 6ex;
  max-width: 6ex;
  min-height: 2.3ex;
  max-height: 2.3ex;
  font-size: 120%;
}
body.chat #chat-input-line.compact #chat-buttons-wrapper #chat-button-submit {
  min-width: 12ex;
}
body.chat #chat-input-line:not(.compact) #chat-input-field {
  /*border-left-style: double;
  border-left-width: 3px;
  border-right-style: double;
  border-right-width: 3px;*/
  min-height: 4rem;
  /*max-height: 50rem;*/
/*
  Problems related to max-height:

  - If we do NOT set a max-height then pasting/typing a large amount
  of text can cause this element to grow without bounds, larger than
  the window, and there's no way to navigate it sensibly.  In this
  case, manually resizing the element (desktop only - mobile doesn't
  offer that) will force it to stay at the selected size even if more
  content is added to it later.

  - If we DO set a max-height then its growth is bounded but it also
  cannot manually expanded by the user.

  The lesser of the two evils seems to be to rely on the browser
  feature that a manual resize of the element will pin its sits.
*/
}

body.chat #chat-input-line > #chat-button-settings{
  margin: 0 0 0 0.25em;
  max-width: 2em;
}
body.chat #chat-input-line > input[type=text],
body.chat #chat-input-line > textarea {
  flex: 20 1 auto;
  max-width: revert;
  min-width: 20em;
}
body.chat #chat-input-line.compact > input[type=text] {
  margin: 0 0 0.25em 0/* gap for if/when buttons wrap*/;
}
/* Widget holding the file selection control and preview */
body.chat #chat-input-file-area  {
  display: flex;
  flex-direction: row;
  margin: 0;
}
body.chat #chat-input-file-area > .file-selection-wrapper {
  align-self: flex-start;
  margin-right: 0.5em;
  flex: 0 1 auto;
  padding: 0.25em 0.5em;
  white-space: nowrap;
}
body.chat #chat-input-file {
  border:1px solid rgba(0,0,0,0);/*avoid UI shift during drop-targeting*/
  border-radius: 0.25em;
  padding: 0.25em;
}
body.chat #chat-input-file > input {
  flex: 1 0 auto;
}
/* Indicator when a drag/drop is in progress */
body.chat #chat-input-file.dragover {
  border: 1px dashed green;
}
/* Widget holding the details of a selected/dropped file/image. */
body.chat #chat-drop-details {
  padding: 0 1em;
  white-space: pre;
  font-family: monospace;
  margin: auto;
  flex: 0;
}

body.chat #chat-drop-details img {
  max-width: 45%;
  max-height: 45%;
}
body.chat .chat-view {
  flex: 20 1 auto
  /*ensure that these grow more than the non-.chat-view elements.
    Note that setting flex shrink to 0 breaks/disables scrolling!*/;
  margin-bottom: 0.2em;
}
body.chat #chat-config,
body.chat #chat-preview {
  /* /chat configuration widget */
  display: flex;
  flex-direction: column;
  overflow: auto;
  padding: 0;
  margin: 0;
  align-items: stretch;
  min-height: 6em;
}
body.chat #chat-config #chat-config-options {
  /* /chat config options go here */
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  overflow: auto;
}
body.chat #chat-config #chat-config-options .menu-entry {
  display: flex;
  align-items: baseline;
  flex-direction: row;
  flex-wrap: nowrap;
  padding: 1em;
}
body.chat #chat-config #chat-config-options .menu-entry label[for] {
  cursor: pointer;
}
body.chat #chat-config #chat-config-options .menu-entry > *:first-child {
  min-width: 1.5rem;
}
body.chat #chat-config #chat-config-options .menu-entry span.hint {
  /* Config menu hint text */
  font-size: 80%;
  white-space: pre-wrap;
  display: inline-block;
}
body.chat #chat-config #chat-config-options .menu-entry:first-child {
}
body.chat #chat-config #chat-config-options .menu-entry div.label-wrapper {
  display: flex;
  flex-direction: column;
  align-self: baseline;
  margin-left: 1em;
}
body.chat #chat-config #chat-config-options .menu-entry select {
}
body.chat #chat-preview #chat-preview-content {
  overflow: auto;
  flex: 1 1 auto;
  padding: 0.5em;
  border: 1px dotted;
}
body.chat #chat-preview #chat-preview-content > * {
  margin: 0;
  padding: 0;
}
body.chat #chat-preview #chat-preview-buttons {
  flex: 0 1 auto;
  display: flex;
  flex-direction: column;
}
body.chat #chat-config > button,
body.chat #chat-preview #chat-preview-buttons > button {
  padding: 0.5em;
  flex: 0 1 auto;
  margin: 0.25em 0;
}

body.chat #chat-user-list-wrapper {
  /* Safari can't do fieldsets right, so we emulate one. */
  border-radius: 0.5em;
  margin: 1em 0 0.2em 0;
  padding: 0 0.5em;
  border-style: inset;
  border-width: 0 1px 1px 1px/*else collides with the LEGEND*/;
}
body.chat #chat-user-list-wrapper.collapsed {
  padding: 0;
}
body.chat #chat-user-list-wrapper > .legend {
  font-weight: initial;
  padding: 0 0.5em 0 0.5em;
  position: relative;
  top: -1.75ex/* place it like a fieldset legend */;
  cursor: pointer;
}
body.chat #chat-user-list-wrapper > .legend > * {
  vertical-align: middle;
}
body.chat #chat-user-list-wrapper > .legend > *:nth-child(2){
  /* Title label */
  opacity: 0.6;
  font-size: 0.8em;
}
body.chat #chat-user-list-wrapper.collapsed > .legend > *:nth-child(2)::after {
  content: " (tap to toggle)";
}
body.chat #chat-user-list-wrapper .help-buttonlet {
  margin: 0;
}
body.chat #chat-user-list-wrapper.collapsed #chat-user-list {
  position: absolute !important;
  opacity: 0 !important;
  pointer-events: none !important;
  display: none !important;
}
body.chat #chat-user-list {
  margin-top: -1.25ex;
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  align-items: center;
}
body.chat #chat-user-list .chat-user {
  margin: 0.2em;
  padding: 0.1em 0.5em 0.2em 0.5em;
  border-radius: 0.5em;
  cursor: pointer;
  text-align: center;
  white-space: pre;
}
body.chat #chat-user-list .timestamp {
  font-size: 85%;
  font-family: monospace;
}
body.chat #chat-user-list:not(.timestamps) .timestamp {
  display: none;
}
body.chat #chat-user-list .chat-user.selected {
  font-weight: bold;
  text-decoration: underline;
}

body.chat.fossil-dark-style #chat-button-attach > svg {
  /* The black paperclip is barely visible in dark-mode
     skins when they have dark buttons */
  filter: invert(0.8);
}

body.chat .anim-rotate-360 {
  animation: rotate-360 750ms linear;
}
@keyframes rotate-360 {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}
body.chat .anim-flip-h {
  animation: flip-h 750ms linear;
}
@keyframes flip-h{
  from { transform: rotateY(0deg); }
  to { transform: rotateY(360deg); }
}
body.chat .anim-flip-v {
  animation: flip-v 750ms linear;
}
@keyframes flip-v{
  from { transform: rotateX(0deg); }
  to { transform: rotateX(360deg); }
}
body.chat .anim-fade-in {
  animation: fade-in 750ms linear;
}
body.chat .anim-fade-in-fast {
  animation: fade-in 350ms linear;
}
@keyframes fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}
body.chat .anim-fade-out-fast {
  animation: fade-out 250ms linear;
}
@keyframes fade-out {
  from { opacity: 1; }
  to { opacity: 0; }
}
Changes to src/style.fileedit.css.
68
69
70
71
72
73
74



75
76
77
78
79
80
81
  padding: 0;
}
body.fileedit #fileedit-tabs {
  margin: 0.5em 0 0 0;
}
body.fileedit #fileedit-tab-preview-wrapper {
  overflow: auto;



}
body.fileedit #fileedit-tab-fileselect > h1 {
  margin: 0;
}
body.fileedit .fileedit-options.commit-message > div {
  display: flex;
  flex-direction: column;







>
>
>







68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
  padding: 0;
}
body.fileedit #fileedit-tabs {
  margin: 0.5em 0 0 0;
}
body.fileedit #fileedit-tab-preview-wrapper {
  overflow: auto;
}
body.fileedit #fileedit-tab-preview-wrapper > pre {
  margin: 0;
}
body.fileedit #fileedit-tab-fileselect > h1 {
  margin: 0;
}
body.fileedit .fileedit-options.commit-message > div {
  display: flex;
  flex-direction: column;
160
161
162
163
164
165
166



167
168
169
170
171
172
173

174
175
176
177
178
179
180
body.fileedit .tab-container > .tabs > .tab-panel {
  display: flex;
  flex-direction: column;
}
body.fileedit #fileedit-tab-diff-wrapper {
  margin: 0;
  padding: 0;



  overflow: auto;
  display: flex;
  flex-direction: column;
  align-items: stretch;
}
body.fileedit #fileedit-tab-diff-wrapper > div {
  margin: 0.5em 0 0.5em 0;

}
body.fileedit table.sbsdiffcols {
  /*width: initial;*/
}
body.fileedit #fileedit-tab-diff-wrapper  > pre.udiff {
  margin-top: 0;
}







>
>
>
|
|

|



>







163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
body.fileedit .tab-container > .tabs > .tab-panel {
  display: flex;
  flex-direction: column;
}
body.fileedit #fileedit-tab-diff-wrapper {
  margin: 0;
  padding: 0;
  /*overflow: hidden;*/
  /* ^^^ we "really" want hidden and let a sub-sub-child element
     handle that, but that isn't working, for unknown reasons. */
  overflow-x: auto;
  /*display: flex;
  flex-direction: column;
  align-items: stretch;*/
}
body.fileedit #fileedit-tab-diff-wrapper > div {
  margin: 0.5em 0 0.5em 0;
  overflow-wrap: break-word;
}
body.fileedit table.sbsdiffcols {
  /*width: initial;*/
}
body.fileedit #fileedit-tab-diff-wrapper  > pre.udiff {
  margin-top: 0;
}
Changes to src/style.wikiedit.css.
18
19
20
21
22
23
24






25
26
27
28
29
30
31
  padding: 0;
}
body.wikiedit #wikiedit-tabs {
  margin: 0.5em 0 0 0;
}
body.wikiedit #wikiedit-tab-preview-wrapper {
  overflow: auto;






}
body.wikiedit .tab-container > .tabs > .tab-panel > .wikiedit-options {
  margin-top: 0;
  border: none;
  border-radius: 0;
  border-bottom-width: 1px;
  border-bottom-style: dotted;







>
>
>
>
>
>







18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
  padding: 0;
}
body.wikiedit #wikiedit-tabs {
  margin: 0.5em 0 0 0;
}
body.wikiedit #wikiedit-tab-preview-wrapper {
  overflow: auto;
}
body.wikiedit #wikiedit-tab-diff-wrapper {
  /*overflow: hidden;*/
  /* ^^^ we "really" want hidden and let a sub-sub-child element
     handle that, but that isn't working, for unknown reasons. */
  overflow-x: auto;
}
body.wikiedit .tab-container > .tabs > .tab-panel > .wikiedit-options {
  margin-top: 0;
  border: none;
  border-radius: 0;
  border-bottom-width: 1px;
  border-bottom-style: dotted;
Changes to src/th_lang.c.
255
256
257
258
259
260
261

262
263
264
265
266
267
268
    zList = Th_TakeResult(interp, &nList);
  }

  for(i=2; i<argc; i++){
    Th_ListAppend(interp, &zList, &nList, argv[i], argl[i]);
  }


  Th_SetResult(interp, zList, nList);
  Th_Free(interp, zList);

  return TH_OK;
}









>







255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
    zList = Th_TakeResult(interp, &nList);
  }

  for(i=2; i<argc; i++){
    Th_ListAppend(interp, &zList, &nList, argv[i], argl[i]);
  }

  Th_SetVar(interp, argv[1], argl[1], zList, nList);
  Th_SetResult(interp, zList, nList);
  Th_Free(interp, zList);

  return TH_OK;
}


Changes to src/unversioned.c.
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
void uvlist_json_page(void){
  Stmt q;
  char *zSep = "[";
  Blob json;

  login_check_credentials();
  if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
  cgi_set_content_type("text/json");
  etag_check(ETAG_DATA,0);
  if( !db_table_exists("repository","unversioned") ){
    blob_init(&json, "[]", -1);
    cgi_set_content(&json);
    return;
  }
  blob_init(&json, 0, 0);







|







655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
void uvlist_json_page(void){
  Stmt q;
  char *zSep = "[";
  Blob json;

  login_check_credentials();
  if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
  cgi_set_content_type("application/json");
  etag_check(ETAG_DATA,0);
  if( !db_table_exists("repository","unversioned") ){
    blob_init(&json, "[]", -1);
    cgi_set_content(&json);
    return;
  }
  blob_init(&json, 0, 0);
Changes to src/url.c.
194
195
196
197
198
199
200

201
202
203
204
205
206
207
    if( c==':' ){
      pUrlData->port = 0;
      i++;
      while( (c = zUrl[i])!=0 && fossil_isdigit(c) ){
        pUrlData->port = pUrlData->port*10 + c - '0';
        i++;
      }

      pUrlData->hostname = mprintf("%s:%d", pUrlData->name, pUrlData->port);
    }else{
      pUrlData->port = pUrlData->dfltPort;
      pUrlData->hostname = pUrlData->name;
    }
    dehttpize(pUrlData->name);
    pUrlData->path = mprintf("%s", &zUrl[i]);







>







194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
    if( c==':' ){
      pUrlData->port = 0;
      i++;
      while( (c = zUrl[i])!=0 && fossil_isdigit(c) ){
        pUrlData->port = pUrlData->port*10 + c - '0';
        i++;
      }
      if( c!=0 && c!='/' ) fossil_fatal("url missing '/' after port number");
      pUrlData->hostname = mprintf("%s:%d", pUrlData->name, pUrlData->port);
    }else{
      pUrlData->port = pUrlData->dfltPort;
      pUrlData->hostname = pUrlData->name;
    }
    dehttpize(pUrlData->name);
    pUrlData->path = mprintf("%s", &zUrl[i]);
225
226
227
228
229
230
231

232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
      if( pUrlData->path[i] ){
        pUrlData->path[i] = 0;
        i++;
      }
      if( fossil_strcmp(zName,"fossil")==0 ){
        pUrlData->fossil = zValue;
        dehttpize(pUrlData->fossil);

        zExe = mprintf("%cfossil=%T", cQuerySep, pUrlData->fossil);
        cQuerySep = '&';
      }
    }

    dehttpize(pUrlData->path);
    if( pUrlData->dfltPort==pUrlData->port ){
      pUrlData->canonical = mprintf(
        "%s://%s%T%T%s",
        pUrlData->protocol, zLogin, pUrlData->name, pUrlData->path, zExe
      );
    }else{
      pUrlData->canonical = mprintf(
        "%s://%s%T:%d%T%s",
        pUrlData->protocol, zLogin, pUrlData->name, pUrlData->port,
        pUrlData->path, zExe
      );
    }
    if( pUrlData->isSsh && pUrlData->path[1] ) pUrlData->path++;
    free(zLogin);
  }else if( strncmp(zUrl, "file:", 5)==0 ){







>








|




|







226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
      if( pUrlData->path[i] ){
        pUrlData->path[i] = 0;
        i++;
      }
      if( fossil_strcmp(zName,"fossil")==0 ){
        pUrlData->fossil = zValue;
        dehttpize(pUrlData->fossil);
        fossil_free(zExe);
        zExe = mprintf("%cfossil=%T", cQuerySep, pUrlData->fossil);
        cQuerySep = '&';
      }
    }

    dehttpize(pUrlData->path);
    if( pUrlData->dfltPort==pUrlData->port ){
      pUrlData->canonical = mprintf(
        "%s://%s%T%T%z",
        pUrlData->protocol, zLogin, pUrlData->name, pUrlData->path, zExe
      );
    }else{
      pUrlData->canonical = mprintf(
        "%s://%s%T:%d%T%z",
        pUrlData->protocol, zLogin, pUrlData->name, pUrlData->port,
        pUrlData->path, zExe
      );
    }
    if( pUrlData->isSsh && pUrlData->path[1] ) pUrlData->path++;
    free(zLogin);
  }else if( strncmp(zUrl, "file:", 5)==0 ){
293
294
295
296
297
298
299















300
301
302
303
304
305
306
        pUrlData->flags = urlFlags |= URL_REMEMBER_PW;
      }else{
        pUrlData->flags = urlFlags &= ~URL_REMEMBER_PW;
      }
    }
  }
}
















/*
** Parse the given URL, which describes a sync server.  Populate variables
** in the global "g.url" structure as shown below.  If zUrl is NULL, then
** parse the URL given in the last-sync-url setting, taking the password
** form last-sync-pw.
**







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







295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
        pUrlData->flags = urlFlags |= URL_REMEMBER_PW;
      }else{
        pUrlData->flags = urlFlags &= ~URL_REMEMBER_PW;
      }
    }
  }
}

/*
** Reclaim malloced memory from a UrlData object
*/
void url_unparse(UrlData *p){
  if( p==0 ){
    p = &g.url;
  }
  fossil_free(p->canonical);
  fossil_free(p->name);
  fossil_free(p->path);
  fossil_free(p->user);
  fossil_free(p->passwd);
  memset(p, 0, sizeof(*p));
}

/*
** Parse the given URL, which describes a sync server.  Populate variables
** in the global "g.url" structure as shown below.  If zUrl is NULL, then
** parse the URL given in the last-sync-url setting, taking the password
** form last-sync-pw.
**
367
368
369
370
371
372
373

374
375
376
377
378
379
380
    fossil_print("g.url.fossil    = %s\n", g.url.fossil);
    fossil_print("g.url.flags     = 0x%02x\n", g.url.flags);
    if( g.url.isFile || g.url.isSsh ) break;
    if( i==0 ){
      fossil_print("********\n");
      url_enable_proxy("Using proxy: ");
    }

  }
}

/*
** Proxy specified on the command-line using the --proxy option.
** If there is no --proxy option on the command-line then this
** variable holds a NULL pointer.







>







384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
    fossil_print("g.url.fossil    = %s\n", g.url.fossil);
    fossil_print("g.url.flags     = 0x%02x\n", g.url.flags);
    if( g.url.isFile || g.url.isSsh ) break;
    if( i==0 ){
      fossil_print("********\n");
      url_enable_proxy("Using proxy: ");
    }
    url_unparse(0);
  }
}

/*
** Proxy specified on the command-line using the --proxy option.
** If there is no --proxy option on the command-line then this
** variable holds a NULL pointer.
657
658
659
660
661
662
663
664

665
666
667
668
669
670
671
  if( sqlite3_strnicmp(zTail, "www.", 4)==0 && strchr(zTail+4,'.')!=0 ){
    /* Remove the "www." prefix if there are more "." characters later.
    ** But don't remove the "www." prefix if what follows is the suffix.
    ** forum:/forumpost/74e111a2ee */
    zTail += 4;
  }
  if( zTail[0]==0 ) return 0;
  for(i=0; zTail[i] && zTail[i]!='.' && zTail[i]!='?'; i++){}

  if( i==0 ) return 0;
  return mprintf("%.*s", i, zTail);
}

/*
** COMMAND: test-url-basename
** Usage: %fossil test-url-basenames URL ...







|
>







675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
  if( sqlite3_strnicmp(zTail, "www.", 4)==0 && strchr(zTail+4,'.')!=0 ){
    /* Remove the "www." prefix if there are more "." characters later.
    ** But don't remove the "www." prefix if what follows is the suffix.
    ** forum:/forumpost/74e111a2ee */
    zTail += 4;
  }
  if( zTail[0]==0 ) return 0;
  for(i=0; zTail[i] && zTail[i]!='.' && zTail[i]!='?' &&
           zTail[i]!=':' && zTail[i]!='/'; i++){}
  if( i==0 ) return 0;
  return mprintf("%.*s", i, zTail);
}

/*
** COMMAND: test-url-basename
** Usage: %fossil test-url-basenames URL ...
Changes to src/utf8.c.
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
  assert( 0 );  /* Never used in unix */
  return fossil_strdup(zUtf8);  /* TODO: implement for unix */
#endif
}

/*
** Deallocate any memory that was previously allocated by
** fossil_unicode_to_utf8().
*/
void fossil_unicode_free(void *pOld){
  fossil_free(pOld);
}

#if defined(__APPLE__) && !defined(WITHOUT_ICONV)
# include <iconv.h>







|







86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
  assert( 0 );  /* Never used in unix */
  return fossil_strdup(zUtf8);  /* TODO: implement for unix */
#endif
}

/*
** Deallocate any memory that was previously allocated by
** fossil_unicode_to_utf8() or fossil_utf8_to_unicode().
*/
void fossil_unicode_free(void *pOld){
  fossil_free(pOld);
}

#if defined(__APPLE__) && !defined(WITHOUT_ICONV)
# include <iconv.h>
Changes to src/util.c.
29
30
31
32
33
34
35


36
37
38
39
40
41
42
** For the fossil_timer_xxx() family of functions...
*/
#ifdef _WIN32
# include <windows.h>
#else
# include <sys/time.h>
# include <sys/resource.h>


# include <unistd.h>
# include <fcntl.h>
# include <errno.h>
#endif

/*
** Exit.  Take care to close the database first.







>
>







29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
** For the fossil_timer_xxx() family of functions...
*/
#ifdef _WIN32
# include <windows.h>
#else
# include <sys/time.h>
# include <sys/resource.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <unistd.h>
# include <fcntl.h>
# include <errno.h>
#endif

/*
** Exit.  Take care to close the database first.
644
645
646
647
648
649
650
651













652





653




654
655


656














657

658

659
660
661
662
663
664
665
** Construct a temporary filename.
**
** The returned string is obtained from sqlite3_malloc() and must be
** freed by the caller.
*/
char *fossil_temp_filename(void){
  char *zTFile = 0;
  sqlite3 *db;













  if( g.db ){





    db = g.db;




  }else{
    sqlite3_open("",&db);


  }














  sqlite3_file_control(db, 0, SQLITE_FCNTL_TEMPFILENAME, (void*)&zTFile);

  if( g.db==0 ) sqlite3_close(db);

  return zTFile;
}

/*
** Turn memory limits for stack and heap on and off.  The argument
** is true to turn memory limits on and false to turn them off.
**







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

>
>
>
>
>
|
>
>
>
>

<
>
>

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







646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678

679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
** Construct a temporary filename.
**
** The returned string is obtained from sqlite3_malloc() and must be
** freed by the caller.
*/
char *fossil_temp_filename(void){
  char *zTFile = 0;
  const char *zDir;
  char cDirSep;
  char zSep[2];
  size_t nDir;
  u64 r[2];
#ifdef _WIN32
  char *zTempDirA = NULL;
  WCHAR zTempDirW[MAX_PATH+1];
  const DWORD dwTempSizeW = sizeof(zTempDirW)/sizeof(zTempDirW[0]);
  DWORD dwTempLenW;
#else
  int i;
  static const char *azTmp[] = {"/var/tmp","/usr/tmp","/tmp"};
#endif
  if( g.db ){
    sqlite3_file_control(g.db, 0, SQLITE_FCNTL_TEMPFILENAME, (void*)&zTFile);
    if( zTFile ) return zTFile;
  }
  sqlite3_randomness(sizeof(r), &r);
#if _WIN32
  cDirSep = '\\';
  dwTempLenW = GetTempPathW(dwTempSizeW, zTempDirW);
  if( dwTempLenW>0 && dwTempLenW<dwTempSizeW
      && ( zTempDirA = fossil_path_to_utf8(zTempDirW) )){
    zDir = zTempDirA;
  }else{

    zDir = fossil_getenv("LOCALAPPDATA");
    if( zDir==0 ) zDir = ".";
  }
#else
  for(i=0; i<sizeof(azTmp)/sizeof(azTmp[0]); i++){
    struct stat buf;
    zDir = azTmp[i];
    if( stat(zDir,&buf)==0 && S_ISDIR(buf.st_mode) && access(zDir,03)==0 ){
      break;
    }
  }
  if( i>=sizeof(azTmp)/sizeof(azTmp[0]) ) zDir = ".";
  cDirSep = '/';
#endif
  nDir = strlen(zDir);
  zSep[1] = 0;
  zSep[0] = (nDir && zDir[nDir-1]==cDirSep) ? 0 : cDirSep;
  zTFile = sqlite3_mprintf("%s%sfossil%016llx%016llx", zDir,zSep,r[0],r[1]);
#ifdef _WIN32
  if( zTempDirA ) fossil_path_free(zTempDirA);
#endif
  return zTFile;
}

/*
** Turn memory limits for stack and heap on and off.  The argument
** is true to turn memory limits on and false to turn them off.
**
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845

/*
** Return the name of a command that will launch a web-browser.
*/
const char *fossil_web_browser(void){
  const char *zBrowser = 0;
#if defined(_WIN32)
  zBrowser = db_get("web-browser", "start");
#elif defined(__DARWIN__) || defined(__APPLE__) || defined(__HAIKU__)
  zBrowser = db_get("web-browser", "open");
#else
  zBrowser = db_get("web-browser", 0);
  if( zBrowser==0 ){
    static const char *const azBrowserProg[] =
        { "xdg-open", "gnome-open", "firefox", "google-chrome" };







|







872
873
874
875
876
877
878
879
880
881
882
883
884
885
886

/*
** Return the name of a command that will launch a web-browser.
*/
const char *fossil_web_browser(void){
  const char *zBrowser = 0;
#if defined(_WIN32)
  zBrowser = db_get("web-browser", "start \"\"");
#elif defined(__DARWIN__) || defined(__APPLE__) || defined(__HAIKU__)
  zBrowser = db_get("web-browser", "open");
#else
  zBrowser = db_get("web-browser", 0);
  if( zBrowser==0 ){
    static const char *const azBrowserProg[] =
        { "xdg-open", "gnome-open", "firefox", "google-chrome" };
Changes to src/wiki.c.
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
    while( zPathInfo[0]=='/' ) zPathInfo++;
    if( fossil_strcmp(zIndexPage, zPathInfo)==0 ) zIndexPage = 0;
  }
  if( zIndexPage ){
    cgi_redirectf("%R/%s", zIndexPage);
  }
  if( !g.perm.RdWiki ){
    cgi_redirectf("%R/login?g=%R/home");
  }
  if( zPageName ){
    login_check_credentials();
    g.zExtra = zPageName;
    cgi_set_parameter_nocopy("name", g.zExtra, 1);
    g.isHome = 1;
    wiki_page();







|







141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
    while( zPathInfo[0]=='/' ) zPathInfo++;
    if( fossil_strcmp(zIndexPage, zPathInfo)==0 ) zIndexPage = 0;
  }
  if( zIndexPage ){
    cgi_redirectf("%R/%s", zIndexPage);
  }
  if( !g.perm.RdWiki ){
    cgi_redirectf("%R/login?g=home");
  }
  if( zPageName ){
    login_check_credentials();
    g.zExtra = zPageName;
    cgi_set_parameter_nocopy("name", g.zExtra, 1);
    g.isHome = 1;
    wiki_page();
744
745
746
747
748
749
750



751

752
753
754
755
756
757
758
    blob_init(&wiki, zBody, -1);
    safe_html_context(DOCSRC_WIKI);
    wiki_render_by_mimetype(&wiki, zMimetype);
    blob_reset(&wiki);
  }
  manifest_destroy(pWiki);
  if( !isPopup ){



    attachment_list(zPageName, "<hr /><h2>Attachments:</h2><ul>");

    document_emit_js(/*for optional pikchr support*/);
    style_finish_page();
  }
}

/*
** Write a wiki artifact into the repository







>
>
>
|
>







744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
    blob_init(&wiki, zBody, -1);
    safe_html_context(DOCSRC_WIKI);
    wiki_render_by_mimetype(&wiki, zMimetype);
    blob_reset(&wiki);
  }
  manifest_destroy(pWiki);
  if( !isPopup ){
    char * zLabel = mprintf("<hr /><h2><a href='%R/attachlist?name=%T'>"
                            "Attachments</a>:</h2><ul>",
                            zPageName);
    attachment_list(zPageName, zLabel);
    fossil_free(zLabel);
    document_emit_js(/*for optional pikchr support*/);
    style_finish_page();
  }
}

/*
** Write a wiki artifact into the repository
1190
1191
1192
1193
1194
1195
1196

1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213



1214
1215
1216
1217
1218
1219
1220
1221
1222
1223

1224
1225
1226
1227
1228
1229
1230
*/
static void wiki_ajax_route_diff(void){
  const char * zPageName = P("page");
  Blob contentNew = empty_blob, contentOrig = empty_blob;
  Manifest * pParent = 0;
  const char * zContent = P("content");
  u64 diffFlags = DIFF_HTML | DIFF_NOTTOOBIG | DIFF_STRIP_EOLCR;


  if( zPageName==0 || zPageName[0]==0 ){
    ajax_route_error(400,"Missing page name.");
    return;
  }else if(!wiki_ajax_can_write(zPageName, 0)){
    return;
  }
  switch(atoi(PD("sbs","0"))){
    case 0: diffFlags |= DIFF_LINENO; break;
    default: diffFlags |= DIFF_SIDEBYSIDE;
  }
  switch(atoi(PD("ws","2"))){
    case 1: diffFlags |= DIFF_IGNORE_EOLWS; break;
    case 2: diffFlags |= DIFF_IGNORE_ALLWS; break;
    default: break;
  }
  wiki_fetch_by_name( zPageName, 0, 0, &pParent );



  if( pParent && pParent->zWiki && *pParent->zWiki ){
    blob_init(&contentOrig, pParent->zWiki, -1);
  }else{
    blob_init(&contentOrig, "", 0);
  }
  blob_init(&contentNew, zContent ? zContent : "", -1);
  cgi_set_content_type("text/html");
  ajax_render_diff(&contentOrig, &contentNew, diffFlags);
  blob_reset(&contentNew);
  blob_reset(&contentOrig);

  manifest_destroy(pParent);
}

/*
** Ajax route handler for /wikiajax/preview.
**
** URL params:







>

















>
>
>







|


>







1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
*/
static void wiki_ajax_route_diff(void){
  const char * zPageName = P("page");
  Blob contentNew = empty_blob, contentOrig = empty_blob;
  Manifest * pParent = 0;
  const char * zContent = P("content");
  u64 diffFlags = DIFF_HTML | DIFF_NOTTOOBIG | DIFF_STRIP_EOLCR;
  char * zParentUuid = 0;

  if( zPageName==0 || zPageName[0]==0 ){
    ajax_route_error(400,"Missing page name.");
    return;
  }else if(!wiki_ajax_can_write(zPageName, 0)){
    return;
  }
  switch(atoi(PD("sbs","0"))){
    case 0: diffFlags |= DIFF_LINENO; break;
    default: diffFlags |= DIFF_SIDEBYSIDE;
  }
  switch(atoi(PD("ws","2"))){
    case 1: diffFlags |= DIFF_IGNORE_EOLWS; break;
    case 2: diffFlags |= DIFF_IGNORE_ALLWS; break;
    default: break;
  }
  wiki_fetch_by_name( zPageName, 0, 0, &pParent );
  if( pParent ){
    zParentUuid = rid_to_uuid(pParent->rid);
  }
  if( pParent && pParent->zWiki && *pParent->zWiki ){
    blob_init(&contentOrig, pParent->zWiki, -1);
  }else{
    blob_init(&contentOrig, "", 0);
  }
  blob_init(&contentNew, zContent ? zContent : "", -1);
  cgi_set_content_type("text/html");
  ajax_render_diff(&contentOrig, zParentUuid, &contentNew, diffFlags);
  blob_reset(&contentNew);
  blob_reset(&contentOrig);
  fossil_free(zParentUuid);
  manifest_destroy(pParent);
}

/*
** Ajax route handler for /wikiajax/preview.
**
** URL params:
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
  const int includeContent = ajax_p_bool("includeContent");

  cgi_set_content_type("application/json");
  wiki_render_page_list_json(verbose, includeContent);
}

/*
** WEBPAGE: wikiajax
**
** An internal dispatcher for wiki AJAX operations. Not for direct
** client use. All routes defined by this interface are app-internal,
** subject to change 
*/
void wiki_ajax_page(void){
  const char * zName = P("name");







|







1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
  const int includeContent = ajax_p_bool("includeContent");

  cgi_set_content_type("application/json");
  wiki_render_page_list_json(verbose, includeContent);
}

/*
** WEBPAGE: wikiajax hidden
**
** An internal dispatcher for wiki AJAX operations. Not for direct
** client use. All routes defined by this interface are app-internal,
** subject to change 
*/
void wiki_ajax_page(void){
  const char * zName = P("name");
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
    CX("<h2>Wiki Name Rules</h2>");
    well_formed_wiki_name_rules();
    CX("</div>"/*#wikiedit-tab-save*/);
  }
  builtin_fossil_js_bundle_or("fetch", "dom", "tabs", "confirmer",
                              "storage", "popupwidget", "copybutton",
                              "pikchr", NULL);
  builtin_request_js("sbsdiff.js");
  builtin_request_js("fossil.page.wikiedit.js");
  builtin_fulfill_js_requests();
  /* Dynamically populate the editor... */
  style_script_begin(__FILE__,__LINE__);
  {
    /* Render the current page list to save us an XHR request
       during page initialization. This must be OUTSIDE of







|







1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
    CX("<h2>Wiki Name Rules</h2>");
    well_formed_wiki_name_rules();
    CX("</div>"/*#wikiedit-tab-save*/);
  }
  builtin_fossil_js_bundle_or("fetch", "dom", "tabs", "confirmer",
                              "storage", "popupwidget", "copybutton",
                              "pikchr", NULL);
  builtin_fossil_js_bundle_or("diff", NULL);
  builtin_request_js("fossil.page.wikiedit.js");
  builtin_fulfill_js_requests();
  /* Dynamically populate the editor... */
  style_script_begin(__FILE__,__LINE__);
  {
    /* Render the current page list to save us an XHR request
       during page initialization. This must be OUTSIDE of
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
*/
void wdiff_page(void){
  const char *zId;
  const char *zPid;
  Manifest *pW1, *pW2 = 0;
  int rid1, rid2, nextRid;
  Blob w1, w2, d;
  u64 diffFlags;

  login_check_credentials();
  if( !g.perm.RdWiki ){ login_needed(g.anon.RdWiki); return; }
  zId = P("id");
  if( zId==0 ){
    rid1 = atoi(PD("rid","0"));
  }else{







|







1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
*/
void wdiff_page(void){
  const char *zId;
  const char *zPid;
  Manifest *pW1, *pW2 = 0;
  int rid1, rid2, nextRid;
  Blob w1, w2, d;
  DiffConfig DCfg;

  login_check_credentials();
  if( !g.perm.RdWiki ){ login_needed(g.anon.RdWiki); return; }
  zId = P("id");
  if( zId==0 ){
    rid1 = atoi(PD("rid","0"));
  }else{
1986
1987
1988
1989
1990
1991
1992
1993

1994
1995
1996
1997
1998
1999
2000
2001
  nextRid = wiki_next(wiki_tagid(pW1->zWikiTitle),pW1->rDate);
  if( nextRid ){
    style_submenu_element("Next", "%R/wdiff?rid=%d", nextRid);
  }
  style_set_current_feature("wiki");
  style_header("Changes To %s", pW1->zWikiTitle);
  blob_zero(&d);
  diffFlags = construct_diff_flags(1);

  text_diff(&w2, &w1, &d, 0, diffFlags | DIFF_HTML | DIFF_LINENO);
  @ <pre class="udiff">
  @ %s(blob_str(&d))
  @ <pre>
  manifest_destroy(pW1);
  manifest_destroy(pW2);
  style_finish_page();
}







|
>
|







1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
  nextRid = wiki_next(wiki_tagid(pW1->zWikiTitle),pW1->rDate);
  if( nextRid ){
    style_submenu_element("Next", "%R/wdiff?rid=%d", nextRid);
  }
  style_set_current_feature("wiki");
  style_header("Changes To %s", pW1->zWikiTitle);
  blob_zero(&d);
  construct_diff_flags(1, &DCfg);
  DCfg.diffFlags |= DIFF_HTML | DIFF_LINENO;
  text_diff(&w2, &w1, &d, &DCfg);
  @ <pre class="udiff">
  @ %s(blob_str(&d))
  @ <pre>
  manifest_destroy(pW1);
  manifest_destroy(pW2);
  style_finish_page();
}
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
  db_begin_transaction();
  wiki_put(&wiki, 0, wiki_need_moderation(localUser));
  db_end_transaction(0);
  return 1;
}

/*
** Determine the rid for a tech note given either its id or its
** timestamp. Returns 0 if there is no such item and -1 if the details
** are ambiguous and could refer to multiple items.
*/
int wiki_technote_to_rid(const char *zETime) {
  int rid=0;                    /* Artifact ID of the tech note */
  int nETime = strlen(zETime);
  Stmt q;
  if( nETime>=4 && nETime<=HNAME_MAX && validate16(zETime, nETime) ){







|
|







2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
  db_begin_transaction();
  wiki_put(&wiki, 0, wiki_need_moderation(localUser));
  db_end_transaction(0);
  return 1;
}

/*
** Determine the rid for a tech note given either its id, its timestamp,
** or its tag. Returns 0 if there is no such item and -1 if the details
** are ambiguous and could refer to multiple items.
*/
int wiki_technote_to_rid(const char *zETime) {
  int rid=0;                    /* Artifact ID of the tech note */
  int nETime = strlen(zETime);
  Stmt q;
  if( nETime>=4 && nETime<=HNAME_MAX && validate16(zETime, nETime) ){
2241
2242
2243
2244
2245
2246
2247





















2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272

2273
2274
2275
2276
2277
2278
2279
                      " WHERE datetime(mtime)=datetime('%q')"
                      "   AND type='e'"
                      "   AND tagid IS NOT NULL"
                      " ORDER BY objid DESC LIMIT 1",
                   zETime);
    }
  }





















  return rid;
}

/*
** COMMAND: wiki*
**
** Usage: %fossil wiki (export|create|commit|list) WikiName
**
** Run various subcommands to work with wiki entries or tech notes.
**
** > fossil wiki export ?OPTIONS? PAGENAME ?FILE?
** > fossil wiki export ?OPTIONS? -t|--technote DATETIME|TECHNOTE-ID ?FILE?
**
**       Sends the latest version of either a wiki page or of a tech
**       note to the given file or standard output.  A filename of "-"
**       writes the output to standard output.  The directory parts of
**       the output filename are created if needed.
**       If PAGENAME is provided, the named wiki page will be output.
**
**       Options:
**         -t|--technote DATETIME|TECHNOTE-ID
**                    Specifies that a technote, rather than a wiki page,
**                    will be exported. If DATETIME is used, the most
**                    recently modified tech note with that DATETIME will
**                    output.

**         -h|--html  The body (only) is rendered in HTML form, without
**                    any page header/foot or HTML/BODY tag wrappers.
**         -H|--HTML  Works like -h|-html but wraps the output in
**                    <html><body>...</body></html>.
**         -p|--pre   If -h|-H is used and the page or technote has
**                    the text/plain mimetype, its HTML-escaped output
**                    will be wrapped in <pre>...</pre>.







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











|








|



|
>







2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
                      " WHERE datetime(mtime)=datetime('%q')"
                      "   AND type='e'"
                      "   AND tagid IS NOT NULL"
                      " ORDER BY objid DESC LIMIT 1",
                   zETime);
    }
  }
  if( !rid ) {
      /*
      ** At present, technote tags are prefixed with 'sym-', which shouldn't
      ** be the case, so we check for both with and without the prefix until
      ** such time as tags have the errant prefix dropped.
      */
      rid = db_int(0, "SELECT e.objid"
		      "  FROM event e, tag t, tagxref tx"
		      " WHERE e.type='e'"
		      "   AND e.tagid IS NOT NULL"
		      "   AND e.objid IN"
                      "       (SELECT rid FROM tagxref"
                      "         WHERE tagid=(SELECT tagid FROM tag"
                      "                       WHERE tagname GLOB '%q'))"
		      "    OR e.objid IN"
                      "       (SELECT rid FROM tagxref"
                      "         WHERE tagid=(SELECT tagid FROM tag"
                      "                       WHERE tagname GLOB 'sym-%q'))"
		      "   ORDER BY e.mtime DESC LIMIT 1",
		   zETime, zETime);
  }
  return rid;
}

/*
** COMMAND: wiki*
**
** Usage: %fossil wiki (export|create|commit|list) WikiName
**
** Run various subcommands to work with wiki entries or tech notes.
**
** > fossil wiki export ?OPTIONS? PAGENAME ?FILE?
** > fossil wiki export ?OPTIONS? -t|--technote DATETIME|TECHNOTE-ID|TAG ?FILE?
**
**       Sends the latest version of either a wiki page or of a tech
**       note to the given file or standard output.  A filename of "-"
**       writes the output to standard output.  The directory parts of
**       the output filename are created if needed.
**       If PAGENAME is provided, the named wiki page will be output.
**
**       Options:
**         -t|--technote DATETIME|TECHNOTE-ID|TAG
**                    Specifies that a technote, rather than a wiki page,
**                    will be exported. If DATETIME is used, the most
**                    recently modified tech note with that DATETIME will
**                    output. If TAG is used, the most recently modified
**                    tech note with that TAG will be output.
**         -h|--html  The body (only) is rendered in HTML form, without
**                    any page header/foot or HTML/BODY tag wrappers.
**         -H|--HTML  Works like -h|-html but wraps the output in
**                    <html><body>...</body></html>.
**         -p|--pre   If -h|-H is used and the page or technote has
**                    the text/plain mimetype, its HTML-escaped output
**                    will be wrapped in <pre>...</pre>.
2313
2314
2315
2316
2317
2318
2319


2320
2321
2322
2323
2324
2325
2326
** > fossil wiki list ?OPTIONS?
** > fossil wiki ls ?OPTIONS?
**
**       Lists all wiki entries, one per line, ordered
**       case-insensitively by name.
**
**       Options:


**         -t|--technote               Technotes will be listed instead of
**                                     pages. The technotes will be in order
**                                     of timestamp with the most recent
**                                     first.
**         -s|--show-technote-ids      The id of the tech note will be listed
**                                     along side the timestamp. The tech note
**                                     id will be the first word on each line.







>
>







2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
** > fossil wiki list ?OPTIONS?
** > fossil wiki ls ?OPTIONS?
**
**       Lists all wiki entries, one per line, ordered
**       case-insensitively by name.
**
**       Options:
**         --all                       Include "deleted" pages in output.
**                                     By default deleted pages are elided.
**         -t|--technote               Technotes will be listed instead of
**                                     pages. The technotes will be in order
**                                     of timestamp with the most recent
**                                     first.
**         -s|--show-technote-ids      The id of the tech note will be listed
**                                     along side the timestamp. The tech note
**                                     id will be the first word on each line.
2336
2337
2338
2339
2340
2341
2342

2343
2344
2345
2346
2347
2348
2349
** The "Sandbox" wiki pseudo-page is a special case. Its name is
** checked case-insensitively and either "create" or "commit" may be
** used to update its contents.
*/
void wiki_cmd(void){
  int n;
  int isSandbox = 0;     /* true if dealing with sandbox pseudo-page */


  db_find_and_open_repository(0, 0);
  if( g.argc<3 ){
    goto wiki_cmd_usage;
  }
  n = strlen(g.argv[2]);
  if( n==0 ){







>







2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
** The "Sandbox" wiki pseudo-page is a special case. Its name is
** checked case-insensitively and either "create" or "commit" may be
** used to update its contents.
*/
void wiki_cmd(void){
  int n;
  int isSandbox = 0;     /* true if dealing with sandbox pseudo-page */
  const int showAll = find_option("all", 0, 0)!=0;

  db_find_and_open_repository(0, 0);
  if( g.argc<3 ){
    goto wiki_cmd_usage;
  }
  n = strlen(g.argv[2]);
  if( n==0 ){
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573




2574
2575
2576
2577
2578
2579
2580
  }else if(( strncmp(g.argv[2],"list",n)==0 )
          || ( strncmp(g.argv[2],"ls",n)==0 )){
    Stmt q;
    const int fTechnote = find_option("technote","t",0)!=0;
    const int showIds = find_option("show-technote-ids","s",0)!=0;
    verify_all_options();
    if (fTechnote==0){
      db_prepare(&q,
        "SELECT substr(tagname, 6) FROM tag WHERE tagname GLOB 'wiki-*'"
        " ORDER BY lower(tagname) /*sort*/"
      );
    }else{
      db_prepare(&q,
        "SELECT datetime(e.mtime), substr(t.tagname,7)"
         " FROM event e, tag t"
        " WHERE e.type='e'"
          " AND e.tagid IS NOT NULL"
          " AND t.tagid=e.tagid"
        " ORDER BY e.mtime DESC /*sort*/"
      );
    }
    while( db_step(&q)==SQLITE_ROW ){
      const char *zName = db_column_text(&q, 0);




      if( showIds ){
        const char *zUuid = db_column_text(&q, 1);
        fossil_print("%s ",zUuid);
      }
      fossil_print( "%s\n",zName);
    }
    db_finalize(&q);







|
<
<
<


|









>
>
>
>







2586
2587
2588
2589
2590
2591
2592
2593



2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
  }else if(( strncmp(g.argv[2],"list",n)==0 )
          || ( strncmp(g.argv[2],"ls",n)==0 )){
    Stmt q;
    const int fTechnote = find_option("technote","t",0)!=0;
    const int showIds = find_option("show-technote-ids","s",0)!=0;
    verify_all_options();
    if (fTechnote==0){
      db_prepare(&q, listAllWikiPages/*works-like:""*/);



    }else{
      db_prepare(&q,
        "SELECT datetime(e.mtime), substr(t.tagname,7), e.objid"
         " FROM event e, tag t"
        " WHERE e.type='e'"
          " AND e.tagid IS NOT NULL"
          " AND t.tagid=e.tagid"
        " ORDER BY e.mtime DESC /*sort*/"
      );
    }
    while( db_step(&q)==SQLITE_ROW ){
      const char *zName = db_column_text(&q, 0);
      const int wrid = db_column_int(&q, 2);
      if(!showAll && !wrid){
        continue;
      }
      if( showIds ){
        const char *zUuid = db_column_text(&q, 1);
        fossil_print("%s ",zUuid);
      }
      fossil_print( "%s\n",zName);
    }
    db_finalize(&q);
Changes to src/wikiformat.c.
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
  int i;

  for(i=2; i<g.argc; i++){
    blob_read_from_file(&in, g.argv[i], ExtFILE);
    blob_zero(&out);
    htmlTidy(blob_str(&in), &out);
    blob_reset(&in);
    fossil_puts(blob_str(&out), 0);
    blob_reset(&out);
  }
}

/*
** Remove all HTML markup from the input text.  The output written into
** pOut is pure text.







|







2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
  int i;

  for(i=2; i<g.argc; i++){
    blob_read_from_file(&in, g.argv[i], ExtFILE);
    blob_zero(&out);
    htmlTidy(blob_str(&in), &out);
    blob_reset(&in);
    fossil_puts(blob_buffer(&out), 0, blob_size(&out));
    blob_reset(&out);
  }
}

/*
** Remove all HTML markup from the input text.  The output written into
** pOut is pure text.
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
  int i;

  for(i=2; i<g.argc; i++){
    blob_read_from_file(&in, g.argv[i], ExtFILE);
    blob_zero(&out);
    html_to_plaintext(blob_str(&in), &out);
    blob_reset(&in);
    fossil_puts(blob_str(&out), 0);
    blob_reset(&out);
  }
}

/****************************************************************************
** safe-html:
**







|







2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
  int i;

  for(i=2; i<g.argc; i++){
    blob_read_from_file(&in, g.argv[i], ExtFILE);
    blob_zero(&out);
    html_to_plaintext(blob_str(&in), &out);
    blob_reset(&in);
    fossil_puts(blob_buffer(&out), 0, blob_size(&out));
    blob_reset(&out);
  }
}

/****************************************************************************
** safe-html:
**
Changes to src/xfer.c.
1866
1867
1868
1869
1870
1871
1872

1873
1874
1875
1876
1877
1878
1879
  double rArrivalTime;    /* Time at which a message arrived */
  const char *zSCode = db_get("server-code", "x");
  const char *zPCode = db_get("project-code", 0);
  int nErr = 0;           /* Number of errors */
  int nRoundtrip= 0;      /* Number of HTTP requests */
  int nArtifactSent = 0;  /* Total artifacts sent */
  int nArtifactRcvd = 0;  /* Total artifacts received */

  const char *zOpType = 0;/* Push, Pull, Sync, Clone */
  double rSkew = 0.0;     /* Maximum time skew */
  int uvHashSent = 0;     /* The "pragma uv-hash" message has been sent */
  int uvDoPush = 0;       /* Generate uvfile messages to send to server */
  int uvPullOnly = 0;     /* 1: pull-only.  2: pull-only warning issued */
  int nUvGimmeSent = 0;   /* Number of uvgimme cards sent on this cycle */
  int nUvFileRcvd = 0;    /* Number of uvfile cards received on this cycle */







>







1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
  double rArrivalTime;    /* Time at which a message arrived */
  const char *zSCode = db_get("server-code", "x");
  const char *zPCode = db_get("project-code", 0);
  int nErr = 0;           /* Number of errors */
  int nRoundtrip= 0;      /* Number of HTTP requests */
  int nArtifactSent = 0;  /* Total artifacts sent */
  int nArtifactRcvd = 0;  /* Total artifacts received */
  int nPriorArtifact = 0; /* Artifacts received on prior round-trips */
  const char *zOpType = 0;/* Push, Pull, Sync, Clone */
  double rSkew = 0.0;     /* Maximum time skew */
  int uvHashSent = 0;     /* The "pragma uv-hash" message has been sent */
  int uvDoPush = 0;       /* Generate uvfile messages to send to server */
  int uvPullOnly = 0;     /* 1: pull-only.  2: pull-only warning issued */
  int nUvGimmeSent = 0;   /* Number of uvgimme cards sent on this cycle */
  int nUvFileRcvd = 0;    /* Number of uvfile cards received on this cycle */
2194
2195
2196
2197
2198
2199
2200

2201
2202
2203
2204
2205
2206
2207
    if( syncFlags & SYNC_PUSH ){
      blob_appendf(&send, "push %s %s\n", zSCode, zPCode);
      nCardSent++;
    }
    go = 0;
    nUvGimmeSent = 0;
    nUvFileRcvd = 0;


    /* Process the reply that came back from the server */
    while( blob_line(&recv, &xfer.line) ){
      if( blob_buffer(&xfer.line)[0]=='#' ){
        const char *zLine = blob_buffer(&xfer.line);
        if( memcmp(zLine, "# timestamp ", 12)==0 ){
          char zTime[20];







>







2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
    if( syncFlags & SYNC_PUSH ){
      blob_appendf(&send, "push %s %s\n", zSCode, zPCode);
      nCardSent++;
    }
    go = 0;
    nUvGimmeSent = 0;
    nUvFileRcvd = 0;
    nPriorArtifact = nArtifactRcvd;

    /* Process the reply that came back from the server */
    while( blob_line(&recv, &xfer.line) ){
      if( blob_buffer(&xfer.line)[0]=='#' ){
        const char *zLine = blob_buffer(&xfer.line);
        if( memcmp(zLine, "# timestamp ", 12)==0 ){
          char zTime[20];
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642












2643






2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
      fossil_print(zBriefFormat /*works-like:"%d%d%d"*/,
                   nRoundtrip, nArtifactSent, nArtifactRcvd);
    }
    nUncRcvd += blob_size(&recv);
    blob_reset(&recv);
    nCycle++;

    /* If we received one or more files on the previous exchange but
    ** there are still phantoms, then go another round.
    */
    nFileRecv = xfer.nFileRcvd + xfer.nDeltaRcvd + xfer.nDanglingFile;
    if( (nFileRecv>0 || newPhantom) && db_exists("SELECT 1 FROM phantom") ){
      go = 1;
      mxPhantomReq = nFileRecv*2;
      if( mxPhantomReq<200 ) mxPhantomReq = 200;
    }else if( (syncFlags & SYNC_CLONE)!=0 && nFileRecv>0 ){
      go = 1;












    }






    nCardRcvd = 0;
    xfer.nFileRcvd = 0;
    xfer.nDeltaRcvd = 0;
    xfer.nDanglingFile = 0;

    /* If we have one or more files queued to send, then go
    ** another round
    */
    if( xfer.nFileSent+xfer.nDeltaSent>0 || uvDoPush ){
      go = 1;
    }
    if( xfer.nPrivIGot>0 && nCycle==1 ) go = 1;

    /* If this is a clone, the go at least two rounds */
    if( (syncFlags & SYNC_CLONE)!=0 && nCycle==1 ) go = 1;

    /* Stop the cycle if the server sends a "clone_seqno 0" card and
    ** we have gone at least two rounds.  Always go at least two rounds
    ** on a clone in order to be sure to retrieve the configuration
    ** information which is only sent on the second round.
    */
    if( cloneSeqno<=0 && nCycle>1 ) go = 0;

    /* Continue looping as long as new uvfile cards are being received
    ** and uvgimme cards are being sent. */
    if( nUvGimmeSent>0 && (nUvFileRcvd>0 || nCycle<3) ) go = 1;

    db_multi_exec("DROP TABLE onremote; DROP TABLE unk;");
    if( go ){
      manifest_crosslink_end(MC_PERMIT_HOOKS);
    }else{
      manifest_crosslink_end(MC_PERMIT_HOOKS);
      content_enable_dephantomize(1);
    }







|
|
<







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




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







2628
2629
2630
2631
2632
2633
2634
2635
2636

2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666























2667
2668
2669
2670
2671
2672
2673
      fossil_print(zBriefFormat /*works-like:"%d%d%d"*/,
                   nRoundtrip, nArtifactSent, nArtifactRcvd);
    }
    nUncRcvd += blob_size(&recv);
    blob_reset(&recv);
    nCycle++;

    /* Set go to 1 if we need to continue the sync/push/pull/clone for
    ** another round.  Set go to 0 if it is time to quit. */

    nFileRecv = xfer.nFileRcvd + xfer.nDeltaRcvd + xfer.nDanglingFile;
    if( (nFileRecv>0 || newPhantom) && db_exists("SELECT 1 FROM phantom") ){
      go = 1;
      mxPhantomReq = nFileRecv*2;
      if( mxPhantomReq<200 ) mxPhantomReq = 200;
    }else if( (syncFlags & SYNC_CLONE)!=0 && nFileRecv>0 ){
      go = 1;
    }else if( xfer.nFileSent+xfer.nDeltaSent>0 || uvDoPush ){
      /* Go another round if files are queued to send */
      go = 1;
    }else if( xfer.nPrivIGot>0 && nCycle==1 ){
      go = 1;
    }else if( (syncFlags & SYNC_CLONE)!=0 ){
      if( nCycle==1 ){
        go = 1;   /* go at least two rounds on a clone */
      }else if( cloneSeqno>0 && nArtifactRcvd>nPriorArtifact ){
        /* Continue the clone until we see the clone_seqno 0" card or
        ** until we stop receiving artifacts */
        go = 1;
      }
    }else if( nUvGimmeSent>0 && (nUvFileRcvd>0 || nCycle<3) ){
      /* Continue looping as long as new uvfile cards are being received
      ** and uvgimme cards are being sent. */
      go = 1;
    }

    nCardRcvd = 0;
    xfer.nFileRcvd = 0;
    xfer.nDeltaRcvd = 0;
    xfer.nDanglingFile = 0;























    db_multi_exec("DROP TABLE onremote; DROP TABLE unk;");
    if( go ){
      manifest_crosslink_end(MC_PERMIT_HOOKS);
    }else{
      manifest_crosslink_end(MC_PERMIT_HOOKS);
      content_enable_dephantomize(1);
    }
Changes to test/diff-test-1.wiki.
18
19
20
21
22
23
24
25



26
27
28
29
30
31
32
  *  <a href="../../../fdiff?v1=d1c60722e0b9d775&v2=58d1a8991bacb113"
     target="testwindow">Column alignment with multibyte characters.</a>
     The edit of a line with multibyte characters is the first chunk.
  *  <a href="../../../fdiff?v1=57b0d8183cab0e3d&v2=37b3ef49d73cdfe6"
     target="testwindow">Large diff of sqlite3.c</a>.  This diff was very
     slow prior to the performance enhancement change [9e15437e97].
  *  <a href="../../../info/bda00cbada#chunk49" target="testwindow">
     A difficult indentation change.</a>



  *  <a href="../../../fdiff?v1=955cc67ace8fb622&v2=e2e1c87b86664b45#chunk13"
      target="testwindow">Another tricky indentation.</a>  Notice especially
      lines 59398 and 59407 on the left.
  *  <a href="../../../fdiff?v2=955cc67ace8fb622&v1=e2e1c87b86664b45#chunk13"
      target="testwindow">Inverse of the previous.</a>
  *  <a href="../../../fdiff?v1=955cc67ace8fb622&v2=e2e1c87b86664b45#chunk24"
      target="testwindow">A complex change</a> that is difficult to align, and







|
>
>
>







18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
  *  <a href="../../../fdiff?v1=d1c60722e0b9d775&v2=58d1a8991bacb113"
     target="testwindow">Column alignment with multibyte characters.</a>
     The edit of a line with multibyte characters is the first chunk.
  *  <a href="../../../fdiff?v1=57b0d8183cab0e3d&v2=37b3ef49d73cdfe6"
     target="testwindow">Large diff of sqlite3.c</a>.  This diff was very
     slow prior to the performance enhancement change [9e15437e97].
  *  <a href="../../../info/bda00cbada#chunk49" target="testwindow">
     A difficult indentation change.</a>  UPDATE:  Notice also the improved
      multi-segment update marks on lines 122648 and 122763 on the new side.
  *  <a href="../../../fdiff?v1=bc8100c9ee01b8c2&v2=1d2acc1a2a65c2bf#chunk42"
      target="testwindow">Inverse of the previous.</a>
  *  <a href="../../../fdiff?v1=955cc67ace8fb622&v2=e2e1c87b86664b45#chunk13"
      target="testwindow">Another tricky indentation.</a>  Notice especially
      lines 59398 and 59407 on the left.
  *  <a href="../../../fdiff?v2=955cc67ace8fb622&v1=e2e1c87b86664b45#chunk13"
      target="testwindow">Inverse of the previous.</a>
  *  <a href="../../../fdiff?v1=955cc67ace8fb622&v2=e2e1c87b86664b45#chunk24"
      target="testwindow">A complex change</a> that is difficult to align, and
Changes to test/tester.tcl.
303
304
305
306
307
308
309

310
311
312
313
314
315
316
      default-perms \
      diff-binary \
      diff-command \
      dont-push \
      dotfiles \
      editor \
      email-admin \

      email-self \
      email-send-command \
      email-send-db \
      email-send-dir \
      email-send-method \
      email-send-relayhost \
      email-subname \







>







303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
      default-perms \
      diff-binary \
      diff-command \
      dont-push \
      dotfiles \
      editor \
      email-admin \
      email-renew-interval \
      email-self \
      email-send-command \
      email-send-db \
      email-send-dir \
      email-send-method \
      email-send-relayhost \
      email-subname \
329
330
331
332
333
334
335

336
337
338
339
340
341
342
      ignore-glob \
      keep-glob \
      localauth \
      lock-timeout \
      main-branch \
      mainmenu \
      manifest \

      max-loadavg \
      max-upload \
      mimetypes \
      mtime-changes \
      pgp-command \
      preferred-diff-type \
      proxy \







>







330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
      ignore-glob \
      keep-glob \
      localauth \
      lock-timeout \
      main-branch \
      mainmenu \
      manifest \
      max-cache-entry \
      max-loadavg \
      max-upload \
      mimetypes \
      mtime-changes \
      pgp-command \
      preferred-diff-type \
      proxy \
Changes to win/Makefile.mingw.
621
622
623
624
625
626
627
628
629
630
631

632
633
634
635
636
637
638
639
640
641

642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678

679
680
681
682
683
684
685
  $(SRCDIR)/../skins/xekri/footer.txt \
  $(SRCDIR)/../skins/xekri/header.txt \
  $(SRCDIR)/accordion.js \
  $(SRCDIR)/alerts/bflat2.wav \
  $(SRCDIR)/alerts/bflat3.wav \
  $(SRCDIR)/alerts/bloop.wav \
  $(SRCDIR)/alerts/plunk.wav \
  $(SRCDIR)/chat.js \
  $(SRCDIR)/ci_edit.js \
  $(SRCDIR)/copybtn.js \
  $(SRCDIR)/default.css \

  $(SRCDIR)/diff.tcl \
  $(SRCDIR)/forum.js \
  $(SRCDIR)/fossil.bootstrap.js \
  $(SRCDIR)/fossil.confirmer.js \
  $(SRCDIR)/fossil.copybutton.js \
  $(SRCDIR)/fossil.dom.js \
  $(SRCDIR)/fossil.fetch.js \
  $(SRCDIR)/fossil.info-diff.js \
  $(SRCDIR)/fossil.numbered-lines.js \
  $(SRCDIR)/fossil.page.brlist.js \

  $(SRCDIR)/fossil.page.fileedit.js \
  $(SRCDIR)/fossil.page.forumpost.js \
  $(SRCDIR)/fossil.page.pikchrshow.js \
  $(SRCDIR)/fossil.page.whistory.js \
  $(SRCDIR)/fossil.page.wikiedit.js \
  $(SRCDIR)/fossil.pikchr.js \
  $(SRCDIR)/fossil.popupwidget.js \
  $(SRCDIR)/fossil.storage.js \
  $(SRCDIR)/fossil.tabs.js \
  $(SRCDIR)/fossil.wikiedit-wysiwyg.js \
  $(SRCDIR)/graph.js \
  $(SRCDIR)/hbmenu.js \
  $(SRCDIR)/href.js \
  $(SRCDIR)/login.js \
  $(SRCDIR)/markdown.md \
  $(SRCDIR)/menu.js \
  $(SRCDIR)/sbsdiff.js \
  $(SRCDIR)/scroll.js \
  $(SRCDIR)/skin.js \
  $(SRCDIR)/sorttable.js \
  $(SRCDIR)/sounds/0.wav \
  $(SRCDIR)/sounds/1.wav \
  $(SRCDIR)/sounds/2.wav \
  $(SRCDIR)/sounds/3.wav \
  $(SRCDIR)/sounds/4.wav \
  $(SRCDIR)/sounds/5.wav \
  $(SRCDIR)/sounds/6.wav \
  $(SRCDIR)/sounds/7.wav \
  $(SRCDIR)/sounds/8.wav \
  $(SRCDIR)/sounds/9.wav \
  $(SRCDIR)/sounds/a.wav \
  $(SRCDIR)/sounds/b.wav \
  $(SRCDIR)/sounds/c.wav \
  $(SRCDIR)/sounds/d.wav \
  $(SRCDIR)/sounds/e.wav \
  $(SRCDIR)/sounds/f.wav \
  $(SRCDIR)/style.admin_log.css \

  $(SRCDIR)/style.fileedit.css \
  $(SRCDIR)/style.wikiedit.css \
  $(SRCDIR)/tree.js \
  $(SRCDIR)/useredit.js \
  $(SRCDIR)/wiki.wiki

TRANS_SRC = \







<



>





|
|
|


>
















<




















>







621
622
623
624
625
626
627

628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658

659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
  $(SRCDIR)/../skins/xekri/footer.txt \
  $(SRCDIR)/../skins/xekri/header.txt \
  $(SRCDIR)/accordion.js \
  $(SRCDIR)/alerts/bflat2.wav \
  $(SRCDIR)/alerts/bflat3.wav \
  $(SRCDIR)/alerts/bloop.wav \
  $(SRCDIR)/alerts/plunk.wav \

  $(SRCDIR)/ci_edit.js \
  $(SRCDIR)/copybtn.js \
  $(SRCDIR)/default.css \
  $(SRCDIR)/diff.js \
  $(SRCDIR)/diff.tcl \
  $(SRCDIR)/forum.js \
  $(SRCDIR)/fossil.bootstrap.js \
  $(SRCDIR)/fossil.confirmer.js \
  $(SRCDIR)/fossil.copybutton.js \
  $(SRCDIR)/fossil.diff.js \
  $(SRCDIR)/fossil.dom.js \
  $(SRCDIR)/fossil.fetch.js \
  $(SRCDIR)/fossil.numbered-lines.js \
  $(SRCDIR)/fossil.page.brlist.js \
  $(SRCDIR)/fossil.page.chat.js \
  $(SRCDIR)/fossil.page.fileedit.js \
  $(SRCDIR)/fossil.page.forumpost.js \
  $(SRCDIR)/fossil.page.pikchrshow.js \
  $(SRCDIR)/fossil.page.whistory.js \
  $(SRCDIR)/fossil.page.wikiedit.js \
  $(SRCDIR)/fossil.pikchr.js \
  $(SRCDIR)/fossil.popupwidget.js \
  $(SRCDIR)/fossil.storage.js \
  $(SRCDIR)/fossil.tabs.js \
  $(SRCDIR)/fossil.wikiedit-wysiwyg.js \
  $(SRCDIR)/graph.js \
  $(SRCDIR)/hbmenu.js \
  $(SRCDIR)/href.js \
  $(SRCDIR)/login.js \
  $(SRCDIR)/markdown.md \
  $(SRCDIR)/menu.js \

  $(SRCDIR)/scroll.js \
  $(SRCDIR)/skin.js \
  $(SRCDIR)/sorttable.js \
  $(SRCDIR)/sounds/0.wav \
  $(SRCDIR)/sounds/1.wav \
  $(SRCDIR)/sounds/2.wav \
  $(SRCDIR)/sounds/3.wav \
  $(SRCDIR)/sounds/4.wav \
  $(SRCDIR)/sounds/5.wav \
  $(SRCDIR)/sounds/6.wav \
  $(SRCDIR)/sounds/7.wav \
  $(SRCDIR)/sounds/8.wav \
  $(SRCDIR)/sounds/9.wav \
  $(SRCDIR)/sounds/a.wav \
  $(SRCDIR)/sounds/b.wav \
  $(SRCDIR)/sounds/c.wav \
  $(SRCDIR)/sounds/d.wav \
  $(SRCDIR)/sounds/e.wav \
  $(SRCDIR)/sounds/f.wav \
  $(SRCDIR)/style.admin_log.css \
  $(SRCDIR)/style.chat.css \
  $(SRCDIR)/style.fileedit.css \
  $(SRCDIR)/style.wikiedit.css \
  $(SRCDIR)/tree.js \
  $(SRCDIR)/useredit.js \
  $(SRCDIR)/wiki.wiki

TRANS_SRC = \
Changes to win/Makefile.mingw.mistachkin.
511
512
513
514
515
516
517

518
519
520
521
522
523
524
  $(SRCDIR)/markdown.c \
  $(SRCDIR)/markdown_html.c \
  $(SRCDIR)/md5.c \
  $(SRCDIR)/merge.c \
  $(SRCDIR)/merge3.c \
  $(SRCDIR)/moderate.c \
  $(SRCDIR)/name.c \

  $(SRCDIR)/path.c \
  $(SRCDIR)/piechart.c \
  $(SRCDIR)/pikchr.c \
  $(SRCDIR)/pikchrshow.c \
  $(SRCDIR)/pivot.c \
  $(SRCDIR)/popen.c \
  $(SRCDIR)/pqueue.c \







>







511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
  $(SRCDIR)/markdown.c \
  $(SRCDIR)/markdown_html.c \
  $(SRCDIR)/md5.c \
  $(SRCDIR)/merge.c \
  $(SRCDIR)/merge3.c \
  $(SRCDIR)/moderate.c \
  $(SRCDIR)/name.c \
  $(SRCDIR)/patch.c \
  $(SRCDIR)/path.c \
  $(SRCDIR)/piechart.c \
  $(SRCDIR)/pikchr.c \
  $(SRCDIR)/pikchrshow.c \
  $(SRCDIR)/pivot.c \
  $(SRCDIR)/popen.c \
  $(SRCDIR)/pqueue.c \
624
625
626
627
628
629
630

631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
  $(SRCDIR)/alerts/bflat3.wav \
  $(SRCDIR)/alerts/bloop.wav \
  $(SRCDIR)/alerts/plunk.wav \
  $(SRCDIR)/chat.js \
  $(SRCDIR)/ci_edit.js \
  $(SRCDIR)/copybtn.js \
  $(SRCDIR)/default.css \

  $(SRCDIR)/diff.tcl \
  $(SRCDIR)/forum.js \
  $(SRCDIR)/fossil.bootstrap.js \
  $(SRCDIR)/fossil.confirmer.js \
  $(SRCDIR)/fossil.copybutton.js \
  $(SRCDIR)/fossil.dom.js \
  $(SRCDIR)/fossil.fetch.js \
  $(SRCDIR)/fossil.info-diff.js \
  $(SRCDIR)/fossil.numbered-lines.js \
  $(SRCDIR)/fossil.page.brlist.js \
  $(SRCDIR)/fossil.page.fileedit.js \
  $(SRCDIR)/fossil.page.forumpost.js \
  $(SRCDIR)/fossil.page.pikchrshow.js \
  $(SRCDIR)/fossil.page.whistory.js \
  $(SRCDIR)/fossil.page.wikiedit.js \
  $(SRCDIR)/fossil.pikchr.js \
  $(SRCDIR)/fossil.popupwidget.js \
  $(SRCDIR)/fossil.storage.js \
  $(SRCDIR)/fossil.tabs.js \
  $(SRCDIR)/fossil.wikiedit-wysiwyg.js \
  $(SRCDIR)/graph.js \
  $(SRCDIR)/hbmenu.js \
  $(SRCDIR)/href.js \
  $(SRCDIR)/login.js \
  $(SRCDIR)/markdown.md \
  $(SRCDIR)/menu.js \
  $(SRCDIR)/sbsdiff.js \
  $(SRCDIR)/scroll.js \
  $(SRCDIR)/skin.js \
  $(SRCDIR)/sorttable.js \
  $(SRCDIR)/sounds/0.wav \
  $(SRCDIR)/sounds/1.wav \
  $(SRCDIR)/sounds/2.wav \
  $(SRCDIR)/sounds/3.wav \







>





|
|
|


















<







625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658

659
660
661
662
663
664
665
  $(SRCDIR)/alerts/bflat3.wav \
  $(SRCDIR)/alerts/bloop.wav \
  $(SRCDIR)/alerts/plunk.wav \
  $(SRCDIR)/chat.js \
  $(SRCDIR)/ci_edit.js \
  $(SRCDIR)/copybtn.js \
  $(SRCDIR)/default.css \
  $(SRCDIR)/diff.js \
  $(SRCDIR)/diff.tcl \
  $(SRCDIR)/forum.js \
  $(SRCDIR)/fossil.bootstrap.js \
  $(SRCDIR)/fossil.confirmer.js \
  $(SRCDIR)/fossil.copybutton.js \
  $(SRCDIR)/fossil.diff.js \
  $(SRCDIR)/fossil.dom.js \
  $(SRCDIR)/fossil.fetch.js \
  $(SRCDIR)/fossil.numbered-lines.js \
  $(SRCDIR)/fossil.page.brlist.js \
  $(SRCDIR)/fossil.page.fileedit.js \
  $(SRCDIR)/fossil.page.forumpost.js \
  $(SRCDIR)/fossil.page.pikchrshow.js \
  $(SRCDIR)/fossil.page.whistory.js \
  $(SRCDIR)/fossil.page.wikiedit.js \
  $(SRCDIR)/fossil.pikchr.js \
  $(SRCDIR)/fossil.popupwidget.js \
  $(SRCDIR)/fossil.storage.js \
  $(SRCDIR)/fossil.tabs.js \
  $(SRCDIR)/fossil.wikiedit-wysiwyg.js \
  $(SRCDIR)/graph.js \
  $(SRCDIR)/hbmenu.js \
  $(SRCDIR)/href.js \
  $(SRCDIR)/login.js \
  $(SRCDIR)/markdown.md \
  $(SRCDIR)/menu.js \

  $(SRCDIR)/scroll.js \
  $(SRCDIR)/skin.js \
  $(SRCDIR)/sorttable.js \
  $(SRCDIR)/sounds/0.wav \
  $(SRCDIR)/sounds/1.wav \
  $(SRCDIR)/sounds/2.wav \
  $(SRCDIR)/sounds/3.wav \
768
769
770
771
772
773
774

775
776
777
778
779
780
781
  $(OBJDIR)/markdown_.c \
  $(OBJDIR)/markdown_html_.c \
  $(OBJDIR)/md5_.c \
  $(OBJDIR)/merge_.c \
  $(OBJDIR)/merge3_.c \
  $(OBJDIR)/moderate_.c \
  $(OBJDIR)/name_.c \

  $(OBJDIR)/path_.c \
  $(OBJDIR)/piechart_.c \
  $(OBJDIR)/pikchr_.c \
  $(OBJDIR)/pikchrshow_.c \
  $(OBJDIR)/pivot_.c \
  $(OBJDIR)/popen_.c \
  $(OBJDIR)/pqueue_.c \







>







769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
  $(OBJDIR)/markdown_.c \
  $(OBJDIR)/markdown_html_.c \
  $(OBJDIR)/md5_.c \
  $(OBJDIR)/merge_.c \
  $(OBJDIR)/merge3_.c \
  $(OBJDIR)/moderate_.c \
  $(OBJDIR)/name_.c \
  $(OBJDIR)/patch_.c \
  $(OBJDIR)/path_.c \
  $(OBJDIR)/piechart_.c \
  $(OBJDIR)/pikchr_.c \
  $(OBJDIR)/pikchrshow_.c \
  $(OBJDIR)/pivot_.c \
  $(OBJDIR)/popen_.c \
  $(OBJDIR)/pqueue_.c \
917
918
919
920
921
922
923

924
925
926
927
928
929
930
 $(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)/pikchr.o \
 $(OBJDIR)/pikchrshow.o \
 $(OBJDIR)/pivot.o \
 $(OBJDIR)/popen.o \
 $(OBJDIR)/pqueue.o \







>







919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
 $(OBJDIR)/markdown.o \
 $(OBJDIR)/markdown_html.o \
 $(OBJDIR)/md5.o \
 $(OBJDIR)/merge.o \
 $(OBJDIR)/merge3.o \
 $(OBJDIR)/moderate.o \
 $(OBJDIR)/name.o \
 $(OBJDIR)/patch.o \
 $(OBJDIR)/path.o \
 $(OBJDIR)/piechart.o \
 $(OBJDIR)/pikchr.o \
 $(OBJDIR)/pikchrshow.o \
 $(OBJDIR)/pivot.o \
 $(OBJDIR)/popen.o \
 $(OBJDIR)/pqueue.o \
1281
1282
1283
1284
1285
1286
1287

1288
1289
1290
1291
1292
1293
1294
		$(OBJDIR)/markdown_.c:$(OBJDIR)/markdown.h \
		$(OBJDIR)/markdown_html_.c:$(OBJDIR)/markdown_html.h \
		$(OBJDIR)/md5_.c:$(OBJDIR)/md5.h \
		$(OBJDIR)/merge_.c:$(OBJDIR)/merge.h \
		$(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h \
		$(OBJDIR)/moderate_.c:$(OBJDIR)/moderate.h \
		$(OBJDIR)/name_.c:$(OBJDIR)/name.h \

		$(OBJDIR)/path_.c:$(OBJDIR)/path.h \
		$(OBJDIR)/piechart_.c:$(OBJDIR)/piechart.h \
		$(OBJDIR)/pikchr_.c:$(OBJDIR)/pikchr.h \
		$(OBJDIR)/pikchrshow_.c:$(OBJDIR)/pikchrshow.h \
		$(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h \
		$(OBJDIR)/popen_.c:$(OBJDIR)/popen.h \
		$(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h \







>







1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
		$(OBJDIR)/markdown_.c:$(OBJDIR)/markdown.h \
		$(OBJDIR)/markdown_html_.c:$(OBJDIR)/markdown_html.h \
		$(OBJDIR)/md5_.c:$(OBJDIR)/md5.h \
		$(OBJDIR)/merge_.c:$(OBJDIR)/merge.h \
		$(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h \
		$(OBJDIR)/moderate_.c:$(OBJDIR)/moderate.h \
		$(OBJDIR)/name_.c:$(OBJDIR)/name.h \
		$(OBJDIR)/patch_.c:$(OBJDIR)/patch.h \
		$(OBJDIR)/path_.c:$(OBJDIR)/path.h \
		$(OBJDIR)/piechart_.c:$(OBJDIR)/piechart.h \
		$(OBJDIR)/pikchr_.c:$(OBJDIR)/pikchr.h \
		$(OBJDIR)/pikchrshow_.c:$(OBJDIR)/pikchrshow.h \
		$(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h \
		$(OBJDIR)/popen_.c:$(OBJDIR)/popen.h \
		$(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h \
2066
2067
2068
2069
2070
2071
2072








2073
2074
2075
2076
2077
2078
2079
$(OBJDIR)/name_.c:	$(SRCDIR)/name.c $(TRANSLATE)
	$(TRANSLATE) $(SRCDIR)/name.c >$@

$(OBJDIR)/name.o:	$(OBJDIR)/name_.c $(OBJDIR)/name.h $(SRCDIR)/config.h
	$(XTCC) -o $(OBJDIR)/name.o -c $(OBJDIR)/name_.c

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









$(OBJDIR)/path_.c:	$(SRCDIR)/path.c $(TRANSLATE)
	$(TRANSLATE) $(SRCDIR)/path.c >$@

$(OBJDIR)/path.o:	$(OBJDIR)/path_.c $(OBJDIR)/path.h $(SRCDIR)/config.h
	$(XTCC) -o $(OBJDIR)/path.o -c $(OBJDIR)/path_.c








>
>
>
>
>
>
>
>







2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
$(OBJDIR)/name_.c:	$(SRCDIR)/name.c $(TRANSLATE)
	$(TRANSLATE) $(SRCDIR)/name.c >$@

$(OBJDIR)/name.o:	$(OBJDIR)/name_.c $(OBJDIR)/name.h $(SRCDIR)/config.h
	$(XTCC) -o $(OBJDIR)/name.o -c $(OBJDIR)/name_.c

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

$(OBJDIR)/patch_.c:	$(SRCDIR)/patch.c $(TRANSLATE)
	$(TRANSLATE) $(SRCDIR)/patch.c >$@

$(OBJDIR)/patch.o:	$(OBJDIR)/patch_.c $(OBJDIR)/patch.h $(SRCDIR)/config.h
	$(XTCC) -o $(OBJDIR)/patch.o -c $(OBJDIR)/patch_.c

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

$(OBJDIR)/path_.c:	$(SRCDIR)/path.c $(TRANSLATE)
	$(TRANSLATE) $(SRCDIR)/path.c >$@

$(OBJDIR)/path.o:	$(OBJDIR)/path_.c $(OBJDIR)/path.h $(SRCDIR)/config.h
	$(XTCC) -o $(OBJDIR)/path.o -c $(OBJDIR)/path_.c

Changes to win/Makefile.msc.
563
564
565
566
567
568
569
570
571
572
573

574
575
576
577
578
579
580
581
582
583

584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620

621
622
623
624
625
626
627
        "$(SRCDIR)\..\skins\xekri\footer.txt" \
        "$(SRCDIR)\..\skins\xekri\header.txt" \
        "$(SRCDIR)\accordion.js" \
        "$(SRCDIR)\alerts\bflat2.wav" \
        "$(SRCDIR)\alerts\bflat3.wav" \
        "$(SRCDIR)\alerts\bloop.wav" \
        "$(SRCDIR)\alerts\plunk.wav" \
        "$(SRCDIR)\chat.js" \
        "$(SRCDIR)\ci_edit.js" \
        "$(SRCDIR)\copybtn.js" \
        "$(SRCDIR)\default.css" \

        "$(SRCDIR)\diff.tcl" \
        "$(SRCDIR)\forum.js" \
        "$(SRCDIR)\fossil.bootstrap.js" \
        "$(SRCDIR)\fossil.confirmer.js" \
        "$(SRCDIR)\fossil.copybutton.js" \
        "$(SRCDIR)\fossil.dom.js" \
        "$(SRCDIR)\fossil.fetch.js" \
        "$(SRCDIR)\fossil.info-diff.js" \
        "$(SRCDIR)\fossil.numbered-lines.js" \
        "$(SRCDIR)\fossil.page.brlist.js" \

        "$(SRCDIR)\fossil.page.fileedit.js" \
        "$(SRCDIR)\fossil.page.forumpost.js" \
        "$(SRCDIR)\fossil.page.pikchrshow.js" \
        "$(SRCDIR)\fossil.page.whistory.js" \
        "$(SRCDIR)\fossil.page.wikiedit.js" \
        "$(SRCDIR)\fossil.pikchr.js" \
        "$(SRCDIR)\fossil.popupwidget.js" \
        "$(SRCDIR)\fossil.storage.js" \
        "$(SRCDIR)\fossil.tabs.js" \
        "$(SRCDIR)\fossil.wikiedit-wysiwyg.js" \
        "$(SRCDIR)\graph.js" \
        "$(SRCDIR)\hbmenu.js" \
        "$(SRCDIR)\href.js" \
        "$(SRCDIR)\login.js" \
        "$(SRCDIR)\markdown.md" \
        "$(SRCDIR)\menu.js" \
        "$(SRCDIR)\sbsdiff.js" \
        "$(SRCDIR)\scroll.js" \
        "$(SRCDIR)\skin.js" \
        "$(SRCDIR)\sorttable.js" \
        "$(SRCDIR)\sounds\0.wav" \
        "$(SRCDIR)\sounds\1.wav" \
        "$(SRCDIR)\sounds\2.wav" \
        "$(SRCDIR)\sounds\3.wav" \
        "$(SRCDIR)\sounds\4.wav" \
        "$(SRCDIR)\sounds\5.wav" \
        "$(SRCDIR)\sounds\6.wav" \
        "$(SRCDIR)\sounds\7.wav" \
        "$(SRCDIR)\sounds\8.wav" \
        "$(SRCDIR)\sounds\9.wav" \
        "$(SRCDIR)\sounds\a.wav" \
        "$(SRCDIR)\sounds\b.wav" \
        "$(SRCDIR)\sounds\c.wav" \
        "$(SRCDIR)\sounds\d.wav" \
        "$(SRCDIR)\sounds\e.wav" \
        "$(SRCDIR)\sounds\f.wav" \
        "$(SRCDIR)\style.admin_log.css" \

        "$(SRCDIR)\style.fileedit.css" \
        "$(SRCDIR)\style.wikiedit.css" \
        "$(SRCDIR)\tree.js" \
        "$(SRCDIR)\useredit.js" \
        "$(SRCDIR)\wiki.wiki"

OBJ   = "$(OX)\add$O" \







<



>





|
|
|


>
















<




















>







563
564
565
566
567
568
569

570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600

601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
        "$(SRCDIR)\..\skins\xekri\footer.txt" \
        "$(SRCDIR)\..\skins\xekri\header.txt" \
        "$(SRCDIR)\accordion.js" \
        "$(SRCDIR)\alerts\bflat2.wav" \
        "$(SRCDIR)\alerts\bflat3.wav" \
        "$(SRCDIR)\alerts\bloop.wav" \
        "$(SRCDIR)\alerts\plunk.wav" \

        "$(SRCDIR)\ci_edit.js" \
        "$(SRCDIR)\copybtn.js" \
        "$(SRCDIR)\default.css" \
        "$(SRCDIR)\diff.js" \
        "$(SRCDIR)\diff.tcl" \
        "$(SRCDIR)\forum.js" \
        "$(SRCDIR)\fossil.bootstrap.js" \
        "$(SRCDIR)\fossil.confirmer.js" \
        "$(SRCDIR)\fossil.copybutton.js" \
        "$(SRCDIR)\fossil.diff.js" \
        "$(SRCDIR)\fossil.dom.js" \
        "$(SRCDIR)\fossil.fetch.js" \
        "$(SRCDIR)\fossil.numbered-lines.js" \
        "$(SRCDIR)\fossil.page.brlist.js" \
        "$(SRCDIR)\fossil.page.chat.js" \
        "$(SRCDIR)\fossil.page.fileedit.js" \
        "$(SRCDIR)\fossil.page.forumpost.js" \
        "$(SRCDIR)\fossil.page.pikchrshow.js" \
        "$(SRCDIR)\fossil.page.whistory.js" \
        "$(SRCDIR)\fossil.page.wikiedit.js" \
        "$(SRCDIR)\fossil.pikchr.js" \
        "$(SRCDIR)\fossil.popupwidget.js" \
        "$(SRCDIR)\fossil.storage.js" \
        "$(SRCDIR)\fossil.tabs.js" \
        "$(SRCDIR)\fossil.wikiedit-wysiwyg.js" \
        "$(SRCDIR)\graph.js" \
        "$(SRCDIR)\hbmenu.js" \
        "$(SRCDIR)\href.js" \
        "$(SRCDIR)\login.js" \
        "$(SRCDIR)\markdown.md" \
        "$(SRCDIR)\menu.js" \

        "$(SRCDIR)\scroll.js" \
        "$(SRCDIR)\skin.js" \
        "$(SRCDIR)\sorttable.js" \
        "$(SRCDIR)\sounds\0.wav" \
        "$(SRCDIR)\sounds\1.wav" \
        "$(SRCDIR)\sounds\2.wav" \
        "$(SRCDIR)\sounds\3.wav" \
        "$(SRCDIR)\sounds\4.wav" \
        "$(SRCDIR)\sounds\5.wav" \
        "$(SRCDIR)\sounds\6.wav" \
        "$(SRCDIR)\sounds\7.wav" \
        "$(SRCDIR)\sounds\8.wav" \
        "$(SRCDIR)\sounds\9.wav" \
        "$(SRCDIR)\sounds\a.wav" \
        "$(SRCDIR)\sounds\b.wav" \
        "$(SRCDIR)\sounds\c.wav" \
        "$(SRCDIR)\sounds\d.wav" \
        "$(SRCDIR)\sounds\e.wav" \
        "$(SRCDIR)\sounds\f.wav" \
        "$(SRCDIR)\style.admin_log.css" \
        "$(SRCDIR)\style.chat.css" \
        "$(SRCDIR)\style.fileedit.css" \
        "$(SRCDIR)\style.wikiedit.css" \
        "$(SRCDIR)\tree.js" \
        "$(SRCDIR)\useredit.js" \
        "$(SRCDIR)\wiki.wiki"

OBJ   = "$(OX)\add$O" \
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181

1182
1183
1184
1185
1186
1187
1188
1189
1190
1191

1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228

1229
1230
1231
1232
1233
1234
1235
	echo "$(SRCDIR)\../skins/xekri/footer.txt" >> $@
	echo "$(SRCDIR)\../skins/xekri/header.txt" >> $@
	echo "$(SRCDIR)\accordion.js" >> $@
	echo "$(SRCDIR)\alerts/bflat2.wav" >> $@
	echo "$(SRCDIR)\alerts/bflat3.wav" >> $@
	echo "$(SRCDIR)\alerts/bloop.wav" >> $@
	echo "$(SRCDIR)\alerts/plunk.wav" >> $@
	echo "$(SRCDIR)\chat.js" >> $@
	echo "$(SRCDIR)\ci_edit.js" >> $@
	echo "$(SRCDIR)\copybtn.js" >> $@
	echo "$(SRCDIR)\default.css" >> $@

	echo "$(SRCDIR)\diff.tcl" >> $@
	echo "$(SRCDIR)\forum.js" >> $@
	echo "$(SRCDIR)\fossil.bootstrap.js" >> $@
	echo "$(SRCDIR)\fossil.confirmer.js" >> $@
	echo "$(SRCDIR)\fossil.copybutton.js" >> $@
	echo "$(SRCDIR)\fossil.dom.js" >> $@
	echo "$(SRCDIR)\fossil.fetch.js" >> $@
	echo "$(SRCDIR)\fossil.info-diff.js" >> $@
	echo "$(SRCDIR)\fossil.numbered-lines.js" >> $@
	echo "$(SRCDIR)\fossil.page.brlist.js" >> $@

	echo "$(SRCDIR)\fossil.page.fileedit.js" >> $@
	echo "$(SRCDIR)\fossil.page.forumpost.js" >> $@
	echo "$(SRCDIR)\fossil.page.pikchrshow.js" >> $@
	echo "$(SRCDIR)\fossil.page.whistory.js" >> $@
	echo "$(SRCDIR)\fossil.page.wikiedit.js" >> $@
	echo "$(SRCDIR)\fossil.pikchr.js" >> $@
	echo "$(SRCDIR)\fossil.popupwidget.js" >> $@
	echo "$(SRCDIR)\fossil.storage.js" >> $@
	echo "$(SRCDIR)\fossil.tabs.js" >> $@
	echo "$(SRCDIR)\fossil.wikiedit-wysiwyg.js" >> $@
	echo "$(SRCDIR)\graph.js" >> $@
	echo "$(SRCDIR)\hbmenu.js" >> $@
	echo "$(SRCDIR)\href.js" >> $@
	echo "$(SRCDIR)\login.js" >> $@
	echo "$(SRCDIR)\markdown.md" >> $@
	echo "$(SRCDIR)\menu.js" >> $@
	echo "$(SRCDIR)\sbsdiff.js" >> $@
	echo "$(SRCDIR)\scroll.js" >> $@
	echo "$(SRCDIR)\skin.js" >> $@
	echo "$(SRCDIR)\sorttable.js" >> $@
	echo "$(SRCDIR)\sounds/0.wav" >> $@
	echo "$(SRCDIR)\sounds/1.wav" >> $@
	echo "$(SRCDIR)\sounds/2.wav" >> $@
	echo "$(SRCDIR)\sounds/3.wav" >> $@
	echo "$(SRCDIR)\sounds/4.wav" >> $@
	echo "$(SRCDIR)\sounds/5.wav" >> $@
	echo "$(SRCDIR)\sounds/6.wav" >> $@
	echo "$(SRCDIR)\sounds/7.wav" >> $@
	echo "$(SRCDIR)\sounds/8.wav" >> $@
	echo "$(SRCDIR)\sounds/9.wav" >> $@
	echo "$(SRCDIR)\sounds/a.wav" >> $@
	echo "$(SRCDIR)\sounds/b.wav" >> $@
	echo "$(SRCDIR)\sounds/c.wav" >> $@
	echo "$(SRCDIR)\sounds/d.wav" >> $@
	echo "$(SRCDIR)\sounds/e.wav" >> $@
	echo "$(SRCDIR)\sounds/f.wav" >> $@
	echo "$(SRCDIR)\style.admin_log.css" >> $@

	echo "$(SRCDIR)\style.fileedit.css" >> $@
	echo "$(SRCDIR)\style.wikiedit.css" >> $@
	echo "$(SRCDIR)\tree.js" >> $@
	echo "$(SRCDIR)\useredit.js" >> $@
	echo "$(SRCDIR)\wiki.wiki" >> $@

"$(OX)\add$O" : "$(OX)\add_.c" "$(OX)\add.h"







<



>





|
|
|


>
















<




















>







1172
1173
1174
1175
1176
1177
1178

1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209

1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
	echo "$(SRCDIR)\../skins/xekri/footer.txt" >> $@
	echo "$(SRCDIR)\../skins/xekri/header.txt" >> $@
	echo "$(SRCDIR)\accordion.js" >> $@
	echo "$(SRCDIR)\alerts/bflat2.wav" >> $@
	echo "$(SRCDIR)\alerts/bflat3.wav" >> $@
	echo "$(SRCDIR)\alerts/bloop.wav" >> $@
	echo "$(SRCDIR)\alerts/plunk.wav" >> $@

	echo "$(SRCDIR)\ci_edit.js" >> $@
	echo "$(SRCDIR)\copybtn.js" >> $@
	echo "$(SRCDIR)\default.css" >> $@
	echo "$(SRCDIR)\diff.js" >> $@
	echo "$(SRCDIR)\diff.tcl" >> $@
	echo "$(SRCDIR)\forum.js" >> $@
	echo "$(SRCDIR)\fossil.bootstrap.js" >> $@
	echo "$(SRCDIR)\fossil.confirmer.js" >> $@
	echo "$(SRCDIR)\fossil.copybutton.js" >> $@
	echo "$(SRCDIR)\fossil.diff.js" >> $@
	echo "$(SRCDIR)\fossil.dom.js" >> $@
	echo "$(SRCDIR)\fossil.fetch.js" >> $@
	echo "$(SRCDIR)\fossil.numbered-lines.js" >> $@
	echo "$(SRCDIR)\fossil.page.brlist.js" >> $@
	echo "$(SRCDIR)\fossil.page.chat.js" >> $@
	echo "$(SRCDIR)\fossil.page.fileedit.js" >> $@
	echo "$(SRCDIR)\fossil.page.forumpost.js" >> $@
	echo "$(SRCDIR)\fossil.page.pikchrshow.js" >> $@
	echo "$(SRCDIR)\fossil.page.whistory.js" >> $@
	echo "$(SRCDIR)\fossil.page.wikiedit.js" >> $@
	echo "$(SRCDIR)\fossil.pikchr.js" >> $@
	echo "$(SRCDIR)\fossil.popupwidget.js" >> $@
	echo "$(SRCDIR)\fossil.storage.js" >> $@
	echo "$(SRCDIR)\fossil.tabs.js" >> $@
	echo "$(SRCDIR)\fossil.wikiedit-wysiwyg.js" >> $@
	echo "$(SRCDIR)\graph.js" >> $@
	echo "$(SRCDIR)\hbmenu.js" >> $@
	echo "$(SRCDIR)\href.js" >> $@
	echo "$(SRCDIR)\login.js" >> $@
	echo "$(SRCDIR)\markdown.md" >> $@
	echo "$(SRCDIR)\menu.js" >> $@

	echo "$(SRCDIR)\scroll.js" >> $@
	echo "$(SRCDIR)\skin.js" >> $@
	echo "$(SRCDIR)\sorttable.js" >> $@
	echo "$(SRCDIR)\sounds/0.wav" >> $@
	echo "$(SRCDIR)\sounds/1.wav" >> $@
	echo "$(SRCDIR)\sounds/2.wav" >> $@
	echo "$(SRCDIR)\sounds/3.wav" >> $@
	echo "$(SRCDIR)\sounds/4.wav" >> $@
	echo "$(SRCDIR)\sounds/5.wav" >> $@
	echo "$(SRCDIR)\sounds/6.wav" >> $@
	echo "$(SRCDIR)\sounds/7.wav" >> $@
	echo "$(SRCDIR)\sounds/8.wav" >> $@
	echo "$(SRCDIR)\sounds/9.wav" >> $@
	echo "$(SRCDIR)\sounds/a.wav" >> $@
	echo "$(SRCDIR)\sounds/b.wav" >> $@
	echo "$(SRCDIR)\sounds/c.wav" >> $@
	echo "$(SRCDIR)\sounds/d.wav" >> $@
	echo "$(SRCDIR)\sounds/e.wav" >> $@
	echo "$(SRCDIR)\sounds/f.wav" >> $@
	echo "$(SRCDIR)\style.admin_log.css" >> $@
	echo "$(SRCDIR)\style.chat.css" >> $@
	echo "$(SRCDIR)\style.fileedit.css" >> $@
	echo "$(SRCDIR)\style.wikiedit.css" >> $@
	echo "$(SRCDIR)\tree.js" >> $@
	echo "$(SRCDIR)\useredit.js" >> $@
	echo "$(SRCDIR)\wiki.wiki" >> $@

"$(OX)\add$O" : "$(OX)\add_.c" "$(OX)\add.h"
Changes to www/aboutcgi.wiki.
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
     at "/home/www/resps/subdir.fossil" but there is no such repository.
     So then it looks at "/home/www/repos/subdir/three.fossil" and finds
     a repository.  The PATH_INFO is shortened by removing
     "subdir/three/" leaving it at just "timeline".
<li> Fossil looks at the rest of PATH_INFO to see that the webpage
     requested is "timeline".
</ol>
<a name="cgivar"></a>
The web server sets many environment variables in step 2 in addition
to just PATH_INFO.  The following diagram shows a few of these variables
and their relationship to the request URL:
<pre>
                                   REQUEST_URI
                         ______________|___________________
                        /                                  \







|







182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
     at "/home/www/resps/subdir.fossil" but there is no such repository.
     So then it looks at "/home/www/repos/subdir/three.fossil" and finds
     a repository.  The PATH_INFO is shortened by removing
     "subdir/three/" leaving it at just "timeline".
<li> Fossil looks at the rest of PATH_INFO to see that the webpage
     requested is "timeline".
</ol>
<a id="cgivar"></a>
The web server sets many environment variables in step 2 in addition
to just PATH_INFO.  The following diagram shows a few of these variables
and their relationship to the request URL:
<pre>
                                   REQUEST_URI
                         ______________|___________________
                        /                                  \
Changes to www/adding_code.wiki.
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
the makefiles, you should be able to recompile Fossil and have it include
your new source file, even before you source file contains any code.
It is recommended that you try this.

Be sure to [/help/add|fossil add] your new source file to the self-hosting
Fossil repository and then [/help/commit|commit] your changes!

<a name="newcmd"></a>
<h2>4.0 Creating A New Command</h2>

By "commands" we mean the keywords that follow "fossil" when invoking
Fossil from the command-line.  So, for example, in

    <b>fossil diff xyzzy.c</b>

The "command" is "diff".  Commands may optionally be followed by







<
|







100
101
102
103
104
105
106

107
108
109
110
111
112
113
114
the makefiles, you should be able to recompile Fossil and have it include
your new source file, even before you source file contains any code.
It is recommended that you try this.

Be sure to [/help/add|fossil add] your new source file to the self-hosting
Fossil repository and then [/help/commit|commit] your changes!


<h2 id="newcmd">4.0 Creating A New Command</h2>

By "commands" we mean the keywords that follow "fossil" when invoking
Fossil from the command-line.  So, for example, in

    <b>fossil diff xyzzy.c</b>

The "command" is "diff".  Commands may optionally be followed by
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
Fossil for parsing command-line options and for
opening and accessing and manipulating the repository and
the working check-out.  Study implementations of existing commands
to get an idea of how things are done.  You can easily find the implementations
of existing commands by searching for "COMMAND: <i>name</i>" in the
files of the "src/" directory.

<a name="newpage"></a>
<h2>5.0 Creating A New Web Page</h2>

As with commands, new webpages can be added simply by inserting a function
that generates the webpage together with a special header comment.  A
template follows:

<blockquote><verbatim>
/*







<
|







165
166
167
168
169
170
171

172
173
174
175
176
177
178
179
Fossil for parsing command-line options and for
opening and accessing and manipulating the repository and
the working check-out.  Study implementations of existing commands
to get an idea of how things are done.  You can easily find the implementations
of existing commands by searching for "COMMAND: <i>name</i>" in the
files of the "src/" directory.


<h2 id="newpage">5.0 Creating A New Web Page</h2>

As with commands, new webpages can be added simply by inserting a function
that generates the webpage together with a special header comment.  A
template follows:

<blockquote><verbatim>
/*
Changes to www/alerts.md.
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
  4.  Send emails to an SMTP relay.
  5.  Send emails directly to the recipients via SMTP.

This wide range of options allows Fossil to talk to pretty much any
SMTP setup.

The first four options let Fossil delegate email handling to an existing
[MTA][mta] so that Fossil does not need to implement the [roughly two
dozen][mprotos] separate [RFCs][rfcs] required in order to properly
support SMTP email in this complex world we've built.  As well, this
design choice means you do not need to do duplicate configuration, such
as to point Fossil at your server's TLS certificate in order to support
users behind mail servers that require STARTTLS encryption.

[mprotos]: http://sqlite.1065341.n5.nabble.com/Many-ML-emails-going-to-GMail-s-SPAM-tp98685p98722.html
[rfcs]:    https://en.wikipedia.org/wiki/Request_for_Comments


<a id="pipe"></a>
### Method 1: Pipe to a Command

This is our ["quick setup" option](#quick) above, but there are some
details we ignored which we'll cover now.

Fossil pipes the email message in [RFC 822 format][rfc822] to the
standard input of the command you gave as the "Email Send Method",
defaulting to `sendmail -ti`. This constitutes a protocol between Fossil
and the SMTP [message transfer agent (MTA)][mta]. Any other MTA which
speaks the same protocol can be used in place of the most common
options: Sendmail, Exim, and Postfix.

The `-t` option tells the command to expect the list of email recipients
in a `To` header in the RFC 822 message presented on its standard input.
Without this option, the `sendmail` command expects to receive the
recipient list on the command line, but that's not possible with the







|



















|







321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
  4.  Send emails to an SMTP relay.
  5.  Send emails directly to the recipients via SMTP.

This wide range of options allows Fossil to talk to pretty much any
SMTP setup.

The first four options let Fossil delegate email handling to an existing
[MTA] so that Fossil does not need to implement the [roughly two
dozen][mprotos] separate [RFCs][rfcs] required in order to properly
support SMTP email in this complex world we've built.  As well, this
design choice means you do not need to do duplicate configuration, such
as to point Fossil at your server's TLS certificate in order to support
users behind mail servers that require STARTTLS encryption.

[mprotos]: http://sqlite.1065341.n5.nabble.com/Many-ML-emails-going-to-GMail-s-SPAM-tp98685p98722.html
[rfcs]:    https://en.wikipedia.org/wiki/Request_for_Comments


<a id="pipe"></a>
### Method 1: Pipe to a Command

This is our ["quick setup" option](#quick) above, but there are some
details we ignored which we'll cover now.

Fossil pipes the email message in [RFC 822 format][rfc822] to the
standard input of the command you gave as the "Email Send Method",
defaulting to `sendmail -ti`. This constitutes a protocol between Fossil
and the SMTP [message transfer agent (MTA)][MTA]. Any other MTA which
speaks the same protocol can be used in place of the most common
options: Sendmail, Exim, and Postfix.

The `-t` option tells the command to expect the list of email recipients
in a `To` header in the RFC 822 message presented on its standard input.
Without this option, the `sendmail` command expects to receive the
recipient list on the command line, but that's not possible with the
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390

It is probably also possible to configure [`procmail`][pmdoc] to work
with this protocol. If you know how to do it, a patch to this document
or a how-to on [the Fossil forum][ff] would be appreciated.

[ff]:     https://fossil-scm.org/forum/
[msmtp]:  https://marlam.de/msmtp/
[mta]:    https://en.wikipedia.org/wiki/Message_transfer_agent
[pmdoc]:  http://pm-doc.sourceforge.net/doc/
[rfc822]: https://www.w3.org/Protocols/rfc822/


<a id="db"></a>
### Method 2: Store in a Database








|







376
377
378
379
380
381
382
383
384
385
386
387
388
389
390

It is probably also possible to configure [`procmail`][pmdoc] to work
with this protocol. If you know how to do it, a patch to this document
or a how-to on [the Fossil forum][ff] would be appreciated.

[ff]:     https://fossil-scm.org/forum/
[msmtp]:  https://marlam.de/msmtp/
[MTA]:    https://en.wikipedia.org/wiki/Message_transfer_agent
[pmdoc]:  http://pm-doc.sourceforge.net/doc/
[rfc822]: https://www.w3.org/Protocols/rfc822/


<a id="db"></a>
### Method 2: Store in a Database

441
442
443
444
445
446
447
448
449
450
451
452
453
454
455

This method may work over a file sharing mechanism that doesn't do file
locking properly, as long as the reading process is somehow restricted
from reading a message file as it's being written.

It might be useful in testing and debugging to temporarily switch to
this method, since you can easily read the generated email messages
without needing to involve [an MTA][mta].


<a id="relay"></a>
### Method 4: SMTP Relay

In this configuration, the Fossil server contacts an open SMTP relay and
sends the messages to it. This method is only appropriate when:







|







441
442
443
444
445
446
447
448
449
450
451
452
453
454
455

This method may work over a file sharing mechanism that doesn't do file
locking properly, as long as the reading process is somehow restricted
from reading a message file as it's being written.

It might be useful in testing and debugging to temporarily switch to
this method, since you can easily read the generated email messages
without needing to involve an [MTA].


<a id="relay"></a>
### Method 4: SMTP Relay

In this configuration, the Fossil server contacts an open SMTP relay and
sends the messages to it. This method is only appropriate when:
Changes to www/blockchain.md.
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

## The Dictionary Argument

The [Wikipedia definition of "blockchain"][bcwp] begins:

>
  "A blockchain…is a growing list of records, called blocks, which are linked using
   cryptography. Each block contains a cryptographic hash of the previous
   block, a timestamp, and transaction data (generally represented as a Merkle tree)."


By that partial definition, Fossil is indeed a blockchain. The blocks
are Fossil’s ["manifest" artifacts](./fileformat.wiki#manifest). Each
manifest has a cryptographically-strong [SHA-1] or [SHA-3] hash linking it to
one or more “parent” blocks. The manifest also contains a timestamp and
the transactional data needed to express a commit to the repository. If
you traverse the Fossil repository from the tips of its [DAG] to the
root by following the parent hashes in each manifest, you will then have
a Merkle tree. Point-for-point, Fossil follows that definition.

Every change in Fossil starts by adding one or more manifests to
the repository, extending this tree.

[bcwp]:  https://en.wikipedia.org/wiki/Blockchain
[DAG]:   https://en.wikipedia.org/wiki/Directed_acyclic_graph
[SHA-1]: https://en.wikipedia.org/wiki/SHA-1
[SHA-3]: https://en.wikipedia.org/wiki/SHA-3









|


|
|



|
|
|
|
<

|







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

28
29
30
31
32
33
34
35
36

## The Dictionary Argument

The [Wikipedia definition of "blockchain"][bcwp] begins:

>
  "A blockchain…is a growing list of records, called blocks, which are linked using
   cryptography Each block contains a cryptographic hash of the previous
   block, a timestamp, and transaction data (generally represented as a Merkle tree)."

Point-for-point, Fossil follows this partial definition.
The blocks
are Fossil’s ["manifest" artifacts](./fileformat.wiki#manifest). Each
manifest has a cryptographically-strong [SHA-1] or [SHA-3] hash linking it to
one or more “parent” blocks. The manifest also contains a timestamp and
the transactional data needed to express a commit to the repository.
To traverse the Fossil repository from the tips of its [DAG] to the
root by following the parent hashes in each manifest is to traverse
a Merkle tree.

Every change in Fossil starts by adding one or more manifests to
the repository, extending this Merkle tree.

[bcwp]:  https://en.wikipedia.org/wiki/Blockchain
[DAG]:   https://en.wikipedia.org/wiki/Directed_acyclic_graph
[SHA-1]: https://en.wikipedia.org/wiki/SHA-1
[SHA-3]: https://en.wikipedia.org/wiki/SHA-3


59
60
61
62
63
64
65
66

67
68
69
70
71
72
73
    claims to be a $100 bill.

*   **Type 2** is creation of new fraudulent currency that will pass
    in commerce.  To extend our analogy, it is the creation of new
    US $10 bills. There are two sub-types to this fraud. In terms of
    our analogy, they are:

    *  **Type 2a**: copying of an existing legitimate $10 bill

    *  **Type 2b**: printing a new $10 bill that is unlike an existing
       legitimate one, yet which will still pass in commerce

*   **Type 3** is double-spending existing legitimate cryptocurrency.
    There is no analogy in paper money due to its physical form; it is a
    problem unique to digital currency due to its infinitely-copyable
    nature.







|
>







58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
    claims to be a $100 bill.

*   **Type 2** is creation of new fraudulent currency that will pass
    in commerce.  To extend our analogy, it is the creation of new
    US $10 bills. There are two sub-types to this fraud. In terms of
    our analogy, they are:

    *  **Type 2a**: copying an existing legitimate $10 bill<p>

    *  **Type 2b**: printing a new $10 bill that is unlike an existing
       legitimate one, yet which will still pass in commerce

*   **Type 3** is double-spending existing legitimate cryptocurrency.
    There is no analogy in paper money due to its physical form; it is a
    problem unique to digital currency due to its infinitely-copyable
    nature.
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141


142
143
144
145
146
147
148
149
    3 frauds by making the *prior* owner of a block sign it over to
    the new owner. To avoid an O(n²) auditing problem as a result,
    cryptocurrencies add a separate chain of hashes to make checking
    for double-spending quick and easy.

    Fossil has [a disabled-by-default feature][cs] to call out to an
    external copy of [PGP] or [GPG] to sign commit manifests before
    inserting them into the repository. You may wish to couple that with
    a server-side [after-receive hook][arh] to reject unsigned commits.

    Although there are several distinctions you can draw between the way
    Fossil’s commit signing scheme works and the way block signing works
    in cryptocurrencies, only one is of material interest for our
    purposes here: Fossil commit signatures apply only to a single
    commit. Fossil does not sign one commit over to the next “owner” of
    that commit in the way that a blockchain-based cryptocurrency must
    when transferring currency from one user to another, beacuse there
    is no useful analog to the double-spending problem in Fossil.  The
    closest you can come to this is double-insert of commits into the
    blockchain, which we’ll address shortly.

    What Fossil commit signatures actually do is provide in-tree forgery
    prevention, both Type 1 and Type 2. You cannot modify existing
    commits (Type 1 forgery) because you do not have the original
    committer’s private signing key, and you cannot forge new commits
    attesting to come from some other trusted committer (Type 2) because
    you don’t have any of their private signing keys, either.
    Cyrptocurrencies also use the work problem to prevent Type 2
    forgeries, but the application of that to Fossil is a matter we get
    to [later](#work).

    Although you have complete control over the contents of your local
    Fossil repository clone, you cannot perform Type 1 forgery on its
    contents short of executing a [preimage attack][prei] on the hash
    algorithm. ([SHA3-256][SHA-3] by default in the current version of
    Fossil.) Even if you could, Fossil’s sync protocol will prevent the
    modification from being pushed into another repository: the remote
    Fossil instance says, “I’ve already got that one, thanks,” and
    ignores the push.  Thus, short of breaking into the remote server
    and modifying the repository in place, you couldn’t even make use of
    a preimage attack if you had that power. This is an attack on the
    server itself, not on Fossil’s data structures, so while it is
    useful to think through this problem, it is not helpful to answering
    our questions here.

    The Fossil sync protocol also prevents the closest analog to Type 3
    frauds in Fossil: copying a commit manifest in your local repo clone
    won’t result in a double-commit on sync.

    In the absence of digital signatures, Fossil’s [RBAC system][caps]
    restricts Type 2 forgery to trusted committers. Thus once again
    we’re reduced to an infosec problem, not a data structure design


    question.  (Inversely, enabling commit clearsigning is a good idea
    if you have committers on your repo whom you don’t trust not to
    commit Type 2 frauds. But let us be clear: your choice of setting
    does not answer the question of whether Fossil is a blockchain.)

    If Fossil signatures prevent Type 1 and Type 2 frauds, you
    may wonder why they are not enabled by default. It is because
    they are defense-in-depth measures, not the minimum sufficient







|



















|











|
|

|


|






>
>
|







90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
    3 frauds by making the *prior* owner of a block sign it over to
    the new owner. To avoid an O(n²) auditing problem as a result,
    cryptocurrencies add a separate chain of hashes to make checking
    for double-spending quick and easy.

    Fossil has [a disabled-by-default feature][cs] to call out to an
    external copy of [PGP] or [GPG] to sign commit manifests before
    inserting them into the repository. You can couple that with
    a server-side [after-receive hook][arh] to reject unsigned commits.

    Although there are several distinctions you can draw between the way
    Fossil’s commit signing scheme works and the way block signing works
    in cryptocurrencies, only one is of material interest for our
    purposes here: Fossil commit signatures apply only to a single
    commit. Fossil does not sign one commit over to the next “owner” of
    that commit in the way that a blockchain-based cryptocurrency must
    when transferring currency from one user to another, beacuse there
    is no useful analog to the double-spending problem in Fossil.  The
    closest you can come to this is double-insert of commits into the
    blockchain, which we’ll address shortly.

    What Fossil commit signatures actually do is provide in-tree forgery
    prevention, both Type 1 and Type 2. You cannot modify existing
    commits (Type 1 forgery) because you do not have the original
    committer’s private signing key, and you cannot forge new commits
    attesting to come from some other trusted committer (Type 2) because
    you don’t have any of their private signing keys, either.
    Cryptocurrencies use the work problem to prevent Type 2
    forgeries, but the application of that to Fossil is a matter we get
    to [later](#work).

    Although you have complete control over the contents of your local
    Fossil repository clone, you cannot perform Type 1 forgery on its
    contents short of executing a [preimage attack][prei] on the hash
    algorithm. ([SHA3-256][SHA-3] by default in the current version of
    Fossil.) Even if you could, Fossil’s sync protocol will prevent the
    modification from being pushed into another repository: the remote
    Fossil instance says, “I’ve already got that one, thanks,” and
    ignores the push.  Thus, short of breaking into the remote server
    and modifying the repository in place, you couldn’t make use of
    a preimage attack even if you had that power. Further, that would be an attack on the
    server itself, not on Fossil’s data structures, so while it is
    useful to think through this problem, it is not helpful in answering
    our questions here.

    The Fossil sync protocol’s duplication detection also prevents the closest analog to Type 3
    frauds in Fossil: copying a commit manifest in your local repo clone
    won’t result in a double-commit on sync.

    In the absence of digital signatures, Fossil’s [RBAC system][caps]
    restricts Type 2 forgery to trusted committers. Thus once again
    we’re reduced to an infosec problem, not a data structure design
    question.

    (Inversely, enabling commit clearsigning is a good idea
    if you have committers on your repo whom you don’t trust not to
    commit Type 2 frauds. But let us be clear: your choice of setting
    does not answer the question of whether Fossil is a blockchain.)

    If Fossil signatures prevent Type 1 and Type 2 frauds, you
    may wonder why they are not enabled by default. It is because
    they are defense-in-depth measures, not the minimum sufficient
243
244
245
246
247
248
249
250
251
252
253
254


255
256
257

258
259
260
261
262
263
264
265
file, effectively destroying money in a similar way. These features
do not permit forgery of either type described above: you can’t use them
to change the value of existing commits (Type 1) or add new commits to
the repository (Type 2).

What if we removed those features from Fossil, creating an append-only
Fossil variant? Is it a DLT then? Arguably still not, because [today’s Fossil
is an AP-mode system][ctap] in the [CAP theorem][cap] sense, which means
there can be no guaranteed consensus on the content of the ledger at any
given time. If you had an AP-mode accounts receivable system, it could
have different bottom-line totals at different sites, because you’ve
cast away “C” to get AP-mode operation.



Because of this, you could still not guarantee that the command
“`fossil info tip`” gives the same result everywhere. A CA or CP-mode Fossil

variant would guarantee that everyone got the same result. (Everyone not
partitioned away from the majority of the network at any rate, in the CP
case.)

What are the prospects for CA-mode or CP-mode Fossil? [We don’t want
CA-mode Fossil][ctca], but [CP-mode could be useful][ctcp]. Until the latter
exists, this author believes Fossil is not a distributed ledger in a
technologically defensible sense.







|

|
|
|
>
>

|
|
>
|







245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
file, effectively destroying money in a similar way. These features
do not permit forgery of either type described above: you can’t use them
to change the value of existing commits (Type 1) or add new commits to
the repository (Type 2).

What if we removed those features from Fossil, creating an append-only
Fossil variant? Is it a DLT then? Arguably still not, because [today’s Fossil
is an AP-mode system][ctap], which means
there can be no guaranteed consensus on the content of the ledger at any
given time. An AP-mode accounts receivable system would allow
different bottom-line totals at different sites, because you’ve
cast away “C” to get AP-mode operation. (See the prior link or
[Wikipedia’s article on the CAP theorem][cap] if you aren’t following
this terminology.)

By the same token, you cannot guarantee that the command
“`fossil info tip`” gives the same result everywhere. You would need to
recast Fossil as a CA or CP-mode system to solve that.
(Everyone not
partitioned away from the majority of the network at any rate, in the CP
case.)

What are the prospects for CA-mode or CP-mode Fossil? [We don’t want
CA-mode Fossil][ctca], but [CP-mode could be useful][ctcp]. Until the latter
exists, this author believes Fossil is not a distributed ledger in a
technologically defensible sense.
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
* You could enable [the `self-register` setting][sreg] and choose not to
  enable [commit clear-signing][cs] so that anonymous users could push
  commits into your repository under any name they want.

On the server side, you can also [scrub] the logging that remembers
where each commit came from.

That info isn’t transmitted from the remote server on clone or pull.
Instead, the size of the `rcvfrom` table after initial clone is 1: it
contains the remote server’s IP address. On each pull containing new
artifacts, your local `fossil` instance adds another entry to this
table, likely with the same IP address unless the server has moved or
you’re using [multiple remotes][mrep]. This table is far more
interesting on the server side, containing the IP addresses of all
contentful pushes; thus [the `scrub` command][scrub].

Because Fossil doesn’t







|
|
|







369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
* You could enable [the `self-register` setting][sreg] and choose not to
  enable [commit clear-signing][cs] so that anonymous users could push
  commits into your repository under any name they want.

On the server side, you can also [scrub] the logging that remembers
where each commit came from.

Commit source info isn’t transmitted from the remote server on clone or pull:
the size of the `rcvfrom` table after initial clone is 1, containing
only the remote server’s IP address. On each pull containing new
artifacts, your local `fossil` instance adds another entry to this
table, likely with the same IP address unless the server has moved or
you’re using [multiple remotes][mrep]. This table is far more
interesting on the server side, containing the IP addresses of all
contentful pushes; thus [the `scrub` command][scrub].

Because Fossil doesn’t
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
[sreg]:  /help?cmd=self-register


# Conclusion

This author believes it is technologically indefensible to call Fossil a
“blockchain” in any sense likely to be understood by a majority of those
you’re communicating with.

Within a certain narrow scope, you can defend this usage, but if you do
that, you’ve failed any goal that requires clear communication: it
doesn’t work to use a term in a nonstandard way just because you can
defend it.  The people you’re communicating your ideas to must have the
same concept of the terms you use.


What term should you use instead? Fossil stores a DAG of hash-chained
commits, so an indisputably correct term is a [Merkle tree][mt], named
after [its inventor][drrm].  You could also use the more generic term
“hash tree.”

Fossil is a technological peer to many common sorts of blockchain
technology. There is a lot of overlap in concepts and implementation
details, but when speaking of what most people understand as
“blockchain,” Fossil is not that.

[drrm]: https://en.wikipedia.org/wiki/Ralph_Merkle
[mt]:   https://en.wikipedia.org/wiki/Merkle_tree







|
<
<
|
<
|

<













455
456
457
458
459
460
461
462


463

464
465

466
467
468
469
470
471
472
473
474
475
476
477
478
[sreg]:  /help?cmd=self-register


# Conclusion

This author believes it is technologically indefensible to call Fossil a
“blockchain” in any sense likely to be understood by a majority of those
you’re communicating with. Using a term in a nonstandard way just because you can


defend it means you’ve failed any goal that requires clear communication.

The people you’re communicating your ideas to must have the
same concept of the terms you use.


What term should you use instead? Fossil stores a DAG of hash-chained
commits, so an indisputably correct term is a [Merkle tree][mt], named
after [its inventor][drrm].  You could also use the more generic term
“hash tree.”

Fossil is a technological peer to many common sorts of blockchain
technology. There is a lot of overlap in concepts and implementation
details, but when speaking of what most people understand as
“blockchain,” Fossil is not that.

[drrm]: https://en.wikipedia.org/wiki/Ralph_Merkle
[mt]:   https://en.wikipedia.org/wiki/Merkle_tree
Changes to www/caps/admin-v-setup.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# Differences Between Setup and Admin Users

This document explains the distinction between [Setup users][caps] and
[Admin users][capa]. For other information about use types, see:

* [Administering User Capabilities](./)
* [How Moderation Works](../forum.wiki#moderation)
* [Users vs Subscribers](../alerts.md#uvs)
* [Defense Against Spiders](../antibot.wiki)


## <a name="philosophy"></a>Philosophical Core

The Setup user "owns" the Fossil repository and may delegate a subset of
that power to one or more Admin users.

The Setup user can grant Admin capability and take it away, but Admin
users cannot grant themselves Setup capability, either directly via the
Admin → Users UI page or via any indirect means. (If you discover











|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# Differences Between Setup and Admin Users

This document explains the distinction between [Setup users][caps] and
[Admin users][capa]. For other information about use types, see:

* [Administering User Capabilities](./)
* [How Moderation Works](../forum.wiki#moderation)
* [Users vs Subscribers](../alerts.md#uvs)
* [Defense Against Spiders](../antibot.wiki)


## <a id="philosophy"></a>Philosophical Core

The Setup user "owns" the Fossil repository and may delegate a subset of
that power to one or more Admin users.

The Setup user can grant Admin capability and take it away, but Admin
users cannot grant themselves Setup capability, either directly via the
Admin → Users UI page or via any indirect means. (If you discover
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
We’ll explore these distinctions in the rest of this document.

[bc]:   ../blockchain.md
[ucap]: ./index.md#ucap
[uv]:   ../unvers.wiki


## <a name="binary"></a>No Granularity

Fossil doesn’t make any distinction between these two user types beyond
this binary choice: Setup or Admin.

A few features of Fossil are broken down so that only part of the
feature is accessible to Admin, with the rest left only to Setup users,
but for the most part each feature affected by this distinction is







|







55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
We’ll explore these distinctions in the rest of this document.

[bc]:   ../blockchain.md
[ucap]: ./index.md#ucap
[uv]:   ../unvers.wiki


## <a id="binary"></a>No Granularity

Fossil doesn’t make any distinction between these two user types beyond
this binary choice: Setup or Admin.

A few features of Fossil are broken down so that only part of the
feature is accessible to Admin, with the rest left only to Setup users,
but for the most part each feature affected by this distinction is
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
the Admin user is allowed to do, and which must be left to Setup? Do we
assign a separate capability letter to each step in `/setup_skin`? Do we
assign one more each to the five sections of a skin? (Header, Footer,
CSS, JavaScript, and Details.) It quickly becomes unmanageable.



## <a name="capgroups"></a>Capability Groups

We can break up the set of powers the Admin user capability grants into
several groups, then defend each group as a coherent whole.


### <a name="security"></a>Security

While establishing the Fossil repository's security policy is a task for
the Setup user, *maintaining* that policy is something that Fossil
allows a Setup user to delegate to trustworthy users via the Admin user
capability:

*   **Manage users**: The only thing an Admin-only user cannot do on the







|





|







89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
the Admin user is allowed to do, and which must be left to Setup? Do we
assign a separate capability letter to each step in `/setup_skin`? Do we
assign one more each to the five sections of a skin? (Header, Footer,
CSS, JavaScript, and Details.) It quickly becomes unmanageable.



## <a id="capgroups"></a>Capability Groups

We can break up the set of powers the Admin user capability grants into
several groups, then defend each group as a coherent whole.


### <a id="security"></a>Security

While establishing the Fossil repository's security policy is a task for
the Setup user, *maintaining* that policy is something that Fossil
allows a Setup user to delegate to trustworthy users via the Admin user
capability:

*   **Manage users**: The only thing an Admin-only user cannot do on the
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146

Some security-conscious people might be bothered by the fact that
Admin-only users have these abilities. Think of a large IT organization:
if the CIO hires a [tiger team][tt] to test the company's internal IT
defenses, the line grunts fix the reported problems, not the CIO.


### <a name="administrivia"></a>Administrivia

It is perfectly fine for a Fossil repository to only have Setup users,
no Admin users. The smaller the repository, the more likely the
repository has no Admin-only users. If the Setup user neither needs nor
wants to grant Admin power to others, there is no requirement in Fossil
to do so. [Setup capability is a pure superset of Admin capability.][sia]








|







132
133
134
135
136
137
138
139
140
141
142
143
144
145
146

Some security-conscious people might be bothered by the fact that
Admin-only users have these abilities. Think of a large IT organization:
if the CIO hires a [tiger team][tt] to test the company's internal IT
defenses, the line grunts fix the reported problems, not the CIO.


### <a id="administrivia"></a>Administrivia

It is perfectly fine for a Fossil repository to only have Setup users,
no Admin users. The smaller the repository, the more likely the
repository has no Admin-only users. If the Setup user neither needs nor
wants to grant Admin power to others, there is no requirement in Fossil
to do so. [Setup capability is a pure superset of Admin capability.][sia]

202
203
204
205
206
207
208
209
210
211
212
213
214
215
216

*   **Configure search**

[ale]:  ../alerts.md
[shun]: ../shunning.wiki


### <a name="cosmetics"></a>Cosmetics

While the Setup user is responsible for setting up the initial "look" of
a Fossil repository, the Setup user entrusts Admin users with
*maintaining* that look. An Admin-only user therefore has the following
special abilities:

*   Modify the repository skin







|







202
203
204
205
206
207
208
209
210
211
212
213
214
215
216

*   **Configure search**

[ale]:  ../alerts.md
[shun]: ../shunning.wiki


### <a id="cosmetics"></a>Cosmetics

While the Setup user is responsible for setting up the initial "look" of
a Fossil repository, the Setup user entrusts Admin users with
*maintaining* that look. An Admin-only user therefore has the following
special abilities:

*   Modify the repository skin
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260

These capabilities allow an Admin-only user to affect the branding and
possibly even the back-end finances of a project. This is why we began
this document with a philosophical discussion: if you cannot entrust a
user with these powers, you should not grant that user Admin capability.


## <a name="clones"></a>Clones and Backups

Fossil is a *distributed* version control system, which has direct
effects on the “Setup user” concept in the face of clones. When you
clone a repository, your local user becomes a Setup user on the local
clone even if you are not one on the remote repository. This may be
surprising to you, but it should also be sensible once you realize that
your operating system will generally give you full control over the
local repository file.  What use trying to apply remote restrictions on
the local file, then?

The distinctions above therefore are intransitive: they apply only
within a single repository instance.

Fossil behaves differently when you do a clone as a user with Setup
capability on the remote repository, which primarily has effects on the
fidelity of clone-as-backup, which we cover [elsewhere](../backup.md).
We strongly encourage you to read that document if you expect to use a
clone as a complete replacement for the remote repository.


## <a name="apsu"></a>The All-Powerful Setup User

Setup users get [every user capability](./ref.html) of Fossil except for
[two exceptionally dangerous capabilities](#dcap), which they can later
grant to themselves or to others.

In addition, Setup users can use every feature of the Fossil UI. If Fossil can do a
thing, a Setup user on that repo can make Fossil do it.







|




















|







225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260

These capabilities allow an Admin-only user to affect the branding and
possibly even the back-end finances of a project. This is why we began
this document with a philosophical discussion: if you cannot entrust a
user with these powers, you should not grant that user Admin capability.


## <a id="clones"></a>Clones and Backups

Fossil is a *distributed* version control system, which has direct
effects on the “Setup user” concept in the face of clones. When you
clone a repository, your local user becomes a Setup user on the local
clone even if you are not one on the remote repository. This may be
surprising to you, but it should also be sensible once you realize that
your operating system will generally give you full control over the
local repository file.  What use trying to apply remote restrictions on
the local file, then?

The distinctions above therefore are intransitive: they apply only
within a single repository instance.

Fossil behaves differently when you do a clone as a user with Setup
capability on the remote repository, which primarily has effects on the
fidelity of clone-as-backup, which we cover [elsewhere](../backup.md).
We strongly encourage you to read that document if you expect to use a
clone as a complete replacement for the remote repository.


## <a id="apsu"></a>The All-Powerful Setup User

Setup users get [every user capability](./ref.html) of Fossil except for
[two exceptionally dangerous capabilities](#dcap), which they can later
grant to themselves or to others.

In addition, Setup users can use every feature of the Fossil UI. If Fossil can do a
thing, a Setup user on that repo can make Fossil do it.
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
through that UI instance, regardless of the capability set defined in
the repo’s user table. This is true even if you cloned a remote repo
where you do not have Setup caps. This is why `ui` always binds to
`localhost` without needing the `--localhost` flag: in this mode, anyone
who can connect to that repo’s web UI has full power over that repo.


## <a name="dcap"></a>Dangerous Capabilities Initially Denied to Everyone

There are two capabilities that Fossil doesn’t grant by default to Setup
or Admin users automatically. They are exceptionally dangerous, so
Fossil makes these users grant themselves (or others) these capabilities
deliberately, hopefully after careful consideration.


### <a name="y"></a>Write Unversioned

Fossil currently doesn’t distinguish the sub-operations of
[`fossil uv`](/help?cmd=uv); they’re all covered by [**WrUnver**][capy]
(“y”) capability. Since some of these operations are unconditionally
destructive due to the nature of unversioned content, and since this
goes against Fossil’s philosophy of immutable history, nobody gets cap
“y” on a Fossil repo by default, not even the Setup or Admin users.  A
Setup or Admin user must grant cap “y” to someone — not necessarily
themselves! — before modifications to remote
unversioned content are possible.

Operations on unversioned content made without this capability affect
your local clone only. In this way, your local unversioned file table
can have different content from that in its parent repo. This state of
affairs will continue until your user either gets cap “y” and syncs that
content with its parent or you say `fossil uv revert` to make your local
unversioned content table match that of its parent repo.


### <a name="x"></a>Private Branch Push

For private branches to remain private, they must never be accidentally
pushed to a public repository. It can be [difficult to impossible][shun]
to recover from such a mistake, so nobody gets [**Private**][capx] (“x”)
capability on a Fossil repo by default, not even Admin or Setup users.

There are two common uses for private branches.







|







|



















|







382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
through that UI instance, regardless of the capability set defined in
the repo’s user table. This is true even if you cloned a remote repo
where you do not have Setup caps. This is why `ui` always binds to
`localhost` without needing the `--localhost` flag: in this mode, anyone
who can connect to that repo’s web UI has full power over that repo.


## <a id="dcap"></a>Dangerous Capabilities Initially Denied to Everyone

There are two capabilities that Fossil doesn’t grant by default to Setup
or Admin users automatically. They are exceptionally dangerous, so
Fossil makes these users grant themselves (or others) these capabilities
deliberately, hopefully after careful consideration.


### <a id="y"></a>Write Unversioned

Fossil currently doesn’t distinguish the sub-operations of
[`fossil uv`](/help?cmd=uv); they’re all covered by [**WrUnver**][capy]
(“y”) capability. Since some of these operations are unconditionally
destructive due to the nature of unversioned content, and since this
goes against Fossil’s philosophy of immutable history, nobody gets cap
“y” on a Fossil repo by default, not even the Setup or Admin users.  A
Setup or Admin user must grant cap “y” to someone — not necessarily
themselves! — before modifications to remote
unversioned content are possible.

Operations on unversioned content made without this capability affect
your local clone only. In this way, your local unversioned file table
can have different content from that in its parent repo. This state of
affairs will continue until your user either gets cap “y” and syncs that
content with its parent or you say `fossil uv revert` to make your local
unversioned content table match that of its parent repo.


### <a id="x"></a>Private Branch Push

For private branches to remain private, they must never be accidentally
pushed to a public repository. It can be [difficult to impossible][shun]
to recover from such a mistake, so nobody gets [**Private**][capx] (“x”)
capability on a Fossil repo by default, not even Admin or Setup users.

There are two common uses for private branches.
Changes to www/caps/impl.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# Implementation Details of User Capabilities

## <a name="choices"></a>Capability Letter Choices

We [assigned][ref] user capability characters using only lowercase ASCII
letters at first, so those are the most important within Fossil: they
control the functions most core to Fossil’s operation. Once we used up
most of the lowercase letters, we started using uppercase, and then
during the development of the [forum feature][for] we assigned most of
the decimal numerals. All of the lowercase ASCII letters are now
assigned. Eventually, we might have to start using ASCII
punctuation and symbols. We expect to run out of reasons to define new caps before
we’re forced to switch to Unicode, though the possibilities for [mnemonic][mn]
assignments with emoji are intriguing. <span style="vertical-align:
bottom">😉</span>

The existing caps are usually mnemonic, especially among the
earliest and therefore most central assignments, made when we still had
lots of letters to choose from.  There is still hope for good future
mnemonic assignments among the uppercase letters, which are mostly still
unused.


## <a name="bitfield"></a>Why Not Bitfields?

Some may question the use of ASCII character strings for [capability
sets][ucap] instead of bitfields, which are more efficient, both in
terms of storage and processing time.

Fossil handles these character strings in one of two ways. For most HTTP
hits, Fossil [expands][sexp] the string into a [`struct` full of


|




















|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# Implementation Details of User Capabilities

## <a id="choices"></a>Capability Letter Choices

We [assigned][ref] user capability characters using only lowercase ASCII
letters at first, so those are the most important within Fossil: they
control the functions most core to Fossil’s operation. Once we used up
most of the lowercase letters, we started using uppercase, and then
during the development of the [forum feature][for] we assigned most of
the decimal numerals. All of the lowercase ASCII letters are now
assigned. Eventually, we might have to start using ASCII
punctuation and symbols. We expect to run out of reasons to define new caps before
we’re forced to switch to Unicode, though the possibilities for [mnemonic][mn]
assignments with emoji are intriguing. <span style="vertical-align:
bottom">😉</span>

The existing caps are usually mnemonic, especially among the
earliest and therefore most central assignments, made when we still had
lots of letters to choose from.  There is still hope for good future
mnemonic assignments among the uppercase letters, which are mostly still
unused.


## <a id="bitfield"></a>Why Not Bitfields?

Some may question the use of ASCII character strings for [capability
sets][ucap] instead of bitfields, which are more efficient, both in
terms of storage and processing time.

Fossil handles these character strings in one of two ways. For most HTTP
hits, Fossil [expands][sexp] the string into a [`struct` full of
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
network connection, followed by the required I/O to satisfy the request.
Either method is plenty fast in that context.

In exchange for this immeasurable cost per hit, we get human-readable
capability sets.


## <a name="filter"></a>Why Doesn’t Fossil Filter “Bad” Artifacts on Sync?

Fossil is more trusting about the content it receives from a remote
clone during sync than you might expect. Common manifestations of this
design choice are:

1.  A user may be able to impersonate other users. This can be
    [accidental](./index.md#defuser) as well as purposeful.







|







41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
network connection, followed by the required I/O to satisfy the request.
Either method is plenty fast in that context.

In exchange for this immeasurable cost per hit, we get human-readable
capability sets.


## <a id="filter"></a>Why Doesn’t Fossil Filter “Bad” Artifacts on Sync?

Fossil is more trusting about the content it receives from a remote
clone during sync than you might expect. Common manifestations of this
design choice are:

1.  A user may be able to impersonate other users. This can be
    [accidental](./index.md#defuser) as well as purposeful.
Changes to www/caps/index.md.
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

[an]:   https://en.wikipedia.org/wiki/Alphanumeric
[avs]:  ./admin-v-setup.md
[lg]:   ./login-groups.md
[rbac]: https://en.wikipedia.org/wiki/Role-based_access_control


## <a name="ucat"></a>User Categories

Before we explain individual user capabilities and their proper
administration, we want to talk about an oft-overlooked and
misunderstood feature of Fossil: user categories.

Fossil defines four user categories. Two of these apply based on the
user’s login status: **nobody** and **anonymous**. The other two act







|







18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

[an]:   https://en.wikipedia.org/wiki/Alphanumeric
[avs]:  ./admin-v-setup.md
[lg]:   ./login-groups.md
[rbac]: https://en.wikipedia.org/wiki/Role-based_access_control


## <a id="ucat"></a>User Categories

Before we explain individual user capabilities and their proper
administration, we want to talk about an oft-overlooked and
misunderstood feature of Fossil: user categories.

Fossil defines four user categories. Two of these apply based on the
user’s login status: **nobody** and **anonymous**. The other two act
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
treat the same category as if it were called “member.”

There is currently no way to define custom user categories.

[svr]: ../server/


## <a name="ucap"></a>Individual User Capabilities

When one or more users need to be different from the basic capabilities
defined in user categories, you can assign caps to individual users. You
may want to have the [cap reference][ref] open when doing such work.

It is useful at this time to expand on the logical
expression [above](#cat), which covered only the four fixed user categories.







|







80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
treat the same category as if it were called “member.”

There is currently no way to define custom user categories.

[svr]: ../server/


## <a id="ucap"></a>Individual User Capabilities

When one or more users need to be different from the basic capabilities
defined in user categories, you can assign caps to individual users. You
may want to have the [cap reference][ref] open when doing such work.

It is useful at this time to expand on the logical
expression [above](#cat), which covered only the four fixed user categories.
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
subscribers, which is why we show it in square brackets.  (See [Users vs
Subscribers](../alerts.md#uvs).)

[apsu]: ./admin-v-setup.md#apsu
[avsp]: ./admin-v-setup.md#philosophy


## <a name="new"></a>New Repository Defaults

Fossil creates one user account in new repos, which is named after your
OS user name [by default](#defuser).

Fossil gives the initial repository user the [all-powerful Setup
capability][apsu].








|







116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
subscribers, which is why we show it in square brackets.  (See [Users vs
Subscribers](../alerts.md#uvs).)

[apsu]: ./admin-v-setup.md#apsu
[avsp]: ./admin-v-setup.md#philosophy


## <a id="new"></a>New Repository Defaults

Fossil creates one user account in new repos, which is named after your
OS user name [by default](#defuser).

Fossil gives the initial repository user the [all-powerful Setup
capability][apsu].

155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
Those in the “developer” category get the “nobody” and “anonymous” cap
sets plus **[e][e][i][i]**: view
sensitive user material and check in changes.

[bot]: ../antibot.wiki


## <a name="pvt"></a>Consequences of Taking a Repository Private

When you click Admin → Security-Audit → “Take it private,” one of the
things it does is set the user capabilities for the “nobody” and
“anonymous” user categories to blank, so that users who haven’t logged
in can’t even see your project’s home page, and the option to log in as
“anonymous” isn’t even offered. Until you log in with a user name, all
you see is the repository’s skin and those few UI elements that work
without any user capability checks at all, such as the “Login” link.

Beware: Fossil does not reassign the capabilities these users had to
other users or to the “reader” or “developer” user category! All users
except those with Setup capability will lose all capabilities they
inherited from “nobody” and “anonymous” categories. Setup is the [lone
exception][apsu].

If you will have non-Setup users in your private repo, you should parcel
out some subset of the capability set the “nobody” and “anonymous”
categories had to other categories or to individual users first.


## <a name="read-v-clone"></a>Reading vs. Cloning

Fossil has two capabilities that are often confused:
[**Read**](./ref.html#o) and [**Clone**](./ref.html#g).

The **Read** capability has nothing to do with reading data from a local
repository, because [caps affect Fossil’s web interfaces
only](#webonly). Once you’ve cloned a remote repository to your local







|




















|







155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
Those in the “developer” category get the “nobody” and “anonymous” cap
sets plus **[e][e][i][i]**: view
sensitive user material and check in changes.

[bot]: ../antibot.wiki


## <a id="pvt"></a>Consequences of Taking a Repository Private

When you click Admin → Security-Audit → “Take it private,” one of the
things it does is set the user capabilities for the “nobody” and
“anonymous” user categories to blank, so that users who haven’t logged
in can’t even see your project’s home page, and the option to log in as
“anonymous” isn’t even offered. Until you log in with a user name, all
you see is the repository’s skin and those few UI elements that work
without any user capability checks at all, such as the “Login” link.

Beware: Fossil does not reassign the capabilities these users had to
other users or to the “reader” or “developer” user category! All users
except those with Setup capability will lose all capabilities they
inherited from “nobody” and “anonymous” categories. Setup is the [lone
exception][apsu].

If you will have non-Setup users in your private repo, you should parcel
out some subset of the capability set the “nobody” and “anonymous”
categories had to other categories or to individual users first.


## <a id="read-v-clone"></a>Reading vs. Cloning

Fossil has two capabilities that are often confused:
[**Read**](./ref.html#o) and [**Clone**](./ref.html#g).

The **Read** capability has nothing to do with reading data from a local
repository, because [caps affect Fossil’s web interfaces
only](#webonly). Once you’ve cloned a remote repository to your local
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
on private or semi-private repos to prevent them from pulling individual
elements of the repo over the web one at a time, as someone may do when
denied the bulk **Clone** capability.

[edoc]: ../embeddeddoc.wiki


## <a name="defuser"></a>Default User Name

By default, Fossil assumes your OS user account name is the same as the
one you use in any Fossil repository. It is the [default for a new
repository](#new), though you can override this with [the `--admin-user`
option][auo]. Fossil has other ways of overriding this in other contexts
such as the `name@` syntax in clone URLs.








|







204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
on private or semi-private repos to prevent them from pulling individual
elements of the repo over the web one at a time, as someone may do when
denied the bulk **Clone** capability.

[edoc]: ../embeddeddoc.wiki


## <a id="defuser"></a>Default User Name

By default, Fossil assumes your OS user account name is the same as the
one you use in any Fossil repository. It is the [default for a new
repository](#new), though you can override this with [the `--admin-user`
option][auo]. Fossil has other ways of overriding this in other contexts
such as the `name@` syntax in clone URLs.

232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270






271
272
273
274

275
276
277
278
279
280
281
282
283
284
285
286

287

288
289
290
291
292
293
294
295
296

297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316

317
318
319
320

321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343

[auo]:  /help?name=new
[fos]:  ./impl.md#filter
[shun]: ../shunning.wiki



## <a name="utclone"></a>Cloning the User Table

When cloning over HTTP, the initial user table in the local clone is set
to its “[new state:](#new)” only one user with Setup capability, named
after either  your OS user account, per the default above, or after the
user given in the clone URL.

There is one exception: if you clone as a named Setup user, you get a
complete copy of the user information. This restriction keeps the user
table private except for the only user allowed to make absolutely
complete clones of a remote repo, such as for failover or backup
purposes. Every other user’s clone is missing this and a few other
items, either for information security or PII privacy reasons.

When cloning with file system paths, `file://` URLs, or over SSH, you
get a complete clone, including the parent repo’s complete user table.

All of the above applies to [login groups][lg] as well.


## <a name="webonly"></a>Caps Affect Web Interfaces Only

Fossil’s user capability system only affects accesses over `http[s]://`
URLs. This includes clone, sync/push/pull, the [UI pages][wp], and [the
JSON API][japi].  For everything else, the user caps aren’t consulted at
all.

The only checks made when working directly with a local repository are
the operating system’s file system permissions.  This should strike you
as sensible, since if you have local file access to the repository, you
can do anything you want to that repo DB including adding a
[**Setup**][s] user for yourself, after which Fossil’s user capability






system is effectively bypassed. This is why the `fossil ui` command
gives you Setup permissions within Fossil UI: it can’t usefully prevent
you from doing anything through the UI since only the local file system
permissions actually matter.


What may be more surprising to you is that this is also true when
working on a *clone* done over a local file path, except that there are
then two sets of file system permission checks: once to modify the
working check-out’s repo clone DB file, then again on [sync][sync] with
the parent DB file. The Fossil capability checks are effectively
defeated because your user has [**Setup**][s] capability on both sides
of the sync. Be aware that those file checks do still matter, however:
Fossil requires write access to a repo DB while cloning from it, so you
can’t clone from a read-only repo DB file over a local file path.

Even more surprising may be the fact that user caps do not affect

cloning and syncing over SSH! When you make a change to such a

repository, the change first goes to the local clone where file system
permissions are all that matter, but then upon sync, the situation is
effectively the same as when the parent repo is on the local file
system. The reason behind this is that if you can log into the remote
system over SSH and that user has the necessary file system permissions
on that remote repo DB file to allow clone and sync operations, then
we’re back in the same situation as with local files: there’s no point
trying to enforce the Fossil user capabilities when you can just modify
the remote DB directly, so the operation proceeds unimpeded.


Where this gets confusing is that *all* Fossil syncs are done over the
HTTP protocol, including those done over `file://` and `ssh://` URLs,
not just those done over `http[s]://` URLs:

*   For `ssh://` URLs, Fossil pipes the HTTP conversation through a
    local SSH client to a remote instance of Fossil running the
    [`test-http`](/help?name=test-http) command to receive the tunneled
    HTTP connection. The reason Fossil’s user capability system is
    bypassed in this case is that [`test-http` gives full capabilities
    to its users][sxycap].

*   For `file://` URLs — as opposed to plain local file paths —
    the “sending” Fossil instance writes its side of
    the HTTP conversation out to a temporary file in the same directory
    as the local repo clone and then calls itself on the “receiving”
    repository to read that same HTTP transcript file back in to apply
    those changes to that repository. Presumably Fossil does this
    instead of using a pipe to ease portability to Windows.


Checks for capabilities like [**Read**][o] and [**Write**][i] within the
HTTP conversation between two Fossil instances only have a useful effect
when done over an `http[s]://` URL.


[sxycap]: /file?ci=ec5efceb8aac6cb4&name=src/main.c&ln=2748-2752


## <a name="pubpg"></a>Public Pages

In Admin → Access, there is an option for giving a list of [globs][glob]
to name URLs which get treated as if the visitor had [the default cap
set](#defcap). For example, you could take the [**Read**][o] capability
away from the “nobody” user category, who has it by default, to prevent
users without logins from pulling down your repository contents one
artifact at a time, yet give those users the ability to read the project
documentation by setting the glob to match your [embedded
documentation][edoc]’s URL root.


## <a name="defcap"></a>Default User Capability Set

In Admin → Access, you can define a default user capability set, which
is used as:

1.  the default caps for users newly created by an Admin or Setup user
2.  the default caps for self-registered users, an option in that same UI
3.  the effective caps for URIs considered [public pages](#pubpg)







|



















|








|
|
|
>
>
>
>
>
>
|


|
>











|
>
|
>
|







|
>








|
<
<









>
|



>



|











|







232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315


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

[auo]:  /help?name=new
[fos]:  ./impl.md#filter
[shun]: ../shunning.wiki



## <a id="utclone"></a>Cloning the User Table

When cloning over HTTP, the initial user table in the local clone is set
to its “[new state:](#new)” only one user with Setup capability, named
after either  your OS user account, per the default above, or after the
user given in the clone URL.

There is one exception: if you clone as a named Setup user, you get a
complete copy of the user information. This restriction keeps the user
table private except for the only user allowed to make absolutely
complete clones of a remote repo, such as for failover or backup
purposes. Every other user’s clone is missing this and a few other
items, either for information security or PII privacy reasons.

When cloning with file system paths, `file://` URLs, or over SSH, you
get a complete clone, including the parent repo’s complete user table.

All of the above applies to [login groups][lg] as well.


## <a id="webonly"></a>Caps Affect Web Interfaces Only

Fossil’s user capability system only affects accesses over `http[s]://`
URLs. This includes clone, sync/push/pull, the [UI pages][wp], and [the
JSON API][japi].  For everything else, the user caps aren’t consulted at
all.

The only checks made when working directly with a local repository are
the operating system’s file system permissions.  This should strike you
as sensible, since if you have read access to the repository file, you
can do anything you want to that repo DB including giving your user’s
record the [**Setup**][s] capability, after which Fossil’s user
capability system is effectively bypassed. (Or, create another Setup
user, with the same end effect.) If you’re objecting that you need
*write* access to the DB file to achieve this, realize that you can copy
a read-only file to another location, giving yourself write access to
it.

This is why the `fossil ui` command
gives you Setup permissions within Fossil UI: it can’t usefully prevent
you from doing anything through the UI since only the local file system
permissions actually matter, and you can’t start `fossil ui` without
having at least read access to that file.

What may be more surprising to you is that this is also true when
working on a *clone* done over a local file path, except that there are
then two sets of file system permission checks: once to modify the
working check-out’s repo clone DB file, then again on [sync][sync] with
the parent DB file. The Fossil capability checks are effectively
defeated because your user has [**Setup**][s] capability on both sides
of the sync. Be aware that those file checks do still matter, however:
Fossil requires write access to a repo DB while cloning from it, so you
can’t clone from a read-only repo DB file over a local file path.

Even more surprising to you may be the fact that user caps do not affect
cloning and syncing over SSH! (Not unless you go [out of your way][sshfc]
patch around it, at any rate.) When you make a change to such a
repository, the stock Fossil behavior is that the change first goes to the
local repo clone where file system
permissions are all that matter, but then upon sync, the situation is
effectively the same as when the parent repo is on the local file
system. The reason behind this is that if you can log into the remote
system over SSH and that user has the necessary file system permissions
on that remote repo DB file to allow clone and sync operations, then
we’re back in the same situation as with local files: there’s no point
trying to enforce the Fossil user capabilities when you can just modify
the remote DB directly, so the operation proceeds unimpeded by any user
capability settings on the remote repo.

Where this gets confusing is that *all* Fossil syncs are done over the
HTTP protocol, including those done over `file://` and `ssh://` URLs,
not just those done over `http[s]://` URLs:

*   For `ssh://` URLs, Fossil pipes the HTTP conversation through a
    local SSH client to a remote instance of Fossil running the
    [`test-http`](/help?name=test-http) command to receive the tunneled
    HTTP connection. [This interface is intentionally permissionless][sxycap].



*   For `file://` URLs — as opposed to plain local file paths —
    the “sending” Fossil instance writes its side of
    the HTTP conversation out to a temporary file in the same directory
    as the local repo clone and then calls itself on the “receiving”
    repository to read that same HTTP transcript file back in to apply
    those changes to that repository. Presumably Fossil does this
    instead of using a pipe to ease portability to Windows.

Despite use of HTTP for these URL types, the fact remains that 
checks for capabilities like [**Read**][o] and [**Write**][i] within the
HTTP conversation between two Fossil instances only have a useful effect
when done over an `http[s]://` URL.

[sshfc]:  ../server/any/http-over-ssh.md
[sxycap]: /file?ci=ec5efceb8aac6cb4&name=src/main.c&ln=2748-2752


## <a id="pubpg"></a>Public Pages

In Admin → Access, there is an option for giving a list of [globs][glob]
to name URLs which get treated as if the visitor had [the default cap
set](#defcap). For example, you could take the [**Read**][o] capability
away from the “nobody” user category, who has it by default, to prevent
users without logins from pulling down your repository contents one
artifact at a time, yet give those users the ability to read the project
documentation by setting the glob to match your [embedded
documentation][edoc]’s URL root.


## <a id="defcap"></a>Default User Capability Set

In Admin → Access, you can define a default user capability set, which
is used as:

1.  the default caps for users newly created by an Admin or Setup user
2.  the default caps for self-registered users, an option in that same UI
3.  the effective caps for URIs considered [public pages](#pubpg)
Changes to www/changes.wiki.
1
2
3
4







5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24


25
26
27


28



29




30


31
32






33

34
35
36
37
38
39
40
41
42
43
<title>Change Log</title>

<a name='v2_17'></a>
<h2>Changes for version 2.17 (pending)</h2>







  *  The --branchcolor option on [/help?cmd=commit|fossil commit] and
     [/help?cmd=amend|fossil amend] can now take the value "auto" to
     force Fossil to use its built-in automatic color choosing algorithm.
  *  Fossil now [./concepts.wiki#workflow|autosyncs] prior to running 
     [/help?cmd=open|fossil open].
  *  Add the [/help?cmd=ticket-default-report|ticket-default-report setting],
     which if set to the title of a ticket report causes that ticket report
     to be displayed below the search box in the /ticket page.
  *  The "nc" query parameter to the [/help?cmd=/timeline|/timeline] page
     causes all graph coloring to be omitted.
  *  Improvements and bug fixes to the new "fossil ui REMOTE" feature so
     that it works better on a wider variety of platforms.
  *  In [/help?cmd=/wikiedit|/wikiedit], show the list of attachments for 
     the current page and list URLs suitable for pasting them into the page.
  *  Add the --no-http-compression option to [/help?cmd=sync|fossil sync]
     and similar.
  *  Print total payload bytes on a [/help?cmd=sync|fossil sync] when using
     the --verbose option.
  *  Add the <tt>close</tt>, <tt>reopen</tt>, <tt>hide</tt>, and
     </tt>unhide</tt> subcommands to [/help?cmd=branch|the branch command].


  *  The [/mdrules|Markdown formatter] now interprets the content of
     block HTML markup (such as &lt;table&gt;) in most cases.  Only content
     of &lt;pre&gt; and &lt;script&gt; is passed through verbatim.


  *  [/wcontent|Listing] of the available wiki pages



     [/timeline?r=wcontent-subsets|gained] the ability to




     [./javascript.md#wcontent|interactively] adjust a subset of


     wiki pages that are shown; this is based on the
     classification of wiki page names according to the






     [/help?cmd=wiki-classes|configurable] glob patterns.


<a name='v2_16'></a>
<h2>Changes for Version 2.16 (2021-07-02)</h2>
  *  <b>Security:</b> Fix the client-side TLS so that it verifies that the
     server hostname matches its certificate.
  *  The default "ssh" command on Windows is changed to "ssh" instead of the
     legacy "plink", as ssh is now generally available on Windows systems.
     Installations that still need to use the legacy "plink" can make that
     happen by running: '<tt>fossil set ssh-command "plink -ssh" --global</tt>'.
  *  Added the [./patchcmd.md|fossil patch] command.


<
|
>
>
>
>
>
>
>










|
|








>
>
|


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

<
|







1
2

3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

51
52
53
54
55
56
57
58
59

60
61
62
63
64
65
66
67
<title>Change Log</title>


<h2 id='v2_17'>Changes for version 2.17 (2021-10-09)</h2>
  *  Major improvements to the "diff" subsystem, including: <ul>
     <li> Added new [/help?cmd=diff|formatting options]: --by, -b, --webpage, --json, --tcl.
     <li> Partial-line matching for unified diffs
     <li> Better partial-line matching for side-by-side diffs
     <li> Buttons on web-based diffs to show more context
     <li> Performance improvements
     </ul>
  *  The --branchcolor option on [/help?cmd=commit|fossil commit] and
     [/help?cmd=amend|fossil amend] can now take the value "auto" to
     force Fossil to use its built-in automatic color choosing algorithm.
  *  Fossil now [./concepts.wiki#workflow|autosyncs] prior to running 
     [/help?cmd=open|fossil open].
  *  Add the [/help?cmd=ticket-default-report|ticket-default-report setting],
     which if set to the title of a ticket report causes that ticket report
     to be displayed below the search box in the /ticket page.
  *  The "nc" query parameter to the [/help?cmd=/timeline|/timeline] page
     causes all graph coloring to be omitted.
  *  Improvements and bug fixes to the new "[/help?cmd=ui|fossil ui REMOTE]"
     feature so that it works better on a wider variety of platforms.
  *  In [/help?cmd=/wikiedit|/wikiedit], show the list of attachments for 
     the current page and list URLs suitable for pasting them into the page.
  *  Add the --no-http-compression option to [/help?cmd=sync|fossil sync]
     and similar.
  *  Print total payload bytes on a [/help?cmd=sync|fossil sync] when using
     the --verbose option.
  *  Add the <tt>close</tt>, <tt>reopen</tt>, <tt>hide</tt>, and
     </tt>unhide</tt> subcommands to [/help?cmd=branch|the branch command].
  *  The "-p" option to [/help?cmd=branch|fossil branch list] shows only
     private branches.
  *  The [/md_rules|Markdown formatter] now interprets the content of
     block HTML markup (such as &lt;table&gt;) in most cases.  Only content
     of &lt;pre&gt; and &lt;script&gt; is passed through verbatim.
  *  The [/help?cmd=wiki|wiki list command] no longer lists "deleted"
     pages by default. Use the new <tt>--all</tt> option to include deleted
     pages in the output.
  *  The [/help?cmd=all|fossil all git status] command only shows reports for
     the subset of repositories that have a configured Git export.
  *  The [/help?cmd=/chat|/chat] configuration was reimplemented and
     provides new options, including the ability for a repository
     administrator to
     [./chat.md#notifications|extend the selection of notification sounds]
     using unversioned files.
  *  Chat now uses fossil's full complement of markdown features,
     instead of the prior small subset of markup it previously supported.
     This retroactively applies to all chat messages, as they are
     markdown-processed when they are sent instead of when they
     are saved.

  *  Added a chat message preview mode so messages can be previewed
     before being sent. Similarly, added a per-message ability to view
     the raw un-parsed message text.
  *  The hotkey to activate preview mode in [/help?cmd=/wikiedit|/wikiedit],
     [/help?cmd=/fileedit|/fileedit], and [/help?cmd=/pikchrshow|/pikchrshow]
     was changed from ctrl-enter to shift-enter in order to align with
     [/help?cmd=/chat|/chat]'s new preview feature and related future
     changes.


<h2 id='v2_16'>Changes for Version 2.16 (2021-07-02)</h2>
  *  <b>Security:</b> Fix the client-side TLS so that it verifies that the
     server hostname matches its certificate.
  *  The default "ssh" command on Windows is changed to "ssh" instead of the
     legacy "plink", as ssh is now generally available on Windows systems.
     Installations that still need to use the legacy "plink" can make that
     happen by running: '<tt>fossil set ssh-command "plink -ssh" --global</tt>'.
  *  Added the [./patchcmd.md|fossil patch] command.
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
     abandoned email accounts forever.
  *  SQL that defines [/tktsetup_tab|database objects for tickets] now
     [/timeline?c=c717f1ef9a1a4c91|can DROP] a VIEW or an INDEX provided
     that its name starts with '<code>ticket</code>' or '<code>fx_</code>'.
  *  Update the built-in SQLite to version 3.36.0.
  *  Numerous other minor enhancements.

<a name='v2_15'></a>
<h2>Changes for Version 2.15 (2021-03-26) and Patch 2.15.1 on (2021-04-07)
    and 2.15.2 on (2021-06-15)</h2>
  *  <b>Patch 2.15.2:</b> Fix the client-side TLS so that it verifies that the
     server hostname matches its certificate. <b>Upgrading to
     the patch is recommended.</b>
  *  <b>Patch 2.15.1:</b> Fix a data exfiltration bug in the server.  <b>Upgrading to
     the patch is recommended.</b>
  *  The [./defcsp.md|default CSP] has been relaxed slightly to allow







<
|







99
100
101
102
103
104
105

106
107
108
109
110
111
112
113
     abandoned email accounts forever.
  *  SQL that defines [/tktsetup_tab|database objects for tickets] now
     [/timeline?c=c717f1ef9a1a4c91|can DROP] a VIEW or an INDEX provided
     that its name starts with '<code>ticket</code>' or '<code>fx_</code>'.
  *  Update the built-in SQLite to version 3.36.0.
  *  Numerous other minor enhancements.


<h2 id='v2_15'>Changes for Version 2.15 (2021-03-26) and Patch 2.15.1 on (2021-04-07)
    and 2.15.2 on (2021-06-15)</h2>
  *  <b>Patch 2.15.2:</b> Fix the client-side TLS so that it verifies that the
     server hostname matches its certificate. <b>Upgrading to
     the patch is recommended.</b>
  *  <b>Patch 2.15.1:</b> Fix a data exfiltration bug in the server.  <b>Upgrading to
     the patch is recommended.</b>
  *  The [./defcsp.md|default CSP] has been relaxed slightly to allow
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
     is recent enough.
  *  Webpage that shows [/help?cmd=/whistory|history of a wiki page]
     gained client-side UI to help with comparison between two arbitrary
     versions of a wiki (by the means of anchoring a "baseline" version)
     and the ability to squeeze several sequential edits made by the same
     user into a single "recycled" row (the latest edit in that sequence).

<a name='v2_14'></a>
<h2>Changes for Version 2.14 (2021-01-20) and Patch 2.14.1 on (2021-04-07)
    and 2.14.2 on (2021-06-15)</h2>
  *  <b>Patch 2.14.2:</b> Fix the client-side TLS so that it verifies that the
     server hostname matches its certificate. <b>Upgrading to
     the patch is recommended.</b><
  *  <b>Patch 2.14.1:</b> Fix a data exfiltration bug in the server.
     <b>Upgrading to the patch is recommended.</b>
  *  <b>Schema Update Notice #1:</b>







<
|







183
184
185
186
187
188
189

190
191
192
193
194
195
196
197
     is recent enough.
  *  Webpage that shows [/help?cmd=/whistory|history of a wiki page]
     gained client-side UI to help with comparison between two arbitrary
     versions of a wiki (by the means of anchoring a "baseline" version)
     and the ability to squeeze several sequential edits made by the same
     user into a single "recycled" row (the latest edit in that sequence).


<h2 id='v2_14'>Changes for Version 2.14 (2021-01-20) and Patch 2.14.1 on (2021-04-07)
    and 2.14.2 on (2021-06-15)</h2>
  *  <b>Patch 2.14.2:</b> Fix the client-side TLS so that it verifies that the
     server hostname matches its certificate. <b>Upgrading to
     the patch is recommended.</b><
  *  <b>Patch 2.14.1:</b> Fix a data exfiltration bug in the server.
     <b>Upgrading to the patch is recommended.</b>
  *  <b>Schema Update Notice #1:</b>
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
     for custom ticket configurations.
  *  The built-in SQLite is updated to version 3.35.0 alpha containing
     performance optimizations, especially performance associated with
     startup, and minor improvements to the CLI.
  *  Performance optimizations to Fossil itself.
  *  Countless improvements and enhancements to the documentation

<a name='v2_13'></a>
<h2>Changes for Version 2.13 (2020-11-01)</h2>

  *  Added support for [./interwiki.md|interwiki links].
  *  Enable &lt;del&gt; and &lt;ins&gt; markup in  wiki.
  *  Improvements to the Forum threading display.
  *  Added support for embedding [./pikchr.md|pikchr]
     markup in markdown and fossil-wiki content.
  *  The new "[/help?cmd=pikchr|pikchr]" command can render







<
|







249
250
251
252
253
254
255

256
257
258
259
260
261
262
263
     for custom ticket configurations.
  *  The built-in SQLite is updated to version 3.35.0 alpha containing
     performance optimizations, especially performance associated with
     startup, and minor improvements to the CLI.
  *  Performance optimizations to Fossil itself.
  *  Countless improvements and enhancements to the documentation


<h2 id='v2_13'>Changes for Version 2.13 (2020-11-01)</h2>

  *  Added support for [./interwiki.md|interwiki links].
  *  Enable &lt;del&gt; and &lt;ins&gt; markup in  wiki.
  *  Improvements to the Forum threading display.
  *  Added support for embedding [./pikchr.md|pikchr]
     markup in markdown and fossil-wiki content.
  *  The new "[/help?cmd=pikchr|pikchr]" command can render
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
  *  The built-in SQLite is updated to an alpha of version 3.34.0, and
     the minimum SQLite version is increased to 3.34.0 because the
     /finfo change in the previous bullet depends on enhancements to
     recursive common table expressions that are only available in
     SQLite 3.34.0 and later.
  *  Countless other minor refinements and documentation improvements.

<a name='v2_12'></a>
<h2>Changes for Version 2.12.1 (2020-08-20)</h2>

  *  (2.12.1): Fix client-side vulnerabilities discovered by Max Justicz.
  *  Security fix in the "[/help?cmd=git|fossil git export]" command.
     The same fix is also backported to version 2.10.1 and 2.11.1.
     New "safety-net" features were added to prevent similar problems
     in the future.
  *  Enhancements to the graph display for cases when there are







<
|







279
280
281
282
283
284
285

286
287
288
289
290
291
292
293
  *  The built-in SQLite is updated to an alpha of version 3.34.0, and
     the minimum SQLite version is increased to 3.34.0 because the
     /finfo change in the previous bullet depends on enhancements to
     recursive common table expressions that are only available in
     SQLite 3.34.0 and later.
  *  Countless other minor refinements and documentation improvements.


<h2 id='v2_12'>Changes for Version 2.12.1 (2020-08-20)</h2>

  *  (2.12.1): Fix client-side vulnerabilities discovered by Max Justicz.
  *  Security fix in the "[/help?cmd=git|fossil git export]" command.
     The same fix is also backported to version 2.10.1 and 2.11.1.
     New "safety-net" features were added to prevent similar problems
     in the future.
  *  Enhancements to the graph display for cases when there are
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
  *  Added virtual tables "<tt>helptext</tt>" and "<tt>builtin</tt>" to
     the "[/help?cmd=sql|fossil sql]" command, providing access to the
     dispatch table including all help text, and the builtin data files,
     respectively.
  *  [./delta_format.wiki|Delta compression] is now applied to forum edits.
  *  The [/help?cmd=/wikiedit|wiki editor] has been modernized and is
     now Ajax-based. The WYSIWYG editing option for Fossil-format wiki
     pages was removed. (Please let us know, via the site's Support menu,
     if that removal unduly impacts you.) This also changes the semantics
     of the wiki "Sandbox": that pseudo-page may be freely edited but
     no longer saved via the UI (the [/help?cmd=wiki|wiki CLI command]
     can, though).
  *  The [/help?cmd=allow-symlinks|allow-symlinks setting] no longer
     syncs. It must be activated individually on any clones which require
     symlinks.
  *  Countless documentation enhancements.

<a name='v2_11'></a>
<h2>Changes for Version 2.11 (2020-05-25)</h2>

  *  (2.11.2): Backport security fixes from 2.12.1
  *  (2.11.1): Backport security fix for the "fossil git export" command.
  *  Support [/md_rules|Markdown] in the default ticket configuration.
  *  Timestamp strings in [./checkin_names.wiki|object names]
     can now omit punctation.  So, for example, "202004181942" and
     "2020-04-18 19:42" mean the same thing.







|









<
|







351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367

368
369
370
371
372
373
374
375
  *  Added virtual tables "<tt>helptext</tt>" and "<tt>builtin</tt>" to
     the "[/help?cmd=sql|fossil sql]" command, providing access to the
     dispatch table including all help text, and the builtin data files,
     respectively.
  *  [./delta_format.wiki|Delta compression] is now applied to forum edits.
  *  The [/help?cmd=/wikiedit|wiki editor] has been modernized and is
     now Ajax-based. The WYSIWYG editing option for Fossil-format wiki
     pages was removed. (Please let us know, via the site's Forum menu,
     if that removal unduly impacts you.) This also changes the semantics
     of the wiki "Sandbox": that pseudo-page may be freely edited but
     no longer saved via the UI (the [/help?cmd=wiki|wiki CLI command]
     can, though).
  *  The [/help?cmd=allow-symlinks|allow-symlinks setting] no longer
     syncs. It must be activated individually on any clones which require
     symlinks.
  *  Countless documentation enhancements.


<h2 id='v2_11'>Changes for Version 2.11 (2020-05-25)</h2>

  *  (2.11.2): Backport security fixes from 2.12.1
  *  (2.11.1): Backport security fix for the "fossil git export" command.
  *  Support [/md_rules|Markdown] in the default ticket configuration.
  *  Timestamp strings in [./checkin_names.wiki|object names]
     can now omit punctation.  So, for example, "202004181942" and
     "2020-04-18 19:42" mean the same thing.
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
     page so that it does not add "anonymous" capabilities to the
     "nobody" user.
  *  Update internal Unicode character tables, used in regular expression
     handling, from version 12.1 to 13.
  *  Many documentation enhancements.
  *  Many minor enhancements to existing features.

<a name='v2_10'></a>
<h2>Changes for Version 2.10 (2019-10-04)</h2>

  *  (2.10.2): backport security fixes from 2.12.1
  *  (2.10.1): backport security fix for the "fossil git export" command.
  *  Added support for [./serverext.wiki|CGI-based Server Extensions].
  *  Added the [/help?cmd=repolist-skin|repolist-skin] setting used to
     add style to repository list pages.
  *  Enhance the hierarchical display of Forum threads to do less







<
|







451
452
453
454
455
456
457

458
459
460
461
462
463
464
465
     page so that it does not add "anonymous" capabilities to the
     "nobody" user.
  *  Update internal Unicode character tables, used in regular expression
     handling, from version 12.1 to 13.
  *  Many documentation enhancements.
  *  Many minor enhancements to existing features.


<h2 id='v2_10'>Changes for Version 2.10 (2019-10-04)</h2>

  *  (2.10.2): backport security fixes from 2.12.1
  *  (2.10.1): backport security fix for the "fossil git export" command.
  *  Added support for [./serverext.wiki|CGI-based Server Extensions].
  *  Added the [/help?cmd=repolist-skin|repolist-skin] setting used to
     add style to repository list pages.
  *  Enhance the hierarchical display of Forum threads to do less
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
  *  The check-in lock interval is reduced from 24 hours to 60 seconds,
     though the interval is now configurable using a setting.
     An additional check for conflicts is added after interactive
     check-in comment entry, to compensate for the reduced lock interval.
  *  Performance optimizations.
  *  Many documentation improvements.

<a name='v2_9'></a>
<h2>Changes for Version 2.9 (2019-07-13)</h2>

  *  Added the [/help?cmd=git|fossil git export] command and instructions
     for [./mirrortogithub.md|creating a GitHub mirror of a Fossil project].
  *  Improved handling of relative hyperlinks on the
     [/help?cmd=/artifact|/artifact] pages for wiki. For example,
     hyperlinks and the lizard &lt;img&gt; now work correctly
     for both [/artifact/2ff24ab0887cf522] and







<
|







487
488
489
490
491
492
493

494
495
496
497
498
499
500
501
  *  The check-in lock interval is reduced from 24 hours to 60 seconds,
     though the interval is now configurable using a setting.
     An additional check for conflicts is added after interactive
     check-in comment entry, to compensate for the reduced lock interval.
  *  Performance optimizations.
  *  Many documentation improvements.


<h2 id='v2_9'>Changes for Version 2.9 (2019-07-13)</h2>

  *  Added the [/help?cmd=git|fossil git export] command and instructions
     for [./mirrortogithub.md|creating a GitHub mirror of a Fossil project].
  *  Improved handling of relative hyperlinks on the
     [/help?cmd=/artifact|/artifact] pages for wiki. For example,
     hyperlinks and the lizard &lt;img&gt; now work correctly
     for both [/artifact/2ff24ab0887cf522] and
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
     caused by concurrent commits when operating in auto-sync mode.
  *  Fix a bug ([https://fossil-scm.org/forum/forumpost/c51b9a1169|details])
     that can cause repository databases to be overwritten with debugging
     output, thus corrupting the repository. This is only a factor when
     CGI debugging is enabled, and even then is a rare occurrence, but it is
     obviously an important fix.

<a name='v2_8'></a>
<h2>Changes for Version 2.8 (2019-02-20)</h2>

  *  Show cherry-pick merges as dotted lines on the timeline graph.
     &rarr; The "fossil rebuild" command must be run to create and
     populate the new "cherrypick" table in the repository in order
     for this feature to operate.
  *  Add the ability to associate branches, check-ins, and tags with
     specially-named Wiki pages. This gives the ability to better







<
|







557
558
559
560
561
562
563

564
565
566
567
568
569
570
571
     caused by concurrent commits when operating in auto-sync mode.
  *  Fix a bug ([https://fossil-scm.org/forum/forumpost/c51b9a1169|details])
     that can cause repository databases to be overwritten with debugging
     output, thus corrupting the repository. This is only a factor when
     CGI debugging is enabled, and even then is a rare occurrence, but it is
     obviously an important fix.


<h2 id='v2_8'>Changes for Version 2.8 (2019-02-20)</h2>

  *  Show cherry-pick merges as dotted lines on the timeline graph.
     &rarr; The "fossil rebuild" command must be run to create and
     populate the new "cherrypick" table in the repository in order
     for this feature to operate.
  *  Add the ability to associate branches, check-ins, and tags with
     specially-named Wiki pages. This gives the ability to better
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
     to the checkout database to avoid any problems.
  *  Add the backoffice-disable setting to completely disable the
     backoffice feature.
  *  Update the built-in SQLite to version 3.27.1.
  *  Various other small enhancements to webpages and documentation.


<a name='v2_7'></a>
<h2>Changes for Version 2.7 (2018-09-22)</h2>

  *  Add the [./alerts.md|email alerts] feature for commits, ticket
     changes, wiki changes, forum posts, and announcements.  This is
     still a work in progress.  It is functional, but it is not as easy to
     setup and use as it ought to be.
  *  Add the [./forum.wiki|discussion forum] feature.
  *  Add new user capabilities letters needed to support alerts and forum.







<
|







623
624
625
626
627
628
629

630
631
632
633
634
635
636
637
     to the checkout database to avoid any problems.
  *  Add the backoffice-disable setting to completely disable the
     backoffice feature.
  *  Update the built-in SQLite to version 3.27.1.
  *  Various other small enhancements to webpages and documentation.



<h2 id='v2_7'>Changes for Version 2.7 (2018-09-22)</h2>

  *  Add the [./alerts.md|email alerts] feature for commits, ticket
     changes, wiki changes, forum posts, and announcements.  This is
     still a work in progress.  It is functional, but it is not as easy to
     setup and use as it ought to be.
  *  Add the [./forum.wiki|discussion forum] feature.
  *  Add new user capabilities letters needed to support alerts and forum.
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
  *  The `mv-rm-files` setting is now compiled into Fossil in the
     default Fossil configuration; no longer must you say
     <tt>./configure --with-legacy-mv-rm</tt> to make it available.  The
     setting remains disabled by default, however, so you must still say
     <tt>fossil set mv-rm-files 1</tt> to enable it on each repository
     where you want hard <tt>mv/rm</tt> behavior.

<a name='v2_6'></a>
<h2>Changes for Version 2.6 (2018-05-04)</h2>

  *  Fix a bug that was causing crashes while trying to clone the TCL
     repository.  This fix is the main reason for the current release.
  *  Added the new "Classic" timeline viewing mode.  "Classic" is the
     same as "Verbose" in the previous release.  The "Verbose" mode is
     now like "Compact" except the extra check-in details are shown by
     default.







<
|







665
666
667
668
669
670
671

672
673
674
675
676
677
678
679
  *  The `mv-rm-files` setting is now compiled into Fossil in the
     default Fossil configuration; no longer must you say
     <tt>./configure --with-legacy-mv-rm</tt> to make it available.  The
     setting remains disabled by default, however, so you must still say
     <tt>fossil set mv-rm-files 1</tt> to enable it on each repository
     where you want hard <tt>mv/rm</tt> behavior.


<h2 id='v2_6'>Changes for Version 2.6 (2018-05-04)</h2>

  *  Fix a bug that was causing crashes while trying to clone the TCL
     repository.  This fix is the main reason for the current release.
  *  Added the new "Classic" timeline viewing mode.  "Classic" is the
     same as "Verbose" in the previous release.  The "Verbose" mode is
     now like "Compact" except the extra check-in details are shown by
     default.
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
     time column.
  *  In the tarball cache replacement algorithm, give extra weight to
     tarballs that have been accessed more than once.
  *  Additional defenses against web-based attacks.  There have not been
     any known vulnerabilities.  We are just being paranoid.
  *  Update the built-in SQLite to an alpha version of 3.24.0.

<a name='v2_5'></a>
<h2>Changes for Version 2.5 (2018-02-07)</h2>

  *  Numerous enhancements to the look and feel of the web interface.
     Especially:  Added separate "Modern", "Compact", "Verbose", and
     "Columnar" view options on timelines.
  *  Common display settings (such as the "view" option and the number
     of rows in a timeline) are held in a cookie and thus persist
     across multiple pages.







<
|







693
694
695
696
697
698
699

700
701
702
703
704
705
706
707
     time column.
  *  In the tarball cache replacement algorithm, give extra weight to
     tarballs that have been accessed more than once.
  *  Additional defenses against web-based attacks.  There have not been
     any known vulnerabilities.  We are just being paranoid.
  *  Update the built-in SQLite to an alpha version of 3.24.0.


<h2 id='v2_5'>Changes for Version 2.5 (2018-02-07)</h2>

  *  Numerous enhancements to the look and feel of the web interface.
     Especially:  Added separate "Modern", "Compact", "Verbose", and
     "Columnar" view options on timelines.
  *  Common display settings (such as the "view" option and the number
     of rows in a timeline) are held in a cookie and thus persist
     across multiple pages.
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
  *  Begin factoring out in-line javascript into separately loaded
     script files.  This is a step along the
     road toward supporting a strict Content Security Policy.  More work
     is to be done.
  *  Initial infrastructure is in place to make use of the pledge()
     system call in OpenBSD.  More work is to be done.

<a name='v2_4'></a>
<h2>Changes for Version 2.4 (2017-11-03)</h2>

  *  New feature: URL Aliases.  URL Aliases allow an administrator
     to define their own URLs on the web interface that are rewritten to
     built-in URLs with specific parameters.  Create and configure URL Aliases
     using the /Setup/URL_Aliases menu option in the web interface.
  *  Add tech-note search capability.
  *  Add the -r|--revision and -o|--origin options to the







<
|







728
729
730
731
732
733
734

735
736
737
738
739
740
741
742
  *  Begin factoring out in-line javascript into separately loaded
     script files.  This is a step along the
     road toward supporting a strict Content Security Policy.  More work
     is to be done.
  *  Initial infrastructure is in place to make use of the pledge()
     system call in OpenBSD.  More work is to be done.


<h2 id='v2_4'>Changes for Version 2.4 (2017-11-03)</h2>

  *  New feature: URL Aliases.  URL Aliases allow an administrator
     to define their own URLs on the web interface that are rewritten to
     built-in URLs with specific parameters.  Create and configure URL Aliases
     using the /Setup/URL_Aliases menu option in the web interface.
  *  Add tech-note search capability.
  *  Add the -r|--revision and -o|--origin options to the
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
     [/help?cmd=zip|zip], and [/help?cmd=tarball|tarball] pages and commands to
     honor the versioned manifest setting when outside of an open checkout
     directory.
  *  The admin-log and access-log settings are now on by default for
     new repositories.
  *  Update the built-in SQLite to version 3.21.0.

<a name='v2_3'></a>
<h2>Changes for Version 2.3 (2017-07-21)</h2>

  *  Update the built-in SQLite to version 3.20.0 (beta).
  *  Update internal Unicode character tables, used in regular expression
     handling, from version 9.0 to 10.0.
  *  Show the last-sync-URL on the [/help?cmd=/urllist|/urllist] page.
  *  Added the "Event Summary" activity report.
     [/reports?type=ci&view=lastchng|example]
  *  Added the "Security Audit" page, available to administrators only
  *  Added the Last Login time to the user list page, for administrators only
  *  Added the --numstat option to the [/help?cmd=diff|fossil diff] command
  *  Limit the size of the heap and stack on unix systems, as a proactive
     defense against the
     [https://www.qualys.com/2017/06/19/stack-clash/stack-clash.txt|Stack Clash]
     attack.
  *  Fix "database locked" warnings caused by "PRAGMA optimize".
  *  Fix a potential XSS vulnerability on the
     [/help?cmd=/help|/help] webpage.
  *  Documentation updates

<a name='v2_2'></a>
<h2>Changes for Version 2.2 (2017-04-11)</h2>

  *  GIT comment tags are now handled by Fossil during import/export.
  *  Show the content of README files on directory listings.
     ([/file/skins|example])
  *  Support for Basic Authentication if enabled (default off).
  *  Show the hash algorithms used on the
     [/help?cmd=/rcvfromlist|/rcvfromlist] page.
  *  The [/help?cmd=/tarball|/tarball] and [/help?cmd=/zip|/zip] pages
     now use the the r= query parameter
     to select which check-in to deliver.  The uuid= query parameter
     is still accepted for backwards compatibility.
  *  Update the built-in SQLite to version 3.18.0.
  *  Run "[https://www.sqlite.org/pragma.html#pragma_optimize|PRAGMA optimize]"
     on the database connection as it is closing.

<a name='v2_1'></a>
<h2>Changes for Version 2.1 (2017-03-10)</h2>

  *  Add support for [./hashpolicy.wiki|hash policies] that control which
     of the Hardened-SHA1 or SHA3-256 algorithms is used to name new
     artifacts.
  *  Add the "gshow" and "gcat" subcommands to [/help?cmd=stash|fossil stash].
  *  Add the [/help?cmd=/juvlist|/juvlist] web page and use it to construct
     the [/uv/download.html|Download Page] of the Fossil self-hosting website
     using Ajax.

<a name='v2_0'></a>
<h2>Changes for Version 2.0 (2017-03-03)</h2>

  *  Use the
     [https://github.com/cr-marcstevens/sha1collisiondetection|hardened SHA1]
     implementation by Marc Stevens and Dan Shumow.
  *  Add the ability to read and understand
     [./fileformat.wiki#names|artifact names] that are based on SHA3-256
     rather than SHA1, but do not actually generate any such names.
  *  Added the [/help?cmd=sha3sum|sha3sum] command.
  *  Update the built-in SQLite to version 3.17.0.

<a name='v1_37'></a>
<h2>Changes for Version 1.37 (2017-01-16)</h2>

  *  Add checkbox widgets to various web pages.  See [/technote/8d18bf27e9|
     this technote] for more information.  To get the checkboxes to look as
     intended, you must update the CSS in your repository and all clones.
  *  Add the [/help/all|fossil all ui] command
  *  Add the [/help?cmd=/file|/file] webpage
  *  Enhance the [/help?cmd=/brlist|/brlist] webpage to make use of branch colors.







<
|



















<
|















<
|









<
|










<
|







767
768
769
770
771
772
773

774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793

794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809

810
811
812
813
814
815
816
817
818
819

820
821
822
823
824
825
826
827
828
829
830

831
832
833
834
835
836
837
838
     [/help?cmd=zip|zip], and [/help?cmd=tarball|tarball] pages and commands to
     honor the versioned manifest setting when outside of an open checkout
     directory.
  *  The admin-log and access-log settings are now on by default for
     new repositories.
  *  Update the built-in SQLite to version 3.21.0.


<h2 id='v2_3'>Changes for Version 2.3 (2017-07-21)</h2>

  *  Update the built-in SQLite to version 3.20.0 (beta).
  *  Update internal Unicode character tables, used in regular expression
     handling, from version 9.0 to 10.0.
  *  Show the last-sync-URL on the [/help?cmd=/urllist|/urllist] page.
  *  Added the "Event Summary" activity report.
     [/reports?type=ci&view=lastchng|example]
  *  Added the "Security Audit" page, available to administrators only
  *  Added the Last Login time to the user list page, for administrators only
  *  Added the --numstat option to the [/help?cmd=diff|fossil diff] command
  *  Limit the size of the heap and stack on unix systems, as a proactive
     defense against the
     [https://www.qualys.com/2017/06/19/stack-clash/stack-clash.txt|Stack Clash]
     attack.
  *  Fix "database locked" warnings caused by "PRAGMA optimize".
  *  Fix a potential XSS vulnerability on the
     [/help?cmd=/help|/help] webpage.
  *  Documentation updates


<h2 id='v2_2'>Changes for Version 2.2 (2017-04-11)</h2>

  *  GIT comment tags are now handled by Fossil during import/export.
  *  Show the content of README files on directory listings.
     ([/file/skins|example])
  *  Support for Basic Authentication if enabled (default off).
  *  Show the hash algorithms used on the
     [/help?cmd=/rcvfromlist|/rcvfromlist] page.
  *  The [/help?cmd=/tarball|/tarball] and [/help?cmd=/zip|/zip] pages
     now use the the r= query parameter
     to select which check-in to deliver.  The uuid= query parameter
     is still accepted for backwards compatibility.
  *  Update the built-in SQLite to version 3.18.0.
  *  Run "[https://www.sqlite.org/pragma.html#pragma_optimize|PRAGMA optimize]"
     on the database connection as it is closing.


<h2 id='v2_1'>Changes for Version 2.1 (2017-03-10)</h2>

  *  Add support for [./hashpolicy.wiki|hash policies] that control which
     of the Hardened-SHA1 or SHA3-256 algorithms is used to name new
     artifacts.
  *  Add the "gshow" and "gcat" subcommands to [/help?cmd=stash|fossil stash].
  *  Add the [/help?cmd=/juvlist|/juvlist] web page and use it to construct
     the [/uv/download.html|Download Page] of the Fossil self-hosting website
     using Ajax.


<h2 id='v2_0'>Changes for Version 2.0 (2017-03-03)</h2>

  *  Use the
     [https://github.com/cr-marcstevens/sha1collisiondetection|hardened SHA1]
     implementation by Marc Stevens and Dan Shumow.
  *  Add the ability to read and understand
     [./fileformat.wiki#names|artifact names] that are based on SHA3-256
     rather than SHA1, but do not actually generate any such names.
  *  Added the [/help?cmd=sha3sum|sha3sum] command.
  *  Update the built-in SQLite to version 3.17.0.


<h2 id='v1_37'>Changes for Version 1.37 (2017-01-16)</h2>

  *  Add checkbox widgets to various web pages.  See [/technote/8d18bf27e9|
     this technote] for more information.  To get the checkboxes to look as
     intended, you must update the CSS in your repository and all clones.
  *  Add the [/help/all|fossil all ui] command
  *  Add the [/help?cmd=/file|/file] webpage
  *  Enhance the [/help?cmd=/brlist|/brlist] webpage to make use of branch colors.
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
  *  Fixes for incremental git import/export.
  *  Minor security enhancements to
     [./encryptedrepos.wiki|encrypted repositories].
  *  Update the built-in SQLite to version 3.16.2.
  *  Update the built-in Zlib to version 1.2.11.


<a name='v1_36'></a>
<h2>Changes for Version 1.36 (2016-10-24)</h2>

  *  Add support for [./unvers.wiki|unversioned content],
     the [/help?cmd=unversioned|fossil unversioned] command and the
     [/help?cmd=/uv|/uv] and [/uvlist] web pages.
  *  The [/uv/download.html|download page] is moved into
     [./unvers.wiki|unversioned content] so that the self-hosting Fossil
     websites no longer uses any external content.







<
|







861
862
863
864
865
866
867

868
869
870
871
872
873
874
875
  *  Fixes for incremental git import/export.
  *  Minor security enhancements to
     [./encryptedrepos.wiki|encrypted repositories].
  *  Update the built-in SQLite to version 3.16.2.
  *  Update the built-in Zlib to version 1.2.11.



<h2 id='v1_36'>Changes for Version 1.36 (2016-10-24)</h2>

  *  Add support for [./unvers.wiki|unversioned content],
     the [/help?cmd=unversioned|fossil unversioned] command and the
     [/help?cmd=/uv|/uv] and [/uvlist] web pages.
  *  The [/uv/download.html|download page] is moved into
     [./unvers.wiki|unversioned content] so that the self-hosting Fossil
     websites no longer uses any external content.
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
     queries are filled in using HTTP query parameter values.
  *  Added support for [./childprojects.wiki|child projects] that are
     able to pull from their parent but not push.
  *  Added the -nocomplain option to the TH1 "query" command.
  *  Added support for the chng=GLOBLIST query parameter on the
     [/help?cmd=/timeline|/timeline] webpage.

<a name='v1_35'></a>
<h2>Changes for Version 1.35 (2016-06-14)</h2>

  *  Enable symlinks by default on all non-Windows platforms.
  *  Enhance the [/md_rules|Markdown formatting] so that hyperlinks that begin
     with "/" are relative to the root of the Fossil repository.
  *  Rework the [/help?cmd=/setup_ulist|/setup_list page] (the User List page)
     to display all users in a click-to-sort table.
  *  Fix backslash-octal escape on filenames while importing from git







<
|







891
892
893
894
895
896
897

898
899
900
901
902
903
904
905
     queries are filled in using HTTP query parameter values.
  *  Added support for [./childprojects.wiki|child projects] that are
     able to pull from their parent but not push.
  *  Added the -nocomplain option to the TH1 "query" command.
  *  Added support for the chng=GLOBLIST query parameter on the
     [/help?cmd=/timeline|/timeline] webpage.


<h2 id='v1_35'>Changes for Version 1.35 (2016-06-14)</h2>

  *  Enable symlinks by default on all non-Windows platforms.
  *  Enhance the [/md_rules|Markdown formatting] so that hyperlinks that begin
     with "/" are relative to the root of the Fossil repository.
  *  Rework the [/help?cmd=/setup_ulist|/setup_list page] (the User List page)
     to display all users in a click-to-sort table.
  *  Fix backslash-octal escape on filenames while importing from git
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
  *  Add support for [./encryptedrepos.wiki|encrypted Fossil repositories].
  *  If the FOSSIL_PWREADER environment variable is set, then use the program it
     names in place of getpass() to read passwords and passphrases
  *  Option --baseurl now works on Windows.
  *  Numerous documentation improvements.
  *  Update the built-in SQLite to version 3.13.0.

<a name='v1_34'></a>
<h2>Changes for Version 1.34 (2015-11-02)</h2>

  *  Make the [/help?cmd=clean|fossil clean] command undoable for files less
     than 10MiB.
  *  Update internal Unicode character tables, used in regular expression
     handling, from version 7.0 to 8.0.
  *  Add the new [/help?cmd=amend|amend] command which is used to modify
     tags of a "check-in".







<
|







934
935
936
937
938
939
940

941
942
943
944
945
946
947
948
  *  Add support for [./encryptedrepos.wiki|encrypted Fossil repositories].
  *  If the FOSSIL_PWREADER environment variable is set, then use the program it
     names in place of getpass() to read passwords and passphrases
  *  Option --baseurl now works on Windows.
  *  Numerous documentation improvements.
  *  Update the built-in SQLite to version 3.13.0.


<h2 id='v1_34'>Changes for Version 1.34 (2015-11-02)</h2>

  *  Make the [/help?cmd=clean|fossil clean] command undoable for files less
     than 10MiB.
  *  Update internal Unicode character tables, used in regular expression
     handling, from version 7.0 to 8.0.
  *  Add the new [/help?cmd=amend|amend] command which is used to modify
     tags of a "check-in".
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
  *  Fix --hard option to [/help?cmd=mv|fossil mv] and [/help?cmd=rm|fossil rm]
     to enable them to work properly with certain relative paths.
  *  Change the mimetype for ".n" and ".man" files to text/plain.
  *  Display improvements in the [/help?cmd=bisect|fossil bisect chart] command.
  *  Updated the built-in SQLite to version 3.9.1 and activated JSON1 and FTS5
     support (both currently unused within Fossil).

<a name='v1_33'></a>
<h2>Changes for Version 1.33 (2015-05-23)</h2>
  *  Improved fork detection on [/help?cmd=update|fossil update],
     [/help?cmd=status|fossil status] and related commands.
  *  Change the default skin to what used to be called "San Francisco Modern".
  *  Add the [/repo-tabsize] web page
  *  Add [/help?cmd=import|fossil import --svn], for importing a subversion
     repository into fossil which was exported using "svnadmin dump".
  *  Add the "--compress-only" option to [/help?cmd=rebuild|fossil rebuild].







<
|







969
970
971
972
973
974
975

976
977
978
979
980
981
982
983
  *  Fix --hard option to [/help?cmd=mv|fossil mv] and [/help?cmd=rm|fossil rm]
     to enable them to work properly with certain relative paths.
  *  Change the mimetype for ".n" and ".man" files to text/plain.
  *  Display improvements in the [/help?cmd=bisect|fossil bisect chart] command.
  *  Updated the built-in SQLite to version 3.9.1 and activated JSON1 and FTS5
     support (both currently unused within Fossil).


<h2 id='v1_33'>Changes for Version 1.33 (2015-05-23)</h2>
  *  Improved fork detection on [/help?cmd=update|fossil update],
     [/help?cmd=status|fossil status] and related commands.
  *  Change the default skin to what used to be called "San Francisco Modern".
  *  Add the [/repo-tabsize] web page
  *  Add [/help?cmd=import|fossil import --svn], for importing a subversion
     repository into fossil which was exported using "svnadmin dump".
  *  Add the "--compress-only" option to [/help?cmd=rebuild|fossil rebuild].
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
  *  Permit filtering weekday and file [/help?cmd=/reports|reports] by user.
     Also ensure the user parameter is preserved when changing types.  Add a
     field for direct entry of the user name to each applicable report.
  *  Create parent directories of [/help?cmd=settings|empty-dirs] if they don't
     already exist.
  *  Inhibit timeline links to wiki pages that have been deleted.

<a name='v1_33'></a>
<h2>Changes for Version 1.32 (2015-03-14)</h2>
  *  When creating a new repository using [/help?cmd=init|fossil init], ensure
     that the new repository is fully compatible with historical versions of
     Fossil by having a valid manifest as RID 1.
  *  Anti-aliased rendering of arrowheads on timeline graphs.
  *  Added vi/less-style key bindings to the --tk diff GUI.
  *  Documentation updates to fix spellings and changes all "checkins" to
     "check-ins".
  *  Add the --repolist option to server commands such as
     [/help?cmd=server|fossil server] or [/help?cmd=http|fossil http].
  *  Added the "Xekri" skin.
  *  Enhance the "ln=" query parameter on artifact displays to accept multiple
     ranges, separate by spaces (or "+" when URL-encoded).
  *  Added [/help?cmd=forget|fossil forget] as an alias for
     [/help?cmd=rm|fossil rm].

<a name='v1_31'></a>
<h2>Changes For Version 1.31 (2015-02-23)</h2>
  *  Change the auxiliary schema by adding columns MLINK.ISAUX and MLINK.PMID
     columns to the schema, to support better drawing of file change graphs.
     A [/help?cmd=rebuild|fossil rebuild] is recommended but is not required.
     so that the new graph drawing logic can work effectively.
  *  Added [/search|search] over Check-in comments, Documents, Tickets and
     Wiki.  Disabled by default.  The search can be either a full-scan or it
     can use an index that is kept up-to-date automatically.  The new







<
|















<
|







1018
1019
1020
1021
1022
1023
1024

1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040

1041
1042
1043
1044
1045
1046
1047
1048
  *  Permit filtering weekday and file [/help?cmd=/reports|reports] by user.
     Also ensure the user parameter is preserved when changing types.  Add a
     field for direct entry of the user name to each applicable report.
  *  Create parent directories of [/help?cmd=settings|empty-dirs] if they don't
     already exist.
  *  Inhibit timeline links to wiki pages that have been deleted.


<h2 id='v1_33'>Changes for Version 1.32 (2015-03-14)</h2>
  *  When creating a new repository using [/help?cmd=init|fossil init], ensure
     that the new repository is fully compatible with historical versions of
     Fossil by having a valid manifest as RID 1.
  *  Anti-aliased rendering of arrowheads on timeline graphs.
  *  Added vi/less-style key bindings to the --tk diff GUI.
  *  Documentation updates to fix spellings and changes all "checkins" to
     "check-ins".
  *  Add the --repolist option to server commands such as
     [/help?cmd=server|fossil server] or [/help?cmd=http|fossil http].
  *  Added the "Xekri" skin.
  *  Enhance the "ln=" query parameter on artifact displays to accept multiple
     ranges, separate by spaces (or "+" when URL-encoded).
  *  Added [/help?cmd=forget|fossil forget] as an alias for
     [/help?cmd=rm|fossil rm].


<h2 id='v1_31'>Changes For Version 1.31 (2015-02-23)</h2>
  *  Change the auxiliary schema by adding columns MLINK.ISAUX and MLINK.PMID
     columns to the schema, to support better drawing of file change graphs.
     A [/help?cmd=rebuild|fossil rebuild] is recommended but is not required.
     so that the new graph drawing logic can work effectively.
  *  Added [/search|search] over Check-in comments, Documents, Tickets and
     Wiki.  Disabled by default.  The search can be either a full-scan or it
     can use an index that is kept up-to-date automatically.  The new
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
  *  Added the [/mimetype_list] page.
  *  Added the [/hash-collisions] page.
  *  Allow the user of Common Table Expressions in the SQL that defaults
     ticket reports.
  *  Break out the components (css, footer, and header) for the
     various built-in skins into separate files in the source tree.

<a name='v1_30'></a>
<h2>Changes For Version 1.30 (2015-01-19)</h2>
  *  Added the [/help?cmd=bundle|fossil bundle] command.
  *  Added the [/help?cmd=purge|fossil purge] command.
  *  Added the [/help?cmd=publish|fossil publish] command.
  *  Added the [/help?cmd=unpublished|fossil unpublished] command.
  *  Enhance the [/tree] webpage to show the age of each file with the option
     to sort by age.
  *  Enhance the [/brlist] webpage to show additional information about each branch







<
|







1085
1086
1087
1088
1089
1090
1091

1092
1093
1094
1095
1096
1097
1098
1099
  *  Added the [/mimetype_list] page.
  *  Added the [/hash-collisions] page.
  *  Allow the user of Common Table Expressions in the SQL that defaults
     ticket reports.
  *  Break out the components (css, footer, and header) for the
     various built-in skins into separate files in the source tree.


<h2 id='v1_30'>Changes For Version 1.30 (2015-01-19)</h2>
  *  Added the [/help?cmd=bundle|fossil bundle] command.
  *  Added the [/help?cmd=purge|fossil purge] command.
  *  Added the [/help?cmd=publish|fossil publish] command.
  *  Added the [/help?cmd=unpublished|fossil unpublished] command.
  *  Enhance the [/tree] webpage to show the age of each file with the option
     to sort by age.
  *  Enhance the [/brlist] webpage to show additional information about each branch
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
     diff option in a separate file for easier editing.
  *  (Internal:) Implement a system of compile-time checks to help ensure
     the correctness of printf-style formatting strings.
  *  Fix CVE-2014-3566, also known as the POODLE SSL 3.0 vulnerability.
  *  Numerous documentation fixes and improvements.
  *  Other obscure and minor bug fixes - see the timeline for details.

<a name='v1_29'></a>
<h2>Changes For Version 1.29 (2014-06-12)</h2>
  *  Add the ability to display content, diffs and annotations for UTF16
     text files in the web interface.
  *  Add the "SaveAs..." and "Invert" buttons
     to the graphical diff display that results
     from using the --tk option with the [/help/diff | fossil diff] command.
  *  The [/reports] page now requires Read ("o") permissions. The "byweek"
     report now properly propagates the selected year through the event type







<
|







1155
1156
1157
1158
1159
1160
1161

1162
1163
1164
1165
1166
1167
1168
1169
     diff option in a separate file for easier editing.
  *  (Internal:) Implement a system of compile-time checks to help ensure
     the correctness of printf-style formatting strings.
  *  Fix CVE-2014-3566, also known as the POODLE SSL 3.0 vulnerability.
  *  Numerous documentation fixes and improvements.
  *  Other obscure and minor bug fixes - see the timeline for details.


<h2 id='v1_29'>Changes For Version 1.29 (2014-06-12)</h2>
  *  Add the ability to display content, diffs and annotations for UTF16
     text files in the web interface.
  *  Add the "SaveAs..." and "Invert" buttons
     to the graphical diff display that results
     from using the --tk option with the [/help/diff | fossil diff] command.
  *  The [/reports] page now requires Read ("o") permissions. The "byweek"
     report now properly propagates the selected year through the event type
Changes to www/chat.md.
1
2
3
4
5
6
7
8
9

10
11
12
13
14
15
16
17
18
19
20
# Fossil Chat

## Introduction

As of version 2.14,
Fossil supports a developer chatroom feature.  The chatroom provides an
ephemeral discussion venue for insiders.  Design goals include:

  *  **Simple but functional** &rarr; Fossil chat is designed to provide a

     convenient real-time communication mechanism for geographically
     dispersed developers.  Fossil chat is *not* intended
     as a replacement or 
     competitor for IRC, Slack, Discord, Telegram, Google Hangouts, etc.

  *  **Low administration** &rarr;
     You can activate the chatroom in seconds without having to
     mess with configuration files or install new software.
     In an existing [server setup](./server/),
     simply enable the [C capability](/setup_ucap_list) for users
     whom you want to give access to the chatroom.








|
>
|
|
<
|







1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
20
# Fossil Chat

## Introduction

As of version 2.14,
Fossil supports a developer chatroom feature.  The chatroom provides an
ephemeral discussion venue for insiders.  Design goals include:

  *  **Simple but functional** &rarr;
     Fossil chat is designed to provide a convenient real-time
     communication mechanism for geographically dispersed developers.
     Fossil chat is *not* intended as a replacement or competitor for

     IRC, Slack, Discord, Telegram, Google Hangouts, etc.

  *  **Low administration** &rarr;
     You can activate the chatroom in seconds without having to
     mess with configuration files or install new software.
     In an existing [server setup](./server/),
     simply enable the [C capability](/setup_ucap_list) for users
     whom you want to give access to the chatroom.
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88

There are also some settings under /Admin/Chat that control the
behavior of chat, though the default settings are reasonable so in most
cases those settings can be ignored.  The settings control things like
the amount of time that chat messages are retained before being purged
from the repository database.

## Usage

For users with appropriate permissions, simply browse to the
[/chat](/help?cmd=/chat) to start up a chat session.  The default
skin includes a "Chat" entry on the menu bar on wide screens for
people with chat privilege.  There is also a "Chat" option on
the [Sitemap page](/sitemap), which means that chat will appear
as an option under the hamburger menu for many [skins](./customskin.md).

Message text is delivered verbatim.  There is no markup.  However,
the chat system does try to identify and tag hyperlinks, as follows:

  *  Any word that begins with "http://" or "https://" is assumed
     to be a hyperlink and is tagged.

  *  Text within `[...]` is parsed, and it if is a valid hyperlink
     target (according to the way that [Fossil Wiki](/wiki_rules) or
     [Markdown](/md_rules) understand hyperlinks), then that text is
     tagged. Note that only URLs and Fossil-internal constructs such
     as checkin hashes and wiki pages names are recognized here, not
     constructs such as `[URL | label]` or `[label](URL)`.

Apart from adding hyperlink anchor tags to bits of text that look
like hyperlinks, no changes are made to the input text.

Files may be sent via chat using the file selection element at the
bottom of the page. If the desktop environment system supports it,
files may be dragged and dropped onto that element. Files are not
automatically sent - selection of a file can be cancelled using the
Cancel button which appears only when a file is selected. When the
Send button is pressed, any pending text is submitted along with the







|








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







51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67

68


69






70


71
72
73
74
75
76
77

There are also some settings under /Admin/Chat that control the
behavior of chat, though the default settings are reasonable so in most
cases those settings can be ignored.  The settings control things like
the amount of time that chat messages are retained before being purged
from the repository database.

## <a id="usage"></a>Usage

For users with appropriate permissions, simply browse to the
[/chat](/help?cmd=/chat) to start up a chat session.  The default
skin includes a "Chat" entry on the menu bar on wide screens for
people with chat privilege.  There is also a "Chat" option on
the [Sitemap page](/sitemap), which means that chat will appear
as an option under the hamburger menu for many [skins](./customskin.md).

As of version 2.17, chat messages are subject to [fossil's

full range of markdown processing](/md_rules). Because chat messages are


stored as-is when they arrive from a client, this change applies






retroactively to messages stored by previous fossil versions.



Files may be sent via chat using the file selection element at the
bottom of the page. If the desktop environment system supports it,
files may be dragged and dropped onto that element. Files are not
automatically sent - selection of a file can be cancelled using the
Cancel button which appears only when a file is selected. When the
Send button is pressed, any pending text is submitted along with the
97
98
99
100
101
102
103

































104
105
106
107
108
109
110
at the top of the message and clicking the button which appears. Such
deletions are local-only, and the messages will reappear if the page
is reloaded. The user who posted a given message, or any Admin users,
may additionally choose to globally delete a message from the chat
record, which deletes it not only from their own browser but also
propagates the removal to all connected clients the next time they
poll for new messages.


































## Implementation Details

*You do not need to understand how Fossil chat works in order to use it.
But many developers prefer to know how their tools work.
This section is provided for the benefit of those curious developers.*








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







86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
at the top of the message and clicking the button which appears. Such
deletions are local-only, and the messages will reappear if the page
is reloaded. The user who posted a given message, or any Admin users,
may additionally choose to globally delete a message from the chat
record, which deletes it not only from their own browser but also
propagates the removal to all connected clients the next time they
poll for new messages.

### <a id='notifications'></a>Customizing New-message Notification Sounds

By default, the list of new-message notification sounds is limited to
a few built in to the fossil binary. In addition, any
[unversioned files](./unvers.wiki) named `alert-sounds/*.{mp3,wav,ogg}`
will be included in that list. To switch sounds, tap the "settings"
button.

### <a id='connection'></a> Who's Online?

Because the chat app has to be able to work over transient CGI-based
connections, as opposed to a stable socket connection to the server,
real-time tracking of "who's online" is not feasible. As of version
2.17, chat offers an optional feature, toggleable in the settings,
which can list users who have posted messages in the client's current
list of loaded messages. This is not the same thing as tracking who's
online, but it gives an overview of which users have been active most
recently, noting that "lurkers" (people who post no messages) will not
show up in that list, nor does the chat infrastructure have a way to
track and present those. That list can be used to filter messages on a
specific user by tapping on that user's name, tapping a second time to
remove the filter.

Sidebar: message deletion is a type of message and deletions count
towards updates in the recent activity list (counted for the person
who performed the deletion, not the author of the deleted
comment). That can potentially lead to odd corner cases where a user
shows up in the list but has no messages which are currently visible
because they were deleted, or an admin user who has not posted
anything but deleted a message. That is a known minor cosmetic-only
bug with a resolution of "will not fix."


## Implementation Details

*You do not need to understand how Fossil chat works in order to use it.
But many developers prefer to know how their tools work.
This section is provided for the benefit of those curious developers.*

Changes to www/concepts.wiki.
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
is a duplicate of a remote repository.

Communication between repositories is via HTTP.  Remote
repositories are identified by URL.  You can also point a web browser
at a repository and get human-readable status, history, and tracking
information about the project.

<h3><a id="artifacts"></a>2.1 Identification Of Artifacts</h3>

A particular version of a particular file is called an "artifact".  Each
artifact has a universally unique name which is the <a
href="http://en.wikipedia.org/wiki/SHA1">SHA1</a> or <a
href="http://en.wikipedia.org/wiki/SHA3">SHA3-256</a> hash of the
content of that file expressed as either 40 or 64 characters of
lower-case hexadecimal. (See the [./hashpolicy.wiki|hash policy







|







94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
is a duplicate of a remote repository.

Communication between repositories is via HTTP.  Remote
repositories are identified by URL.  You can also point a web browser
at a repository and get human-readable status, history, and tracking
information about the project.

<h3 id="artifacts">2.1 Identification Of Artifacts</h3>

A particular version of a particular file is called an "artifact".  Each
artifact has a universally unique name which is the <a
href="http://en.wikipedia.org/wiki/SHA1">SHA1</a> or <a
href="http://en.wikipedia.org/wiki/SHA3">SHA3-256</a> hash of the
content of that file expressed as either 40 or 64 characters of
lower-case hexadecimal. (See the [./hashpolicy.wiki|hash policy
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
manifest also contains a check-in comment, the date and time
when the check-in was established, who created the check-in,
and links to other check-ins from which the current check-in
is derived.  There is also a couple of checksums used to verify
the integrity of the check-in.  And the whole manifest might
be PGP clearsigned.</p>

<a name="keyconc"></a>
<h3>2.3 Key concepts</h3>

<ul>
<li>A <b>check-in</b> is a set of files arranged
    in a hierarchy.</li>
<li>A <b>repository</b> keeps a record of historical check-ins.</li>
<li>Repositories share their changes using <b>push</b>, <b>pull</b>,
    <b>sync</b>, and <b>clone</b>.</li>







<
|







180
181
182
183
184
185
186

187
188
189
190
191
192
193
194
manifest also contains a check-in comment, the date and time
when the check-in was established, who created the check-in,
and links to other check-ins from which the current check-in
is derived.  There is also a couple of checksums used to verify
the integrity of the check-in.  And the whole manifest might
be PGP clearsigned.</p>


<h3 id="keyconc">2.3 Key concepts</h3>

<ul>
<li>A <b>check-in</b> is a set of files arranged
    in a hierarchy.</li>
<li>A <b>repository</b> keeps a record of historical check-ins.</li>
<li>Repositories share their changes using <b>push</b>, <b>pull</b>,
    <b>sync</b>, and <b>clone</b>.</li>
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
fossil help
</b></blockquote>

In the next section, when we say things like "use the <b>help</b>
command" we mean to use the command name "help" as the first
token after the name of the Fossil executable, as shown above.

<a name="workflow"></a>
<h2>4.0 Workflow</h2>

<verbatim type="pikchr float-right">
    down
R1: cylinder "Remote" "Repository" fill 0xadd8e6 rad 70%
    move 150%
R2: cylinder same "Local" "Repository" fill 0x90ee90
    move 120%







<
|







244
245
246
247
248
249
250

251
252
253
254
255
256
257
258
fossil help
</b></blockquote>

In the next section, when we say things like "use the <b>help</b>
command" we mean to use the command name "help" as the first
token after the name of the Fossil executable, as shown above.


<h2 id="workflow">4.0 Workflow</h2>

<verbatim type="pikchr float-right">
    down
R1: cylinder "Remote" "Repository" fill 0xadd8e6 rad 70%
    move 150%
R2: cylinder same "Local" "Repository" fill 0x90ee90
    move 120%
Added www/css/diff.md.
































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
Notes On Diff Formatting
========================

There are two main kinds of diff display for the web interface:
unified and side-by-side.  Both displays are implemented using
a &lt;table&gt;.  The unified diff is a 4-column table, and the
side-by-side diff is a 5-column table.  In a page like /info that
might show multiple file diffs, each file diff is in a separate
&lt;table&gt;.  For side-by-side diffs, a small amount of Javascript
code is used to resize the text columns so that they fill the screen
width and to keep horizontal scrollbars in sync.

For the unified diff, the basic structure
is like this:

> ~~~~
<table class='diff udiff'>
<tr>
  <td class='diffln difflnl'><pre>
     Line numbers for the left-hand file
  </pre></td>
  <td class='diffln difflnr'><pre>
     Line numbers for the right-hand file
  </pre></td>
  <td class='diffsep'><pre>
     Change marks.  "+" or "=" or nothing
  </pre></td>
  <td class='difftxt difftxtu'><pre>
     The text
  </pre></td>
</tr>
</table>
~~~~

The structure for a side-by-side diff follows the
same basic pattern, though with 5 columns instead of
4, and slightly different class names:

> ~~~~
<table class='diff splitdiff'>
<tr>
  <td class='diffln difflnl'><pre>
     Line numbers for the left-hand file
  </pre></td>
  <td class='difftxt difftxtl'><pre>
     The text for the left side
  </pre></td>
  <td class='diffsep'><pre>
     Change marks.  "+" or "=" or nothing
  </pre></td>
  <td class='diffln difflnr'><pre>
     Line numbers for the right-hand file
  </pre></td>
  <td class='difftxt difftxtr'><pre>
     The text on the right-hand side
  </pre></td>
</tr>
</table>
~~~~

The outer &lt;table&gt; always has class "diff".  The "diffu" class
is added for unified diffs and the "splitdiff" class is added for
side-by-side diffs.

All line-number columns have the "diffln" class.  They also always
have one of "difflnl" or "difflnr" depending on whether they hold
line numbers for the left or right files, respectively.

Text is always kept in a separate column so that it can be scraped
and copied by the user.  All text columns have the "difftxt" class.
One additional class "difftxtu", "difftxtl", or "difftxtr" is added
depending on if the text is for a unified diff, the left column of
a side-by-side diff, or the right column of a side-by-side diff.

The content of all columns is a single &lt;pre&gt; that contains the
appropriate diff-text for that column.  Scrolling is done on the
&lt;pre&gt; element.

Within text columns, highlighting is done with &lt;del&gt; and
&lt;ins&gt; markup.  All text on a line that contains an isert or
delete is surrounded by &lt;ins&gt;...&lt;/ins&gt; or
&lt;del&gt;..&lt;/del&gt;.  Within that line, specific characters
of text that specifically inserted deleted have an additional
layer of &lt;ins&gt; or &lt;del&gt; markup.  Thus CSS like the
following is appropriate:

> ~~~~
td.difftxt ins {
  background-color: #dafbe1;  /* Light green for the whole line */
  text-decoration: none;
}
td.difftxt ins > ins {
  background-color: #a0e4b2;  /* Dark green for specific characters that change */
  text-decoration: none;
}
~~~~

In a side-by-side diff, if an interior &lt;ins&gt; or &lt;del&gt; that mark
specific characters that change correspond to a delete/insert on the other
side, they they have the "edit" class tag.  (ex:  &lt;ins&nbsp;class='edit'&gt;
or &lt;del&nbsp;class='edit'&gt;).  Some skins choose to paint these "modified"
regions blue:

> ~~~~
td.difftxt ins > ins.edit {
  background-color: #c0c0ff;  /* Blue for "modified" text region */
  text-decoration: none;
}
~~~~

Line number text also has &lt;ins&gt; and &lt;del&gt; tags for lines which
are pure insert or pure delete.  But the tags do not nest for line numbers.
Added www/css/index.md.
























>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
Cascading Style Sheet Notes
===========================

This is a collection of technical notes that document the design of
the Document Object Model (DOM) and corresponding Cascading Style Sheet (CSS)
attributes used for customing the look-and-feel of Fossil.  These notes
are of interest to people who want to customize the Fossil skin or
enhance the internal display logic.

This is a collection of documents that we hope will grow over time.

  *  [Diff styling](./diff.md)
Changes to www/custom_ticket.wiki.
65
66
67
68
69
70
71







72
73
74
75
76
77
78
&lt;/tr>
&lt;th1>enable_output 1&lt;/th1>
</pre>
This bit of code will get rid of the "email" field entry for logged-in users.
Since we know the user's information, we don't have to ask for it. NOTE: it
might be good to automatically scoop up the user's email and put it here.
</p>







</blockquote>

<h2>Modify the 'view ticket' page</h2><blockquote>
<p>
Look for the text "Contact:" (about halfway through).  Then insert these lines
after the closing tr tag and before the "enable_output" line:
<pre>







>
>
>
>
>
>
>







65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
&lt;/tr>
&lt;th1>enable_output 1&lt;/th1>
</pre>
This bit of code will get rid of the "email" field entry for logged-in users.
Since we know the user's information, we don't have to ask for it. NOTE: it
might be good to automatically scoop up the user's email and put it here.
</p>
<p>
You might also want to enable people to actually assign the ticket to a specific
person during creation. For this to work, you need to add the code
for "assigned_to" as shown below under the heading "Modify the 'edit ticket' page".
This will give you an additional combobox where you can choose a person during
ticket creation.
</p>
</blockquote>

<h2>Modify the 'view ticket' page</h2><blockquote>
<p>
Look for the text "Contact:" (about halfway through).  Then insert these lines
after the closing tr tag and before the "enable_output" line:
<pre>
93
94
95
96
97
98
99
100







101
102
103
104
105
106
107
<p>
Before the "Severity:" line, add this:
<pre>
&lt;tr>&lt;td align="right">Assigned to:&lt;/td>&lt;td>
&lt;th1>combobox assigned_to $assigned_choices 1&lt;/th1>
&lt;/td>&lt;/tr>
</pre>
That will give you a drop-down list of assignees.  Now, similar to the previous







section, look for "Contact:" and add this:
<pre>
  &lt;tr>&lt;td align="right">Reported by:&lt;/td>&lt;td>
  &lt;input type="text" name="opened_by" size="40"
   value="$&lt;opened_by>">
  &lt;/td>&lt;/tr>
</pre>







|
>
>
>
>
>
>
>







100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
<p>
Before the "Severity:" line, add this:
<pre>
&lt;tr>&lt;td align="right">Assigned to:&lt;/td>&lt;td>
&lt;th1>combobox assigned_to $assigned_choices 1&lt;/th1>
&lt;/td>&lt;/tr>
</pre>
That will give you a drop-down list of assignees. The first argument to the TH1
command 'combobox' is the database field which the combobox is associated to.
The next argument is the list of choices you want to show in the combobox (and
that you specified in the second step above. The last argument should be 1 for a
true combobox (see the <a href="th1.md#combobox">TH1 documentation</a> for
details).</p>

<p>Now, similar to the previous
section, look for "Contact:" and add this:
<pre>
  &lt;tr>&lt;td align="right">Reported by:&lt;/td>&lt;td>
  &lt;input type="text" name="opened_by" size="40"
   value="$&lt;opened_by>">
  &lt;/td>&lt;/tr>
</pre>
Changes to www/customgraph.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# Customizing the Timeline Graph

Beginning with version 1.33, Fossil gives users and skin authors significantly
more control over the look and feel of the timeline graph.

## <a id="basic-style"></a>Basic Style Options

Fossil includes several options for changing the graph's style without having
to delve into CSS. These can be found in the details.txt file of your skin or
under Admin/Skins/Details in the web UI.

*   ###`timeline-arrowheads`

    Set this to `0` to hide arrowheads on primary child lines.

*   ###`timeline-circle-nodes`

    Set this to `1` to make check-in nodes circular instead of square.

*   ###`timeline-color-graph-lines`

    Set this to `1` to colorize primary child lines.

*   ###`white-foreground`

    Set this to `1` if your skin uses white (or any light color) text.
    This tells Fossil to generate darker background colors for branches.


## <a id="adv-style"></a>Advanced Styling












|



|



|



|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# Customizing the Timeline Graph

Beginning with version 1.33, Fossil gives users and skin authors significantly
more control over the look and feel of the timeline graph.

## <a id="basic-style"></a>Basic Style Options

Fossil includes several options for changing the graph's style without having
to delve into CSS. These can be found in the details.txt file of your skin or
under Admin/Skins/Details in the web UI.

*   ### `timeline-arrowheads`

    Set this to `0` to hide arrowheads on primary child lines.

*   ### `timeline-circle-nodes`

    Set this to `1` to make check-in nodes circular instead of square.

*   ### `timeline-color-graph-lines`

    Set this to `1` to colorize primary child lines.

*   ### `white-foreground`

    Set this to `1` if your skin uses white (or any light color) text.
    This tells Fossil to generate darker background colors for branches.


## <a id="adv-style"></a>Advanced Styling

40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
latter, less obvious type.

## <a id="pos-elems"></a>Positioning Elements

These elements aren't intended to be seen. They're only used to help position
the graph and its visible elements.

*   ###<a id="tl-canvas"></a>`.tl-canvas`

    Set the left and right margins on this class to give the desired amount
    of space between the graph and its adjacent columns in the timeline.

    #### Additional Classes

    * `.sel`: See [`.tl-node`](#tl-node) for more information.

*   ###<a id="tl-rail"></a>`.tl-rail`

    Think of rails as invisible vertical lines on which check-in nodes are
    placed. The more simultaneous branches in a graph, the more rails required
    to draw it. Setting the `width` property on this class determines the
    maximum spacing between rails. This spacing is automatically reduced as
    the number of rails increases. If you change the `width` of `.tl-node`
    elements, you'll probably need to change this value, too.

*   ###<a id="tl-mergeoffset"></a>`.tl-mergeoffset`

    A merge line often runs vertically right beside a primary child line. This
    class's `width` property specifies the maximum spacing between the two.
    Setting this value to `0` will eliminate the vertical merge lines.
    Instead, the merge arrow will extend directly off the primary child line.
    As with rail spacing, this is also adjusted automatically as needed.

*   ###<a id="tl-nodemark"></a>`.tl-nodemark`

    In the timeline table, the second cell in each check-in row contains an
    invisible div with this class. These divs are used to determine the
    vertical position of the nodes. By setting the `margin-top` property,
    you can adjust this position.

## <a id="vis-elems"></a>Visible Elements

These are the elements you can actually see on the timeline graph: the nodes,
arrows, and lines. Each of these elements may also have additional classes
attached to them, depending on their context.

*   ###<a id="tl-node"></a>`.tl-node`

    A node exists for each check-in in the timeline.

    #### Additional Classes

    *   `.leaf`: Specifies that the check-in is a leaf (i.e. that it has no
        children in the same branch).

    *   `.merge`: Specifies that the check-in contains a merge.

    *   `.sel`: When the user clicks a node to designate it as the beginning
        of a diff, this class is added to both the node itself and the
        [`.tl-canvas`](#tl-canvas) element. The class is removed from both
        elements when the node is clicked again.

*   ###<a id="tl-arrow"></a>`.tl-arrow`

    Arrows point from parent nodes to their children. Technically, this
    class is just for the arrowhead. The rest of the arrow is composed
    of [`.tl-line`](#tl-line) elements.

    There are six additional classes that are used to distinguish the different
    types of arrows. However, only these combinations are valid:

    *   `.u`: Up arrow that points to a child from its primary parent.

    *   `.u.sm`: Smaller up arrow, used when there is limited space between
        parent and child nodes.

    *   `.merge.l` or `.merge.r`: Merge arrow pointing either to the left or
        right.

    *   `.warp`: A timewarped arrow (always points to the right), used when a
        misconfigured clock makes a check-in appear to have occurred before its
        parent ([example](https://www.sqlite.org/src/timeline?c=2010-09-29&nd)).

*   ###<a id="tl-line"></a>`.tl-line`

    Along with arrows, lines connect parent and child nodes. Line thickness is
    determined by the `width` property, regardless of whether the line is
    horizontal or vertical. You can also use borders to create special line
    styles. Here's a CSS snippet for making dotted merge lines:

        .tl-line.merge {







|








|








|







|












|















|




















|







40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
latter, less obvious type.

## <a id="pos-elems"></a>Positioning Elements

These elements aren't intended to be seen. They're only used to help position
the graph and its visible elements.

*   ### <a id="tl-canvas"></a>`.tl-canvas`

    Set the left and right margins on this class to give the desired amount
    of space between the graph and its adjacent columns in the timeline.

    #### Additional Classes

    * `.sel`: See [`.tl-node`](#tl-node) for more information.

*   ### <a id="tl-rail"></a>`.tl-rail`

    Think of rails as invisible vertical lines on which check-in nodes are
    placed. The more simultaneous branches in a graph, the more rails required
    to draw it. Setting the `width` property on this class determines the
    maximum spacing between rails. This spacing is automatically reduced as
    the number of rails increases. If you change the `width` of `.tl-node`
    elements, you'll probably need to change this value, too.

*   ### <a id="tl-mergeoffset"></a>`.tl-mergeoffset`

    A merge line often runs vertically right beside a primary child line. This
    class's `width` property specifies the maximum spacing between the two.
    Setting this value to `0` will eliminate the vertical merge lines.
    Instead, the merge arrow will extend directly off the primary child line.
    As with rail spacing, this is also adjusted automatically as needed.

*   ### <a id="tl-nodemark"></a>`.tl-nodemark`

    In the timeline table, the second cell in each check-in row contains an
    invisible div with this class. These divs are used to determine the
    vertical position of the nodes. By setting the `margin-top` property,
    you can adjust this position.

## <a id="vis-elems"></a>Visible Elements

These are the elements you can actually see on the timeline graph: the nodes,
arrows, and lines. Each of these elements may also have additional classes
attached to them, depending on their context.

*   ### <a id="tl-node"></a>`.tl-node`

    A node exists for each check-in in the timeline.

    #### Additional Classes

    *   `.leaf`: Specifies that the check-in is a leaf (i.e. that it has no
        children in the same branch).

    *   `.merge`: Specifies that the check-in contains a merge.

    *   `.sel`: When the user clicks a node to designate it as the beginning
        of a diff, this class is added to both the node itself and the
        [`.tl-canvas`](#tl-canvas) element. The class is removed from both
        elements when the node is clicked again.

*   ### <a id="tl-arrow"></a>`.tl-arrow`

    Arrows point from parent nodes to their children. Technically, this
    class is just for the arrowhead. The rest of the arrow is composed
    of [`.tl-line`](#tl-line) elements.

    There are six additional classes that are used to distinguish the different
    types of arrows. However, only these combinations are valid:

    *   `.u`: Up arrow that points to a child from its primary parent.

    *   `.u.sm`: Smaller up arrow, used when there is limited space between
        parent and child nodes.

    *   `.merge.l` or `.merge.r`: Merge arrow pointing either to the left or
        right.

    *   `.warp`: A timewarped arrow (always points to the right), used when a
        misconfigured clock makes a check-in appear to have occurred before its
        parent ([example](https://www.sqlite.org/src/timeline?c=2010-09-29&nd)).

*   ### <a id="tl-line"></a>`.tl-line`

    Along with arrows, lines connect parent and child nodes. Line thickness is
    determined by the `width` property, regardless of whether the line is
    horizontal or vertical. You can also use borders to create special line
    styles. Here's a CSS snippet for making dotted merge lines:

        .tl-line.merge {
Changes to www/customskin.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Skinning the Fossil Web Interface

The Fossil web interface comes with a pre-configured look and feel.  The default
look and feel works fine in many situations.  However, you may want to change
the look and feel (the "skin") of Fossil to better suite your own individual tastes.
This document provides background information to aid you in that task.

## <a name="builtin"></a>Built-in Skins

Fossil comes with [multiple built-in skins](/skins).  If the default skin does not
suite your tastes, perhaps one of the other built-in skins will work better.
If nothing else, the built-in skins can serve as examples or templates that
you can use to develop your own custom skin.

The sources to these built-ins can







|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Skinning the Fossil Web Interface

The Fossil web interface comes with a pre-configured look and feel.  The default
look and feel works fine in many situations.  However, you may want to change
the look and feel (the "skin") of Fossil to better suite your own individual tastes.
This document provides background information to aid you in that task.

## <a id="builtin"></a>Built-in Skins

Fossil comes with [multiple built-in skins](/skins).  If the default skin does not
suite your tastes, perhaps one of the other built-in skins will work better.
If nothing else, the built-in skins can serve as examples or templates that
you can use to develop your own custom skin.

The sources to these built-ins can
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
   * footer.txt
   * header.txt
   * js.txt

Try out the built-in skins by using the --skin option on the
[fossil ui](/help?cmd=ui) or [fossil server](/help?cmd=server) commands.

## <a name="sharing"></a>Sharing Skins

The skin of a repository is not part of the versioned state and does not
"push" or "pull" like checked-in files.  The skin is local to the
repository.  However, skins can be shared between repositories using
the [fossil config](/help?cmd=configuration) command.
The "fossil config push skin" command will send the local skin to a remote
repository and the "fossil config pull skin" command will import a skin







|







23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
   * footer.txt
   * header.txt
   * js.txt

Try out the built-in skins by using the --skin option on the
[fossil ui](/help?cmd=ui) or [fossil server](/help?cmd=server) commands.

## <a id="sharing"></a>Sharing Skins

The skin of a repository is not part of the versioned state and does not
"push" or "pull" like checked-in files.  The skin is local to the
repository.  However, skins can be shared between repositories using
the [fossil config](/help?cmd=configuration) command.
The "fossil config push skin" command will send the local skin to a remote
repository and the "fossil config pull skin" command will import a skin
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164

Finally, Fossil always adds its own footer (unless overridden)
to close out the generated HTML:

        </body>
        </html>

## <a name="mainmenu"></a>Changing the Main Menu Contents

As of Fossil 2.15, the actual text content of the skin’s main menu is no
longer part of the skin proper if you’re using one of the stock skins.
If you look at the Header section of the skin, you’ll find a
`<div class="mainmenu">` element whose contents are set by a short
[TH1](./th1.md) script from the contents of the **Main Menu** section of
the Setup → Configuration screen.

This feature allows the main menu contents to stay the same across
different skins, so you no longer have to reapply menu customizations
when trying different skins.

See the [`capexpr`](./th1.md#capexpr) section of the TH1 docs for help
on interpreting the default contents of this block.


## <a name="override"></a>Overriding the HTML Header and Footer

Notice that the `<html>`, `<head>`, and opening `<body>` 
elements at the beginning of the document,
and the closing `</body>` and `</html>` elements at the end are automatically
generated by Fossil.  This is recommended.

However, for maximum design flexibility, Fossil allows those elements to be







|
















|







133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164

Finally, Fossil always adds its own footer (unless overridden)
to close out the generated HTML:

        </body>
        </html>

## <a id="mainmenu"></a>Changing the Main Menu Contents

As of Fossil 2.15, the actual text content of the skin’s main menu is no
longer part of the skin proper if you’re using one of the stock skins.
If you look at the Header section of the skin, you’ll find a
`<div class="mainmenu">` element whose contents are set by a short
[TH1](./th1.md) script from the contents of the **Main Menu** section of
the Setup → Configuration screen.

This feature allows the main menu contents to stay the same across
different skins, so you no longer have to reapply menu customizations
when trying different skins.

See the [`capexpr`](./th1.md#capexpr) section of the TH1 docs for help
on interpreting the default contents of this block.


## <a id="override"></a>Overriding the HTML Header and Footer

Notice that the `<html>`, `<head>`, and opening `<body>` 
elements at the beginning of the document,
and the closing `</body>` and `</html>` elements at the end are automatically
generated by Fossil.  This is recommended.

However, for maximum design flexibility, Fossil allows those elements to be
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
put your web browser into developer mode and disable the cache.
If you fail to do this, then you might make some change to your skin
under development and press "Reload" only to find that the display
did not change.  After you have finished work your skin, the
caches should synchronize with your new design and you can reactivate
your web browser's cache and take it out of developer mode.

## <a name="headfoot"></a>Header and Footer Processing

The `header.txt` and `footer.txt` control files of a skin are the HTML text
of the Content Header and Content Footer, except that before being inserted
into the output stream, the text is run through a
[TH1 interpreter](./th1.md) that might adjust the text as follows:

  *  All text within &lt;th1&gt;...&lt;/th1&gt; is omitted from the







|







314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
put your web browser into developer mode and disable the cache.
If you fail to do this, then you might make some change to your skin
under development and press "Reload" only to find that the display
did not change.  After you have finished work your skin, the
caches should synchronize with your new design and you can reactivate
your web browser's cache and take it out of developer mode.

## <a id="headfoot"></a>Header and Footer Processing

The `header.txt` and `footer.txt` control files of a skin are the HTML text
of the Content Header and Content Footer, except that before being inserted
into the output stream, the text is run through a
[TH1 interpreter](./th1.md) that might adjust the text as follows:

  *  All text within &lt;th1&gt;...&lt;/th1&gt; is omitted from the
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360

As you can see, two TH1 variable substitutions were done.

The same TH1 interpreter is used for both the header and the footer
and for all scripts contained within them both.  Hence, any global
TH1 variables that are set by the header are available to the footer.

## <a name="menu"></a>Customizing the ≡ Hamburger Menu

The menu bar of the default skin has an entry to open a drop-down menu with
additional navigation links, represented by the ≡ button (hence the name
"hamburger menu"). The Javascript logic to open and close the hamburger menu
when the button is clicked is usually handled by a script named
"hbmenu.js" that is one of the [built-in resource files](/test-builtin-files)
that are part of Fossil.







|







346
347
348
349
350
351
352
353
354
355
356
357
358
359
360

As you can see, two TH1 variable substitutions were done.

The same TH1 interpreter is used for both the header and the footer
and for all scripts contained within them both.  Hence, any global
TH1 variables that are set by the header are available to the footer.

## <a id="menu"></a>Customizing the ≡ Hamburger Menu

The menu bar of the default skin has an entry to open a drop-down menu with
additional navigation links, represented by the ≡ button (hence the name
"hamburger menu"). The Javascript logic to open and close the hamburger menu
when the button is clicked is usually handled by a script named
"hbmenu.js" that is one of the [built-in resource files](/test-builtin-files)
that are part of Fossil.
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424

The custom `data-anim-ms` attribute can be added to the panel element to direct
the Javascript logic to override the default menu animation duration of 400 ms.
A faster animation duration of 80-200 ms may be preferred for smaller menus. The
animation is disabled by setting the attribute to `"0"`.


## <a name="vars"></a>TH1 Variables

Before expanding the TH1 within the header and footer, Fossil first
initializes a number of TH1 variables to values that depend on
repository settings and the specific page being generated.

   *   **project_name** - The project_name variable is filled with the
       name of the project as configured under the Admin/Configuration







|







410
411
412
413
414
415
416
417
418
419
420
421
422
423
424

The custom `data-anim-ms` attribute can be added to the panel element to direct
the Javascript logic to override the default menu animation duration of 400 ms.
A faster animation duration of 80-200 ms may be preferred for smaller menus. The
animation is disabled by setting the attribute to `"0"`.


## <a id="vars"></a>TH1 Variables

Before expanding the TH1 within the header and footer, Fossil first
initializes a number of TH1 variables to values that depend on
repository settings and the specific page being generated.

   *   **project_name** - The project_name variable is filled with the
       name of the project as configured under the Admin/Configuration
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501

All of the above are variables in the sense that either the header or the
footer is free to change or erase them.  But they should probably be treated
as constants.  New predefined values are likely to be added in future
releases of Fossil.


## <a name="procedure"></a>Suggested Skin Customization Procedure

Developers are free, of course, to develop new skins using any method they
want, but the following is a technique that has worked well in the past and
can serve as a starting point for future work:

   1.  Select a built-in skin that is closest to the desired look.  Make
       copies of the css, footer, and header into files name "css.txt",







|







487
488
489
490
491
492
493
494
495
496
497
498
499
500
501

All of the above are variables in the sense that either the header or the
footer is free to change or erase them.  But they should probably be treated
as constants.  New predefined values are likely to be added in future
releases of Fossil.


## <a id="procedure"></a>Suggested Skin Customization Procedure

Developers are free, of course, to develop new skins using any method they
want, but the following is a technique that has worked well in the past and
can serve as a starting point for future work:

   1.  Select a built-in skin that is closest to the desired look.  Make
       copies of the css, footer, and header into files name "css.txt",
Changes to www/defcsp.md.
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

<pre>
     default-src *;
</pre>

The following sections detail the maining of the default CSP setting.

### <a name="base"></a> default-src 'self' data:

This policy means mixed-origin content isn’t allowed, so you can’t refer
to resources on other web domains. Browsers will ignore a link like the
one in the following Markdown under our default CSP:

         ![fancy 3D Fossil logotype](https://i.imgur.com/HalpMgt.png)








|







38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

<pre>
     default-src *;
</pre>

The following sections detail the maining of the default CSP setting.

### <a id="base"></a> default-src 'self' data:

This policy means mixed-origin content isn’t allowed, so you can’t refer
to resources on other web domains. Browsers will ignore a link like the
one in the following Markdown under our default CSP:

         ![fancy 3D Fossil logotype](https://i.imgur.com/HalpMgt.png)

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

There are many other cases, [covered below](#serving).

[b64]: https://en.wikipedia.org/wiki/Base64
[svr]: ./server/


### <a name="img"></a> img-src * data:

As of Fossil 2.15, we don’t restrict the source of inline images at all.
You can pull them in from remote systems as well as pull them from
within the Fossil repository itself, or use `data:` URIs.

If you are certain all images come from only within the repository, you
can close off certain risks — tracking pixels, broken image format
decoders, system dialog box spoofing, etc. — by changing this to
“`img-src 'self'`” possibly followed by “`data:`” if you will also use
`data:` URIs.


### <a name="style"></a> style-src 'self' 'unsafe-inline'

This policy allows CSS information to come from separate files hosted
under the Fossil repo server’s Internet domain. It also allows inline CSS
`<style>` tags within the document text.

The `'unsafe-inline'` declaration allows CSS within individual HTML
elements:

        <p style="margin-left: 4em">Indented text.</p>

As the "`unsafe-`" prefix on the name implies, the `'unsafe-inline'`
feature is suboptimal for security.  However, there are
a few places in the Fossil-generated HTML that benefit from this
flexibility and the work-arounds are verbose and difficult to maintain.
Furthermore, the harm that can be done with style injections is far
less than the harm possible with injected javascript.  And so the
`'unsafe-inline'` compromise is accepted for now, though it might
go away in some future release of Fossil.


### <a name="script"></a> script-src 'self' 'nonce-%s'

This policy disables in-line JavaScript and only allows `<script>`
elements if the `<script>` includes a `nonce` attribute that matches the
one declared by the CSP. That nonce is a large random number, unique for
each HTTP page generated by Fossil, so an attacker cannot guess the
value, so the browser will ignore an attacker’s injected JavaScript.








|












|




















|







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

There are many other cases, [covered below](#serving).

[b64]: https://en.wikipedia.org/wiki/Base64
[svr]: ./server/


### <a id="img"></a> img-src * data:

As of Fossil 2.15, we don’t restrict the source of inline images at all.
You can pull them in from remote systems as well as pull them from
within the Fossil repository itself, or use `data:` URIs.

If you are certain all images come from only within the repository, you
can close off certain risks — tracking pixels, broken image format
decoders, system dialog box spoofing, etc. — by changing this to
“`img-src 'self'`” possibly followed by “`data:`” if you will also use
`data:` URIs.


### <a id="style"></a> style-src 'self' 'unsafe-inline'

This policy allows CSS information to come from separate files hosted
under the Fossil repo server’s Internet domain. It also allows inline CSS
`<style>` tags within the document text.

The `'unsafe-inline'` declaration allows CSS within individual HTML
elements:

        <p style="margin-left: 4em">Indented text.</p>

As the "`unsafe-`" prefix on the name implies, the `'unsafe-inline'`
feature is suboptimal for security.  However, there are
a few places in the Fossil-generated HTML that benefit from this
flexibility and the work-arounds are verbose and difficult to maintain.
Furthermore, the harm that can be done with style injections is far
less than the harm possible with injected javascript.  And so the
`'unsafe-inline'` compromise is accepted for now, though it might
go away in some future release of Fossil.


### <a id="script"></a> script-src 'self' 'nonce-%s'

This policy disables in-line JavaScript and only allows `<script>`
elements if the `<script>` includes a `nonce` attribute that matches the
one declared by the CSP. That nonce is a large random number, unique for
each HTTP page generated by Fossil, so an attacker cannot guess the
value, so the browser will ignore an attacker’s injected JavaScript.

152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
    can only be installed by the Fossil server’s system administrator,
    this path is also considered safe.

[ext]: ./serverext.wiki
[su]:  ./caps/admin-v-setup.md#apsu


#### <a name="xss"></a>Cross-Site Scripting via Ordinary User Capabilities

We’re so restrictive about how we treat JavaScript because it can lead
to difficult-to-avoid scripting attacks. If we used the same CSP for
`<script>` tags [as for `<style>` tags](#style), anyone with check-in
rights on your repository could add a JavaScript file to your repository
and then refer to it from other content added to the site.  Since
JavaScript code can access any data from any URI served under its same







|







152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
    can only be installed by the Fossil server’s system administrator,
    this path is also considered safe.

[ext]: ./serverext.wiki
[su]:  ./caps/admin-v-setup.md#apsu


#### <a id="xss"></a>Cross-Site Scripting via Ordinary User Capabilities

We’re so restrictive about how we treat JavaScript because it can lead
to difficult-to-avoid scripting attacks. If we used the same CSP for
`<script>` tags [as for `<style>` tags](#style), anyone with check-in
rights on your repository could add a JavaScript file to your repository
and then refer to it from other content added to the site.  Since
JavaScript code can access any data from any URI served under its same
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
through check-ins.

[ed]:   ./embeddeddoc.wiki
[edtf]: ./embeddeddoc.wiki#th1
[hfed]: ./embeddeddoc.wiki#html


## <a name="serving"></a>Serving Files Within the Limits

There are several ways to serve files within the above restrictions,
avoiding the need to [override the default CSP](#override). In
decreasing order of simplicity and preference:

1.  Within [embedded documentation][ed] (only!) you can refer to files
    stored in the repo using document-relative file URLs:







|







212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
through check-ins.

[ed]:   ./embeddeddoc.wiki
[edtf]: ./embeddeddoc.wiki#th1
[hfed]: ./embeddeddoc.wiki#html


## <a id="serving"></a>Serving Files Within the Limits

There are several ways to serve files within the above restrictions,
avoiding the need to [override the default CSP](#override). In
decreasing order of simplicity and preference:

1.  Within [embedded documentation][ed] (only!) you can refer to files
    stored in the repo using document-relative file URLs:
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
[tkt]:  ./tickets.wiki
[tn]:   ./event.wiki
[uu]:   /help?cmd=/uv
[uv]:   ./unvers.wiki
[wiki]: ./wikitheory.wiki


## <a name="override"></a>Overriding the Default CSP

If you wish to relax the default CSP’s restrictions or to tighten them
further, there are multiple ways to accomplish that.

The following methods are listed in top-down order to give the simplest
and most straightforward method first.  Further methods dig down deeper
into the stack, which is helpful to understand even if you end up using
a higher-level method.


### <a name="cspsetting"></a>The `default-csp` Setting

If the [`default-csp` setting](/help?cmd=default-csp) is defined and is
not an empty string, its value is injected into the page using
[TH1](./th1.md) via one or more of the methods below, depending on the
skin you’re using and local configuration.

Changing this setting is the easiest way to set a nonstandard CSP on







|










|







303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
[tkt]:  ./tickets.wiki
[tn]:   ./event.wiki
[uu]:   /help?cmd=/uv
[uv]:   ./unvers.wiki
[wiki]: ./wikitheory.wiki


## <a id="override"></a>Overriding the Default CSP

If you wish to relax the default CSP’s restrictions or to tighten them
further, there are multiple ways to accomplish that.

The following methods are listed in top-down order to give the simplest
and most straightforward method first.  Further methods dig down deeper
into the stack, which is helpful to understand even if you end up using
a higher-level method.


### <a id="cspsetting"></a>The `default-csp` Setting

If the [`default-csp` setting](/help?cmd=default-csp) is defined and is
not an empty string, its value is injected into the page using
[TH1](./th1.md) via one or more of the methods below, depending on the
skin you’re using and local configuration.

Changing this setting is the easiest way to set a nonstandard CSP on
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
2.  For more complicated CSPs, the quoting rules for your shell and the
    CSP syntax may interact, making it difficult or impossible to set
    your desired CSP via the command line.  Setting it via the web UI
    doesn’t have this problem.



### <a name="th1"></a>TH1 Setup Hook

Fossil sets [the TH1 variable `$default_csp`][thvar] from the
`default-csp` setting and uses *that* to inject the value into generated
HTML pages in its stock configuration.

This means that another way you can override this value is to use
the [`th1-setup` hook script](./th1-hooks.md), which runs before TH1
processing happens during skin processing:

        $ fossil set th1-setup "set default_csp {default-src 'self'}"

After [the above](#admin-ui), this is the cleanest method.

[thvar]: ./customskin.md#vars



### <a name="csrc"></a>Fossil C Source Code

When you do neither of the above things, Fossil uses
[a hard-coded default](/info?ln=527-530&name=65a555d0d4fb846b).

We tell you about this not to suggest that you hack the Fossil C source
code to change the CSP but simply to document the next step before we
move down-stack.



### <a name="header"></a>Skin Header

[In the normal case](./customskin.md#override), Fossil injects the CSP
retrieved by one of the above methods into the header of all HTML
documents it generates:

```HTML
<head>...







|

















|










|







353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
2.  For more complicated CSPs, the quoting rules for your shell and the
    CSP syntax may interact, making it difficult or impossible to set
    your desired CSP via the command line.  Setting it via the web UI
    doesn’t have this problem.



### <a id="th1"></a>TH1 Setup Hook

Fossil sets [the TH1 variable `$default_csp`][thvar] from the
`default-csp` setting and uses *that* to inject the value into generated
HTML pages in its stock configuration.

This means that another way you can override this value is to use
the [`th1-setup` hook script](./th1-hooks.md), which runs before TH1
processing happens during skin processing:

        $ fossil set th1-setup "set default_csp {default-src 'self'}"

After [the above](#admin-ui), this is the cleanest method.

[thvar]: ./customskin.md#vars



### <a id="csrc"></a>Fossil C Source Code

When you do neither of the above things, Fossil uses
[a hard-coded default](/info?ln=527-530&name=65a555d0d4fb846b).

We tell you about this not to suggest that you hack the Fossil C source
code to change the CSP but simply to document the next step before we
move down-stack.



### <a id="header"></a>Skin Header

[In the normal case](./customskin.md#override), Fossil injects the CSP
retrieved by one of the above methods into the header of all HTML
documents it generates:

```HTML
<head>...
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
`$default_csp` variable like the Bootstrap skin does so you can use one
of the methods above with your custom skin, so the CSP can vary
independently of the skin.

[dcinj]: /info?ln=7&name=bef080a6929a3e6f


### <a name="fep"></a>Front-End Proxy

If your Fossil repo is behind some sort of HTTP [front-end proxy][svr],
the [preferred method][pmcsp] for setting the CSP is via a custom HTTP
header, which most HTTP reverse proxy programs allow.

Beware that if you have a CSP set via both the HTTP and HTML headers
that the two CSPs [merge](https://stackoverflow.com/a/51153816/142454),







|







443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
`$default_csp` variable like the Bootstrap skin does so you can use one
of the methods above with your custom skin, so the CSP can vary
independently of the skin.

[dcinj]: /info?ln=7&name=bef080a6929a3e6f


### <a id="fep"></a>Front-End Proxy

If your Fossil repo is behind some sort of HTTP [front-end proxy][svr],
the [preferred method][pmcsp] for setting the CSP is via a custom HTTP
header, which most HTTP reverse proxy programs allow.

Beware that if you have a CSP set via both the HTTP and HTML headers
that the two CSPs [merge](https://stackoverflow.com/a/51153816/142454),
Changes to www/delta_encoder_algorithm.wiki.
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
companion specification titled "<a href="delta_format.wiki">Fossil
Delta Format</a>".
</p>

<p>The algorithm is inspired
by <a href="http://samba.anu.edu.au/rsync/">rsync</a>.</p>

<a name="argresparam"></a><h2>1.0 Arguments, Results, and Parameters</h2>

<p>The encoder takes two byte-sequences as input, the "original", and
the "target", and returns a single byte-sequence containing the
"delta" which transforms the original into the target upon its
application.</p>

<p>Note that the data of a "byte-sequence" includes its length,
i.e. the number of bytes contained in the sequence.</p>

<p>The algorithm has one parameter named "NHASH", the size of the
"sliding window" for the "rolling hash", in bytes. These two terms are
explained in the next section. The value of this parameter has to be a
power of two for the algorithm to work. For Fossil the value of this
parameter is set to "16".</p>

<a name="operation"></a><h2>2.0 Operation</h2>

<p>The algorithm is split into three phases which generate
the <a href="delta_format.wiki#header">header</a>,
<a href="delta_format.wiki#slist">segment list</a>,
and <a href="delta_format.wiki#trailer">trailer</a> of the delta, per
its general <a href="delta_format.wiki#structure">structure</a>.</p>

<p>The two phases generating header and trailer are not covered here
as their implementation trivially follows directly from the
specification of the <a href="delta_format.wiki">delta format</a>.</p>

<p>This leaves the segment-list. Its generation is done in two phases,
a pre-processing step operating on the "original" byte-sequence,
followed by the processing of the "target" byte-sequence using the
information gathered by the first step.</p>

<a name="preprocessing"></a><h3>2.1 Preprocessing the original</h3>

<p>A major part of the processing of the "target" is to find a range
in the "original" which contains the same content as found at the
current location in the "target".</p>

<p>A naive approach to this would be to search the whole "original"
for such content. This however is very inefficient as it would search







|















|
















|







15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
companion specification titled "<a href="delta_format.wiki">Fossil
Delta Format</a>".
</p>

<p>The algorithm is inspired
by <a href="http://samba.anu.edu.au/rsync/">rsync</a>.</p>

<h2 id="argresparam">1.0 Arguments, Results, and Parameters</h2>

<p>The encoder takes two byte-sequences as input, the "original", and
the "target", and returns a single byte-sequence containing the
"delta" which transforms the original into the target upon its
application.</p>

<p>Note that the data of a "byte-sequence" includes its length,
i.e. the number of bytes contained in the sequence.</p>

<p>The algorithm has one parameter named "NHASH", the size of the
"sliding window" for the "rolling hash", in bytes. These two terms are
explained in the next section. The value of this parameter has to be a
power of two for the algorithm to work. For Fossil the value of this
parameter is set to "16".</p>

<h2 id="operation">2.0 Operation</h2>

<p>The algorithm is split into three phases which generate
the <a href="delta_format.wiki#header">header</a>,
<a href="delta_format.wiki#slist">segment list</a>,
and <a href="delta_format.wiki#trailer">trailer</a> of the delta, per
its general <a href="delta_format.wiki#structure">structure</a>.</p>

<p>The two phases generating header and trailer are not covered here
as their implementation trivially follows directly from the
specification of the <a href="delta_format.wiki">delta format</a>.</p>

<p>This leaves the segment-list. Its generation is done in two phases,
a pre-processing step operating on the "original" byte-sequence,
followed by the processing of the "target" byte-sequence using the
information gathered by the first step.</p>

<h3 id="preprocessing">2.1 Preprocessing the original</h3>

<p>A major part of the processing of the "target" is to find a range
in the "original" which contains the same content as found at the
current location in the "target".</p>

<p>A naive approach to this would be to search the whole "original"
for such content. This however is very inefficient as it would search
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
computed.
</li>
<li>A hash table is filled, mapping from the hashes of the chunks to
the list of chunk locations having this hash.
</li>
</ol>

<a name="processing"></a><h3>2.1 Processing the target</h3>

<p>This, the main phase of the encoder, processes the target in a loop
from beginning to end. The state of the encoder is captured by two
locations, the "base" and the "slide". "base" points to the first byte
of the target for which no delta output has been generated yet, and
"slide" is the location of the window used to look in the "origin" for
commonalities. This window is NHASH bytes long.</p>







|







81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
computed.
</li>
<li>A hash table is filled, mapping from the hashes of the chunks to
the list of chunk locations having this hash.
</li>
</ol>

<h3 id="processing">2.1 Processing the target</h3>

<p>This, the main phase of the encoder, processes the target in a loop
from beginning to end. The state of the encoder is captured by two
locations, the "base" and the "slide". "base" points to the first byte
of the target for which no delta output has been generated yet, and
"slide" is the location of the window used to look in the "origin" for
commonalities. This window is NHASH bytes long.</p>
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
</p>

<p>If the processing loop left bytes unencoded, i.e. "base" not
exactly at the end of the "target", as is possible for both end
conditions, then one last insert instruction is emitted to put these
bytes into the delta.<p>

<a name="exceptions"></a><h2>3.0 Exceptions</h2>

<p>If the "original" is at most NHASH bytes long no compression of
changes is possible, and the segment-list of the delta consists of a
single literal which contains the entire "target".</p>

<p>This is actually equivalent to the second end condition of the
processing loop described in the previous section, just checked before
actually entering the loop.</p>

<a name="rollhash"></a><h2>4.0 The rolling hash</h2>

<p>The rolling hash described below and used to compute content
signatures was chosen not only for good hashing properties, but also
to enable the easy (incremental) recalculation of its value for a
sliding window, i.e. where the oldest byte is removed from the window
and a new byte is shifted in.<p>

<a name="rhdef"></a><h3>4.1 Definition</h3>

<p>Assuming an array Z of NHASH bytes (indexing starting at 0) the
hash V is computed via</p>

<p align=center><table><tr><td>
<p><img src="encode1.gif" align="center"></p>
<p><img src="encode2.gif" align="center"></p>
<p><img src="encode3.gif" align="center"></p>
</td></tr></table></p>

where A and B are unsigned 16-bit integers (hence the <u>mod</u>), and
V is a 32-bit unsigned integer with B as MSB, A as LSB.

<a name="rhincr"></a><h3>4.2 Incremental recalculation</h3>

<p>Assuming an array Z of NHASH bytes (indexing starting at 0) with
hash V (and components A and B), the dropped
byte <img src="encode4.gif" align="center">, and the new byte
<img src="encode5.gif" align="center"> , the new hash can
be computed incrementally via: </p>








|









|







|













|







192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
</p>

<p>If the processing loop left bytes unencoded, i.e. "base" not
exactly at the end of the "target", as is possible for both end
conditions, then one last insert instruction is emitted to put these
bytes into the delta.<p>

<h2 id="exceptions">3.0 Exceptions</h2>

<p>If the "original" is at most NHASH bytes long no compression of
changes is possible, and the segment-list of the delta consists of a
single literal which contains the entire "target".</p>

<p>This is actually equivalent to the second end condition of the
processing loop described in the previous section, just checked before
actually entering the loop.</p>

<h2 id="rollhash">4.0 The rolling hash</h2>

<p>The rolling hash described below and used to compute content
signatures was chosen not only for good hashing properties, but also
to enable the easy (incremental) recalculation of its value for a
sliding window, i.e. where the oldest byte is removed from the window
and a new byte is shifted in.<p>

<h3 id="rhdef">4.1 Definition</h3>

<p>Assuming an array Z of NHASH bytes (indexing starting at 0) the
hash V is computed via</p>

<p align=center><table><tr><td>
<p><img src="encode1.gif" align="center"></p>
<p><img src="encode2.gif" align="center"></p>
<p><img src="encode3.gif" align="center"></p>
</td></tr></table></p>

where A and B are unsigned 16-bit integers (hence the <u>mod</u>), and
V is a 32-bit unsigned integer with B as MSB, A as LSB.

<h3 id="rhincr">4.2 Incremental recalculation</h3>

<p>Assuming an array Z of NHASH bytes (indexing starting at 0) with
hash V (and components A and B), the dropped
byte <img src="encode4.gif" align="center">, and the new byte
<img src="encode5.gif" align="center"> , the new hash can
be computed incrementally via: </p>

Changes to www/delta_format.wiki.
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
       Return the size of the output that would result from applying delta D.

   *   <b>delta_parse(</b><i>D</i>)</b> &rarr; This is a table-valued function
       that returns one row for the header, for the trailer, and for each segment
       in delta D.


<a name="structure"></a><h1>2.0 Structure</h1>
<verbatim type="pikchr">
    leftmargin = 0.1
    box height 50% "Header"
    box same "Segments"
    box same "Trailer"
</verbatim>

<p>A delta consists of three parts, a "header", a "trailer", and a
"segment-list" between them.</p>

<p>Both header and trailer provide information about the target
helping the decoder, and the segment-list describes how the target can
be constructed from the original.</p>

<a name="header"></a><h2>2.1 Header</h2>
<verbatim type="pikchr">
    leftmargin = 0.1
    box height 50% "Size"
    box same "\"\\n\""
</verbatim>

<p>The header consists of a single number followed by a newline
character (ASCII 0x0a). The number is the length of the target in
bytes.</p>

<p>This means that, given a delta, the decoder can compute the size of
the target (and allocate any necessary memory based on that) by simply
reading the first line of the delta and decoding the number found
there. In other words, before it has to decode everything else.</p>

<a name="trailer"></a><h2>2.2 Trailer</h2>
<verbatim type="pikchr">
    leftmargin = 0.1
    box height 50% "Checksum"
    box same "\";\""
</verbatim>

<p>The trailer consists of a single number followed by a semicolon (ASCII
0x3b). This number is a checksum of the target and can be used by a
decoder to verify that the delta applied correctly, reconstructing the
target from the original.</p>

<p>The checksum is computed by treating the target as a series of
32-bit integer numbers (MSB first), and summing these up, modulo
2^32-1. A target whose length is not a multiple of 4 is padded with
0-bytes (ASCII 0x00) at the end.</p>

<p>By putting this information at the end of the delta a decoder has
it available immediately after the target has been reconstructed
fully.</p>

<a name="slist"></a><h2>2.3 Segment-List</h2>
<verbatim type="pikchr">
    leftmargin = 0.1
    PART1: [
        B1: box height 50% width 15% ""
        B2: box same ""
        B3: box same ""
            "***"







|














|















|




















|







58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
       Return the size of the output that would result from applying delta D.

   *   <b>delta_parse(</b><i>D</i>)</b> &rarr; This is a table-valued function
       that returns one row for the header, for the trailer, and for each segment
       in delta D.


<h1 id="structure">2.0 Structure</h1>
<verbatim type="pikchr">
    leftmargin = 0.1
    box height 50% "Header"
    box same "Segments"
    box same "Trailer"
</verbatim>

<p>A delta consists of three parts, a "header", a "trailer", and a
"segment-list" between them.</p>

<p>Both header and trailer provide information about the target
helping the decoder, and the segment-list describes how the target can
be constructed from the original.</p>

<h2 id="header">2.1 Header</h2>
<verbatim type="pikchr">
    leftmargin = 0.1
    box height 50% "Size"
    box same "\"\\n\""
</verbatim>

<p>The header consists of a single number followed by a newline
character (ASCII 0x0a). The number is the length of the target in
bytes.</p>

<p>This means that, given a delta, the decoder can compute the size of
the target (and allocate any necessary memory based on that) by simply
reading the first line of the delta and decoding the number found
there. In other words, before it has to decode everything else.</p>

<h2 id="trailer">2.2 Trailer</h2>
<verbatim type="pikchr">
    leftmargin = 0.1
    box height 50% "Checksum"
    box same "\";\""
</verbatim>

<p>The trailer consists of a single number followed by a semicolon (ASCII
0x3b). This number is a checksum of the target and can be used by a
decoder to verify that the delta applied correctly, reconstructing the
target from the original.</p>

<p>The checksum is computed by treating the target as a series of
32-bit integer numbers (MSB first), and summing these up, modulo
2^32-1. A target whose length is not a multiple of 4 is padded with
0-bytes (ASCII 0x00) at the end.</p>

<p>By putting this information at the end of the delta a decoder has
it available immediately after the target has been reconstructed
fully.</p>

<h2 id="slist">2.3 Segment-List</h2>
<verbatim type="pikchr">
    leftmargin = 0.1
    PART1: [
        B1: box height 50% width 15% ""
        B2: box same ""
        B3: box same ""
            "***"
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
compression takes place, by encoding the large common parts of
original and target in small copy instructions.</p>

<p>The target is constructed from beginning to end, with the data
generated by each instruction appended after the data of all previous
instructions, with no gaps.</p>

<a name="insertlit"></a><h3>2.3.1 Insert Literal</h3>

<p>A literal is specified by two elements, the size of the literal in
bytes, and the bytes of the literal itself.</p>

<verbatim type="pikchr">
    leftmargin = 0.1
    box "Length" height 50%
    box "\":\"" same
    box "Bytes" same
</verbatim>

<p>The length is written first, followed by a colon character (ASCII
0x3a), followed by the bytes of the literal.</p>

<a name="copyrange"></a><h3>2.3.2 Copy Range</h3>

<p>A range to copy is specified by two numbers, the offset of the
first byte in the original to copy, and the size of the range, in
bytes. The size zero is special, its usage indicates that the range
extends to the end of the original.</p>

<verbatim type="pikchr">
    leftmargin = 0.1
    box "Length" height 50%
    box "\"@\"" same
    box "Offset" same
    box "\",\"" same
</verbatim>


<p>The length is written first, followed by an "at" character (ASCII
0x40), then the offset, followed by a comma (ASCII 0x2c).</p>

<a name="intcoding"></a><h1>3.0 Encoding of integers</h1>

<p>
The format currently handles only 32 bit integer numbers. They are
written base-64 encoded, MSB first, and without leading
"0"-characters, except if they are significant (i.e. 0 => "0").
</p>








|














|


















|







146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
compression takes place, by encoding the large common parts of
original and target in small copy instructions.</p>

<p>The target is constructed from beginning to end, with the data
generated by each instruction appended after the data of all previous
instructions, with no gaps.</p>

<h3 id="insertlit">2.3.1 Insert Literal</h3>

<p>A literal is specified by two elements, the size of the literal in
bytes, and the bytes of the literal itself.</p>

<verbatim type="pikchr">
    leftmargin = 0.1
    box "Length" height 50%
    box "\":\"" same
    box "Bytes" same
</verbatim>

<p>The length is written first, followed by a colon character (ASCII
0x3a), followed by the bytes of the literal.</p>

<h3 id="copyrange">2.3.2 Copy Range</h3>

<p>A range to copy is specified by two numbers, the offset of the
first byte in the original to copy, and the size of the range, in
bytes. The size zero is special, its usage indicates that the range
extends to the end of the original.</p>

<verbatim type="pikchr">
    leftmargin = 0.1
    box "Length" height 50%
    box "\"@\"" same
    box "Offset" same
    box "\",\"" same
</verbatim>


<p>The length is written first, followed by an "at" character (ASCII
0x40), then the offset, followed by a comma (ASCII 0x2c).</p>

<h1 id="intcoding">3.0 Encoding of integers</h1>

<p>
The format currently handles only 32 bit integer numbers. They are
written base-64 encoded, MSB first, and without leading
"0"-characters, except if they are significant (i.e. 0 => "0").
</p>

205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
the first character, followed by
the next 6 bits, and so on until all non-zero bits of the integer
are encoded.  The minimum number of encoding characters is used.
Note that for integers less than 10, the base-64 coding is a
ASCII decimal rendering of the number itself.
</p>

<a name="examples"></a><h1>4.0 Examples</h1>

<a name="examplesint"></a><h2>4.1 Integer encoding</h2>

<table border=1>
<tr>
<th>Value</th>
<th>Encoding</th>
</tr>
<tr>
<td>0</td>
<td>0</td>
</tr>
<tr>
<td>6246</td>
<td>1Xb</td>
</tr>
<tr>
<td>-1101438770</td>
<td>2zMM3E</td>
</tr>
</table>

<a name="examplesdelta"></a><h2>4.2 Delta encoding</h2>

<p>An example of a delta using the specified encoding is:</p>

<table border=1><tr><td><pre>
1Xb
4E@0,2:thFN@4C,6:scenda1B@Jd,6:scenda5x@Kt,6:pieces79@Qt,F: Example: eskil~E@Y0,2zMM3E;</pre>
</td></tr></table>







|

|




















|







205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
the first character, followed by
the next 6 bits, and so on until all non-zero bits of the integer
are encoded.  The minimum number of encoding characters is used.
Note that for integers less than 10, the base-64 coding is a
ASCII decimal rendering of the number itself.
</p>

<h1 id="examples">4.0 Examples</h1>

<h2 id="examplesint">4.1 Integer encoding</h2>

<table border=1>
<tr>
<th>Value</th>
<th>Encoding</th>
</tr>
<tr>
<td>0</td>
<td>0</td>
</tr>
<tr>
<td>6246</td>
<td>1Xb</td>
</tr>
<tr>
<td>-1101438770</td>
<td>2zMM3E</td>
</tr>
</table>

<h2 id="examplesdelta">4.2 Delta encoding</h2>

<p>An example of a delta using the specified encoding is:</p>

<table border=1><tr><td><pre>
1Xb
4E@0,2:thFN@4C,6:scenda1B@Jd,6:scenda5x@Kt,6:pieces79@Qt,F: Example: eskil~E@Y0,2zMM3E;</pre>
</td></tr></table>
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323

  *  Ticketing interface (expand this bullet)

</pre></td></tr></table>



<a name="notes"></a><h1>Notes</h1>

<ul>
<li>Pure text files generate a pure text delta.
</li>
<li>Binary files generate a delta that may contain some binary data.
</li>
<li>The delta encoding does not attempt to compress the content.
It was considered to be much
more sensible to do compression using a separate general-purpose
compression library, like <a href="http://www.zlib.net">zlib</a>.
</li>
</ul>







|












304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323

  *  Ticketing interface (expand this bullet)

</pre></td></tr></table>



<h1 id="notes">Notes</h1>

<ul>
<li>Pure text files generate a pure text delta.
</li>
<li>Binary files generate a delta that may contain some binary data.
</li>
<li>The delta encoding does not attempt to compress the content.
It was considered to be much
more sensible to do compression using a separate general-purpose
compression library, like <a href="http://www.zlib.net">zlib</a>.
</li>
</ul>
Changes to www/embeddeddoc.wiki.
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
The <i>&lt;version&gt;</i> is the
[./checkin_names.wiki|name of a check-in]
that contains the embedded document.  This might be a hash prefix for
the check-in, or it might be the name of a branch or tag, or it might
be a timestamp.  See the prior link
for more possibilities and examples.

<a id="ckout"></a>The <i>&lt;version&gt;</i> can
also be the special identifier "<b>ckout</b>".
The "<b>ckout</b>" keywords means to
pull the documentation file from the local source tree on disk, not
from the any check-in.  The "<b>ckout</b>" keyword
only works when you start your server using the 
"[/help?cmd=server|fossil server]" or "[/help?cmd=ui|fossil ui]"
commands.  The "/doc/ckout" URL is intended to show a preview of







|







46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
The <i>&lt;version&gt;</i> is the
[./checkin_names.wiki|name of a check-in]
that contains the embedded document.  This might be a hash prefix for
the check-in, or it might be the name of a branch or tag, or it might
be a timestamp.  See the prior link
for more possibilities and examples.

The <i id="ckout">&lt;version&gt;</i> can
also be the special identifier "<b>ckout</b>".
The "<b>ckout</b>" keywords means to
pull the documentation file from the local source tree on disk, not
from the any check-in.  The "<b>ckout</b>" keyword
only works when you start your server using the 
"[/help?cmd=server|fossil server]" or "[/help?cmd=ui|fossil ui]"
commands.  The "/doc/ckout" URL is intended to show a preview of
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
[/md_rules  | Markdown markup language].
Documentation files ending in ".txt" are plain text.
Wiki, markdown, and plain text documentation files
are rendered with the standard fossil header and footer added.
Most other mimetypes are delivered directly to the requesting
web browser without interpretation, additions, or changes.

<h2>1.1 HTML Rendering With Fossil Headers And Footers</h2>

<a name="html"></a>Files with the mimetype "text/html" (the .html or .htm suffix) are
usually rendered directly to the browser without interpretation.
However, if the file begins with a &lt;div&gt; element like this:

    <b>&lt;div class='fossil-doc' data-title='<i>Title Text</i>'&gt;</b>

Then the standard Fossil header and footer are added to the document
prior to being displayed.  The "class='fossil-doc'" attribute is







|

|







96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
[/md_rules  | Markdown markup language].
Documentation files ending in ".txt" are plain text.
Wiki, markdown, and plain text documentation files
are rendered with the standard fossil header and footer added.
Most other mimetypes are delivered directly to the requesting
web browser without interpretation, additions, or changes.

<h2 id="html">1.1 HTML Rendering With Fossil Headers And Footers</h2>

Files with the mimetype "text/html" (the .html or .htm suffix) are
usually rendered directly to the browser without interpretation.
However, if the file begins with a &lt;div&gt; element like this:

    <b>&lt;div class='fossil-doc' data-title='<i>Title Text</i>'&gt;</b>

Then the standard Fossil header and footer are added to the document
prior to being displayed.  The "class='fossil-doc'" attribute is
Changes to www/env-opts.md.
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429

If the default VFS underneath SQLite is not suitable, an alternative
can be selected with either the `--vfs VFSNAME` option or the
`FOSSIL_VFS` environment variable. The `--vfs` option takes
precedence.


### <a name="temp"></a>Temporary File Location

Fossil places some temporary files in the checkout directory. Most notably,
supporting files related to merge conflicts are placed in the same
folder as the merge result.

Other temporary files need a different home. The rules for choosing one are
complicated.







|







415
416
417
418
419
420
421
422
423
424
425
426
427
428
429

If the default VFS underneath SQLite is not suitable, an alternative
can be selected with either the `--vfs VFSNAME` option or the
`FOSSIL_VFS` environment variable. The `--vfs` option takes
precedence.


### <a id="temp"></a>Temporary File Location

Fossil places some temporary files in the checkout directory. Most notably,
supporting files related to merge conflicts are placed in the same
folder as the merge result.

Other temporary files need a different home. The rules for choosing one are
complicated.
Changes to www/event.wiki.
41
42
43
44
45
46
47






48
49
50
51
52
53
54
     domain name of the canonical website for a project changes, or new
     server hardware is obtained.  Such happenings are appropriate for
     reporting as news.

  *  <b>Announcements</b>.  Changes to the composition of the development
     team or acquisition of new project sponsors can be communicated as
     announcements which can be implemented as technotes.







No project is required to use technotes.  But technotes can help many projects
stay better organized and provide a better historical record of the
development progress.

<h2>Viewing Technotes</h2>








>
>
>
>
>
>







41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
     domain name of the canonical website for a project changes, or new
     server hardware is obtained.  Such happenings are appropriate for
     reporting as news.

  *  <b>Announcements</b>.  Changes to the composition of the development
     team or acquisition of new project sponsors can be communicated as
     announcements which can be implemented as technotes.

  *  <b>Signed Checksums</b>.  Technotes containing cryptographically signed
     checksums can be linked to repository artifacts, thereby creating a
     traceable, auditable chain so that users can readily verify the integrity
     and authenticity of project deliverables. And the command line interface
     to technotes enables embedding such processes in scripts.

No project is required to use technotes.  But technotes can help many projects
stay better organized and provide a better historical record of the
development progress.

<h2>Viewing Technotes</h2>

80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97















98
99
100
101
102
103
104
105
the contents of file <b>technote.md</b> and comment "TestTechnote". Specifying a different time using
<b>-t DATETIME</b> will insert the technote at the specified timestamp location in the timeline.
Different technotes can have the same timestamp.

The first argument to create, <b>TECHNOTE-COMMENT</b>, is the title text for the technote
that appears in the timeline. 

To view technotes, use the <b>wiki ls</b> command:

<blockquote>
<b>
fossil wiki ls --technote --show-technote-ids<br>
<tt>z739263a134bf0da1d28e939f4c4367f51ef4c51 2020-12-19 13:20:19</tt><br>
<tt>e15a918a8bed71c2ac091d74dc397b8d3340d5e1 2018-09-22 17:40:10</tt><br>
</b>
</blockquote>

A technote ID is the UUID of the technote.
















Users must have check-in privileges (permission "i") in order to
create or edit technotes.  In addition, users must have create-wiki
privilege (permission "f") to create new technotes and edit-wiki
privilege (permission "k") in order to edit existing technotes.

Technote content may be formatted as [/wiki_rules | Fossil wiki],
[/md_rules | Markdown], or a plain text.







|










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








86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
the contents of file <b>technote.md</b> and comment "TestTechnote". Specifying a different time using
<b>-t DATETIME</b> will insert the technote at the specified timestamp location in the timeline.
Different technotes can have the same timestamp.

The first argument to create, <b>TECHNOTE-COMMENT</b>, is the title text for the technote
that appears in the timeline. 

To view all technotes, use the <b>wiki ls</b> command:

<blockquote>
<b>
fossil wiki ls --technote --show-technote-ids<br>
<tt>z739263a134bf0da1d28e939f4c4367f51ef4c51 2020-12-19 13:20:19</tt><br>
<tt>e15a918a8bed71c2ac091d74dc397b8d3340d5e1 2018-09-22 17:40:10</tt><br>
</b>
</blockquote>

A technote ID is the UUID of the technote.

To view an individual technote, use the <b>wiki export</b> command:

<blockquote>
<b>
fossil wiki export --technote version-2.16<br>
Release Notes 2021-07-02

This note describes changes in the Fossil snapshot for ...
</b>
</blockquote>

The <b>-t|--technote</b> option to the <b>export</b> subcommand takes one of
three identifiers: <b>DATETIME</b>; <b>TECHNOTE-ID</b>; and <b>TAG</b>.
See the [/help?cmd=wiki | wiki help] for specifics.

Users must have check-in privileges (permission "i") in order to
create or edit technotes.  In addition, users must have create-wiki
privilege (permission "f") to create new technotes and edit-wiki
privilege (permission "k") in order to edit existing technotes.

Technote content may be formatted as [/wiki_rules | Fossil wiki],
[/md_rules | Markdown], or a plain text.
Changes to www/faq.tcl.
165
166
167
168
169
170
171
172
173
174
175
176
177
178
for {set i 1} {$i<$cnt} {incr i} {
  puts "<li><a href=\"#q$i\">[lindex $faq($i) 0]</a></li>"
}
puts {</ol>}
puts {<hr>}

for {set i 1} {$i<$cnt} {incr i} {
  puts "<a name=\"q$i\"></a>"
  puts "<p><b>($i) [lindex $faq($i) 0]</b></p>\n"
  set body [lindex $faq($i) 1]
  regsub -all "\n *" [string trim $body] "\n" body
  puts "<blockquote>$body</blockquote></li>\n"
}
puts {</ol>}







<
|





165
166
167
168
169
170
171

172
173
174
175
176
177
for {set i 1} {$i<$cnt} {incr i} {
  puts "<li><a href=\"#q$i\">[lindex $faq($i) 0]</a></li>"
}
puts {</ol>}
puts {<hr>}

for {set i 1} {$i<$cnt} {incr i} {

  puts "<p id=\"q$i\"><b>($i) [lindex $faq($i) 0]</b></p>\n"
  set body [lindex $faq($i) 1]
  regsub -all "\n *" [string trim $body] "\n" body
  puts "<blockquote>$body</blockquote></li>\n"
}
puts {</ol>}
Changes to www/faq.wiki.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<title>Fossil FAQ</title>
<h1 align="center">Frequently Asked Questions</h1>

<p>Note:
This page is old and has not been kept up-to-date.  See the
[/finfo?name=www/faq.wiki|change history of this page].</p>

<ol>
<li><a href="#q1">What GUIs are available for fossil?</a></li>
<li><a href="#q2">What is the difference between a "branch" and a "fork"?</a></li>
<li><a href="#q3">How do I create a new branch?</a></li>
<li><a href="#q4">How do I tag a check-in?</a></li>
<li><a href="#q5">How do I create a private branch that won't get pushed back to the
  main repository.</a></li>
<li><a href="#q6">How can I delete inappropriate content from my fossil repository?</a></li>
<li><a href="#q7">How do I make a clone of the fossil self-hosting repository?</a></li>
<li><a href="#q8">How do I import or export content from and to other version control systems?</a></li>
</ol>
<hr>
<a name="q1"></a>
<p><b>(1) What GUIs are available for fossil?</b></p>

<blockquote>The fossil executable comes with a [./webui.wiki | web-based GUI] built in.
Just run:

<blockquote>
<b>fossil [/help/ui|ui]</b> <i>REPOSITORY-FILENAME</i>
</blockquote>

And your default web browser should pop up and automatically point to
the fossil interface.  (Hint:  You can omit the <i>REPOSITORY-FILENAME</i>
if you are within an open check-out.)

See also: [http://fuelscm.org/]
</blockquote></li>

<a name="q2"></a>
<p><b>(2) What is the difference between a "branch" and a "fork"?</b></p>

<blockquote>This is a big question - too big to answer in a FAQ.  Please
read the <a href="branching.wiki">Branching, Forking, Merging,
and Tagging</a> document.</blockquote></li>

<a name="q3"></a>
<p><b>(3) How do I create a new branch?</b></p>

<blockquote>There are lots of ways:

When you are checking in a new change using the <b>[/help/commit|commit]</b>
command, you can add the option  "--branch <i>BRANCH-NAME</i>" to
make the new check-in be the first check-in for a new branch.




|
<
<













<
|










|

<
<
<
<
|





<
|







1
2
3
4


5
6
7
8
9
10
11
12
13
14
15
16
17

18
19
20
21
22
23
24
25
26
27
28
29
30




31
32
33
34
35
36

37
38
39
40
41
42
43
44
<title>Fossil FAQ</title>
<h1 align="center">Frequently Asked Questions</h1>

<p>Note: See also <a href="qandc.wiki">Questions and Criticisms</a>.



<ol>
<li><a href="#q1">What GUIs are available for fossil?</a></li>
<li><a href="#q2">What is the difference between a "branch" and a "fork"?</a></li>
<li><a href="#q3">How do I create a new branch?</a></li>
<li><a href="#q4">How do I tag a check-in?</a></li>
<li><a href="#q5">How do I create a private branch that won't get pushed back to the
  main repository.</a></li>
<li><a href="#q6">How can I delete inappropriate content from my fossil repository?</a></li>
<li><a href="#q7">How do I make a clone of the fossil self-hosting repository?</a></li>
<li><a href="#q8">How do I import or export content from and to other version control systems?</a></li>
</ol>
<hr>

<p id="q1"><b>(1) What GUIs are available for fossil?</b></p>

<blockquote>The fossil executable comes with a [./webui.wiki | web-based GUI] built in.
Just run:

<blockquote>
<b>fossil [/help/ui|ui]</b> <i>REPOSITORY-FILENAME</i>
</blockquote>

And your default web browser should pop up and automatically point to
the fossil interface.  (Hint:  You can omit the <i>REPOSITORY-FILENAME</i>
if you are within an open check-out.)</blockquote></li>





<p id="q2"><b>(2) What is the difference between a "branch" and a "fork"?</b></p>

<blockquote>This is a big question - too big to answer in a FAQ.  Please
read the <a href="branching.wiki">Branching, Forking, Merging,
and Tagging</a> document.</blockquote></li>


<p id="q3"><b>(3) How do I create a new branch?</b></p>

<blockquote>There are lots of ways:

When you are checking in a new change using the <b>[/help/commit|commit]</b>
command, you can add the option  "--branch <i>BRANCH-NAME</i>" to
make the new check-in be the first check-in for a new branch.

67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
the initial check-in of your branch on the timeline and click on its
link so that you are on the <b>ci</b> page.  Then find the "<b>edit</b>"
link (near the "Commands:" label) and click on that.  On the
"Edit Check-in" page, check the box beside "Branching:" and fill in
the name of your new branch to the right and press the "Apply Changes"
button.</blockquote></li>

<a name="q4"></a>
<p><b>(4) How do I tag a check-in?</b></p>

<blockquote>There are several ways:

When you are checking in a new change using the <b>[/help/commit|commit]</b>
command, you can add a tag to that check-in using the
"--tag <i>TAGNAME</i>" command-line option.  You can repeat the --tag
option to give a check-in multiple tags.  Tags need not be unique.  So,







<
|







59
60
61
62
63
64
65

66
67
68
69
70
71
72
73
the initial check-in of your branch on the timeline and click on its
link so that you are on the <b>ci</b> page.  Then find the "<b>edit</b>"
link (near the "Commands:" label) and click on that.  On the
"Edit Check-in" page, check the box beside "Branching:" and fill in
the name of your new branch to the right and press the "Apply Changes"
button.</blockquote></li>


<p id="q4"><b>(4) How do I tag a check-in?</b></p>

<blockquote>There are several ways:

When you are checking in a new change using the <b>[/help/commit|commit]</b>
command, you can add a tag to that check-in using the
"--tag <i>TAGNAME</i>" command-line option.  You can repeat the --tag
option to give a check-in multiple tags.  Tags need not be unique.  So,
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
[./webui.wiki | web interface].  First locate the check-in that you
what to tag on the timeline, then click on the link to go the detailed
information page for that check-in.  Then find the "<b>edit</b>"
link (near the "Commands:" label) and click on that.  There are
controls on the edit page that allow new tags to be added and existing
tags to be removed.</blockquote></li>

<a name="q5"></a>
<p><b>(5) How do I create a private branch that won't get pushed back to the
  main repository.</b></p>

<blockquote>Use the <b>--private</b> command-line option on the
<b>commit</b> command.  The result will be a check-in which exists on
your local repository only and is never pushed to other repositories.
All descendants of a private check-in are also private.








<
|







87
88
89
90
91
92
93

94
95
96
97
98
99
100
101
[./webui.wiki | web interface].  First locate the check-in that you
what to tag on the timeline, then click on the link to go the detailed
information page for that check-in.  Then find the "<b>edit</b>"
link (near the "Commands:" label) and click on that.  There are
controls on the edit page that allow new tags to be added and existing
tags to be removed.</blockquote></li>


<p id="q5"><b>(5) How do I create a private branch that won't get pushed back to the
  main repository.</b></p>

<blockquote>Use the <b>--private</b> command-line option on the
<b>commit</b> command.  The result will be a check-in which exists on
your local repository only and is never pushed to other repositories.
All descendants of a private check-in are also private.

121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
as if all the changes that occurred on your private branch occurred in
a single check-in.
Of course, you can also keep your branch private forever simply
by not merging the changes in the private branch back into the trunk.

[./private.wiki | Additional information]</blockquote></li>

<a name="q6"></a>
<p><b>(6) How can I delete inappropriate content from my fossil repository?</b></p>

<blockquote>See the article on [./shunning.wiki | "shunning"] for details.</blockquote></li>

<a name="q7"></a>
<p><b>(7) How do I make a clone of the fossil self-hosting repository?</b></p>

<blockquote>Any of the following commands should work:
<blockquote><pre>
fossil [/help/clone|clone]  http://fossil-scm.org/  fossil.fossil
fossil [/help/clone|clone]  http://www2.fossil-scm.org/  fossil.fossil
fossil [/help/clone|clone]  http://www3.fossil-scm.org/site.cgi  fossil.fossil
</pre></blockquote>
Once you have the repository cloned, you can open a local check-out
as follows:
<blockquote><pre>
mkdir src; cd src; fossil [/help/open|open] ../fossil.fossil
</pre></blockquote>
Thereafter you should be able to keep your local check-out up to date
with the latest code in the public repository by typing:
<blockquote><pre>
fossil [/help/update|update]
</pre></blockquote></blockquote></li>

<a name="q8"></a>
<p><b>(8) How do I import or export content from and to other version control systems?</b></p>

<blockquote>Please see [./inout.wiki | Import And Export]</blockquote></li>

</ol>







<
|



<
|


















<
|




111
112
113
114
115
116
117

118
119
120
121

122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140

141
142
143
144
145
as if all the changes that occurred on your private branch occurred in
a single check-in.
Of course, you can also keep your branch private forever simply
by not merging the changes in the private branch back into the trunk.

[./private.wiki | Additional information]</blockquote></li>


<p id="q6"><b>(6) How can I delete inappropriate content from my fossil repository?</b></p>

<blockquote>See the article on [./shunning.wiki | "shunning"] for details.</blockquote></li>


<p id="q7"><b>(7) How do I make a clone of the fossil self-hosting repository?</b></p>

<blockquote>Any of the following commands should work:
<blockquote><pre>
fossil [/help/clone|clone]  http://fossil-scm.org/  fossil.fossil
fossil [/help/clone|clone]  http://www2.fossil-scm.org/  fossil.fossil
fossil [/help/clone|clone]  http://www3.fossil-scm.org/site.cgi  fossil.fossil
</pre></blockquote>
Once you have the repository cloned, you can open a local check-out
as follows:
<blockquote><pre>
mkdir src; cd src; fossil [/help/open|open] ../fossil.fossil
</pre></blockquote>
Thereafter you should be able to keep your local check-out up to date
with the latest code in the public repository by typing:
<blockquote><pre>
fossil [/help/update|update]
</pre></blockquote></blockquote></li>


<p id="q8"><b>(8) How do I import or export content from and to other version control systems?</b></p>

<blockquote>Please see [./inout.wiki | Import And Export]</blockquote></li>

</ol>
Changes to www/fileformat.wiki.
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
different in separate repositories.
The local state is not versioned and is not synchronized
with the global state.
The local state is not composed of artifacts and is not intended to be enduring.
This document is concerned with global state only.  Local state is only
mentioned here in order to distinguish it from global state.

<a id="names"></a>
<h2>1.0 Artifact Names</h2>

Each artifact in the repository is named by a hash of its content.
No prefixes, suffixes, or other information is added to an artifact before
the hash is computed.  The artifact name is just the (lower-case
hexadecimal) hash of the raw artifact.

Fossil currently computes artifact names using either SHA1 or SHA3-256.  It
is relatively easy to add new algorithms in the future, but there are no
plans to do so at this time.

When referring to artifacts in using tty commands or webpage URLs, it is
sufficient to specify a unique prefix for the artifact name.  If the input
prefix is not unique, Fossil will show an error.  Within a structural
artifact, however, all references to other artifacts must be the complete
hash.

Prior to Fossil version 2.0, all names were formed from the SHA1 hash of
the artifact.  The key innovation in Fossil 2.0 was adding support for
alternative hash algorithms.

<a id="structural"></a>
<h2>2.0 Structural Artifacts</h2>

A structural artifact is an artifact with a particular format
that is used to define the relationships between other artifacts in the
repository.
Fossil recognizes the following kinds of structural
artifacts:








<
|




















<
|







30
31
32
33
34
35
36

37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57

58
59
60
61
62
63
64
65
different in separate repositories.
The local state is not versioned and is not synchronized
with the global state.
The local state is not composed of artifacts and is not intended to be enduring.
This document is concerned with global state only.  Local state is only
mentioned here in order to distinguish it from global state.


<h2 id="names">1.0 Artifact Names</h2>

Each artifact in the repository is named by a hash of its content.
No prefixes, suffixes, or other information is added to an artifact before
the hash is computed.  The artifact name is just the (lower-case
hexadecimal) hash of the raw artifact.

Fossil currently computes artifact names using either SHA1 or SHA3-256.  It
is relatively easy to add new algorithms in the future, but there are no
plans to do so at this time.

When referring to artifacts in using tty commands or webpage URLs, it is
sufficient to specify a unique prefix for the artifact name.  If the input
prefix is not unique, Fossil will show an error.  Within a structural
artifact, however, all references to other artifacts must be the complete
hash.

Prior to Fossil version 2.0, all names were formed from the SHA1 hash of
the artifact.  The key innovation in Fossil 2.0 was adding support for
alternative hash algorithms.


<h2 id="structural">2.0 Structural Artifacts</h2>

A structural artifact is an artifact with a particular format
that is used to define the relationships between other artifacts in the
repository.
Fossil recognizes the following kinds of structural
artifacts:

98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
is an implementation detail and might change in a future release.  For
the purpose of this article "file format" means the format of the artifacts,
not how the artifacts are stored on disk.  It is the artifact format that
is intended to be enduring.  The specifics of how artifacts are stored on
disk, though stable, is not intended to live as long as the
artifact format.

<a id="manifest"></a>
<h3>2.1 The Manifest</h3>

A manifest defines a check-in.
A manifest contains a list of artifacts for
each file in the project and the corresponding filenames, as
well as information such as parent check-ins, the username of the
programmer who created the check-in, the date and time when
the check-in was created, and any check-in comments associated







<
|







96
97
98
99
100
101
102

103
104
105
106
107
108
109
110
is an implementation detail and might change in a future release.  For
the purpose of this article "file format" means the format of the artifacts,
not how the artifacts are stored on disk.  It is the artifact format that
is intended to be enduring.  The specifics of how artifacts are stored on
disk, though stable, is not intended to live as long as the
artifact format.


<h3 id="manifest">2.1 The Manifest</h3>

A manifest defines a check-in.
A manifest contains a list of artifacts for
each file in the project and the corresponding filenames, as
well as information such as parent check-ins, the username of the
programmer who created the check-in, the date and time when
the check-in was created, and any check-in comments associated
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
clear-signing prefix.  The <b>Z</b> card is
a sanity check to prove that the manifest is well-formed and
consistent.

A sample manifest from Fossil itself can be seen
[/artifact/28987096ac | here].

<a id="cluster"></a>
<h3>2.2 Clusters</h3>

A cluster is an artifact that declares the existence of other artifacts.
Clusters are used during repository synchronization to help
reduce network traffic.  As such, clusters are an optimization and
may be removed from a repository without loss or damage to the
underlying project code.








<
|







251
252
253
254
255
256
257

258
259
260
261
262
263
264
265
clear-signing prefix.  The <b>Z</b> card is
a sanity check to prove that the manifest is well-formed and
consistent.

A sample manifest from Fossil itself can be seen
[/artifact/28987096ac | here].


<h3 id="cluster">2.2 Clusters</h3>

A cluster is an artifact that declares the existence of other artifacts.
Clusters are used during repository synchronization to help
reduce network traffic.  As such, clusters are an optimization and
may be removed from a repository without loss or damage to the
underlying project code.

280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
the <b>Z</b> card of a manifest.  The argument to the <b>Z</b> card is the
lower-case hexadecimal representation of the MD5 checksum of all
prior cards in the cluster.  The <b>Z</b> card is required.

An example cluster from Fossil can be seen
[/artifact/d03dbdd73a2a8 | here].

<a id="ctrl"></a>
<h3>2.3 Control Artifacts</h3>

Control artifacts are used to assign properties to other artifacts
within the repository.
Allowed cards in a control artifact are as follows:

<blockquote>
<b>D</b> <i>time-and-date-stamp</i><br />







<
|







276
277
278
279
280
281
282

283
284
285
286
287
288
289
290
the <b>Z</b> card of a manifest.  The argument to the <b>Z</b> card is the
lower-case hexadecimal representation of the MD5 checksum of all
prior cards in the cluster.  The <b>Z</b> card is required.

An example cluster from Fossil can be seen
[/artifact/d03dbdd73a2a8 | here].


<h3 id="ctrl">2.3 Control Artifacts</h3>

Control artifacts are used to assign properties to other artifacts
within the repository.
Allowed cards in a control artifact are as follows:

<blockquote>
<b>D</b> <i>time-and-date-stamp</i><br />
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349

The <b>U</b> card is the name of the user that created the control
artifact.  The <b>Z</b> card is the usual required artifact checksum.

An example control artifact can be seen [/info/9d302ccda8 | here].


<a id="wikichng"></a>
<h3>2.4 Wiki Pages</h3>

A wiki artifact defines a single version of a
single wiki page.
Wiki artifacts accept
the following card types:

<blockquote>







<
|







329
330
331
332
333
334
335

336
337
338
339
340
341
342
343

The <b>U</b> card is the name of the user that created the control
artifact.  The <b>Z</b> card is the usual required artifact checksum.

An example control artifact can be seen [/info/9d302ccda8 | here].



<h3 id="wikichng">2.4 Wiki Pages</h3>

A wiki artifact defines a single version of a
single wiki page.
Wiki artifacts accept
the following card types:

<blockquote>
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
of user George Krivov and is not currently used or generated by the 
implementation. Older versions of Fossil will reject a wiki-page
artifact that includes a <b>C</b> card.

An example wiki artifact can be seen
[/artifact?name=7b2f5fd0e0&txt=1 | here].

<a id="tktchng"></a>
<h3>2.5 Ticket Changes</h3>

A ticket-change artifact represents a change to a trouble ticket.
The following cards are allowed on a ticket change artifact:

<blockquote>
<b>D</b> <i>time-and-date-stamp</i><br />
<b>J</b> ?<b>+</b>?<i>name</i> ?<i>value</i>?<br />







<
|







372
373
374
375
376
377
378

379
380
381
382
383
384
385
386
of user George Krivov and is not currently used or generated by the 
implementation. Older versions of Fossil will reject a wiki-page
artifact that includes a <b>C</b> card.

An example wiki artifact can be seen
[/artifact?name=7b2f5fd0e0&txt=1 | here].


<h3 id="tktchng">2.5 Ticket Changes</h3>

A ticket-change artifact represents a change to a trouble ticket.
The following cards are allowed on a ticket change artifact:

<blockquote>
<b>D</b> <i>time-and-date-stamp</i><br />
<b>J</b> ?<b>+</b>?<i>name</i> ?<i>value</i>?<br />
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
on the <b>J</b> card replaces any previous value of the field.
The field name and value are both encoded using the character
escapes defined for the <b>C</b> card of a manifest.

An example ticket-change artifact can be seen
[/artifact/91f1ec6af053 | here].

<a id="attachment"></a>
<h3>2.6 Attachments</h3>

An attachment artifact associates some other artifact that is the
attachment (the source artifact) with a ticket or wiki page or
technical note to which
the attachment is connected (the target artifact).
The following cards are allowed on an attachment artifact:








<
|







417
418
419
420
421
422
423

424
425
426
427
428
429
430
431
on the <b>J</b> card replaces any previous value of the field.
The field name and value are both encoded using the character
escapes defined for the <b>C</b> card of a manifest.

An example ticket-change artifact can be seen
[/artifact/91f1ec6af053 | here].


<h3 id="attachment">2.6 Attachments</h3>

An attachment artifact associates some other artifact that is the
attachment (the source artifact) with a ticket or wiki page or
technical note to which
the attachment is connected (the target artifact).
The following cards are allowed on an attachment artifact:

466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
A single <b>U</b> card gives the name of the user who added the attachment.
If an attachment is added anonymously, then the <b>U</b> card may be omitted.

The <b>Z</b> card is the usual checksum over the rest of the attachment artifact.
The <b>Z</b> card is required.


<a id="event"></a>
<h3>2.7 Technical Notes</h3>

A technical note or "technote" artifact (formerly known as an "event" artifact)
associates a timeline comment and a page of text
(similar to a wiki page) with a point in time.  Technotes can be used
to record project milestones, release notes, blog entries, process
checkpoints, or news articles.
The following cards are allowed on an technote artifact:







<
|







458
459
460
461
462
463
464

465
466
467
468
469
470
471
472
A single <b>U</b> card gives the name of the user who added the attachment.
If an attachment is added anonymously, then the <b>U</b> card may be omitted.

The <b>Z</b> card is the usual checksum over the rest of the attachment artifact.
The <b>Z</b> card is required.



<h3 id="event">2.7 Technical Notes</h3>

A technical note or "technote" artifact (formerly known as an "event" artifact)
associates a timeline comment and a page of text
(similar to a wiki page) with a point in time.  Technotes can be used
to record project milestones, release notes, blog entries, process
checkpoints, or news articles.
The following cards are allowed on an technote artifact:
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549

A single <b>W</b> card provides wiki text for the document associated with the
technote.  The format of the <b>W</b> card is exactly the same as for a
[#wikichng | wiki artifact].

The <b>Z</b> card is the required checksum over the rest of the artifact.

<a id="forum"></a>
<h3>2.8 Forum Posts</h3>

Forum posts are intended as a mechanism for users and developers to
discuss a project.  Forum posts are like messages on a mailing list.

The following cards are allowed on an forum post artifact:

<blockquote>







<
|







525
526
527
528
529
530
531

532
533
534
535
536
537
538
539

A single <b>W</b> card provides wiki text for the document associated with the
technote.  The format of the <b>W</b> card is exactly the same as for a
[#wikichng | wiki artifact].

The <b>Z</b> card is the required checksum over the rest of the artifact.


<h3 id="forum">2.8 Forum Posts</h3>

Forum posts are intended as a mechanism for users and developers to
discuss a project.  Forum posts are like messages on a mailing list.

The following cards are allowed on an forum post artifact:

<blockquote>
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
A single <b>W</b> card provides wiki text for the forum post.
The format of the <b>W</b> card is exactly the same as for a
[#wikichng | wiki artifact].

The <b>Z</b> card is the required checksum over the rest of the artifact.


<a id="summary"></a>
<h2>3.0 Card Summary</h2>

The following table summarizes the various kinds of cards that appear
on Fossil artifacts. A blank entry means that combination of card and
artifact is not legal. A number or range of numbers indicates the number
of times a card may (or must) appear in the corresponding artifact type.
e.g. a value of 1 indicates a required unique card and 1+ indicates that one
or more such cards are required.







<
|







599
600
601
602
603
604
605

606
607
608
609
610
611
612
613
A single <b>W</b> card provides wiki text for the forum post.
The format of the <b>W</b> card is exactly the same as for a
[#wikichng | wiki artifact].

The <b>Z</b> card is the required checksum over the rest of the artifact.



<h2 id="summary">3.0 Card Summary</h2>

The following table summarizes the various kinds of cards that appear
on Fossil artifacts. A blank entry means that combination of card and
artifact is not legal. A number or range of numbers indicates the number
of times a card may (or must) appear in the corresponding artifact type.
e.g. a value of 1 indicates a required unique card and 1+ indicates that one
or more such cards are required.
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906

4) [#forum | Forum Posts] must have either one H-card or one
   I-card, not both.

5) [#forum | Forum Post] P-cards may have only a single parent
   hash. i.e. they may not have merge parents.

<a id="addenda"></a>
<h2>4.0 Addenda</h2>

This section contains additional information which may be useful when
implementing algorithms described above.

<a id="outofordercards"></a>
<h3>4.1 Relaxed Card Ordering Due To An Historical Bug</h3>

All cards of a structural artifact should be in lexicographical order.
The Fossil implementation verifies this and rejects any structural
artifact which has out-of-order cards.  Futhermore, when Fossil is
generating new structural artifacts, it runs the generated artifact
through the parser to confirm that all cards really are in the correct
order before committing the transaction.  In this way, Fossil prevents







<
|




<
|







874
875
876
877
878
879
880

881
882
883
884
885

886
887
888
889
890
891
892
893

4) [#forum | Forum Posts] must have either one H-card or one
   I-card, not both.

5) [#forum | Forum Post] P-cards may have only a single parent
   hash. i.e. they may not have merge parents.


<h2 id="addenda">4.0 Addenda</h2>

This section contains additional information which may be useful when
implementing algorithms described above.


<h3 id="outofordercards">4.1 Relaxed Card Ordering Due To An Historical Bug</h3>

All cards of a structural artifact should be in lexicographical order.
The Fossil implementation verifies this and rejects any structural
artifact which has out-of-order cards.  Futhermore, when Fossil is
generating new structural artifacts, it runs the generated artifact
through the parser to confirm that all cards really are in the correct
order before committing the transaction.  In this way, Fossil prevents
Changes to www/fossil-v-git.wiki.
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
[https://git-scm.com/book/en/v2/Git-Internals-Packfiles|pack-files],
whereas Fossil stores its objects in a [https://www.sqlite.org/|SQLite]
database file which provides ACID transactions and a high-level query
language.
This difference is more than an implementation detail. It has important
practical consequences.

One notable consequence is that it is difficult to find the descendents
of check-ins in Git.
One can easily locate the ancestors of a particular Git check-in
by following the pointers embedded in the check-in object, but it is
difficult to go the other direction and locate the descendants of a
check-in.  It is so difficult, in fact, that neither native Git nor
GitHub provide this capability short of crawling the
[https://www.git-scm.com/docs/git-log|commit log].  With Fossil,
on the other hand, finding descendents is a simple SQL query.
It is common in Fossil to ask to see
[/timeline?df=release&y=ci|all check-ins since the last release].
Git lets you see "what came before".  Fossil makes it just as
easy to also see "what came after".

Leaf check-ins in Git that lack a "ref" become "detached," making them
difficult to locate and subject to garbage collection. This







|







|







246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
[https://git-scm.com/book/en/v2/Git-Internals-Packfiles|pack-files],
whereas Fossil stores its objects in a [https://www.sqlite.org/|SQLite]
database file which provides ACID transactions and a high-level query
language.
This difference is more than an implementation detail. It has important
practical consequences.

One notable consequence is that it is difficult to find the descendants
of check-ins in Git.
One can easily locate the ancestors of a particular Git check-in
by following the pointers embedded in the check-in object, but it is
difficult to go the other direction and locate the descendants of a
check-in.  It is so difficult, in fact, that neither native Git nor
GitHub provide this capability short of crawling the
[https://www.git-scm.com/docs/git-log|commit log].  With Fossil,
on the other hand, finding descendants is a simple SQL query.
It is common in Fossil to ask to see
[/timeline?df=release&y=ci|all check-ins since the last release].
Git lets you see "what came before".  Fossil makes it just as
easy to also see "what came after".

Leaf check-ins in Git that lack a "ref" become "detached," making them
difficult to locate and subject to garbage collection. This
401
402
403
404
405
406
407
408
409
410
411
412
413



414
415
416
417
418
419
420
421
allows an anonymous developer to rebase and push specific locally-named
private branches, so that a Git repo clone often isn't really a clone at
all: it may have an arbitrary number of differences relative to the
repository it originally cloned from. Git encourages siloed development.
Select work in a developer's local repository may remain private
indefinitely.

The Git preference for siloed development has been strongly adopted by Github,
who say
"[https://guides.github.com/activities/forking|Forking is at the core of social coding at GitHub]".
As a result, as of January 2021,
[https://github.com/search?q=is:public|Github hosts 43 million distinct software projects],
most of them created as a results of Git/Github forking and very many



of them discontinued.

All of this is exactly what one wants when doing bazaar-style
development.

Fossil's normal mode of operation differs on every one of these points,
with the specific designed-in goal of promoting SQLite's cathedral
development model:







|


|
|
|
>
>
>
|







401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
allows an anonymous developer to rebase and push specific locally-named
private branches, so that a Git repo clone often isn't really a clone at
all: it may have an arbitrary number of differences relative to the
repository it originally cloned from. Git encourages siloed development.
Select work in a developer's local repository may remain private
indefinitely.

The Git preference for siloed development has been strongly adopted by GitHub,
who say
"[https://guides.github.com/activities/forking|Forking is at the core of social coding at GitHub]".
As of September 2021,
[https://github.com/search?q=is:public|Github hosts 46 million distinct software projects],
most of them created by forking a previously-existing project. Since
this is [https://evansdata.com/reports/viewRelease.php?reportID=9 |
roughly twice the number of developers in the world], it beggars belief
that most of these forks are still under active development. We expect
that the vast bulk of these are abandoned one-off efforts.

All of this is exactly what one wants when doing bazaar-style
development.

Fossil's normal mode of operation differs on every one of these points,
with the specific designed-in goal of promoting SQLite's cathedral
development model:
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
    [https://en.wikipedia.org/wiki/Flat_organization|flat
    organizations].</p></li>

    <li><p><b>No easy drive-by contributions:</b> Git
    [https://www.git-scm.com/docs/git-request-pull|pull requests] offer
    a low-friction path to accepting
    [https://www.jonobacon.com/2012/07/25/building-strong-community-structural-integrity/|drive-by
    contributions]. Fossil's closest equivalent is its unique
    [/help?cmd=bundle|bundle] feature, which requires higher engagement
    than firing off a PR.⁷ This difference comes directly from the
    initial designed purpose for each tool: the SQLite project doesn't
    accept outside contributions from previously-unknown developers, but
    the Linux kernel does.</p></li>

    <li><p><b>No rebasing:</b> When your local repo clone syncs changes
    up to its parent, those changes are sent exactly as they were







|
|







441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
    [https://en.wikipedia.org/wiki/Flat_organization|flat
    organizations].</p></li>

    <li><p><b>No easy drive-by contributions:</b> Git
    [https://www.git-scm.com/docs/git-request-pull|pull requests] offer
    a low-friction path to accepting
    [https://www.jonobacon.com/2012/07/25/building-strong-community-structural-integrity/|drive-by
    contributions]. Fossil's closest equivalents are its unique
    [/help?cmd=bundle|bundle] and [/help?cmd=patch|patch] features, which require higher engagement
    than firing off a PR.⁷ This difference comes directly from the
    initial designed purpose for each tool: the SQLite project doesn't
    accept outside contributions from previously-unknown developers, but
    the Linux kernel does.</p></li>

    <li><p><b>No rebasing:</b> When your local repo clone syncs changes
    up to its parent, those changes are sent exactly as they were
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490

    <li><p><b>Branch names sync:</b> Unlike in Git, branch names in
    Fossil are not purely local labels. They sync along with everything
    else, so everyone sees the same set of branch names. Fossil's design
    choice here is a direct reflection of the Linux vs. SQLite project
    outlook: SQLite's developers collaborate closely on a single
    coherent project, whereas Linux's developers go off on tangents and
    occasionally sync changes up with each other.</p></li>

    <li><p><b>Private branches are rare:</b>
    [/doc/trunk/www/private.wiki|Private branches exist in Fossil], but
    they're normally used to handle rare exception cases, whereas in
    many Git projects, they're part of the straight-line development
    process.</p></li>








|







479
480
481
482
483
484
485
486
487
488
489
490
491
492
493

    <li><p><b>Branch names sync:</b> Unlike in Git, branch names in
    Fossil are not purely local labels. They sync along with everything
    else, so everyone sees the same set of branch names. Fossil's design
    choice here is a direct reflection of the Linux vs. SQLite project
    outlook: SQLite's developers collaborate closely on a single
    coherent project, whereas Linux's developers go off on tangents and
    occasionally send selected change sets to each other.</p></li>

    <li><p><b>Private branches are rare:</b>
    [/doc/trunk/www/private.wiki|Private branches exist in Fossil], but
    they're normally used to handle rare exception cases, whereas in
    many Git projects, they're part of the straight-line development
    process.</p></li>

504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
[https://en.wikipedia.org/wiki/Feedback | feedback loop size], which we
know from the mathematics of
[https://en.wikipedia.org/wiki/Control_theory | control theory] to
directly affect the speed at which any system can safely make changes.
The larger the feedback loop, the slower the whole system must run in
order to avoid loss of control. The same concept shows up in other
contexts, such as in the [https://en.wikipedia.org/wiki/OODA_loop | OODA
loop] concept originally developed to explain the success of the US F-86
Sabre fighter aircraft over the on-paper superior MiG-15, then later
applied in other contexts, such as business process management.
Committing your changes to private branches in order to delay a public
push to the parent repo increases the size of your collaborators'
control loops, either causing them to slow their work in order to safely
react to your work, or to overcorrect in response to each change.

Each DVCS can be used in the opposite style, but doing so works against
their low-friction paths.







|
<
<







507
508
509
510
511
512
513
514


515
516
517
518
519
520
521
[https://en.wikipedia.org/wiki/Feedback | feedback loop size], which we
know from the mathematics of
[https://en.wikipedia.org/wiki/Control_theory | control theory] to
directly affect the speed at which any system can safely make changes.
The larger the feedback loop, the slower the whole system must run in
order to avoid loss of control. The same concept shows up in other
contexts, such as in the [https://en.wikipedia.org/wiki/OODA_loop | OODA
loop] concept.


Committing your changes to private branches in order to delay a public
push to the parent repo increases the size of your collaborators'
control loops, either causing them to slow their work in order to safely
react to your work, or to overcorrect in response to each change.

Each DVCS can be used in the opposite style, but doing so works against
their low-friction paths.
922
923
924
925
926
927
928
929
930
931
932
933
934





935
    distribution is 44.7&nbsp;MiB but the current <tt>fossil.exe</tt>
    zip file for Windows is 2.24&nbsp;MiB. Fossil is much smaller
    despite using a roughly similar amount of high-level scripting code
    because its interpreters are compact and built into Fossil itself.

    <li><p>Both Fossil and Git support
    [https://en.wikipedia.org/wiki/Patch_(Unix)|<tt>patch(1)</tt>
    files], a common way to allow drive-by contributions, but it's a
    lossy contribution path for both systems. Unlike Git PRs and Fossil
    bundles, patch files collapse multiple checkins together, they don't
    include check-in comments, and they cannot encode changes made above
    the individual file content layer: you lose branching decisions,
    tag changes, file renames, and more when using patch files.</p></li>





</ol></i></small>







|




|
>
>
>
>
>

923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
    distribution is 44.7&nbsp;MiB but the current <tt>fossil.exe</tt>
    zip file for Windows is 2.24&nbsp;MiB. Fossil is much smaller
    despite using a roughly similar amount of high-level scripting code
    because its interpreters are compact and built into Fossil itself.

    <li><p>Both Fossil and Git support
    [https://en.wikipedia.org/wiki/Patch_(Unix)|<tt>patch(1)</tt>
    files] — unified diff formatted output — for accepting drive-by contributions, but it's a
    lossy contribution path for both systems. Unlike Git PRs and Fossil
    bundles, patch files collapse multiple checkins together, they don't
    include check-in comments, and they cannot encode changes made above
    the individual file content layer: you lose branching decisions,
    tag changes, file renames, and more when using patch files. Fossil
    2.16 adds [./patchcmd.md | a <tt>fossil patch</tt> command] that
    also solves these problems, but it is because it works like a Fossil
    bundle, only for uncommitted changes; it doesn't use Larry Wall's
    <tt>patch</tt> tool to apply unified diff output to the receiving
    Fossil checkout.</p></li>
</ol></i></small>
Changes to www/gitusers.md.
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
There is no implicit “and update the local working directory” step in Fossil’s
push, pull, or sync commands, as there is with `git pull`.

Someone coming from the Git perspective may perceive that `fossil up`
has two purposes:

*   Without the optional `VERSION` argument, it updates the working
    checkout to the tip of the current branch, like `git pull`.

*   Given a `VERSION` argument, it updates to the named version. If that’s the
    name of a branch, it updates to the tip of that branch rather than
    the current one, like `git checkout BRANCH`.

In fact, these are the same operation, so they’re the same command in
Fossil. The first form simply allows the `VERSION` to be implicit: the
current branch.

We think this is a more sensible command design than `git pull` vs
`git checkout`. ([…vs `git checkout` vs `git checkout`!][gcokoan])

[fpull]:   /help?cmd=pull
[gpull]:   https://git-scm.com/docs/git-pull
[gcokoan]: https://stevelosh.com/blog/2013/04/git-koans/#s2-one-thing-well







|


|
|



|







111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
There is no implicit “and update the local working directory” step in Fossil’s
push, pull, or sync commands, as there is with `git pull`.

Someone coming from the Git perspective may perceive that `fossil up`
has two purposes:

*   Without the optional `VERSION` argument, it updates the working
    checkout to the tip of the current branch, as `git pull` does.

*   Given a `VERSION` argument, it updates to the named version. If that’s the
    name of a branch, it updates to the *tip* of that branch, as
    `git checkout BRANCH` does.

In fact, these are the same operation, so they’re the same command in
Fossil. The first form simply allows the `VERSION` to be implicit: the
tip of the current branch.

We think this is a more sensible command design than `git pull` vs
`git checkout`. ([…vs `git checkout` vs `git checkout`!][gcokoan])

[fpull]:   /help?cmd=pull
[gpull]:   https://git-scm.com/docs/git-pull
[gcokoan]: https://stevelosh.com/blog/2013/04/git-koans/#s2-one-thing-well
142
143
144
145
146
147
148

149
150
151
152
153
154
155
"`.fossil`" suffixes. That aside, you can follow any other convention that
makes sense to you.

This author uses a scheme like the following on mobile machines that
shuttle between home and the office:

``` pikchr toggle indent

box "~/museum/" fit
move right 0.1
line right dotted
move right 0.05
box invis "where one stores valuable fossils" ljust

arrow down 50% from first box.s then right 50%







>







142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
"`.fossil`" suffixes. That aside, you can follow any other convention that
makes sense to you.

This author uses a scheme like the following on mobile machines that
shuttle between home and the office:

``` pikchr toggle indent
scale=0.8
box "~/museum/" fit
move right 0.1
line right dotted
move right 0.05
box invis "where one stores valuable fossils" ljust

arrow down 50% from first box.s then right 50%
174
175
176
177
178
179
180
181
182
183
184


185
186
187
188
189
190
191
192
193
194
195
196
197
box invis "clones of Fossil itself, SQLite, etc." ljust
```

On a Windows box, you might instead choose "`C:\Fossils`"
and do without the subdirectory scheme, for example.


#### <a id="close" name="dotfile"></a> Closing A Check-Out

The [`fossil close`][close] command dissociates a check-out directory from the
Fossil repository database, nondestructively inverting [`fossil open`][open]. It


won’t remove the managed files, and unless you give the `--force`
option, it won’t let you close the check-out with uncommitted changes to
those managed files.

The `close` command refuses to run without `--force` when you have
certain precious per-checkout data, which Fossil stores in the
`.fslckout` file at the root of a check-out directory. This is a SQLite
database that keeps track of local state such as what version you have
checked out, the contents of the [stash] for that working directory, the
[undo] buffers, per-checkout [settings][set], and so forth. The stash
and undo buffers are considered precious uncommitted changes,
so you have to force Fossil to discard these as part of closing the
check-out.







|


|
>
>
|



|
|







175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
box invis "clones of Fossil itself, SQLite, etc." ljust
```

On a Windows box, you might instead choose "`C:\Fossils`"
and do without the subdirectory scheme, for example.


#### <a id="close" name="dotfile"></a> Closing a Check-Out

The [`fossil close`][close] command dissociates a check-out directory from the
Fossil repository database, nondestructively inverting [`fossil open`][open].
(Contrast [its closest inverse](#worktree), `git worktree remove`, which *is*
destructive in Git!) This Fossil command does not
remove the managed files, and unless you give the `--force`
option, it won’t let you close the check-out with uncommitted changes to
those managed files.

The `close` command also refuses to run without `--force` when you have
certain other precious per-checkout data that Fossil stores in the
`.fslckout` file at the root of a check-out directory. This is a SQLite
database that keeps track of local state such as what version you have
checked out, the contents of the [stash] for that working directory, the
[undo] buffers, per-checkout [settings][set], and so forth. The stash
and undo buffers are considered precious uncommitted changes,
so you have to force Fossil to discard these as part of closing the
check-out.
224
225
226
227
228
229
230

231
232
233
234
235
236
237
238
239

240






241
242
243
244
245
246
247
        ln -s ../actual-clone-dir/.git .
        git checkout foo-branch

The symlink trick has a number of problems, the largest being that
symlinks weren’t available on Windows until Vista, and until the Windows
10 Creators Update was released in spring of 2017, you had to be an
Administrator to use the feature besides. ([Source][wsyml]) Git solved

this problem two years earlier with the `git-worktree` command in Git
2.5:

        git worktree add ../foo-branch foo-branch
        cd ../foo-branch

That is approximately equivalent to this in Fossil:

        mkdir ../foo-branch

        fossil open /path/to/repo.fossil foo-branch







That then leads us to the closest equivalent in Git to [closing a Fossil
check-out](#close):

        git worktree remove .

Note, however, that unlike `fossil close`, once the Git command







>
|
<







>

>
>
>
>
>
>







227
228
229
230
231
232
233
234
235

236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
        ln -s ../actual-clone-dir/.git .
        git checkout foo-branch

The symlink trick has a number of problems, the largest being that
symlinks weren’t available on Windows until Vista, and until the Windows
10 Creators Update was released in spring of 2017, you had to be an
Administrator to use the feature besides. ([Source][wsyml]) Git solved
this problem back when Windows XP was Microsoft’s current offering
with the `git-worktree` command, added in Git 2.5:


        git worktree add ../foo-branch foo-branch
        cd ../foo-branch

That is approximately equivalent to this in Fossil:

        mkdir ../foo-branch
        cd ../foo-branch
        fossil open /path/to/repo.fossil foo-branch

The Fossil alternative is wordier, but this tends to be one-time setup,
not something you do everyday. This author keeps a “scratch” checkout
for cases where is isn’t appropriate to reuse the “trunk” checkout. The
other peer checkouts therefore tend to track long-lived branches, so
they rarely change once a development machine is set up.

That then leads us to the closest equivalent in Git to [closing a Fossil
check-out](#close):

        git worktree remove .

Note, however, that unlike `fossil close`, once the Git command
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
generally run in O(log n) time, faster than O(n) for equal *n* when the
constants are equal. Yet the constants are *not* equal because Fossil
reads from a single disk file rather than visit potentially many
files in sequence as Git must, so the OS’s buffer cache can result in
[still better performance][35pct].

Unlike Git’s log, Fossil’s timeline shows info across branches by
default, a feature for maintaining better situational awareness. The
`fossil timeline` command has no way to show a single branch’s commits,
but you can restrict your view like this using the web UI equivalent by
clicking the name of a branch on the `/timeline` or `/brlist` page. (Or
manually, by adding the `r=` query parameter.) Note that even in this
case, the Fossil timeline still shows other branches where they interact
with the one you’ve referenced in this way; again, better situational
awareness.









|

|







348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
generally run in O(log n) time, faster than O(n) for equal *n* when the
constants are equal. Yet the constants are *not* equal because Fossil
reads from a single disk file rather than visit potentially many
files in sequence as Git must, so the OS’s buffer cache can result in
[still better performance][35pct].

Unlike Git’s log, Fossil’s timeline shows info across branches by
default, a feature for maintaining better situational awareness. Although the
`fossil timeline` command has no way to show a single branch’s commits,
you can restrict your view like this using the web UI equivalent by
clicking the name of a branch on the `/timeline` or `/brlist` page. (Or
manually, by adding the `r=` query parameter.) Note that even in this
case, the Fossil timeline still shows other branches where they interact
with the one you’ve referenced in this way; again, better situational
awareness.


505
506
507
508
509
510
511



512
513
514
515
516
517
518
automatically.  There is no need for the "-a" option as with Git.

If you only want to commit _some_ of the changes, list the names
of the files or directories you want to commit as arguments, like this:

        fossil commit src/feature.c doc/feature.md examples/feature




Although there are currently no
<a id="csplit"></a>[commit splitting][gcspl] features in Fossil like
`git add -p`, `git commit -p`, or `git rebase -i`, you can get the same
effect by converting an uncommitted change set to a patch and then
running it through [Patchouli].

Rather than use `fossil diff -i` to produce such a patch, a safer and







>
>
>







515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
automatically.  There is no need for the "-a" option as with Git.

If you only want to commit _some_ of the changes, list the names
of the files or directories you want to commit as arguments, like this:

        fossil commit src/feature.c doc/feature.md examples/feature

Note that the last element is a directory name, meaning “any changed
file under the `examples/feature` directory.”

Although there are currently no
<a id="csplit"></a>[commit splitting][gcspl] features in Fossil like
`git add -p`, `git commit -p`, or `git rebase -i`, you can get the same
effect by converting an uncommitted change set to a patch and then
running it through [Patchouli].

Rather than use `fossil diff -i` to produce such a patch, a safer and
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569


570
571
572
573
574
575
576
577
578
579

580
581


582
583
584
585
586
587








588
589
590
591
592
593
594

[ctrb]:      https://fossil-scm.org/fossil/doc/trunk/www/contribute.wiki
[gcspl]:     https://git-scm.com/docs/git-rebase#_splitting_commits
[Patchouli]: https://pypi.org/project/patchouli/


<a id="bneed"></a>
## Create Branches At Point Of Need, Rather Than Ahead of Need

Fossil prefers that you create new branches as part of the first commit
on that branch:

        fossil commit --branch my-new-branch

If that commit is successful, your local check-out directory is then
switched to the tip of that branch, so subsequent commits don’t need the
“`--branch`” option. You simply say `fossil commit` again to continue
adding commits to the tip of that branch.

To switch back to the parent branch, say something like:

        fossil update trunk       # ≅ git checkout master



Fossil does also support the Git style, creating the branch ahead of
need:

        fossil branch new my-new-branch
        fossil update my-new-branch
        ...work on first commit...
        fossil commit

This is more verbose, but it has the same effect: put the first commit

onto `my-new-branch` and switch the check-out directory to that branch so
subsequent commits are descendants of that initial branch commit.



Fossil also allows you to move a check-in to a different branch
*after* you commit it, using the "`fossil amend`" command.
For example:

        fossil amend current --branch my-new-branch









(The version string “current” is one of the [special check-in names][scin] in Fossil. See
that document for the many other names you can give to “`amend`”, or
indeed to any other Fossil command documented to accept a `VERSION` or
`NAME` string.)

[scin]: ./checkin_names.wiki







|




|








|
>
>




|
|



|
>
|
|
>
>





|
>
>
>
>
>
>
>
>







561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620

[ctrb]:      https://fossil-scm.org/fossil/doc/trunk/www/contribute.wiki
[gcspl]:     https://git-scm.com/docs/git-rebase#_splitting_commits
[Patchouli]: https://pypi.org/project/patchouli/


<a id="bneed"></a>
## Create Branches at Point of Need, Rather Than Ahead of Need

Fossil prefers that you create new branches as part of the first commit
on that branch:

        fossil commit --branch my-branch

If that commit is successful, your local check-out directory is then
switched to the tip of that branch, so subsequent commits don’t need the
“`--branch`” option. You simply say `fossil commit` again to continue
adding commits to the tip of that branch.

To switch back to the parent branch, say something like:

        fossil update trunk

(This is approximately equivalent to `git checkout master`.)

Fossil does also support the Git style, creating the branch ahead of
need:

        fossil branch new my-branch
        fossil up my-branch
        ...work on first commit...
        fossil commit

This is more verbose, giving the same overall effect though the initial
actions are inverted: create a new branch for the first commit, switch
the check-out directory to that branch, and make that first commit. As
above, subsequent commits are descendants of that initial branch commit.
We think you’ll agree that creating a branch as part of the initial
commit is simpler.

Fossil also allows you to move a check-in to a different branch
*after* you commit it, using the "`fossil amend`" command.
For example:

        fossil amend current --branch my-branch

This works by inserting a tag into the repository that causes the web UI
to relabel commits from that point forward with the new name. Like Git,
Fossil’s fundamental data structure is the interlinked DAG of commit
hashes; branch names are supplemental data for making it easier for the
humans to understand this DAG, so this command does not change the core
history of the project, only annotate it for better display to the
humans.

(The version string “current” is one of the [special check-in names][scin] in Fossil. See
that document for the many other names you can give to “`amend`”, or
indeed to any other Fossil command documented to accept a `VERSION` or
`NAME` string.)

[scin]: ./checkin_names.wiki
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
pulls all remote changes down to your local clone of the repository as
part of a "`fossil update`".
This provides most of the advantages of a centralized version control
system while retaining the advantages of distributed version control:

1.  Your work stays synced up with your coworkers’ efforts as long as your
    machine can connect to the remote repository. At need, you can go
    off-network and continue work atop the last version you syncd with
    the remote.

2.  It provides immediate off-machine backup of your commits. Unlike
    centralized version control, though, you can still work while
    disconnected; your changes will sync up with the remote once you get
    back online.








|







637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
pulls all remote changes down to your local clone of the repository as
part of a "`fossil update`".
This provides most of the advantages of a centralized version control
system while retaining the advantages of distributed version control:

1.  Your work stays synced up with your coworkers’ efforts as long as your
    machine can connect to the remote repository. At need, you can go
    off-network and continue work atop the last version you synced with
    the remote.

2.  It provides immediate off-machine backup of your commits. Unlike
    centralized version control, though, you can still work while
    disconnected; your changes will sync up with the remote once you get
    back online.

637
638
639
640
641
642
643
644
645
646
647
648
649
650
651

[bu]:    ./backup.md
[setup]: ./caps/admin-v-setup.md#apsu
[wflow]: ./concepts.wiki#workflow


<a id="syncall"></a>
## Sync Is All-Or-Nothing

Fossil does not support the concept of syncing, pushing, or pulling
individual branches.  When you sync/push/pull in Fossil, it
processes all artifacts in its hash tree:
branches, tags, wiki articles, tickets, forum posts, technotes…
This is [not quite “everything,” full stop][bu], but it’s close.








|







663
664
665
666
667
668
669
670
671
672
673
674
675
676
677

[bu]:    ./backup.md
[setup]: ./caps/admin-v-setup.md#apsu
[wflow]: ./concepts.wiki#workflow


<a id="syncall"></a>
## Sync Is All-or-Nothing

Fossil does not support the concept of syncing, pushing, or pulling
individual branches.  When you sync/push/pull in Fossil, it
processes all artifacts in its hash tree:
branches, tags, wiki articles, tickets, forum posts, technotes…
This is [not quite “everything,” full stop][bu], but it’s close.

709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738

739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777




778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
draft was written, it’s been revised multiple times to address less
common objections as well. Chances are not good that you are going to
come up with a new objection that we haven’t already considered and
addressed there.

There is only one sub-feature of `git rebase` that is philosophically
compatible with Fossil yet which currently has no functional equivalent.
We cover [this and the workaround for it](#csplit) above.

[3]: ./rebaseharm.md


## <a name="cdiff"></a> Colorized Diffs

The graphical diffs in the Fossil web UI and `fossil diff --tk` use
color to distinguish insertions, deletions, and replacements, but unlike
with `git diff` when the output is to an ANSI X3.64 capable terminal,
`fossil diff` does not.

There are a few easy ways to add this feature to Fossil, though.

One is to install
[`colordiff`][cdiff], which is included in [many package systems][cdpkg],
then say:

        fossil set --global diff-command 'colordiff -wu'

Because this is unconditional, unlike `git diff --color=auto`, you will
then have to remember to add the `-i` option to `fossil diff` commands
when you want color disabled, such as when piping diff output to another

command that doesn’t understand ANSI escape sequences. There’s an
example of this [below](#dstat).

Another way, which avoids this problem, is to say instead:

        fossil set --global diff-command 'git diff --no-index'

This delegates `fossil diff` to `git diff` by using the latter’s
ability to run on files not inside any repository.

[cdpkg]: https://repology.org/project/colordiff/versions


## <a id="show"></a> Showing Information About Commits

While there is no direct equivalent to Git’s “`show`” command, similar
functionality may be present in Fossil under other commands:


#### <a name="patch"></a> Show A Patch For A Commit

        git show -p COMMIT_ID

…gives much the same output as

        fossil diff --checkin COMMIT_ID

…only without the patch email header. Git comes out of the [LKML] world,
where emailing a patch is a normal thing to do. Fossil is [designed for
cohesive teams][devorg] where such drive-by patches are rarer.

You can use any of [Fossil’s special check-in names][scin] in place of
the `COMMIT_ID` in this and later examples. Fossil docs usually say
“`VERSION`” or “`NAME`” where this is allowed, since the version string
or name might not refer to a commit ID, but instead to a forum post, a
wiki document, etc. The following command answers the question “What did
I just commit?”

        fossil diff --checkin tip





[devorg]: ./fossil-v-git.wiki#devorg
[LKML]:   https://lkml.org/


#### <a name="cmsg"></a> Show A Specific Commit Message

        git show -s COMMIT_ID


…is

        fossil time -n 1 COMMIT_ID

…or with a shorter, more obvious command, though with more verbose output:

        fossil info COMMIT_ID

The `fossil info` command isn’t otherwise a good equivalent to
`git show`; it just overlaps its functionality in some areas. Much of
what’s missing is present in the corresponding [`/info` web
view][infow], though.


#### <a name="dstat"></a> Diff Statistics

Fossil’s closest internal equivalent to commands like
`git show --stat` is:

        fossil diff -i --from 2020-04-01 --numstat

The `--numstat` output is a bit cryptic, so we recommend delegating







|




|
















|
>
















|


|















|



>
>
>
>





|


















|







735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
draft was written, it’s been revised multiple times to address less
common objections as well. Chances are not good that you are going to
come up with a new objection that we haven’t already considered and
addressed there.

There is only one sub-feature of `git rebase` that is philosophically
compatible with Fossil yet which currently has no functional equivalent.
We [covered this and the workaround for its lack](#csplit) above.

[3]: ./rebaseharm.md


## <a id="cdiff"></a> Colorized Diffs

The graphical diffs in the Fossil web UI and `fossil diff --tk` use
color to distinguish insertions, deletions, and replacements, but unlike
with `git diff` when the output is to an ANSI X3.64 capable terminal,
`fossil diff` does not.

There are a few easy ways to add this feature to Fossil, though.

One is to install
[`colordiff`][cdiff], which is included in [many package systems][cdpkg],
then say:

        fossil set --global diff-command 'colordiff -wu'

Because this is unconditional, unlike `git diff --color=auto`, you will
then have to remember to add the `-i` option to `fossil diff` commands
when you want color disabled, such as when producing `patch(1)` files
or piping diff output to another
command that doesn’t understand ANSI escape sequences. There’s an
example of this [below](#dstat).

Another way, which avoids this problem, is to say instead:

        fossil set --global diff-command 'git diff --no-index'

This delegates `fossil diff` to `git diff` by using the latter’s
ability to run on files not inside any repository.

[cdpkg]: https://repology.org/project/colordiff/versions


## <a id="show"></a> Showing Information About Commits

While there is no direct equivalent to Git’s “`show`” command, similar
functionality is present in Fossil under other commands:


#### <a id="patch"></a> Show a Patch for a Commit

        git show -p COMMIT_ID

…gives much the same output as

        fossil diff --checkin COMMIT_ID

…only without the patch email header. Git comes out of the [LKML] world,
where emailing a patch is a normal thing to do. Fossil is [designed for
cohesive teams][devorg] where such drive-by patches are rarer.

You can use any of [Fossil’s special check-in names][scin] in place of
the `COMMIT_ID` in this and later examples. Fossil docs usually say
“`VERSION`” or “`NAME`” where this is allowed, since the version string
or name might not refer to a commit ID, but instead to a forum post, a
wiki document, etc. For instance, the following command answers the question “What did
I just commit?”

        fossil diff --checkin tip

…or equivalently using a different symbolic commit name:

        fossil diff --from prev

[devorg]: ./fossil-v-git.wiki#devorg
[LKML]:   https://lkml.org/


#### <a id="cmsg"></a> Show a Specific Commit Message

        git show -s COMMIT_ID


…is

        fossil time -n 1 COMMIT_ID

…or with a shorter, more obvious command, though with more verbose output:

        fossil info COMMIT_ID

The `fossil info` command isn’t otherwise a good equivalent to
`git show`; it just overlaps its functionality in some areas. Much of
what’s missing is present in the corresponding [`/info` web
view][infow], though.


#### <a id="dstat"></a> Diff Statistics

Fossil’s closest internal equivalent to commands like
`git show --stat` is:

        fossil diff -i --from 2020-04-01 --numstat

The `--numstat` output is a bit cryptic, so we recommend delegating
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
[mv]: /help?cmd=mv
[rm]: /help?cmd=rm


----


## <a id="cvdate" name="cs1"></a> Case Study 1: Checking Out A Version By Date

Let’s get into something a bit more complicated: a case study showing
how the concepts lined out above cause Fossil to materially differ in
day-to-day operation from Git.

Why would you want to check out a version of a project by date?  Perhaps
because your customer gave you a vague bug report referencing only a
date rather than a version. Or, you may be poking semi-randomly through
history to find a “good” version to anchor the start point of a
[`fossil bisect`][fbis] operation.

My search engine’s first result for “git checkout by date” is [this
highly-upvoted accepted Stack Overflow answer][gcod]. The first command
it gives is based on Git’s [`rev-parse` feature][grp]:

        git checkout master@{2020-03-17}

There are a number of weaknesses in this command. From least to most
critical:

1.  It’s a bit cryptic. Leave off the refname or punctuation, and it
    means something else. You cannot simplify the cryptic incantation in
    the typical use case.

2.  A date string in Git without a time will be interpreted as
    “[at the local wall clock time on the given date][gapxd],” so the
    command means something different from one second to the next. This
    can be a problem if there are multiple commits on that date, because
    the command will give different results depending on the time of
    day you run it.

3.  It gives misleading output if there is no close match for the date
    in the local [reflog]. It starts out empty after a fresh clone, and
    while it does build up as you use that clone, Git [automatically
    prunes][gle] the reflog to 90 days of history by default. This means







|






|



















|
|







919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
[mv]: /help?cmd=mv
[rm]: /help?cmd=rm


----


## <a id="cvdate" name="cs1"></a> Case Study 1: Checking Out a Version by Date

Let’s get into something a bit more complicated: a case study showing
how the concepts lined out above cause Fossil to materially differ in
day-to-day operation from Git.

Why would you want to check out a version of a project by date?  Perhaps
your customer gave you a vague bug report referencing only a
date rather than a version. Or, you may be poking semi-randomly through
history to find a “good” version to anchor the start point of a
[`fossil bisect`][fbis] operation.

My search engine’s first result for “git checkout by date” is [this
highly-upvoted accepted Stack Overflow answer][gcod]. The first command
it gives is based on Git’s [`rev-parse` feature][grp]:

        git checkout master@{2020-03-17}

There are a number of weaknesses in this command. From least to most
critical:

1.  It’s a bit cryptic. Leave off the refname or punctuation, and it
    means something else. You cannot simplify the cryptic incantation in
    the typical use case.

2.  A date string in Git without a time will be interpreted as
    “[at the local wall clock time on the given date][gapxd],” so the
    command means something different from one second to the next! This
    can be a serious problem if there are multiple commits on that date, because
    the command will give different results depending on the time of
    day you run it.

3.  It gives misleading output if there is no close match for the date
    in the local [reflog]. It starts out empty after a fresh clone, and
    while it does build up as you use that clone, Git [automatically
    prunes][gle] the reflog to 90 days of history by default. This means
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
    useful result, and sometimes it doesn’t. If you’re on a fresh clone,
    you are likely to get the “tip” commit’s revision ID no matter what
    date value you give.

    Git tries its best, but because it’s working from a purgeable and
    possibly-stale local cache, you cannot trust its results.

We cannot recommend this command at all. It’s unreliable even in the
best case.

That same Stack Overflow answer therefore goes on to recommend an
entirely different command:

        git checkout $(git rev-list -n 1 --first-parent --before="2020-03-17" master)








|







969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
    useful result, and sometimes it doesn’t. If you’re on a fresh clone,
    you are likely to get the “tip” commit’s revision ID no matter what
    date value you give.

    Git tries its best, but because it’s working from a purgeable and
    possibly-stale local cache, you cannot trust its results.

Consequently, we cannot recommend this command at all. It’s unreliable even in the
best case.

That same Stack Overflow answer therefore goes on to recommend an
entirely different command:

        git checkout $(git rev-list -n 1 --first-parent --before="2020-03-17" master)

1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032

*  Parse timestamps from all commits on clone into a local commit index,
   then maintain that index through subsequent commits and syncs.

*  Use an indexed SQL `ORDER BY` query to match timestamps to commit
   IDs for a fast and consistent result.

*  Round timestamp strings up using [rules][frud] consistent across
   computers and local time of day.

[frud]:   https://fossil-scm.org/home/file/src/name.c?ci=d2a59b03727bc3&ln=122-141
[gbash]:  https://appuals.com/what-is-git-bash/
[gapxd]:  https://github.com/git/git/blob/7f7ebe054a/date.c#L1298-L1300
[gcod]:   https://stackoverflow.com/a/6990682/142454
[gdh]:    https://www.git-tower.com/learn/git/faq/detached-head-when-checkout-commit/







|







1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063

*  Parse timestamps from all commits on clone into a local commit index,
   then maintain that index through subsequent commits and syncs.

*  Use an indexed SQL `ORDER BY` query to match timestamps to commit
   IDs for a fast and consistent result.

*  Round incomplete timestamp strings up using [rules][frud] consistent across
   computers and local time of day.

[frud]:   https://fossil-scm.org/home/file/src/name.c?ci=d2a59b03727bc3&ln=122-141
[gbash]:  https://appuals.com/what-is-git-bash/
[gapxd]:  https://github.com/git/git/blob/7f7ebe054a/date.c#L1298-L1300
[gcod]:   https://stackoverflow.com/a/6990682/142454
[gdh]:    https://www.git-tower.com/learn/git/faq/detached-head-when-checkout-commit/
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202






1203
1204
1205
1206
1207
[staging feature](#staging).

The “Friday afternoon sync-up” case is simpler, too:

        fossil remote work
        fossil sync

Back at home, it’s simpler still: we can do away with the second command,
saying just “`fossil remote home`” because the sync will happen as part
of the next commit, thanks once again to Fossil’s autosync feature.







[grsync]: https://stackoverflow.com/q/1398018/142454
[qs]:     ./quickstart.wiki
[shwmd]:  ./fossil-v-git.wiki#checkouts
[sn]:     https://en.wikipedia.org/wiki/Sneakernet







|

|
>
>
>
>
>
>





1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
[staging feature](#staging).

The “Friday afternoon sync-up” case is simpler, too:

        fossil remote work
        fossil sync

Back at home, it’s simpler still: we may be able to do away with the second command,
saying just “`fossil remote home`” because the sync will happen as part
of the next commit, thanks once again to Fossil’s autosync feature. If
the working branch now has commits from other developers after syncing
with the central repository, though, you’ll want to say “`fossil up`” to
avoid creating an inadvertent fork in the branch.

(Which is easy to fix if it occurs: `fossil merge` without arguments
means “merge open tips on the current branch.”)

[grsync]: https://stackoverflow.com/q/1398018/142454
[qs]:     ./quickstart.wiki
[shwmd]:  ./fossil-v-git.wiki#checkouts
[sn]:     https://en.wikipedia.org/wiki/Sneakernet
Changes to www/globs.md.
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
settings` commands.

That advice does not help you when you are giving one-off glob patterns
in `fossil` commands. The remainder of this section gives remedies and
workarounds for these problems.


### <a name="posix"></a>POSIX Systems

If you are using Fossil on a system with a POSIX-compatible shell
&mdash; Linux, macOS, the BSDs, Unix, Cygwin, WSL etc. &mdash; the shell
may expand the glob patterns before passing the result to the `fossil`
executable.

Sometimes this is exactly what you want.  Consider this command for







|







280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
settings` commands.

That advice does not help you when you are giving one-off glob patterns
in `fossil` commands. The remainder of this section gives remedies and
workarounds for these problems.


### <a id="posix"></a>POSIX Systems

If you are using Fossil on a system with a POSIX-compatible shell
&mdash; Linux, macOS, the BSDs, Unix, Cygwin, WSL etc. &mdash; the shell
may expand the glob patterns before passing the result to the `fossil`
executable.

Sometimes this is exactly what you want.  Consider this command for
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
above to make sure the right set of files were scheduled for insertion
into the repository before checking the changes in. You never want to
accidentally check something like a password, an API key, or the
private half of a public cryptographic key into Fossil repository that
can be read by people who should not have such secrets.


### <a name="windows"></a>Windows

Before we get into Windows-specific details here, beware that this
section does not apply to the several Microsoft Windows extensions that
provide POSIX semantics to Windows, for which you want to use the advice
in [the POSIX section above](#posix) instead:

  *  the ancient and rarely-used [Microsoft POSIX subsystem][mps];







|







367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
above to make sure the right set of files were scheduled for insertion
into the repository before checking the changes in. You never want to
accidentally check something like a password, an API key, or the
private half of a public cryptographic key into Fossil repository that
can be read by people who should not have such secrets.


### <a id="windows"></a>Windows

Before we get into Windows-specific details here, beware that this
section does not apply to the several Microsoft Windows extensions that
provide POSIX semantics to Windows, for which you want to use the advice
in [the POSIX section above](#posix) instead:

  *  the ancient and rarely-used [Microsoft POSIX subsystem][mps];
Changes to www/hashes.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Hashes: Fossil Artifact Identification

All artifacts in Fossil are identified by a unique hash, currently using
[the SHA3 algorithm by default][hpol], but historically using the SHA1
algorithm:

<table border="1" cellspacing="0" cellpadding="10">
<tr><th>Algorithm<</th><th>Raw Bits</th> <th>Hexadecimal digits</th></tr>
<tr><td>SHA3-256</td>  <td>256</td>      <td>64</td></tr>
<tr><td>SHA1</td>      <td>160</td>      <td>40</td></tr>
</table>

There are many types of artifacts in Fossil: commits (a.k.a. check-ins),
tickets, ticket comments, wiki articles, forum postings, file data
belonging to check-ins, etc. ([More info...](./concepts.wiki#artifacts)).







|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Hashes: Fossil Artifact Identification

All artifacts in Fossil are identified by a unique hash, currently using
[the SHA3 algorithm by default][hpol], but historically using the SHA1
algorithm:

<table border="1" cellspacing="0" cellpadding="10">
<tr><th>Algorithm</th><th>Raw Bits</th> <th>Hexadecimal digits</th></tr>
<tr><td>SHA3-256</td>  <td>256</td>      <td>64</td></tr>
<tr><td>SHA1</td>      <td>160</td>      <td>40</td></tr>
</table>

There are many types of artifacts in Fossil: commits (a.k.a. check-ins),
tickets, ticket comments, wiki articles, forum postings, file data
belonging to check-ins, etc. ([More info...](./concepts.wiki#artifacts)).
Changes to www/index.wiki.
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
      atomic even if interrupted by a power loss or system crash.
      Automatic [./selfcheck.wiki | self-checks] verify that all aspects of
      the repository are consistent prior to each commit.

  8.  <b>Free and Open-Source</b> - [../COPYRIGHT-BSD2.txt|2-clause BSD license].

<hr>
<h3>Latest Release: 2.16 ([/timeline?c=version-2.16|2021-07-02])</h3>

  *  [/uv/download.html|Download]
  *  [./changes.wiki#v2_16|Change Summary]
  *  [/timeline?p=version-2.16&bt=version-2.15&y=ci|Check-ins in version 2.16]
  *  [/timeline?df=version-2.16&y=ci|Check-ins derived from the 2.16 release]
  *  [/timeline?t=release|Timeline of all past releases]

<hr>
<h3>Quick Start</h3>

  1.  [/uv/download.html|Download] or install using a package manager or
      [./build.wiki|compile from sources].







|


|
|
|







81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
      atomic even if interrupted by a power loss or system crash.
      Automatic [./selfcheck.wiki | self-checks] verify that all aspects of
      the repository are consistent prior to each commit.

  8.  <b>Free and Open-Source</b> - [../COPYRIGHT-BSD2.txt|2-clause BSD license].

<hr>
<h3>Latest Release: 2.17 ([/timeline?c=version-2.17|2021-10-09])</h3>

  *  [/uv/download.html|Download]
  *  [./changes.wiki#v2_17|Change Summary]
  *  [/timeline?p=version-2.17&bt=version-2.16&y=ci|Check-ins in version 2.17]
  *  [/timeline?df=version-2.17&y=ci|Check-ins derived from the 2.17 release]
  *  [/timeline?t=release|Timeline of all past releases]

<hr>
<h3>Quick Start</h3>

  1.  [/uv/download.html|Download] or install using a package manager or
      [./build.wiki|compile from sources].
Changes to www/inout.wiki.
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

The --git option is not actually required.  The git-fast-export file format
is currently the only VCS interchange format that Fossil understands.  But
future versions of Fossil might be enhanced to understand other VCS
interchange formats, and so for compatibility, use of the
--git option is recommended.

<a name="fx_git"></a>
Note that in new imports, Fossil defaults to using the email component of the
Git <em>committer</em> (or <em>author</em> if <code>--use-author</code> is
passed) to attribute check-ins in the imported repository. Alternatively, the
[/help?cmd=import | <code>--attribute</code>] option can be passed to have all
commits by a given committer attributed to a desired username. This will create
and populate the new <code>fx_git</code> table in the repository database to
maintain a record of correspondent usernames and email addresses that can be







|







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

The --git option is not actually required.  The git-fast-export file format
is currently the only VCS interchange format that Fossil understands.  But
future versions of Fossil might be enhanced to understand other VCS
interchange formats, and so for compatibility, use of the
--git option is recommended.

<a id="fx_git"></a>
Note that in new imports, Fossil defaults to using the email component of the
Git <em>committer</em> (or <em>author</em> if <code>--use-author</code> is
passed) to attribute check-ins in the imported repository. Alternatively, the
[/help?cmd=import | <code>--attribute</code>] option can be passed to have all
commits by a given committer attributed to a desired username. This will create
and populate the new <code>fx_git</code> table in the repository database to
maintain a record of correspondent usernames and email addresses that can be
Changes to www/interwiki.md.
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
  3.  <b>Wiki Links</b> &rarr; An PageName that is not a Path or Hash.

The Intermap defines a base URL for each Tag.  Path links are appended
directly to the URL contained in the Intermap.  The Intermap can define
additional text to put in between the base URL and the PageName for
Hash and Wiki links, respectively.

<a name="intermap"></a>
## Intermap

The intermap defines a mapping from interwiki Tags to full URLs.  The
Intermap can be viewed and managed using the [fossil interwiki][iwiki]
command or the [/intermap][imap] webpages.  

[iwiki]: /help?cmd=interwiki







|







55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
  3.  <b>Wiki Links</b> &rarr; An PageName that is not a Path or Hash.

The Intermap defines a base URL for each Tag.  Path links are appended
directly to the URL contained in the Intermap.  The Intermap can define
additional text to put in between the base URL and the PageName for
Hash and Wiki links, respectively.

<a id="intermap"></a>
## Intermap

The intermap defines a mapping from interwiki Tags to full URLs.  The
Intermap can be viewed and managed using the [fossil interwiki][iwiki]
command or the [/intermap][imap] webpages.  

[iwiki]: /help?cmd=interwiki
Changes to www/javascript.md.
461
462
463
464
465
466
467












468
469
470
471
472
473
474
therefore scrolls both boxes when you drag the scroll bar on one because
if you want to examine part of a line scrolled out of the HTML element
in one box, you probably want to examine the same point on that line in
the other box.

_Graceful Fallback:_ Manually scroll both boxes to sync their views.














### <a id="sort"></a>Table Sorting

On pages showing a data table, the column headers may be clickable to do
a client-side sort of the data on that column.

_Potential Workaround:_ This feature could be enhanced to do the sort on







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







461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
therefore scrolls both boxes when you drag the scroll bar on one because
if you want to examine part of a line scrolled out of the HTML element
in one box, you probably want to examine the same point on that line in
the other box.

_Graceful Fallback:_ Manually scroll both boxes to sync their views.

### <a id="diffcontext"></a>Diff Context Loading

As of version 2.17, fossil adds the ability for the diff views to
dynamically load more lines of context around changed blocks. The UI
controls for this feature are injected using JavaScript when the page
initializes and make use of XHR requests to fetch data from the
fossil instance.

_Graceful Fallback:_ The UI controls for this feature do not appear
when JS is unavailable, leaving the user with the "legacy" static diff
view.


### <a id="sort"></a>Table Sorting

On pages showing a data table, the column headers may be clickable to do
a client-side sort of the data on that column.

_Potential Workaround:_ This feature could be enhanced to do the sort on
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528

[abd]:  ./antibot.wiki
[caps]: ./caps/


### <a id="hbm"></a>Hamburger Menu

The default skin includes a “hamburger menu” (&#9776;) which uses
JavaScript to show a simplified version of the Fossil UI site map using
an animated-in dropdown.

_Graceful Fallback:_ Clicking the hamburger menu button with JavaScript
disabled will take you to the `/sitemap` page instead of showing a
simplified version of that page’s content in a drop-down.








|







526
527
528
529
530
531
532
533
534
535
536
537
538
539
540

[abd]:  ./antibot.wiki
[caps]: ./caps/


### <a id="hbm"></a>Hamburger Menu

Several of the stock skins (including the default) include a “hamburger menu” (&#9776;) which uses
JavaScript to show a simplified version of the Fossil UI site map using
an animated-in dropdown.

_Graceful Fallback:_ Clicking the hamburger menu button with JavaScript
disabled will take you to the `/sitemap` page instead of showing a
simplified version of that page’s content in a drop-down.

583
584
585
586
587
588
589
590
591
592
593
594
595
596
597

_Potential Workaround:_ A user can manually construct an appropriate
regular expession and put it into the "Tag Filter" entry of the
`/timeline` page (in its advanced mode).

### <a id="wcontent"></a>Wiki content listing

[Since](/timeline?r=wcontent-subsets) version 2.16 it is possible to
add [configurable](/help?cmd=wiki-classes) checkbox controls to the
submenu of [available wiki pages](/wcontent) for the interactive
adjustment of a subset of wiki pages that are shown.
Client-side script is used to toggle visibility of the corresponding
rows according to the state of these checkboxes.

----







|







595
596
597
598
599
600
601
602
603
604
605
606
607
608
609

_Potential Workaround:_ A user can manually construct an appropriate
regular expession and put it into the "Tag Filter" entry of the
`/timeline` page (in its advanced mode).

### <a id="wcontent"></a>Wiki content listing

[Since](/timeline?r=wcontent-subsets) version 2.18 it is possible to
add [configurable](/help?cmd=wiki-classes) checkbox controls to the
submenu of [available wiki pages](/wcontent) for the interactive
adjustment of a subset of wiki pages that are shown.
Client-side script is used to toggle visibility of the corresponding
rows according to the state of these checkboxes.

----
Changes to www/makefile.wiki.
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
want to compile the code themselves can use one of the
[./build.wiki | existing makefiles].
So must people do not need to be concerned with the
build complexities of Fossil.  But hard-core developers who desire
a deep understanding of how Fossil is put together can benefit
from reviewing this article.

<a name="srctour"></a>
<h1>2.0 Source Code Tour</h1>

The source code for Fossil is found in the
[/dir?ci=trunk&name=src | src/] subdirectory of the
source tree.  The src/ subdirectory contains all code, including
the code for the separate preprocessor programs.

Each preprocessor program is a separate C program implemented in







<
|







10
11
12
13
14
15
16

17
18
19
20
21
22
23
24
want to compile the code themselves can use one of the
[./build.wiki | existing makefiles].
So must people do not need to be concerned with the
build complexities of Fossil.  But hard-core developers who desire
a deep understanding of how Fossil is put together can benefit
from reviewing this article.


<h1 id="srctour">2.0 Source Code Tour</h1>

The source code for Fossil is found in the
[/dir?ci=trunk&name=src | src/] subdirectory of the
source tree.  The src/ subdirectory contains all code, including
the code for the separate preprocessor programs.

Each preprocessor program is a separate C program implemented in
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
</pre></blockquote>

At the time of this writing, the "diff.tcl" script (a Tcl/Tk script used
to generate implement --tk option on the diff command) is the only resource
file processed using mkbuiltin.exe.  However, new resources will likely be
added using this facility in future versions of Fossil.

<a name="preprocessing"></a>
<h1>4.0 Preprocessing</h1>

There are three preprocessors for the Fossil sources.  The mkindex
and translate preprocessors can be run in any order.  The makeheaders
preprocessor must be run after translate.

<h2>4.1 The mkindex preprocessor</h2>








<
|







168
169
170
171
172
173
174

175
176
177
178
179
180
181
182
</pre></blockquote>

At the time of this writing, the "diff.tcl" script (a Tcl/Tk script used
to generate implement --tk option on the diff command) is the only resource
file processed using mkbuiltin.exe.  However, new resources will likely be
added using this facility in future versions of Fossil.


<h1 id="preprocessing">4.0 Preprocessing</h1>

There are three preprocessors for the Fossil sources.  The mkindex
and translate preprocessors can be run in any order.  The makeheaders
preprocessor must be run after translate.

<h2>4.1 The mkindex preprocessor</h2>

Changes to www/mirrortogithub.md.
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
     abovementioned generic address be used.

[attr]: /help?cmd=import
[fxgit]: ./inout.wiki#fx_git
[ui]: /help?cmd=ui
[usercmd]: /help?cmd=user

<a name='ex1'></a>
## Example GitHub Mirrors

As of this writing (2019-03-16) Fossil’s own repository is mirrored
on GitHub at:

>
<https://github.com/drhsqlite/fossil-mirror>








|
|







141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
     abovementioned generic address be used.

[attr]: /help?cmd=import
[fxgit]: ./inout.wiki#fx_git
[ui]: /help?cmd=ui
[usercmd]: /help?cmd=user


## <a id='ex1'></a>Example GitHub Mirrors

As of this writing (2019-03-16) Fossil’s own repository is mirrored
on GitHub at:

>
<https://github.com/drhsqlite/fossil-mirror>

Changes to www/mkindex.tcl.
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
<li> <a href='$ROOT/help'>Built-in help for commands and webpages</a>
<li> <a href='history.md'>Purpose and History of Fossil</a>
<li> <a href='build.wiki'>Compiling and installing Fossil</a>
<li> <a href='../COPYRIGHT-BSD2.txt'>License</a>
<li> <a href='userlinks.wiki'>Miscellaneous Docs for Fossil Users</a>
<li> <a href='hacker-howto.wiki'>Fossil Developer's Guide</a>
<li> <a href='$ROOT/wiki?name=To+Do+List'>To Do List (Wiki)</a>
<li> <a href='http://fossil-scm.org/schimpf-book/home'>Jim Schimpf's
book</a>
</ul>
<a name="pindex"></a>
<h2>Other Documents:</h2>
<ul>}
foreach entry $permindex {
  foreach {title file bold} $entry break
#  if {$bold} {set title <b>$title</b>}
  if {[string match /* $file]} {set file ../../..$file}
  puts $out "<li><a href=\"$file\">$title</a></li>"
}







|
<

<
|







163
164
165
166
167
168
169
170

171

172
173
174
175
176
177
178
179
<li> <a href='$ROOT/help'>Built-in help for commands and webpages</a>
<li> <a href='history.md'>Purpose and History of Fossil</a>
<li> <a href='build.wiki'>Compiling and installing Fossil</a>
<li> <a href='../COPYRIGHT-BSD2.txt'>License</a>
<li> <a href='userlinks.wiki'>Miscellaneous Docs for Fossil Users</a>
<li> <a href='hacker-howto.wiki'>Fossil Developer's Guide</a>
<li> <a href='$ROOT/wiki?name=To+Do+List'>To Do List (Wiki)</a>
<li> <a href='http://fossil-scm.org/fossil-book/home'>Fossil book</a>

</ul>

<h2 id="pindex">Other Documents:</h2>
<ul>}
foreach entry $permindex {
  foreach {title file bold} $entry break
#  if {$bold} {set title <b>$title</b>}
  if {[string match /* $file]} {set file ../../..$file}
  puts $out "<li><a href=\"$file\">$title</a></li>"
}
Changes to www/permutedindex.html.
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<li> <a href='$ROOT/help'>Built-in help for commands and webpages</a>
<li> <a href='history.md'>Purpose and History of Fossil</a>
<li> <a href='build.wiki'>Compiling and installing Fossil</a>
<li> <a href='../COPYRIGHT-BSD2.txt'>License</a>
<li> <a href='userlinks.wiki'>Miscellaneous Docs for Fossil Users</a>
<li> <a href='hacker-howto.wiki'>Fossil Developer's Guide</a>
<li> <a href='$ROOT/wiki?name=To+Do+List'>To Do List (Wiki)</a>
<li> <a href='http://fossil-scm.org/schimpf-book/home'>Jim Schimpf's
book</a>
</ul>
<a name="pindex"></a>
<h2>Other Documents:</h2>
<ul>
<li><a href="tech_overview.wiki">A Technical Overview Of The Design And Implementation Of Fossil</a></li>
<li><a href="serverext.wiki">Adding Extensions To A Fossil Server Using CGI Scripts</a></li>
<li><a href="adding_code.wiki">Adding New Features To Fossil</a></li>
<li><a href="caps/">Administering User Capabilities</a></li>
<li><a href="backup.md">Backing Up a Remote Fossil Repository</a></li>
<li><a href="whyusefossil.wiki">Benefits Of Version Control</a></li>







|
<

<
|







12
13
14
15
16
17
18
19

20

21
22
23
24
25
26
27
28
<li> <a href='$ROOT/help'>Built-in help for commands and webpages</a>
<li> <a href='history.md'>Purpose and History of Fossil</a>
<li> <a href='build.wiki'>Compiling and installing Fossil</a>
<li> <a href='../COPYRIGHT-BSD2.txt'>License</a>
<li> <a href='userlinks.wiki'>Miscellaneous Docs for Fossil Users</a>
<li> <a href='hacker-howto.wiki'>Fossil Developer's Guide</a>
<li> <a href='$ROOT/wiki?name=To+Do+List'>To Do List (Wiki)</a>
<li> <a href='http://fossil-scm.org/fossil-book/home'>Fossil book</a>

</ul>

<h2 id="pindex">Other Documents:</h2>
<ul>
<li><a href="tech_overview.wiki">A Technical Overview Of The Design And Implementation Of Fossil</a></li>
<li><a href="serverext.wiki">Adding Extensions To A Fossil Server Using CGI Scripts</a></li>
<li><a href="adding_code.wiki">Adding New Features To Fossil</a></li>
<li><a href="caps/">Administering User Capabilities</a></li>
<li><a href="backup.md">Backing Up a Remote Fossil Repository</a></li>
<li><a href="whyusefossil.wiki">Benefits Of Version Control</a></li>
Changes to www/private.wiki.
29
30
31
32
33
34
35
36

37
38
39
40
41
42
43

<blockquote><pre>
fossil update trunk
fossil merge private
fossil commit
</pre></blockquote>

The private branch remains private, but all of the changes associated with

the private branch are now folded into the public branch and are hence
visible to other users of the project.

A private branch created with Fossil version 1.30 or newer can also be
converted into a public branch using the <code>fossil publish</code>
command.  However, there is no way to convert a private branch created with
older versions of Fossil into a public branch.







|
>







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

<blockquote><pre>
fossil update trunk
fossil merge private
fossil commit
</pre></blockquote>

The private branch remains private and is not recorded as a parent
in the merge manifest's P-card, but all of the changes associated with
the private branch are now folded into the public branch and are hence
visible to other users of the project.

A private branch created with Fossil version 1.30 or newer can also be
converted into a public branch using the <code>fossil publish</code>
command.  However, there is no way to convert a private branch created with
older versions of Fossil into a public branch.
Changes to www/quickstart.wiki.
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65

<blockquote>
<b>fossil init </b><i> repository-filename</i>
</blockquote>

You can name the database anything you like, and you can place it anywhere in the filesystem.
The <tt>.fossil</tt> extension is traditional but only required if you are going to use the 
<tt>[./help?cmd=/server | fossil server DIRECTORY]</tt> feature.”

<h2 id="clone">Cloning An Existing Repository</h2>

<p>Most fossil operations interact with a repository that is on the
local disk drive, not on a remote system.  Hence, before accessing
a remote repository it is necessary to make a local copy of that
repository.  Making a local copy of a remote repository is called







|







51
52
53
54
55
56
57
58
59
60
61
62
63
64
65

<blockquote>
<b>fossil init </b><i> repository-filename</i>
</blockquote>

You can name the database anything you like, and you can place it anywhere in the filesystem.
The <tt>.fossil</tt> extension is traditional but only required if you are going to use the 
<tt>[/help/server | fossil server DIRECTORY]</tt> feature.”

<h2 id="clone">Cloning An Existing Repository</h2>

<p>Most fossil operations interact with a repository that is on the
local disk drive, not on a remote system.  Hence, before accessing
a remote repository it is necessary to make a local copy of that
repository.  Making a local copy of a remote repository is called
Changes to www/rebaseharm.md.
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
Most people, even strident advocates of rebase, agree that rebase can
cause problems when misused. The Git rebase documentation talks about the
[golden rule of rebasing][golden]: never rebase on a public
branch.  Horror stories of misused rebase abound, and the rebase 
documentation devotes considerable space toward explaining how to
recover from rebase errors and/or misuse.

## <a name="cap-loss"></a>2.0 Rebase provides no new capabilities

Sometimes sharp and dangerous tools are justified,
because they accomplish things that cannot be
done otherwise, or at least cannot be done easily.
Rebase does not fall into that category,
because it provides no new capabilities.

### <a name="orphaning"></a>2.1 A rebase is just a merge with historical references omitted

A rebase is really nothing more than a merge (or a series of merges)
that deliberately forgets one of the parents of each merge step.
To help illustrate this fact,
consider the first rebase example from the 
[Git documentation][gitrebase].  The merge looks like this:








|







|







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
Most people, even strident advocates of rebase, agree that rebase can
cause problems when misused. The Git rebase documentation talks about the
[golden rule of rebasing][golden]: never rebase on a public
branch.  Horror stories of misused rebase abound, and the rebase 
documentation devotes considerable space toward explaining how to
recover from rebase errors and/or misuse.

## <a id="cap-loss"></a>2.0 Rebase provides no new capabilities

Sometimes sharp and dangerous tools are justified,
because they accomplish things that cannot be
done otherwise, or at least cannot be done easily.
Rebase does not fall into that category,
because it provides no new capabilities.

### <a id="orphaning"></a>2.1 A rebase is just a merge with historical references omitted

A rebase is really nothing more than a merge (or a series of merges)
that deliberately forgets one of the parents of each merge step.
To help illustrate this fact,
consider the first rebase example from the 
[Git documentation][gitrebase].  The merge looks like this:

86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
So, another way of thinking about rebase is that it is a kind of
merge that intentionally forgets some details in order to
not overwhelm the weak history display mechanisms available in Git.
Wouldn't it be better, less error-prone, and easier on users
to enhance the history display mechanisms in Git so that rebasing 
for a clean, linear history became unnecessary?

### <a name="clean-diffs"></a>2.2 Rebase does not actually provide better feature-branch diffs

Another argument, often cited, is that rebasing a feature branch
allows one to see just the changes in the feature branch without
the concurrent changes in the main line of development. 
Consider a hypothetical case:

~~~ pikchr toggle







|







86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
So, another way of thinking about rebase is that it is a kind of
merge that intentionally forgets some details in order to
not overwhelm the weak history display mechanisms available in Git.
Wouldn't it be better, less error-prone, and easier on users
to enhance the history display mechanisms in Git so that rebasing 
for a clean, linear history became unnecessary?

### <a id="clean-diffs"></a>2.2 Rebase does not actually provide better feature-branch diffs

Another argument, often cited, is that rebasing a feature branch
allows one to see just the changes in the feature branch without
the concurrent changes in the main line of development. 
Consider a hypothetical case:

~~~ pikchr toggle
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
diff is not determined by whether you select C7 or C5\' as the target
of the diff, but rather by your choice of the diff source, C2 or C6.

So, to help with the problem of viewing changes associated with a feature
branch, perhaps what is needed is not rebase but rather better tools to 
help users identify an appropriate baseline for their diffs.

## <a name="siloing"></a>3.0 Rebase encourages siloed development

The [golden rule of rebasing][golden] is that you should never do it
on public branches, so if you are using rebase as intended, that means
you are keeping private branches.  Or, to put it another way, you are
doing siloed development.  You are not sharing your intermediate work
with collaborators.  This is not good for product quality.








|







210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
diff is not determined by whether you select C7 or C5\' as the target
of the diff, but rather by your choice of the diff source, C2 or C6.

So, to help with the problem of viewing changes associated with a feature
branch, perhaps what is needed is not rebase but rather better tools to 
help users identify an appropriate baseline for their diffs.

## <a id="siloing"></a>3.0 Rebase encourages siloed development

The [golden rule of rebasing][golden] is that you should never do it
on public branches, so if you are using rebase as intended, that means
you are keeping private branches.  Or, to put it another way, you are
doing siloed development.  You are not sharing your intermediate work
with collaborators.  This is not good for product quality.

249
250
251
252
253
254
255
256
257
258
259
260
261
262
263

Given that, is it better for those many eyeballs to find your problems
while they're still isolated on a feature branch, or should that vetting
wait until you finally push a collapsed version of a private working
branch to the parent repo? Will the many eyeballs even see those errors
when they’re intermingled with code implementing some compelling new feature?

## <a name="timestamps"></a>4.0 Rebase causes timestamp confusion

Consider the earlier example of rebasing a feature branch:

~~~ pikchr toggle
# Copy of second diagram in section 2.2 above
scale = 0.8
circle "C0" fit fill white







|







249
250
251
252
253
254
255
256
257
258
259
260
261
262
263

Given that, is it better for those many eyeballs to find your problems
while they're still isolated on a feature branch, or should that vetting
wait until you finally push a collapsed version of a private working
branch to the parent repo? Will the many eyeballs even see those errors
when they’re intermingled with code implementing some compelling new feature?

## <a id="timestamps"></a>4.0 Rebase causes timestamp confusion

Consider the earlier example of rebasing a feature branch:

~~~ pikchr toggle
# Copy of second diagram in section 2.2 above
scale = 0.8
circle "C0" fit fill white
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
system clocks, so they are not unique to rebase, but they are very
confusing and so best avoided.  The other option is to provide new
unique timestamps for C3' and C5' but then you lose the information
about when those check-ins were originally created, which can make
historical analysis of changes more difficult. It might also
complicate the legal defense of prior art claims.

## <a name="lying"></a>5.0 Rebase misrepresents the project history

By discarding parentage information, rebase attempts to deceive the
reader about how the code actually came together.

Git’s rebase feature is more than just an
alternative to merging: it also provides mechanisms for changing the
project history in order to make editorial changes.  Fossil shows that







|







291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
system clocks, so they are not unique to rebase, but they are very
confusing and so best avoided.  The other option is to provide new
unique timestamps for C3' and C5' but then you lose the information
about when those check-ins were originally created, which can make
historical analysis of changes more difficult. It might also
complicate the legal defense of prior art claims.

## <a id="lying"></a>5.0 Rebase misrepresents the project history

By discarding parentage information, rebase attempts to deceive the
reader about how the code actually came together.

Git’s rebase feature is more than just an
alternative to merging: it also provides mechanisms for changing the
project history in order to make editorial changes.  Fossil shows that
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
Git needs rebase because it lacks these annotation facilities.  Rather
than consider rebase a desirable feature missing in Fossil, ask instead
why Git lacks support for making editorial changes to check-ins without
modifying history?  Wouldn't it be better to fix the version control
tool rather than requiring users to fabricate a fictitious project
history?

## <a name="collapsing"></a>6.0 Collapsing check-ins throws away valuable information

One of the oft-cited advantages of rebasing in Git is that it lets you
collapse multiple check-ins down to a single check-in to make the
development history “clean.” The intent is that development appear as
though every feature were created in a single step: no multi-step
evolution, no back-tracking, no false starts, no mistakes. This ignores
actual developer psychology: ideas rarely spring forth from fingers to
files in faultless finished form. A wish for collapsed, finalized
check-ins is a wish for a counterfactual situation.

The common counterargument is that collapsed check-ins represent a
better world, the ideal we're striving for. What that argument overlooks
is that we must throw away valuable information to get there.

### <a name="empathy"></a>6.1 Individual check-ins support mutual understanding

Ideally, future developers of our software can understand every feature
in it using only context available in the version of the code they start
work with. Prior to widespread version control, developers had no choice
but to work that way.  Pre-existing codebases could only be understood
as-is or not at all.  Developers in that world had an incentive to
develop software that was easy to understand retrospectively, even if







|














|







327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
Git needs rebase because it lacks these annotation facilities.  Rather
than consider rebase a desirable feature missing in Fossil, ask instead
why Git lacks support for making editorial changes to check-ins without
modifying history?  Wouldn't it be better to fix the version control
tool rather than requiring users to fabricate a fictitious project
history?

## <a id="collapsing"></a>6.0 Collapsing check-ins throws away valuable information

One of the oft-cited advantages of rebasing in Git is that it lets you
collapse multiple check-ins down to a single check-in to make the
development history “clean.” The intent is that development appear as
though every feature were created in a single step: no multi-step
evolution, no back-tracking, no false starts, no mistakes. This ignores
actual developer psychology: ideas rarely spring forth from fingers to
files in faultless finished form. A wish for collapsed, finalized
check-ins is a wish for a counterfactual situation.

The common counterargument is that collapsed check-ins represent a
better world, the ideal we're striving for. What that argument overlooks
is that we must throw away valuable information to get there.

### <a id="empathy"></a>6.1 Individual check-ins support mutual understanding

Ideally, future developers of our software can understand every feature
in it using only context available in the version of the code they start
work with. Prior to widespread version control, developers had no choice
but to work that way.  Pre-existing codebases could only be understood
as-is or not at all.  Developers in that world had an incentive to
develop software that was easy to understand retrospectively, even if
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
check-in it was a part of — and then to understand the surrounding
check-ins as necessary — than it is to understand a 500-line check-in
that collapses a whole branch's worth of changes down to a single
finished feature.

[sdm]: ./fossil-v-git.wiki#durable

### <a name="bisecting"></a>6.2 Bisecting works better on small check-ins

Git lets a developer write a feature in ten check-ins but collapse it
down to an eleventh check-in and then deliberately push only that final
collapsed check-in to the parent repo. Someone else may then do a bisect
that blames the merged check-in as the source of the problem they’re
chasing down; they then have to manually work out which of the 10 steps
the original developer took to create it to find the source of the
actual problem.

An equivalent push in Fossil will send all 11 check-ins to the parent
repository so that a later investigator doing the same sort of bisect
sees the complete check-in history. That bisect will point the
investigator at the single original check-in that caused the problem.

### <a name="comments"></a>6.3 Multiple check-ins require multiple check-in comments

The more comments you have from a given developer on a given body of
code, the more concise documentation you have of that developer's
thought process. To resume the bisecting example, a developer trying to
work out what the original developer was thinking with a given change
will have more success given a check-in comment that explains what the
one check-in out of ten blamed by the "bisect" command was trying to
accomplish than if they must work that out from the eleventh check-in's
comment, which only explains the "clean" version of the collapsed
feature.

### <a name="cherrypicking"></a>6.4 Cherry-picks work better with small check-ins

While working on a new feature in one branch, you may come across a bug
in the pre-existing code that you need to fix in order for work on that
feature to proceed. You could choose to switch briefly back to the
parent branch, develop the fix there, check it in, then merge the parent
back up to the feature branch in order to continue work, but that's
distracting. If the fix isn't for a critical bug, fixing it on the







|














|











|







387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
check-in it was a part of — and then to understand the surrounding
check-ins as necessary — than it is to understand a 500-line check-in
that collapses a whole branch's worth of changes down to a single
finished feature.

[sdm]: ./fossil-v-git.wiki#durable

### <a id="bisecting"></a>6.2 Bisecting works better on small check-ins

Git lets a developer write a feature in ten check-ins but collapse it
down to an eleventh check-in and then deliberately push only that final
collapsed check-in to the parent repo. Someone else may then do a bisect
that blames the merged check-in as the source of the problem they’re
chasing down; they then have to manually work out which of the 10 steps
the original developer took to create it to find the source of the
actual problem.

An equivalent push in Fossil will send all 11 check-ins to the parent
repository so that a later investigator doing the same sort of bisect
sees the complete check-in history. That bisect will point the
investigator at the single original check-in that caused the problem.

### <a id="comments"></a>6.3 Multiple check-ins require multiple check-in comments

The more comments you have from a given developer on a given body of
code, the more concise documentation you have of that developer's
thought process. To resume the bisecting example, a developer trying to
work out what the original developer was thinking with a given change
will have more success given a check-in comment that explains what the
one check-in out of ten blamed by the "bisect" command was trying to
accomplish than if they must work that out from the eleventh check-in's
comment, which only explains the "clean" version of the collapsed
feature.

### <a id="cherrypicking"></a>6.4 Cherry-picks work better with small check-ins

While working on a new feature in one branch, you may come across a bug
in the pre-existing code that you need to fix in order for work on that
feature to proceed. You could choose to switch briefly back to the
parent branch, develop the fix there, check it in, then merge the parent
back up to the feature branch in order to continue work, but that's
distracting. If the fix isn't for a critical bug, fixing it on the
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
complete. If a support organization must manually disentangle a fix from
a feature check-in, they are likely to introduce new bugs on the stable
branch. Even if they manage to do their work without error, it takes
them more time to do the cherry-pick that way.

[rh]: https://en.wikipedia.org/wiki/Red_Hat

### <a name="backouts"></a>6.5 Back-outs also work better with small check-ins

The inverse of the cherry-pick merge is the back-out merge. If you push
only a collapsed version of a private working branch up to the parent
repo, those working from that parent repo cannot automatically back out
any of the individual check-ins that went into that private branch.
Others must either manually disentangle the problematic part of your
merge check-in or back out the entire feature.

## <a name="better-plan"></a>7.0 Cherry-pick merges work better than rebase

Perhaps there are some cases where a rebase-like transformation
is actually helpful, but those cases are rare, and when they do
come up, running a series of cherry-pick merges achieves the same
topology with several advantages:

  1.  In Fossil, cherry-pick merges preserve an honest and clear record







|








|







456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
complete. If a support organization must manually disentangle a fix from
a feature check-in, they are likely to introduce new bugs on the stable
branch. Even if they manage to do their work without error, it takes
them more time to do the cherry-pick that way.

[rh]: https://en.wikipedia.org/wiki/Red_Hat

### <a id="backouts"></a>6.5 Back-outs also work better with small check-ins

The inverse of the cherry-pick merge is the back-out merge. If you push
only a collapsed version of a private working branch up to the parent
repo, those working from that parent repo cannot automatically back out
any of the individual check-ins that went into that private branch.
Others must either manually disentangle the problematic part of your
merge check-in or back out the entire feature.

## <a id="better-plan"></a>7.0 Cherry-pick merges work better than rebase

Perhaps there are some cases where a rebase-like transformation
is actually helpful, but those cases are rare, and when they do
come up, running a series of cherry-pick merges achieves the same
topology with several advantages:

  1.  In Fossil, cherry-pick merges preserve an honest and clear record
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
      `git reset --hard` to repair the damage.

  3.  Cherry-picks keep both the original and the revised check-ins,
      so both timestamps are preserved.

[tbc]: ./fossil-v-git.wiki#testing

## <a name="conclusion"></a>8.0 Summary and conclusion

Rebasing is an anti-pattern.  It is dishonest.  It deliberately
omits historical information.  It causes problems for collaboration.
And it has no offsetting benefits.

For these reasons, rebase is intentionally and deliberately omitted
from the design of Fossil.


[golden]: https://www.atlassian.com/git/tutorials/merging-vs-rebasing#the-golden-rule-of-rebasing
[gitrebase]: https://git-scm.com/book/en/v2/Git-Branching-Rebasing
[nagappan]: https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/tr-2008-11.pdf
[weinberg]: https://books.google.com/books?id=76dIAAAAMAAJ







|













499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
      `git reset --hard` to repair the damage.

  3.  Cherry-picks keep both the original and the revised check-ins,
      so both timestamps are preserved.

[tbc]: ./fossil-v-git.wiki#testing

## <a id="conclusion"></a>8.0 Summary and conclusion

Rebasing is an anti-pattern.  It is dishonest.  It deliberately
omits historical information.  It causes problems for collaboration.
And it has no offsetting benefits.

For these reasons, rebase is intentionally and deliberately omitted
from the design of Fossil.


[golden]: https://www.atlassian.com/git/tutorials/merging-vs-rebasing#the-golden-rule-of-rebasing
[gitrebase]: https://git-scm.com/book/en/v2/Git-Branching-Rebasing
[nagappan]: https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/tr-2008-11.pdf
[weinberg]: https://books.google.com/books?id=76dIAAAAMAAJ
Changes to www/selfhost.wiki.
8
9
10
11
12
13
14
15

16
17
18
19
20
21
22
  3.  [https://www3.fossil-scm.org/site.cgi]

The canonical repository is (1).  Repositories (2) and (3) automatically
stay in synchronization with (1) via a
<a href="http://en.wikipedia.org/wiki/Cron">cron job</a> that invokes
"fossil sync" at regular intervals.
Repository (2) also publishes a
[./mirrortogithub.md|GitHub mirror of Fossil] as a demonstration.


Note that the two secondary repositories are more than just read-only mirrors.
All three servers support full read/write capabilities.
Changes (such as new tickets or wiki or check-ins) can be implemented
on any of the three servers and those changes automatically propagate to the
other two servers.








|
>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  3.  [https://www3.fossil-scm.org/site.cgi]

The canonical repository is (1).  Repositories (2) and (3) automatically
stay in synchronization with (1) via a
<a href="http://en.wikipedia.org/wiki/Cron">cron job</a> that invokes
"fossil sync" at regular intervals.
Repository (2) also publishes a
[https://github.com/drhsqlite/fossil-mirror|GitHub mirror of Fossil]
as a demonstration of [./mirrortogithub.md|how that can be done].

Note that the two secondary repositories are more than just read-only mirrors.
All three servers support full read/write capabilities.
Changes (such as new tickets or wiki or check-ins) can be implemented
on any of the three servers and those changes automatically propagate to the
other two servers.

Added www/server/any/http-over-ssh.md.


























































































































































































































































































































































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

Andy Bradford posted a [clever solution][sshfc] to the problem of
Fossil’s RBAC system [being ignored](../../caps/#webonly) over `ssh://`
URLs: use OpenSSH’s `ForceCommand` feature to route the sync transfer
protocol data over `fossil http` rather than `fossil test-http`.

The setup for this is complicated, but it’s a worthy option when you
need encrypted communications between the client and server, you already
have SSH set up, and [the HTTPS alternative](../../ssl.wiki) is
unworkable for some reason.


## 1. Force remote Fossil access through a wrapper script <a id="sshd"></a>

Put something like the following into the `sshd_config` file on the
Fossil repository server:

``` ssh-config
    Match Group fossil
        X11Forwarding no
        AllowTcpForwarding no
        AllowAgentForwarding no
        ForceCommand /home/fossil/bin/wrapper
```

This file is usually found in `/etc/ssh`, but some OSes put it
elsewhere.

The first line presumes that we will put all users who need to use our
Fossil repositories into the `fossil` group, as we will do
[below](#perms). You could instead say something like:

``` ssh-config
    Match User alice,bob,carol,dave
```

You have to list the users allowed to use Fossil in this case because
your system likely has a system administrator that uses SSH for remote
shell access, so you want to *exclude* that user from the list. For the
same reason, you don’t want to put the `ForceCommand` directive outside
a `Match` block of some sort.

You could instead list the exceptions:

``` ssh-config
    Match User !evi
```

This would permit only [Evi the System Administrator][evi] to bypass this
mechanism.

[evi]: https://en.wikipedia.org/wiki/Evi_Nemeth

If you have a user that needs both interactive SSH shell access *and*
Fossil access, exclude that user from the `Match` rule and use Fossil’s
normal `ssh://` URL scheme for those cases. This user will bypass the
Fossil RBAC, but they effectively have Setup capability on those
repositories anyway by having full read/write access to the DB files via
the shell.


## 2. Rewrite the sync command with that wrapper <a id="wrapper"></a>

When Fossil syncs over SSH, it attempts to launch a remote Fossil
instance with certain parameters in order to set up the HTTP-based sync
protocol over that SSH tunnel. We need to preserve some of this command
and rewrite other parts to make this work.

Here is a simpler variant of Andy’s original wrapper script:

``` sh
    #!/bin/bash
    set -- $SSH_ORIGINAL_COMMAND
    while [ $# -gt 1 ] ; do shift ; done
    export REMOTE_USER="$USER"
    ROOT=/home/fossil
    exec "$ROOT/bin/fossil" http "$ROOT/museum/$(/bin/basename "$1")"
```

The substantive changes are:

1.  Move the command rewriting bits to the start.

2.  Be explicit about executable paths.  You might extend this idea by
    using chroot, BSD jails, Linux containers, etc.

3.  Restrict the Fossil repositories to a single flat subdirectory under
    the `fossil` user’s home directory. This scheme is easier to secure
    than one allowing subdirectories, since you’d need to take care of
    `../` and such to prevent a sandbox escape.

4.  Don’t take the user name via the SSH command; to this author’s mind,
    the user should not get to override their Fossil user name on the
    remote server, as that permits impersonation.  The identity you
    present to the SSH server must be the same identity that the Fossil
    repository you’re working with knows you by.  Since the users
    selected by “`Match`” block above are dedicated to using only Fossil
    in this setup, this restriction shouldn’t present a practical problem.

The script’s shebang line assumes `/bin/sh` is POSIX-compliant, but that
is not the case everywhere. If the script fails to run on your system,
try changing this line to point at `bash`, `dash`, `ksh`, or `zsh`. Also
check the absolute paths for local correctness: is `/bin/basename`
installed on your system, for example?

Under this scheme, you clone with a command like:

        $ fossil clone ssh://HOST/repo.fossil

This will clone the remote `/home/fossil/museum/repo.fossil` repository
to your local machine under the same name and open it into a “`repo/`”
subdirectory. Notice that we didn’t have to give the `museum/` part of
the path: it’s implicit per point #3 above.

This presumes your local user name matches the remote user name.  Unlike
with `http[s]://` URLs, you don’t have to provide the `USER@` part to
get authenticated access
since this scheme doesn’t permit anonymous cloning. Only
if these two user names are different do you need to add the `USER@` bit to the
URL.


## 3. Set permissions <a id="perms"></a>

This scheme assumes that the users covered by the `Match` rule can read
the wrapper script from where you placed it and execute it, and that
they have read/write access on the directory where the Fossil
repositories are stored.

You can achieve all of this on a Linux box with:

``` shell
    sudo adduser fossil
    for u in alice bob carol dave ; do 
        sudo adduser $u
        sudo gpasswd -a fossil $u
    done
    sudo -i -u fossil
    chmod 710 .
    mkdir -m 750 bin
    mkdir -m 770 museum
    ln -s /usr/local/bin/fossil bin
```

You then need to copy the Fossil repositories into `~fossil/museum` and
make them readable and writable by group `fossil`. These repositories
presumably already have Fossil users configured, with the necessary
[user capabilities](../../caps/), the point of this article being to
show you how to make Fossil-over-SSH pay attention to those caps.

You must also permit use of `REMOTE_USER` on each shared repository.
Fossil only pays attention to this environment variable in certain
contexts, of which “`fossil http`” is not one. Run this command against
each repo to allow that:

``` shell
    echo "INSERT OR REPLACE INTO config VALUES ('remote_user_ok',1,strftime('%s','now'));" |
    fossil sql -R museum/repo.fossil
```

Now you can configure SSH authentication for each user. Since Fossil’s
password-saving feature doesn’t work in this case, I suggest setting up
SSH keys via `~USER/.ssh/authorized_keys` since the SSH authentication
occurs on each sync, which Fossil’s default-enabled autosync setting
makes frequent.

Equivalent commands for other OSes should be readily discerned from the
script above.

[sshfc]: forum:/forumpost/0d7d6c3df41fcdfd

<div style="height:50em" id="this-space-intentionally-left-blank"></div>
Changes to www/server/any/stunnel.md.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
that made the request.

You can run `stunnel` in one of two modes: socket listener — much like
in our [`inetd` doc](./inetd.md) — and as an HTTP reverse proxy. We’ll
cover both cases here, separately.


## S<a name="sa"></a>ocket Activation

The following `stunnel.conf` configuration configures it to run Fossil
in socket listener mode, launching Fossil only when an HTTPS hit comes
in, then shutting it back down as soon as the transaction is complete:

```dosini
    [fossil]







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
that made the request.

You can run `stunnel` in one of two modes: socket listener — much like
in our [`inetd` doc](./inetd.md) — and as an HTTP reverse proxy. We’ll
cover both cases here, separately.


## <a id="sa"></a>Socket Activation

The following `stunnel.conf` configuration configures it to run Fossil
in socket listener mode, launching Fossil only when an HTTPS hit comes
in, then shutting it back down as soon as the transaction is complete:

```dosini
    [fossil]
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

It is important that the [`fossil http`](/help/http) command in that
configuration include the `--https` option to let Fossil know to use
“`https://`” instead of “`http://`” in generated hyperlinks.



## <a name="proxy"></a>Reverse Proxy

You can instead have Fossil running in the background in [standalone
HTTP server mode](./none.md), bound to a high random TCP port number on
localhost via the `--localhost` and `--port` flags, then configure
`stunnel` to reverse proxy public HTTPS connections down to it via HTTP.

The configuration is the same as the above except that you drop the







|







45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

It is important that the [`fossil http`](/help/http) command in that
configuration include the `--https` option to let Fossil know to use
“`https://`” instead of “`http://`” in generated hyperlinks.



## <a id="proxy"></a>Reverse Proxy

You can instead have Fossil running in the background in [standalone
HTTP server mode](./none.md), bound to a high random TCP port number on
localhost via the `--localhost` and `--port` flags, then configure
`stunnel` to reverse proxy public HTTPS connections down to it via HTTP.

The configuration is the same as the above except that you drop the
73
74
75
76
77
78
79


    than in socket listener mode, where the Fossil binary has to be
    loaded and re-initialized on each HTTPS hit.

2.  The socket listener mode doesn’t work on all platforms that
    `stunnel` runs on, particularly [on Windows](../windows/stunnel.md).

*[Return to the top-level Fossil server article.](../)*









>
>
73
74
75
76
77
78
79
80
81
    than in socket listener mode, where the Fossil binary has to be
    loaded and re-initialized on each HTTPS hit.

2.  The socket listener mode doesn’t work on all platforms that
    `stunnel` runs on, particularly [on Windows](../windows/stunnel.md).

*[Return to the top-level Fossil server article.](../)*

<div style="height:50em" id="this-space-intentionally-left-blank"></div>
Changes to www/server/debian/nginx.md.
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
details depend on the host OS and web stack details. Besides, TLS is
widely considered part of the baseline configuration these days.

[scgii]: ../any/scgi.md
[vps]:   https://en.wikipedia.org/wiki/Virtual_private_server


## <a name="benefits"></a>Benefits

This scheme is considerably more complicated than the [standalone HTTP
server](../any/none.md) and [CGI options](../any/cgi.md). Even with the
benefit of this guide and pre-built binary packages, it requires quite a
bit of work to set it up. Why should you put up with this complexity?
Because it gives many benefits that are difficult or impossible to get
with the less complicated options:







|







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
details depend on the host OS and web stack details. Besides, TLS is
widely considered part of the baseline configuration these days.

[scgii]: ../any/scgi.md
[vps]:   https://en.wikipedia.org/wiki/Virtual_private_server


## <a id="benefits"></a>Benefits

This scheme is considerably more complicated than the [standalone HTTP
server](../any/none.md) and [CGI options](../any/cgi.md). Even with the
benefit of this guide and pre-built binary packages, it requires quite a
bit of work to set it up. Why should you put up with this complexity?
Because it gives many benefits that are difficult or impossible to get
with the less complicated options:
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
world and interior site services like Fossil. It allows Fossil to
participate seamlessly as part of a larger web stack.

*   **Availability** — nginx is already in most operating system binary
package repositories, so you don’t need to go out of your way to get it.


## <a name="modes"></a>Fossil Service Modes

Fossil provides four major ways to access a repository it’s serving
remotely, three of which are straightforward to use with nginx:

*   **HTTP** — Fossil has [a built-in HTTP server](../any/none.md).
    While this method is efficient and it’s
    possible to use nginx to proxy access to another HTTP server, we







|







57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
world and interior site services like Fossil. It allows Fossil to
participate seamlessly as part of a larger web stack.

*   **Availability** — nginx is already in most operating system binary
package repositories, so you don’t need to go out of your way to get it.


## <a id="modes"></a>Fossil Service Modes

Fossil provides four major ways to access a repository it’s serving
remotely, three of which are straightforward to use with nginx:

*   **HTTP** — Fossil has [a built-in HTTP server](../any/none.md).
    While this method is efficient and it’s
    possible to use nginx to proxy access to another HTTP server, we
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
    without its performance problems.

SCGI it is, then.

[scgip]: https://en.wikipedia.org/wiki/Simple_Common_Gateway_Interface


## <a name="deps"></a>Installing the Dependencies

The first step is to install some non-default packages we’ll need. SSH into
your server, then say:

       $ sudo apt install fossil nginx

You can leave “`fossil`” out of that if you’re building Fossil from
source to get a more up-to-date version than is shipped with the host
OS.


## <a name="scgi"></a>Running Fossil in SCGI Mode

For the following nginx configuration to work, it needs to contact a
Fossil instance speaking the SCGI protocol. There are [many ways](../)
to set that up. For Debian type systems, we recommend
following [our systemd system service guide](service.md).

There are other ways to arrange for Fossil to run as a service backing
nginx, but however you do it, you need to match up the TCP port numbers between it
and those in the nginx configuration below.


## <a name="config"></a>Configuration

On Debian and Ubuntu systems the primary user-level configuration file
for nginx is `/etc/nginx/sites-enabled/default`. I recommend that this
file contain only a list of include statements, one for each site that
server hosts:

      include local/example.com







|











|











|







92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
    without its performance problems.

SCGI it is, then.

[scgip]: https://en.wikipedia.org/wiki/Simple_Common_Gateway_Interface


## <a id="deps"></a>Installing the Dependencies

The first step is to install some non-default packages we’ll need. SSH into
your server, then say:

       $ sudo apt install fossil nginx

You can leave “`fossil`” out of that if you’re building Fossil from
source to get a more up-to-date version than is shipped with the host
OS.


## <a id="scgi"></a>Running Fossil in SCGI Mode

For the following nginx configuration to work, it needs to contact a
Fossil instance speaking the SCGI protocol. There are [many ways](../)
to set that up. For Debian type systems, we recommend
following [our systemd system service guide](service.md).

There are other ways to arrange for Fossil to run as a service backing
nginx, but however you do it, you need to match up the TCP port numbers between it
and those in the nginx configuration below.


## <a id="config"></a>Configuration

On Debian and Ubuntu systems the primary user-level configuration file
for nginx is `/etc/nginx/sites-enabled/default`. I recommend that this
file contain only a list of include statements, one for each site that
server hosts:

      include local/example.com
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
on a single server.

The configuration for `foo.net` is similar.

See [the nginx docs](https://nginx.org/en/docs/) for more ideas.


## <a name="http"></a>Proxying HTTP Anyway

[Above](#modes), we argued that proxying SCGI is a better option than
making nginx reinterpret Fossil’s own implementation of HTTP.  If you
want Fossil to speak HTTP, just [set Fossil up as a standalone
server](../any/none.md). And if you want nginx to [provide TLS
encryption for Fossil](#tls), proxying HTTP instead of SCGI provides no
benefit.







|







192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
on a single server.

The configuration for `foo.net` is similar.

See [the nginx docs](https://nginx.org/en/docs/) for more ideas.


## <a id="http"></a>Proxying HTTP Anyway

[Above](#modes), we argued that proxying SCGI is a better option than
making nginx reinterpret Fossil’s own implementation of HTTP.  If you
want Fossil to speak HTTP, just [set Fossil up as a standalone
server](../any/none.md). And if you want nginx to [provide TLS
encryption for Fossil](#tls), proxying HTTP instead of SCGI provides no
benefit.
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246

The most common thing people get wrong when hand-rolling a configuration
like this is to get the slashes wrong. Fossil is sensitive to this. For
instance, Fossil will not collapse double slashes down to a single
slash, as some other HTTP servers will.


## <a name="large-uv"></a> Allowing Large Unversioned Files

By default, nginx only accepts HTTP messages [up to a
meg](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size)
in size. Fossil chunks its sync protocol such that this is not normally
a problem, but when sending [unversioned content][uv], it uses a single
message for the entire file. Therefore, if you will be storing files
larger than this limit as unversioned content, you need to raise the
limit. Within the `location` block:

        # Allow large unversioned file uploads, such as PDFs
        client_max_body_size 20M;

[uv]: ../../unvers.wiki


## <a name="fail2ban"></a> Integrating `fail2ban`

One of the nice things that falls out of proxying Fossil behind nginx is
that it makes it easier to configure `fail2ban` to recognize attacks on
Fossil and automatically block them. Fossil logs the sorts of errors we
want to detect, but it does so in places like the repository’s admin
log, a SQL table, which `fail2ban` doesn’t know how to query. By putting
Fossil behind an nginx proxy, we convert these failures to log file







|















|







216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246

The most common thing people get wrong when hand-rolling a configuration
like this is to get the slashes wrong. Fossil is sensitive to this. For
instance, Fossil will not collapse double slashes down to a single
slash, as some other HTTP servers will.


## <a id="large-uv"></a> Allowing Large Unversioned Files

By default, nginx only accepts HTTP messages [up to a
meg](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size)
in size. Fossil chunks its sync protocol such that this is not normally
a problem, but when sending [unversioned content][uv], it uses a single
message for the entire file. Therefore, if you will be storing files
larger than this limit as unversioned content, you need to raise the
limit. Within the `location` block:

        # Allow large unversioned file uploads, such as PDFs
        client_max_body_size 20M;

[uv]: ../../unvers.wiki


## <a id="fail2ban"></a> Integrating `fail2ban`

One of the nice things that falls out of proxying Fossil behind nginx is
that it makes it easier to configure `fail2ban` to recognize attacks on
Fossil and automatically block them. Fossil logs the sorts of errors we
want to detect, but it does so in places like the repository’s admin
log, a SQL table, which `fail2ban` doesn’t know how to query. By putting
Fossil behind an nginx proxy, we convert these failures to log file
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
There’s a [lot more you can do][dof2b], but that gets us out of scope of
this guide.


[dof2b]: https://www.digitalocean.com/community/tutorials/how-to-protect-an-nginx-server-with-fail2ban-on-ubuntu-14-04


## <a name="tls"></a> Adding TLS (HTTPS) Support

One of the [many ways](../../ssl.wiki) to provide TLS-encrypted HTTP access
(a.k.a. HTTPS) to Fossil is to run it behind a web proxy that supports
TLS. One such option is nginx on Debian, so we show the details of that
here.

You can extend this guide to other operating systems by following the







|







277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
There’s a [lot more you can do][dof2b], but that gets us out of scope of
this guide.


[dof2b]: https://www.digitalocean.com/community/tutorials/how-to-protect-an-nginx-server-with-fail2ban-on-ubuntu-14-04


## <a id="tls"></a> Adding TLS (HTTPS) Support

One of the [many ways](../../ssl.wiki) to provide TLS-encrypted HTTP access
(a.k.a. HTTPS) to Fossil is to run it behind a web proxy that supports
TLS. One such option is nginx on Debian, so we show the details of that
here.

You can extend this guide to other operating systems by following the
Changes to www/server/index.html.
104
105
106
107
108
109
110
111
112
113
114
115
116
117

118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189








190
191
192
193
194
195
196
repository file to your server and proceed with server setup, below.
Further configuration steps can wait until <a href="#postsetup">after
the server is running</a>.</p>


<h2 id="methods">Activation Methods</h2>

<p>There are basically four ways to run a Fossil server:</p>

<ol>
  <li><a id="cgi"        href="any/cgi.md">CGI</a>
  <li>Socket listener
  <li><a id="standalone" href="any/none.md">Stand-alone HTTP server</a>
  <li><a id="scgi"       href="any/scgi.md">SCGI</a>

</ol>

<p>All of these methods can serve either a single repository or a
directory hierarchy containing mulitiple repositories.</p>

<p>You are not restricted to a single server setup. The same Fossil
repository can be served using two or more of the above techniques at
the same time. These methods use clean, well-defined, standard
interfaces (CGI, SCGI, and HTTP) which allow you to easily migrate from
one method to another in response to changes in hosting providers or
administrator preferences.</p>

<h3>CGI</h3>

<p>Most ordinary web servers can <a href="any/cgi.md">run Fossil as a
CGI script</a>. This method is known to work with Apache,
<tt>lighttpd</tt>, and <a
href="any/althttpd.md"><tt>althttpd</tt></a>.  The Fossil server
administrator places a <a href="$ROOT/help?cmd=cgi">short CGI script</a> in
the web server's document hierarchy and when a client requests the URL
that corresponds to that script, Fossil runs and generates the
response.</p>

<p>CGI is a good choice for merging Fossil into an existing web site,
particularly on hosts that have CGI set up and working.
The Fossil <a href="../selfhost.wiki">self-hosting repositories</a> are
implemented with CGI underneath <tt>althttpd</tt>.</p>

<h3>Socket Listener</h3>

<p>Socket listener daemons such as
<a id="inetd" href="any/inetd.md"><tt>inetd</tt></a>, <a id="xinetd"
href="any/xinetd.md"><tt>xinetd</tt></a>, <a id="stunnel"
href="any/stunnel.md"><tt>stunnel</tt></a>, <a
href="macos/service.md"><tt>launchd</tt></a>, and <a
href="debian/service.md"><tt>systemd</tt></a>
can be configured to invoke the the
<a href="$ROOT/help?cmd=http"><tt>fossil http</tt></a> command to handle
each incoming HTTP request.  The "<tt>fossil http</tt>" command reads
the HTTP request off of standard input, computes an appropriate
reply, and writes the reply on standard output.  There is a separate
invocation of the "<tt>fossil http</tt>" command for each HTTP request.
The socket listener daemon takes care of relaying content to and from
the client, and (in the case of <a href="any/stunnel.md">stunnel</a>) 
handling TLS decryption and encryption.

<h3>Stand-alone HTTP Server</h3>

<p>This is the <a href="any/none.md">easiest method</a>.
A stand-alone server uses the
<a href="$ROOT/help?cmd=server"><tt>fossil server</tt></a> command to run a
process that listens for incoming HTTP requests on a socket and then
dispatches a copy of itself to deal with each incoming request. You can
expose Fossil directly to the clients in this way or you can interpose a
<a href="https://en.wikipedia.org/wiki/Reverse_proxy">reverse proxy</a>
layer between the clients and Fossil.</p>

<h3>SCGI</h3>

<p>The Fossil standalone server can also handle <a href="any/scgi.md">SCGI</a>.
When the <a href="$ROOT/help?cmd=server"><tt>fossil server</tt></a> command is
run with the extra <tt>--scgi</tt> option, it listens for incoming
SCGI requests rather than HTTP requests. This allows Fossil to
respond to requests from web servers <a href="debian/nginx.md">such as
nginx</a> that don't support CGI. SCGI is a simpler protocol to proxy
than HTTP, since the HTTP doesn't have to be re-interpreted in terms of
the proxy's existing HTTP implementation, but it's more complex to set
up because you also have to set up an SCGI-to-HTTP proxy for it. It is
worth taking on this difficulty only when you need to integrate Fossil
into an existing web site already being served by an SCGI-capable web
server.</p>









<h2 id="matrix">Activation Tutorials</h2>

<p>We've broken the configuration for each method out into a series of
sub-articles. Some of these are generic, while others depend on
particular operating systems or front-end software:</p>

<div id="tutpick" class="show"></div>







|


|
|
|
|
>












|















|

















|










|














>
>
>
>
>
>
>
>







104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
repository file to your server and proceed with server setup, below.
Further configuration steps can wait until <a href="#postsetup">after
the server is running</a>.</p>


<h2 id="methods">Activation Methods</h2>

<p>There are basically five ways to run a Fossil server:</p>

<ol>
  <li><a href="any/cgi.md">CGI</a>
  <li><a href="#slist">Socket listener</a>
  <li><a href="any/none.md">Stand-alone HTTP server</a>
  <li><a href="any/scgi.md">SCGI</a>
  <li><a href="#ssh">SSH</a>
</ol>

<p>All of these methods can serve either a single repository or a
directory hierarchy containing mulitiple repositories.</p>

<p>You are not restricted to a single server setup. The same Fossil
repository can be served using two or more of the above techniques at
the same time. These methods use clean, well-defined, standard
interfaces (CGI, SCGI, and HTTP) which allow you to easily migrate from
one method to another in response to changes in hosting providers or
administrator preferences.</p>

<h3 id="cgi">CGI</h3>

<p>Most ordinary web servers can <a href="any/cgi.md">run Fossil as a
CGI script</a>. This method is known to work with Apache,
<tt>lighttpd</tt>, and <a
href="any/althttpd.md"><tt>althttpd</tt></a>.  The Fossil server
administrator places a <a href="$ROOT/help?cmd=cgi">short CGI script</a> in
the web server's document hierarchy and when a client requests the URL
that corresponds to that script, Fossil runs and generates the
response.</p>

<p>CGI is a good choice for merging Fossil into an existing web site,
particularly on hosts that have CGI set up and working.
The Fossil <a href="../selfhost.wiki">self-hosting repositories</a> are
implemented with CGI underneath <tt>althttpd</tt>.</p>

<h3 id="slist">Socket Listener</h3>

<p>Socket listener daemons such as
<a id="inetd" href="any/inetd.md"><tt>inetd</tt></a>, <a id="xinetd"
href="any/xinetd.md"><tt>xinetd</tt></a>, <a id="stunnel"
href="any/stunnel.md"><tt>stunnel</tt></a>, <a
href="macos/service.md"><tt>launchd</tt></a>, and <a
href="debian/service.md"><tt>systemd</tt></a>
can be configured to invoke the the
<a href="$ROOT/help?cmd=http"><tt>fossil http</tt></a> command to handle
each incoming HTTP request.  The "<tt>fossil http</tt>" command reads
the HTTP request off of standard input, computes an appropriate
reply, and writes the reply on standard output.  There is a separate
invocation of the "<tt>fossil http</tt>" command for each HTTP request.
The socket listener daemon takes care of relaying content to and from
the client, and (in the case of <a href="any/stunnel.md">stunnel</a>) 
handling TLS decryption and encryption.

<h3 id="standalone">Stand-alone HTTP Server</h3>

<p>This is the <a href="any/none.md">easiest method</a>.
A stand-alone server uses the
<a href="$ROOT/help?cmd=server"><tt>fossil server</tt></a> command to run a
process that listens for incoming HTTP requests on a socket and then
dispatches a copy of itself to deal with each incoming request. You can
expose Fossil directly to the clients in this way or you can interpose a
<a href="https://en.wikipedia.org/wiki/Reverse_proxy">reverse proxy</a>
layer between the clients and Fossil.</p>

<h3 id="scgi"3>SCGI</h3>

<p>The Fossil standalone server can also handle <a href="any/scgi.md">SCGI</a>.
When the <a href="$ROOT/help?cmd=server"><tt>fossil server</tt></a> command is
run with the extra <tt>--scgi</tt> option, it listens for incoming
SCGI requests rather than HTTP requests. This allows Fossil to
respond to requests from web servers <a href="debian/nginx.md">such as
nginx</a> that don't support CGI. SCGI is a simpler protocol to proxy
than HTTP, since the HTTP doesn't have to be re-interpreted in terms of
the proxy's existing HTTP implementation, but it's more complex to set
up because you also have to set up an SCGI-to-HTTP proxy for it. It is
worth taking on this difficulty only when you need to integrate Fossil
into an existing web site already being served by an SCGI-capable web
server.</p>

<h3 id="ssh">SSH</h3>

<p>Fossil supports <tt>ssh://</tt> URLs, but there are <a
href="../caps/#webonly">practical limitations</a> with the default
behavior. You can get the full power of <a href="../caps/">Fossil's RBAC
system</a> over SSH <a href="any/http-over-ssh.md">with a bit of clever
configuration</a>.</p>

<h2 id="matrix">Activation Tutorials</h2>

<p>We've broken the configuration for each method out into a series of
sub-articles. Some of these are generic, while others depend on
particular operating systems or front-end software:</p>

<div id="tutpick" class="show"></div>
Changes to www/server/openbsd/fastcgi.md.
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
a single directory within a chroot, and allow `ssh` access to create
new repositories remotely.

**NOTE:** The following instructions assume an OpenBSD 6.7 installation.

[httpd]: https://www.openbsd.org/papers/httpd-asiabsdcon2015.pdf

## <a name="fslinstall"></a>Install Fossil

Use the OpenBSD package manager `pkg_add` to install Fossil, making sure
to select the statically linked binary.

```console
    $ doas pkg_add fossil
    quirks-3.325 signed on 2020-06-12T06:24:53Z







|







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
a single directory within a chroot, and allow `ssh` access to create
new repositories remotely.

**NOTE:** The following instructions assume an OpenBSD 6.7 installation.

[httpd]: https://www.openbsd.org/papers/httpd-asiabsdcon2015.pdf

## <a id="fslinstall"></a>Install Fossil

Use the OpenBSD package manager `pkg_add` to install Fossil, making sure
to select the statically linked binary.

```console
    $ doas pkg_add fossil
    quirks-3.325 signed on 2020-06-12T06:24:53Z
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
    $ doas mkdir /var/www/htdocs/fsl.domain.tld
    $ doas touch /var/www/logs/fossil.log
    $ doas chown www /var/www/logs/fossil.log
    $ doas chmod 660 /var/www/logs/fossil.log
    $ doas chmod 755 /var/www/cgi-bin/scm
```

## <a name="chroot"></a>Setup chroot

Fossil needs both `/dev/random` and `/dev/null`, which aren't accessible
from within the chroot, so need to be constructed; `/var`, however, is
mounted with the `nodev` option. Rather than removing this default
setting, create a small memory filesystem and then mount it on to
`/var/www/dev` with [`mount_mfs(8)`][mfs] so that the `random` and
`null` device files can be created. In order to avoid necessitating a







|







60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
    $ doas mkdir /var/www/htdocs/fsl.domain.tld
    $ doas touch /var/www/logs/fossil.log
    $ doas chown www /var/www/logs/fossil.log
    $ doas chmod 660 /var/www/logs/fossil.log
    $ doas chmod 755 /var/www/cgi-bin/scm
```

## <a id="chroot"></a>Setup chroot

Fossil needs both `/dev/random` and `/dev/null`, which aren't accessible
from within the chroot, so need to be constructed; `/var`, however, is
mounted with the `nodev` option. Rather than removing this default
setting, create a small memory filesystem and then mount it on to
`/var/www/dev` with [`mount_mfs(8)`][mfs] so that the `random` and
`null` device files can be created. In order to avoid necessitating a
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
user who will push to, pull from, and create repositories.

```console
   $ doas chown -R user:www /var/www/htdocs/fsl.domain.tld
   $ doas chmod 770 /var/www/htdocs/fsl.domain.tld
```

## <a name="httpdconfig"></a>Configure httpd

On OpenBSD, [httpd.conf(5)][httpd] is the configuration file for
`httpd`. To setup the server to serve all Fossil repositores within the
directory specified in the CGI script, and automatically redirect
standard HTTP requests to HTTPS—apart from [Let's Encrypt][LE]
challenges issued in response to [acme-client(1)][acme] certificate
requests—create `/etc/httpd.conf` as a privileged user with the







|







106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
user who will push to, pull from, and create repositories.

```console
   $ doas chown -R user:www /var/www/htdocs/fsl.domain.tld
   $ doas chmod 770 /var/www/htdocs/fsl.domain.tld
```

## <a id="httpdconfig"></a>Configure httpd

On OpenBSD, [httpd.conf(5)][httpd] is the configuration file for
`httpd`. To setup the server to serve all Fossil repositores within the
directory specified in the CGI script, and automatically redirect
standard HTTP requests to HTTPS—apart from [Let's Encrypt][LE]
challenges issued in response to [acme-client(1)][acme] certificate
requests—create `/etc/httpd.conf` as a privileged user with the
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190

**NOTE:** If not already in possession of a HTTPS certificate, comment
out the `https` server block and proceed to securing a free
[Let's Encrypt Certificate](#letsencrypt); otherwise skip to
[Start `httpd`](#starthttpd).


## <a name="letsencrypt"></a>Let's Encrypt Certificate

In order for `httpd` to serve HTTPS, secure a free certificate from
Let's Encrypt using `acme-client`. Before issuing the request, however,
ensure you have a zone record for the subdomain with your registrar or
nameserver. Then open `/etc/acme-client.conf` as a privileged user to
configure the request.








|







176
177
178
179
180
181
182
183
184
185
186
187
188
189
190

**NOTE:** If not already in possession of a HTTPS certificate, comment
out the `https` server block and proceed to securing a free
[Let's Encrypt Certificate](#letsencrypt); otherwise skip to
[Start `httpd`](#starthttpd).


## <a id="letsencrypt"></a>Let's Encrypt Certificate

In order for `httpd` to serve HTTPS, secure a free certificate from
Let's Encrypt using `acme-client`. Before issuing the request, however,
ensure you have a zone record for the subdomain with your registrar or
nameserver. Then open `/etc/acme-client.conf` as a privileged user to
configure the request.

237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
   /etc/ssl/private:
   -r--------  1 root  wheel   3.2K Mar  2 01:31:03 2018 domain.tld.key
```

Make sure to reopen `/etc/httpd.conf` to uncomment the second server
block responsible for serving HTTPS requests before proceeding.

## <a name="starthttpd"></a>Start `httpd`

With `httpd` configured to serve Fossil repositories out of
`/var/www/htdocs/fsl.domain.tld`, and the certificates and key in place,
enable and start `slowcgi`—OpenBSD's FastCGI wrapper server that will
execute the above Fossil CGI script—before checking that the syntax of
the `httpd.conf` configuration file is correct, and (re)starting the
server (if still running from requesting a Let's Encrypt certificate).

```console
    $ doas rcctl enable slowcgi
    $ doas rcctl start slowcgi
    slowcgi(ok)
    $ doas httpd -vnf /etc/httpd.conf
    configuration OK
    $ doas rcctl start httpd
    httpd(ok)
```

## <a name="clientconfig"></a>Configure Client

To facilitate creating new repositories and pushing them to the server,
add the following function to your `~/.cshrc` or `~/.zprofile` or the
config file for whichever shell you are using on your development box.

```sh
    finit() {







|


















|







237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
   /etc/ssl/private:
   -r--------  1 root  wheel   3.2K Mar  2 01:31:03 2018 domain.tld.key
```

Make sure to reopen `/etc/httpd.conf` to uncomment the second server
block responsible for serving HTTPS requests before proceeding.

## <a id="starthttpd"></a>Start `httpd`

With `httpd` configured to serve Fossil repositories out of
`/var/www/htdocs/fsl.domain.tld`, and the certificates and key in place,
enable and start `slowcgi`—OpenBSD's FastCGI wrapper server that will
execute the above Fossil CGI script—before checking that the syntax of
the `httpd.conf` configuration file is correct, and (re)starting the
server (if still running from requesting a Let's Encrypt certificate).

```console
    $ doas rcctl enable slowcgi
    $ doas rcctl start slowcgi
    slowcgi(ok)
    $ doas httpd -vnf /etc/httpd.conf
    configuration OK
    $ doas rcctl start httpd
    httpd(ok)
```

## <a id="clientconfig"></a>Configure Client

To facilitate creating new repositories and pushing them to the server,
add the following function to your `~/.cshrc` or `~/.zprofile` or the
config file for whichever shell you are using on your development box.

```sh
    finit() {
Changes to www/server/windows/iis.md.
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
instructions](../any/none.md) for further details.

For a more robust setup, we recommend that you [install Fossil as a
Windows service](./service.md), which will allow Fossil to start at
system boot, before anyone has logged in interactively.


## <a name="install"></a>Install IIS

IIS might not be installed in your system yet, so follow the path
appropriate to your host OS.  We’ve tested only the latest Microsoft
OSes as of the time of this writing, but the basic process should be
similar on older OSes.









|







41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
instructions](../any/none.md) for further details.

For a more robust setup, we recommend that you [install Fossil as a
Windows service](./service.md), which will allow Fossil to start at
system boot, before anyone has logged in interactively.


## <a id="install"></a>Install IIS

IIS might not be installed in your system yet, so follow the path
appropriate to your host OS.  We’ve tested only the latest Microsoft
OSes as of the time of this writing, but the basic process should be
similar on older OSes.


Changes to www/server/windows/service.md.
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
If you wish to server a directory of repositories, the `fossil winsrv` command
requires a slightly different set of options vs. `fossil server`:

```
fossil winsrv create --repository D:/Path/to/Repos --repolist
```

<a name='PowerShell'></a>
### Advanced service installation using PowerShell

As great as `fossil winsrv` is, it does not have one to one reflection of all of
the `fossil server` [options](/help?cmd=server).  When you need to use some of
the more advanced options, such as `--https`, `--skin`, or `--extroot`, you will
need to use PowerShell to configure and install the Windows service.

PowerShell provides the [New-Service](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/new-service?view=powershell-5.1)







|
|







44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
If you wish to server a directory of repositories, the `fossil winsrv` command
requires a slightly different set of options vs. `fossil server`:

```
fossil winsrv create --repository D:/Path/to/Repos --repolist
```


### <a id='PowerShell'></a>Advanced service installation using PowerShell

As great as `fossil winsrv` is, it does not have one to one reflection of all of
the `fossil server` [options](/help?cmd=server).  When you need to use some of
the more advanced options, such as `--https`, `--skin`, or `--extroot`, you will
need to use PowerShell to configure and install the Windows service.

PowerShell provides the [New-Service](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/new-service?view=powershell-5.1)
Changes to www/server/windows/stunnel.md.
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119

Get-ChildItem Cert:\LocalMachine\My | Where{$_.FriendlyName -eq "FriendlyName"} |
Export-PfxCertificate -FilePath fossil-scm.pfx -Password $passwd
```

You will now have your certificate stored as a PFX file.

<a name="convert"></a>
### Convert Certificate from PFX to PEM

For this step you will need the openssl tools that were installed with stunnel.

```PowerShell
# Add stunnel\bin directory to path for this session.
$env:PATH += ";${env:ProgramFiles(x86)}\stunnel\bin"







|







105
106
107
108
109
110
111
112
113
114
115
116
117
118
119

Get-ChildItem Cert:\LocalMachine\My | Where{$_.FriendlyName -eq "FriendlyName"} |
Export-PfxCertificate -FilePath fossil-scm.pfx -Password $passwd
```

You will now have your certificate stored as a PFX file.

<a id="convert"></a>
### Convert Certificate from PFX to PEM

For this step you will need the openssl tools that were installed with stunnel.

```PowerShell
# Add stunnel\bin directory to path for this session.
$env:PATH += ";${env:ProgramFiles(x86)}\stunnel\bin"
Changes to www/sync.wiki.
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
some local state is transferred during a [/help?cmd=clone|clone]
in order to initialize the local state of the new repository.  Also,
an administrator can sync local state using
the [/help?cmd=configuration|config push] and
[/help?cmd=configuration|config pull]
commands.

<a name="crdt"></a>
<h3>1.1 Conflict-Free Replicated Datatypes</h3>

<p>The "bag of artifacts" data model used by Fossil
Fossil is apparently an implementation of a particular 
[https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type|Conflict-Free Replicated
Datatype (CRDT)]
called a "G-Set" or "Grow-only Set".
The academic literature on CRDTs only began to appear in about 2011, and







<
|







28
29
30
31
32
33
34

35
36
37
38
39
40
41
42
some local state is transferred during a [/help?cmd=clone|clone]
in order to initialize the local state of the new repository.  Also,
an administrator can sync local state using
the [/help?cmd=configuration|config push] and
[/help?cmd=configuration|config pull]
commands.


<h3 id="crdt">1.1 Conflict-Free Replicated Datatypes</h3>

<p>The "bag of artifacts" data model used by Fossil
Fossil is apparently an implementation of a particular 
[https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type|Conflict-Free Replicated
Datatype (CRDT)]
called a "G-Set" or "Grow-only Set".
The academic literature on CRDTs only began to appear in about 2011, and
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
the client because the client login lacks the "write-unversioned"
permission.</p>

<li><p><b>uv-push-ok</b></i>
<p>A server sends the uv-push-ok pragma to the client in response
to a uv-hash pragma with a mismatched content hash argument.  This
pragma indicates that there are differences in unversioned content
between the client and server and that content can only be transferred
in either direction.  The server is willing to accept content from
the client because the client login has the "write-unversioned"
permission.</p>

<li><p><b>ci-lock</b> <i>CHECKIN-HASH CLIENT-ID</i></p>
<p>A client sends the "ci-lock" pragma to the server to indicate
that it is about to add a new check-in as a child of the
CHECKIN-HASH check-in and on the same branch as CHECKIN-HASH.
If some other client has already indicated that it was also
trying to commit against CHECKIN-HASH, that indicates that a
fork is about to occur, and the server will reply with
a "ci-lock-fail" pragma (see below).  Check-in locks
automatically expire when the check-in actually occurs, or
after a timeout (currently 24-hours but subject to change).

<li><p><b>ci-lock-fail</b> <i>LOGIN MTIME</i></p>
<p>When a server receives two or more "ci-lock" pragma messages
for the same check-in but from different clients, the second a
subsequent ci-lock will provoke a ci-lock-fail pragma in the
reply to let the client know that it if continues with the
check-in it will likely generate a fork.  The LOGIN and MTIME







|













|







702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
the client because the client login lacks the "write-unversioned"
permission.</p>

<li><p><b>uv-push-ok</b></i>
<p>A server sends the uv-push-ok pragma to the client in response
to a uv-hash pragma with a mismatched content hash argument.  This
pragma indicates that there are differences in unversioned content
between the client and server and that content can be transferred
in either direction.  The server is willing to accept content from
the client because the client login has the "write-unversioned"
permission.</p>

<li><p><b>ci-lock</b> <i>CHECKIN-HASH CLIENT-ID</i></p>
<p>A client sends the "ci-lock" pragma to the server to indicate
that it is about to add a new check-in as a child of the
CHECKIN-HASH check-in and on the same branch as CHECKIN-HASH.
If some other client has already indicated that it was also
trying to commit against CHECKIN-HASH, that indicates that a
fork is about to occur, and the server will reply with
a "ci-lock-fail" pragma (see below).  Check-in locks
automatically expire when the check-in actually occurs, or
after a timeout (currently one minute but subject to change).

<li><p><b>ci-lock-fail</b> <i>LOGIN MTIME</i></p>
<p>When a server receives two or more "ci-lock" pragma messages
for the same check-in but from different clients, the second a
subsequent ci-lock will provoke a ci-lock-fail pragma in the
reply to let the client know that it if continues with the
check-in it will likely generate a fork.  The LOGIN and MTIME
Changes to www/tech_overview.wiki.
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
<li>The "[/help/stash | stash]"
<li>Information needed to "[/help/undo|undo]" or "[/help/redo|redo]"
</ul>
</td>
</tr>
</table>

<a name='configdb'></a>
<h3>2.1 The Configuration Database</h3>

The configuration database holds cross-repository preferences and a list of all
repositories for a single user.

The [/help/settings | fossil settings] command can be used to specify various
operating parameters and preferences for Fossil repositories.  Settings can
apply to a single repository, or they can apply globally to all repositories
for a user.  If both a global and a repository value exists for a setting,
then the repository-specific value takes precedence.  All of the settings
have reasonable defaults, and so many users will never need to change them.
But if changes to settings are desired, the configuration database provides
a way to change settings for all repositories with a single command, rather
than having to change the setting individually on each repository.

The configuration database also maintains a list of repositories.  This
list is used by the [/help/all | fossil all] command in order to run various
operations such as "sync" or "rebuild" on all repositories managed by a user.

<a name='configloc'></a>
<h4>2.1.1 Location Of The Configuration Database</h4>

On Unix systems, the configuration database is named by the following
algorithm:

<blockquote><table border="0">
<tr><td>1. if environment variable FOSSIL_HOME exists
<td>&nbsp;&rarr;&nbsp;<td>$FOSSIL_HOME/.fossil







<
|


















<
|







103
104
105
106
107
108
109

110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128

129
130
131
132
133
134
135
136
<li>The "[/help/stash | stash]"
<li>Information needed to "[/help/undo|undo]" or "[/help/redo|redo]"
</ul>
</td>
</tr>
</table>


<h3 id="configdb">2.1 The Configuration Database</h3>

The configuration database holds cross-repository preferences and a list of all
repositories for a single user.

The [/help/settings | fossil settings] command can be used to specify various
operating parameters and preferences for Fossil repositories.  Settings can
apply to a single repository, or they can apply globally to all repositories
for a user.  If both a global and a repository value exists for a setting,
then the repository-specific value takes precedence.  All of the settings
have reasonable defaults, and so many users will never need to change them.
But if changes to settings are desired, the configuration database provides
a way to change settings for all repositories with a single command, rather
than having to change the setting individually on each repository.

The configuration database also maintains a list of repositories.  This
list is used by the [/help/all | fossil all] command in order to run various
operations such as "sync" or "rebuild" on all repositories managed by a user.


<h4 id="configloc">2.1.1 Location Of The Configuration Database</h4>

On Unix systems, the configuration database is named by the following
algorithm:

<blockquote><table border="0">
<tr><td>1. if environment variable FOSSIL_HOME exists
<td>&nbsp;&rarr;&nbsp;<td>$FOSSIL_HOME/.fossil
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
The "shun" table in the repository database records the hash values for
all shunned artifacts.

The shun table can be pushed or pulled using
the [/help/config | fossil config] command with the "shun" AREA argument.
The shun table is also copied during a [/help/clone | clone].

<a name='localdb'></a>
<h3>2.3 Checkout Databases</h3>

Fossil allows a single repository
to have multiple working checkouts.  Each working checkout has a single
database in its root directory that records the state of that checkout.
The checkout database is named "_FOSSIL_" or ".fslckout".
The checkout database records information such as the following:








<
|







325
326
327
328
329
330
331

332
333
334
335
336
337
338
339
The "shun" table in the repository database records the hash values for
all shunned artifacts.

The shun table can be pushed or pulled using
the [/help/config | fossil config] command with the "shun" AREA argument.
The shun table is also copied during a [/help/clone | clone].


<h3 id="localdb">2.3 Checkout Databases</h3>

Fossil allows a single repository
to have multiple working checkouts.  Each working checkout has a single
database in its root directory that records the state of that checkout.
The checkout database is named "_FOSSIL_" or ".fslckout".
The checkout database records information such as the following:

Changes to www/th1-hooks.md.
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
TH1 Hook Related Variables for Web Pages
----------------------------------------

  *  web\_name -- _Name of web page being rendered._
  *  web\_args -- _Current web page arguments._
  *  web\_flags -- _Bitmask of CMDFLAG values for the web page being rendered._

<a name="cmdReturnCodes"></a>TH1 Hook Related Return Codes for Commands
-----------------------------------------------------------------------

  *  TH\_OK -- _Command will be executed, notification will be executed._
  *  TH\_ERROR -- _Command will be skipped, notification will be skipped,
                  error message will be emitted._
  *  TH\_BREAK -- _Command will be skipped, notification will be skipped._
  *  TH\_RETURN -- _Command will be executed, notification will be skipped._
  *  TH\_CONTINUE -- _Command will be skipped, notification will be executed._

For commands that are not included in the Fossil binary, allowing their
execution will cause the standard "unknown command" error message to be
generated, which will typically exit the process.  Therefore, adding a
new command generally requires using the TH_CONTINUE return code.

<a name="webReturnCodes"></a>TH1 Hook Related Return Codes for Web Pages
------------------------------------------------------------------------

  *  TH\_OK -- _Web page will be rendered, notification will be executed._
  *  TH\_ERROR -- _Web page will be skipped, notification will be skipped,
                  error message will be emitted._
  *  TH\_BREAK -- _Web page will be skipped, notification will be skipped._
  *  TH\_RETURN -- _Web page will be rendered, notification will be skipped._
  *  TH\_CONTINUE -- _Web page will be skipped, notification will be executed._

For web pages that are not included in the Fossil binary, allowing their
rendering will cause the standard "Not Found" error message to be generated,
which will cause an HTTP 404 status code to be sent.  Therefore, adding a
new web page generally requires using the TH_CONTINUE return code.

<a name="triggerReturnCodes"></a>Triggering TH1 Return Codes from a Script
--------------------------------------------------------------------------

  *  TH\_OK -- _This is the default return code, nothing special needed._
  *  TH\_ERROR -- _Use the **error** command._
  *  TH\_BREAK -- _Use the **break** command._
  *  TH\_RETURN -- _Use the **return -code 5** command._
  *  TH\_CONTINUE -- _Use the **continue** command._

<a name="command_hook"></a>TH1 command_hook Procedure
-----------------------------------------------------

  *  command\_hook

This user-defined procedure, if present, is called just before the
execution of a command.  The name of the command being executed will
be stored in the "cmd\_name" global variable.  The arguments to the
command being executed will be stored in the "cmd\_args" global variable.
The associated CMDFLAG value will be stored in the "cmd\_flags" global
variable.  Before exiting, the procedure should trigger the return
<a href="#cmdReturnCodes">code</a> that corresponds to the desired action
to take next.

<a name="command_notify"></a>TH1 command_notify Procedure
---------------------------------------------------------

  *  command\_notify

This user-defined procedure, if present, is called just after the
execution of a command.  The name of the command being executed will
be stored in the "cmd\_name" global variable.  The arguments to the
command being executed will be stored in the "cmd\_args" global variable.
The associated CMDFLAG value will be stored in the "cmd\_flags" global
variable.  Before exiting, the procedure should trigger the return
<a href="#cmdReturnCodes">code</a> that corresponds to the desired action
to take next.

<a name="webpage_hook"></a>TH1 webpage_hook Procedure
-----------------------------------------------------

  *  webpage\_hook

This user-defined procedure, if present, is called just before the
rendering of a web page.  The name of the web page being rendered will
be stored in the "web\_name" global variable.  The arguments to the
web page being rendered will be stored in the "web\_args" global variable.
The associated CMDFLAG value will be stored in the "web\_flags" global
variable.  Before exiting, the procedure should trigger the return
<a href="#webReturnCodes">code</a> that corresponds to the desired action
to take next.

<a name="webpage_notify"></a>TH1 webpage_notify Procedure
---------------------------------------------------------

  *  webpage\_notify

This user-defined procedure, if present, is called just after the
rendering of a web page.  The name of the web page being rendered will
be stored in the "web\_name" global variable.  The arguments to the
web page being rendered will be stored in the "web\_args" global variable.
The associated CMDFLAG value will be stored in the "web\_flags" global
variable.  Before exiting, the procedure should trigger the return
<a href="#webReturnCodes">code</a> that corresponds to the desired action
to take next.







|














|














|








|













|













|













|












34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
TH1 Hook Related Variables for Web Pages
----------------------------------------

  *  web\_name -- _Name of web page being rendered._
  *  web\_args -- _Current web page arguments._
  *  web\_flags -- _Bitmask of CMDFLAG values for the web page being rendered._

<a id="cmdReturnCodes"></a>TH1 Hook Related Return Codes for Commands
-----------------------------------------------------------------------

  *  TH\_OK -- _Command will be executed, notification will be executed._
  *  TH\_ERROR -- _Command will be skipped, notification will be skipped,
                  error message will be emitted._
  *  TH\_BREAK -- _Command will be skipped, notification will be skipped._
  *  TH\_RETURN -- _Command will be executed, notification will be skipped._
  *  TH\_CONTINUE -- _Command will be skipped, notification will be executed._

For commands that are not included in the Fossil binary, allowing their
execution will cause the standard "unknown command" error message to be
generated, which will typically exit the process.  Therefore, adding a
new command generally requires using the TH_CONTINUE return code.

<a id="webReturnCodes"></a>TH1 Hook Related Return Codes for Web Pages
------------------------------------------------------------------------

  *  TH\_OK -- _Web page will be rendered, notification will be executed._
  *  TH\_ERROR -- _Web page will be skipped, notification will be skipped,
                  error message will be emitted._
  *  TH\_BREAK -- _Web page will be skipped, notification will be skipped._
  *  TH\_RETURN -- _Web page will be rendered, notification will be skipped._
  *  TH\_CONTINUE -- _Web page will be skipped, notification will be executed._

For web pages that are not included in the Fossil binary, allowing their
rendering will cause the standard "Not Found" error message to be generated,
which will cause an HTTP 404 status code to be sent.  Therefore, adding a
new web page generally requires using the TH_CONTINUE return code.

<a id="triggerReturnCodes"></a>Triggering TH1 Return Codes from a Script
--------------------------------------------------------------------------

  *  TH\_OK -- _This is the default return code, nothing special needed._
  *  TH\_ERROR -- _Use the **error** command._
  *  TH\_BREAK -- _Use the **break** command._
  *  TH\_RETURN -- _Use the **return -code 5** command._
  *  TH\_CONTINUE -- _Use the **continue** command._

<a id="command_hook"></a>TH1 command_hook Procedure
-----------------------------------------------------

  *  command\_hook

This user-defined procedure, if present, is called just before the
execution of a command.  The name of the command being executed will
be stored in the "cmd\_name" global variable.  The arguments to the
command being executed will be stored in the "cmd\_args" global variable.
The associated CMDFLAG value will be stored in the "cmd\_flags" global
variable.  Before exiting, the procedure should trigger the return
<a href="#cmdReturnCodes">code</a> that corresponds to the desired action
to take next.

<a id="command_notify"></a>TH1 command_notify Procedure
---------------------------------------------------------

  *  command\_notify

This user-defined procedure, if present, is called just after the
execution of a command.  The name of the command being executed will
be stored in the "cmd\_name" global variable.  The arguments to the
command being executed will be stored in the "cmd\_args" global variable.
The associated CMDFLAG value will be stored in the "cmd\_flags" global
variable.  Before exiting, the procedure should trigger the return
<a href="#cmdReturnCodes">code</a> that corresponds to the desired action
to take next.

<a id="webpage_hook"></a>TH1 webpage_hook Procedure
-----------------------------------------------------

  *  webpage\_hook

This user-defined procedure, if present, is called just before the
rendering of a web page.  The name of the web page being rendered will
be stored in the "web\_name" global variable.  The arguments to the
web page being rendered will be stored in the "web\_args" global variable.
The associated CMDFLAG value will be stored in the "web\_flags" global
variable.  Before exiting, the procedure should trigger the return
<a href="#webReturnCodes">code</a> that corresponds to the desired action
to take next.

<a id="webpage_notify"></a>TH1 webpage_notify Procedure
---------------------------------------------------------

  *  webpage\_notify

This user-defined procedure, if present, is called just after the
rendering of a web page.  The name of the web page being rendered will
be stored in the "web\_name" global variable.  The arguments to the
web page being rendered will be stored in the "web\_args" global variable.
The associated CMDFLAG value will be stored in the "web\_flags" global
variable.  Before exiting, the procedure should trigger the return
<a href="#webReturnCodes">code</a> that corresponds to the desired action
to take next.
Changes to www/whyusefossil.wiki.
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
     <li>Everyone always has the latest code
     <li>Failed disk-drives cause no loss of work
     <li>Avoid wasting time doing manual file copying
     <li>Avoid human errors during manual backups
     </ol>
  </ol>

<a name='definitions'></a>
<p><b>II. Definitions</b></p>

<ul>
<li><p><b>Project</b> &rarr;
  a collection of computer files that serve some common
  purpose.  Often the project is a software application and the
  individual files are source code together with makefiles, scripts, and
  "README.txt" files.  Other examples of projects include books or







<
|







35
36
37
38
39
40
41

42
43
44
45
46
47
48
49
     <li>Everyone always has the latest code
     <li>Failed disk-drives cause no loss of work
     <li>Avoid wasting time doing manual file copying
     <li>Avoid human errors during manual backups
     </ol>
  </ol>


<p id="definitions"><b>II. Definitions</b></p>

<ul>
<li><p><b>Project</b> &rarr;
  a collection of computer files that serve some common
  purpose.  Often the project is a software application and the
  individual files are source code together with makefiles, scripts, and
  "README.txt" files.  Other examples of projects include books or
Changes to www/wikitheory.wiki.
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
<h2>Bug-reports and check-in comments and Forum messages</h2>

The comments on check-ins and the text in the descriptions of bug reports
both use wiki formatting.  Exactly the same set of formatting rules apply.
There is never a need to learn one formatting language for documentation
and a different markup for bugs or for check-in comments.

<a name="assocwiki"></a>
<h2>Auxiliary notes attached to check-ins or branches</h2>

Stand-alone wiki pages with special names "branch/<i>BRANCHNAME</i>"
or "checkin/<i>HASH</i>" are associated with the corresponding
branch or check-in.  The wiki text appears in an "About" section of
timelines and info screens.  Examples:

   *  [/timeline?r=graph-test-branch] shows the text of the







<
|







63
64
65
66
67
68
69

70
71
72
73
74
75
76
77
<h2>Bug-reports and check-in comments and Forum messages</h2>

The comments on check-ins and the text in the descriptions of bug reports
both use wiki formatting.  Exactly the same set of formatting rules apply.
There is never a need to learn one formatting language for documentation
and a different markup for bugs or for check-in comments.


<h2 id="assocwiki">Auxiliary notes attached to check-ins or branches</h2>

Stand-alone wiki pages with special names "branch/<i>BRANCHNAME</i>"
or "checkin/<i>HASH</i>" are associated with the corresponding
branch or check-in.  The wiki text appears in an "About" section of
timelines and info screens.  Examples:

   *  [/timeline?r=graph-test-branch] shows the text of the