Tcl Source Code

Check-in [59daece720]
Login

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

Overview
Comment:Merge updates from trunk
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | ferrieux-nacl
Files: files | file ages | folders
SHA1: 59daece72047639570efab3bed8f4d7bb5568163
User & Date: ferrieux 2011-10-07 12:16:08
Context
2011-10-18
06:33
Update to new (incompatible, stabilized) ABI. Now requires Chrome 15 or above. check-in: d6b778727b user: ferrieux tags: ferrieux-nacl
2011-10-07
12:16
Merge updates from trunk check-in: 59daece720 user: ferrieux tags: ferrieux-nacl
12:01
Fix gcc warnings (discovered with latest mingw, based on gcc 4.6.1) check-in: 91a0a93dad user: jan.nijtmans tags: trunk
2011-05-16
09:09
* fixed problem with quoting in ::nacl::evall - failed on things that looked like strings check-in: 141843d0f4 user: colin tags: ferrieux-nacl
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to ChangeLog.



























































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































1
2
3
4
5
6
7
8
9
10
11
12


























































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































2011-04-04 Alexandre Ferrieux  <[email protected]>

	* nacl/...: New branch ferrieux-nacl : a port of Tcl to
	Google's Nacl (Native Client)


2011-04-03  Donal K. Fellows  <[email protected]>

	* generic/tclNamesp.c, generic/tclObj.c, generic/tclPathObj.c:
	* generic/tclPipe.c, generic/tclPkg.c, generic/tclProc.c:
	* generic/tclScan.c: More generation of error codes (namespace
	creation, path normalization, pipeline creation, package handling,
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>




<







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
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
2011-10-07  Jan Nijtmans  <[email protected]>

	* generic/tcl.h:        Fix gcc warnings (discovered with
	* generic/tclIORChan.c: latest mingw, based on gcc 4.6.1)

2011-10-06  Donal K. Fellows  <[email protected]>

	* generic/tclDictObj.c (TclDictWithInit, TclDictWithFinish):
	* generic/tclCompCmds.c (TclCompileDictWithCmd): Experimental
	compilation for the [dict with] subcommand, using parts factored out
	from the interpreted version of the command.

2011-10-05  Jan Nijtmans  <[email protected]>

	* win/tclWinInt.h:   Remove tclWinProcs, as it is no longer
	* win/tclWin32Dll.c: being used.

2011-10-03  Venkat Iyer <[email protected]>

	* library/tzdata/Africa/Dar_es_Salaam: Update to Olson's tzdata2011k
	* library/tzdata/Africa/Kampala
	* library/tzdata/Africa/Nairobi
	* library/tzdata/Asia/Gaza
	* library/tzdata/Europe/Kaliningrad
	* library/tzdata/Europe/Kiev
	* library/tzdata/Europe/Minsk
	* library/tzdata/Europe/Simferopol
	* library/tzdata/Europe/Uzhgorod
	* library/tzdata/Europe/Zaporozhye
	* library/tzdata/Pacific/Apia

2011-09-29  Donal K. Fellows  <[email protected]>

	* tools/tcltk-man2html.tcl, tools/tcltk-man2html-utils.tcl: More
	refactoring so that more of the utility code is decently out of the
	way. Adjusted the header-material generator so that version numbers
	are only included in locations where there is room.

2011-09-28  Jan Nijtmans  <[email protected]>

	* generic/tclOO.h:      [RFE 3010352]: make all TclOO API functions
	* generic/tclOODecls.h: MODULE_SCOPE
	* generic/tclOOIntDecls.h:

2011-09-27  Donal K. Fellows  <[email protected]>

	* generic/tclIndexObj.c (Tcl_ParseArgsObjv): [Bug 3413857]: Corrected
	the memory management for the code parsing arguments when returning
	"large" numbers of arguments. Also unbroke the TCL_ARGV_AUTO_REST
	macro in passing.

2011-09-26  Donal K. Fellows  <[email protected]>

	* generic/tclCmdAH.c (TclMakeFileCommandSafe): [Bug 3211758]: Also
	make the main [file] command hidden by default in safe interpreters,
	because that's what existing code expects. This will reduce the amount
	which the code breaks, but not necessarily eliminate it...

2011-09-23  Don Porter  <[email protected]>

	* generic/tclIORTrans.c: More revisions to get finalization of
	ReflectedTransforms correct, including adopting a "dead" field as
	was done in tclIORChan.c.

	* tests/thread.test:	Stop using the deprecated thread management
	commands of the tcltest package.  The test suite ought to provide
	these tools for itself.  They do not belong in a testing harness.

2011-09-22  Don Porter  <[email protected]>

	* generic/tclCmdIL.c:	Revise [info frame] so that it stops creating
	cycles in the iPtr->cmdFramePtr stack.

2011-09-22  Donal K. Fellows  <[email protected]>

	* doc/re_syntax.n: [Bug 2903743]: Add more magic so that we can do at
	least something sane on Solaris.
	* tools/tcltk-man2html-utils.tcl (process-text): Teach the HTML
	generator how to handle this magic.

2011-09-21  Don Porter  <[email protected]>

	* generic/tclThreadTest.c: Revise the thread exit handling of the
	[testthread] command so that it properly maintains the per-process
	data structures even when the thread exits for reasons other than
	the [testthread exit] command.

2011-09-21  Alexandre Ferrieux  <[email protected]>

	* unix/tclIO.c: [Bug 3412487]: Now short reads are allowed in
	synchronous fcopy, avoid mistaking them as nonblocking ones.

2011-09-21  Andreas Kupries  <[email protected]>

	* generic/tclIORTrans.c (ForwardOpToOwnerThread): Fixed the missing
	initialization of the 'dsti' field. Reported by Don Porter, on chat.

2011-09-20  Don Porter  <[email protected]>

	* generic/tclIORChan.c: Re-using the "interp" field to signal a dead
	channel (via NULL value) interfered with conditional cleanup tasks
	testing for "the right interp". Added a new field "dead" to perform
	the dead channel signalling task so the corrupted logic is avoided.

	* generic/tclIORTrans.c: Revised ReflectClose() and
	FreeReflectedTransform() so that we stop leaking ReflectedTransforms,
	yet free all Tcl_Obj values in the same thread that alloced them.

2011-09-19  Don Porter  <[email protected]>

	* tests/ioTrans.test:	Conversion from [testthread] to Thread package
	stops most memory leaks.

	* tests/thread.test:	Plug most memory leaks in thread.test.
	Constrain the rest to be skipped during `make valgrind'.  Tests using
	the [testthread cancel] testing command are leaky.  Corrections wait
	for either addition of [thread::cancel] to the Thread package, or
	improvements to the [testthread] testing command to make leak-free
	versions of these tests possible.

	* generic/tclIORChan.c:	Plug all memory leaks in ioCmd.test exposed
	* tests/ioCmd.test:	by `make valgrind'.
	* unix/Makefile.in:

2011-09-16  Jan Nijtmans  <[email protected]>

	IMPLEMENTATION OF TIP #388

	* doc/Tcl.n
	* doc/re_syntax.n
	* generic/regc_lex.c
	* generic/regcomp.c
	* generic/regcustom.h
	* generic/tcl.h
	* generic/tclParse.c
	* tests/reg.test
	* tests/utf.test

2011-09-16  Donal K. Fellows  <[email protected]>

	* generic/tclProc.c (ProcWrongNumArgs): [Bugs 3400658,3408830]:
	Corrected the handling of procedure error messages (found by TclOO).

2011-09-16  Jan Nijtmans  <[email protected]>

	* generic/tcl.h:        Don't change Tcl_UniChar type when
	* generic/regcustom.h:  TCL_UTF_MAX == 4 (not supported anyway)

2011-09-16  Donal K. Fellows  <[email protected]>

	* generic/tclProc.c (ProcWrongNumArgs): [Bugs 3400658,3408830]:
	Ensemble-like rewriting of error messages is complex, and TclOO (in
	combination with iTcl) hits the most tricky cases.

	* library/http/http.tcl (http::geturl): [Bug 3391977]: Ensure that the
	-headers option overrides the -type option (important because -type
	has a default that is not always appropriate, and the header must not
	be duplicated).

2011-09-15  Don Porter  <[email protected]>

	* generic/tclCompExpr.c: [Bug 3408408]: Partial improvement by sharing
	as literals the computed values of constant subexpressions when we can
	do so without incurring the cost of string rep generation.

2011-09-13  Don Porter  <[email protected]>

	* generic/tclUtil.c:	[Bug 3390638]: Workaround broken solaris
	studio cc optimizer.  Thanks to Wolfgang S. Kechel.

	* generic/tclDTrace.d:	[Bug 3405652]: Portability workaround for
	broken system DTrace support.  Thanks to Dagobert Michelson.

2011-09-12  Jan Nijtmans  <[email protected]>

	* win/tclWinPort.h: [Bug 3407070]: tclPosixStr.c won't build with
	EOVERFLOW==E2BIG

2011-09-11  Don Porter  <[email protected]>

	* tests/thread.test:	Convert [testthread] use to Thread package
	use in thread-6.1.  Eliminates a memory leak in `make valgrind`.

	* tests/socket.test:	[Bug 3390699]: Convert [testthread] use to
	Thread package use in socket_*-13.1.  Eliminates a memory leak in
	`make valgrind`.

2011-09-09  Don Porter  <[email protected]>

	* tests/chanio.test:	[Bug 3389733]: Convert [testthread] use to
	* tests/io.test:	Thread package use in *io-70.1.  Eliminates a
	memory leak in `make valgrind`.

2011-09-07  Don Porter  <[email protected]>

	* generic/tclCompExpr.c: [Bug 3401704]: Allow function names like
	* tests/parseExpr.test:	 influence(), nanobot(), and 99bottles() that
	have been parsed as missing operator syntax errors before with the
	form NUMBER + FUNCTION.
	***POTENTIAL INCOMPATIBILITY***

2011-09-06  Venkat Iyer <[email protected]>

	* library/tzdata/America/Goose_Bay: Update to Olson's tzdata2011i
	* library/tzdata/America/Metlakatla:
	* library/tzdata/America/Resolute:
	* library/tzdata/America/St_Johns:
	* library/tzdata/Europe/Kaliningrad:
	* library/tzdata/Pacific/Apia:
	* library/tzdata/Pacific/Honolulu:
	* library/tzdata/Africa/Juba: (new)

2011-09-06  Jan Nijtmans  <[email protected]>

	* generic/tcl.h:   [RFE 1711975]: Tcl_MainEx() (like Tk_MainEx())
	* generic/tclDecls.h
	* generic/tclMain.c

2011-09-02  Don Porter  <[email protected]>

	* tests/http.test:	Convert [testthread] use to Thread package use.
	Eliminates memory leak seen in `make valgrind`.

2011-09-01  Alexandre Ferrieux  <[email protected]>

	* unix/tclUnixSock.c: [Bug 3401422]: Cache script-level changes to the
	nonblocking flag of an async client socket in progress, and commit
	them on completion.

2011-09-01  Don Porter  <[email protected]>

	* generic/tclStrToD.c:	[Bug 3402540]: Corrections to TclParseNumber()
	* tests/binary.test:	to make it reject invalid Nan(Hex) strings.

	* tests/scan.test:	[scan Inf %g] is portable; remove constraint.

2011-08-30  Donal K. Fellows  <[email protected]>

	* generic/tclInterp.c (SlaveCommandLimitCmd, SlaveTimeLimitCmd):
	[Bug 3398794]: Ensure that low-level conditions in the limit API are
	enforced at the script level through errors, not a Tcl_Panic. This
	means that interpreters cannot read their own limits (writing already
	did not work).

2011-08-30  Reinhard Max  <[email protected]>

	* unix/tclUnixSock.c (TcpWatchProc): [Bug 3394732]: Put back the check
	for server sockets.

2011-08-29  Don Porter  <[email protected]>

	* generic/tclIORTrans.c: Leak of ReflectedTransformMap.

2011-08-27  Don Porter  <[email protected]>

	* generic/tclStringObj.c:  [RFE 3396731]: Revise the [string reverse]
	* tests/string.test:	implementation to operate on the representation
	that comes in, avoid conversion to other reps.

2011-08-23  Don Porter  <[email protected]>

	* generic/tclIORChan.c:	[Bug 3396948]: Leak of ReflectedChannelMap.

2011-08-19  Don Porter  <[email protected]>

	* generic/tclIORTrans.c: [Bugs 3393279, 3393280]: ReflectClose(.) is
	missing Tcl_EventuallyFree() calls at some of its exits.

	* generic/tclIO.c: [Bugs 3394654, 3393276]: Revise FlushChannel() to
	account for the possibility that the ChanWrite() call might recycle
	the buffer out from under us.

	* generic/tclIO.c: Preserve the chanPtr during FlushChannel so that
	channel drivers don't yank it away before we're done with it.

2011-08-19  Alexandre Ferrieux  <[email protected]>

	* generic/tclTest.c: [Bug 2981154]: async-4.3 segfault.
	* tests/async.test:  [Bug 1774689]: async-4.3 sometimes fails.

2011-08-18  Alexandre Ferrieux  <[email protected]>

	* generic/tclIO.c: [Bug 3096275]: Sync fcopy buffers input.

2011-08-18  Jan Nijtmans  <[email protected]>

	* generic/tclUniData.c: [Bug 3393714]: Overflow in toupper delta
	* tools/uniParse.tcl
	* tests/utf.test

2011-08-17  Alexandre Ferrieux  <[email protected]>

	* generic/tclIO.c:  [Bug 2946474]: Consistently resume backgrounded
	* tests/ioCmd.test: flushes+closes when exiting.

2011-08-17  Alexandre Ferrieux  <[email protected]>

	* doc/interp.n: Document TIP 378's one-way-ness.

2011-08-17  Don Porter  <[email protected]>

	* generic/tclGet.c: [Bug 3393150]: Overlooked free of intreps.
	(It matters for bignums!)

2011-08-16  Don Porter  <[email protected]>

	* generic/tclCompile.c: [Bug 3392070]: More complete prevention of
	Tcl_Obj reference cycles when producing an intrep of ByteCode.

2011-08-16  Donal K. Fellows  <[email protected]>

	* generic/tclListObj.c (TclLindexList, TclLsetFlat): Silence warnings
	about (unreachable) cases of uninitialized variables.
	* generic/tclCmdIL.c (SelectObjFromSublist): Improve the generation of
	* generic/tclIndexObj.c (Tcl_ParseArgsObjv): messages through the use
	* generic/tclVar.c (ArrayStartSearchCmd):    of Tcl_ObjPrintf.

2011-08-15  Don Porter  <[email protected]>

	* generic/tclBasic.c: [Bug 3390272]: Leak of [info script] value.

2011-08-15  Jan Nijtmans  <[email protected]>

	* generic/tclPosixStr.c:    [Bug 3388350]: mingw64 compiler warnings
	* win/tclWinPort.h:
	* win/configure.in
	* win/configure

2011-08-14  Jan Nijtmans  <[email protected]>

	* doc/FindExec.3: [Patch 3124554]: Move WishPanic from Tk to Tcl
	* doc/Panic.3     Added Documentation

2011-08-12  Don Porter  <[email protected]>

	* generic/tclPathObj.c:	[Bug 3389764]: Eliminate possibility that dup
	of a "path" value can create reference cycle.

2011-08-12  Donal K. Fellows  <[email protected]>

	* generic/tclZlib.c (ZlibTransformOutput): [Bug 3390073]: Return the
	correct length of written data for a compressing transform.

2011-08-10 Alexandre Ferrieux  <[email protected]>

	* generic/tclTestObj.c: [Bug 3386721]: Allow multiple [load]ing of the
	Tcltest package.

2011-08-09 Alexandre Ferrieux  <[email protected]>

	* generic/tclBasic.c: [Bug 2919042]: Restore "valgrindability" of Tcl
	* generic/tclEvent.c: that was lost by the streamlining of [exit], by
	* generic/tclExecute.c: conditionally forcing a full Finalize:
	* generic/tclInt.h:  use -DPURIFY or ::env(TCL_FINALIZE_ON_EXIT)

2011-08-09 Alexandre Ferrieux  <[email protected]>

	* generic/tclCompCmds.c: [Bug 3386417]: Avoid a reference loop between
	* generic/tclInt.h:      the bytecode and its companion errostack
	* generic/tclResult.c:   when compiling a syntax error.

2011-08-09  Jan Nijtmans  <[email protected]>

	* win/tclWinConsole.c: [Bug 3388350]: mingw64 compiler warnings
	* win/tclWinDde.c
	* win/tclWinPipe.c
	* win/tclWinSerial.c

2011-08-09  Jan Nijtmans  <[email protected]>

	* generic/tclInt.h: Change the signature of TclParseHex(), such that
	* generic/tclParse.c: it can now parse up to 8 hex characters.

2011-08-08  Donal K. Fellows  <[email protected]>

	* generic/tclZlib.c (ZlibStreamCmd): Make the -buffersize option to
	'$zstream add' function correctly instead of having its value just be
	discarded unceremoniously. Also generate error codes from more of the
	code, not just the low-level code but also the Tcl infrastructure.

2011-08-07  Donal K. Fellows  <[email protected]>

	* generic/tclOOInfo.c (InfoClassCallCmd): [Bug 3387082]: Plug memory
	leak in call chain introspection.

2011-08-06  Kevin B, Kenny  <[email protected]>

	* generic/tclAssemnbly.c: [Bug 3384840]: Plug another memory leak.
	* generic/tclStrToD.c: [Bug 3386975]: Plug another memory leak.

2011-08-05  Kevin B. Kenny  <[email protected]>

	* generic/tclStrToD.c: [Bug 3386975]: Plugged a memory leak in
	double->string conversion.

2011-08-05  Don Porter  <[email protected]>

	*** 8.6b2 TAGGED FOR RELEASE ***

	* changes:	Updates for 8.6b2 release.

2011-08-05  Donal K. Fellows  <[email protected]>

	* generic/tclAssembly.c (AssembleOneLine): Ensure that memory isn't
	leaked when an unknown instruction is encountered. Also simplify code
	through use of Tcl_ObjPrintf in error message generation.

	* generic/tclZlib.c (ZlibTransformClose): [Bug 3386197]: Plug a memory
	leak found by Miguel with valgrind, and ensure that the correct
	direction's buffers are released.

2011-08-04  Miguel Sofer  <[email protected]>

	* generic/tclVar.c (TclPtrSetVar): Fix valgrind-detected error when
	newValuePtr is the interp's result obj.

2011-08-04  Donal K. Fellows  <[email protected]>

	* generic/tclAssembly.c (FreeAssemblyEnv): [Bug 3384840]: Plug another
	possible memory leak due to over-complex code for freeing the table of
	labels.

2011-08-04  Reinhard Max  <[email protected]>

	* generic/tclIOSock.c (TclCreateSocketAddress): Don't bother using
	AI_ADDRCONFIG for now, as it was causing problems in various
	situations.

2011-08-04  Donal K. Fellows  <[email protected]>

	* generic/tclAssembly.c (AssembleOneLine, GetBooleanOperand)
	(GetIntegerOperand, GetListIndexOperand, FindLocalVar): [Bug 3384840]:
	A Tcl_Obj is allocated by GetNextOperand, so callers of it must not
	hold a reference to one in the 'out' parameter when calling it. This
	was causing a great many memory leaks.
	* tests/assemble.test (assemble-51.*): Added group of memory leak
	tests.

2011-08-02  Don Porter  <[email protected]>

	* changes:	Updates for 8.6b2 release.
	* tools/tcltk-man2html.tcl: Variable substitution botch.

2011-08-02  Donal K. Fellows  <[email protected]>

	* generic/tclObj.c (Tcl_DbIncrRefCount, Tcl_DbDecrRefCount)
	(Tcl_DbIsShared): [Bug 3384007]: Fix the panic messages so they share
	what should be shared and have the right number of spaces.

2011-08-01  Miguel Sofer  <[email protected]>

	* generic/tclProc.c (TclProcCompileProc): [Bug 3383616]: Fix for leak
	of resolveInfo when recompiling procs. Thanks go to Gustaf Neumann for
	detecting the bug and providing the fix.

2011-08-01  Donal K. Fellows  <[email protected]>

	* doc/tclvars.n (EXAMPLES): Added some examples of how some of the
	standard global variables can be used, following prompting by a
	request by Robert Hicks.

	* tools/tcltk-man2html.tcl (plus-pkgs): [Bug 3382474]: Added code to
	determine the version number of contributed packages from their
	directory names so that HTML documentation builds are less confusing.

2011-07-29  Donal K. Fellows  <[email protected]>

	* tools/tcltk-man2html.tcl (ensemble_commands, remap_link_target):
	Small enhancements to improve cross-linking with contributed packages.
	* tools/tcltk-man2html-utils.tcl (insert-cross-references): Enhance to
	cope with contributed packages' C API.

2011-07-28  Reinhard Max  <[email protected]>

	* unix/tcl.m4 (SC_TCL_IPV6): Fix AC_DEFINE invocation for
	NEED_FAKE_RFC2553.
	* unix/configure:	autoconf-2.59

2011-07-28  Don Porter  <[email protected]>

	* changes:	Updates for 8.6b2 release.

	* library/tzdata/Asia/Anadyr: Update to Olson's tzdata2011h
	* library/tzdata/Asia/Irkutsk:
	* library/tzdata/Asia/Kamchatka:
	* library/tzdata/Asia/Krasnoyarsk:
	* library/tzdata/Asia/Magadan:
	* library/tzdata/Asia/Novokuznetsk:
	* library/tzdata/Asia/Novosibirsk:
	* library/tzdata/Asia/Omsk:
	* library/tzdata/Asia/Sakhalin:
	* library/tzdata/Asia/Vladivostok:
	* library/tzdata/Asia/Yakutsk:
	* library/tzdata/Asia/Yekaterinburg:
	* library/tzdata/Europe/Kaliningrad:
	* library/tzdata/Europe/Moscow:
	* library/tzdata/Europe/Samara:
	* library/tzdata/Europe/Volgograd:
	* library/tzdata/America/Kralendijk: (new)
	* library/tzdata/America/Lower_Princes: (new)

2011-07-26  Donal K. Fellows  <[email protected]>

	* generic/tclOO.c (initScript): Ensure that TclOO is properly found by
	all the various package mechanisms (by adding a dummy ifneeded script)
	and not just some of them.

2011-07-21  Jan Nijtmans  <[email protected]>

	* win/tclWinPort.h: [Bug 3372130]: Fix hypot math function with MSVC10

2011-07-19  Don Porter  <[email protected]>

	* generic/tclUtil.c:	[Bug 3371644]: Repair failure to properly handle
	* tests/util.test: (length == -1) scanning in TclConvertElement().
	Thanks to Thomas Sader and Alexandre Ferrieux.

2011-07-19  Donal K. Fellows  <[email protected]>

	* doc/*.3, doc/*.n: Many small fixes to documentation as part of
	project to improve quality of generated HTML docs.

	* tools/tcltk-man2html.tcl (remap_link_target): More complete set of
	definitions of link targets, especially for major C API types.
	* tools/tcltk-man2html-utils.tcl (output-IP-list, cross-reference):
	Update to generation to produce proper HTML bulleted and enumerated
	lists.

2011-07-19 Alexandre Ferrieux  <[email protected]>

	* doc/upvar.n: Undocument long gone limitation of [upvar].

2011-07-18  Don Porter  <[email protected]>

	* generic/tcl.h:	Bump version number to 8.6b2.
	* library/init.tcl:
	* unix/configure.in:
	* win/configure.in:
	* unix/tcl.spec:
	* tools/tcl.wse.in:
	* README:

	* unix/configure:	autoconf-2.59
	* win/configure:

2011-07-15  Don Porter  <[email protected]>

	* generic/tclCompile.c: Avoid segfaults when RecordByteCodeStats()
	is called in a deleted interp.

	* generic/tclCompile.c:	[Bug 467523, 3357771]: Prevent circular
	references in values with ByteCode intreps.  They can lead to
	memory leaks.

2011-07-14  Donal K. Fellows  <[email protected]>

	* generic/tclOOCall.c (TclOORenderCallChain): [Bug 3365156]: Remove
	stray refcount bump that caused a memory leak.

2011-07-12  Don Porter  <[email protected]>

	* generic/tclUnixSock.c:  [Bug 3364777]: Stop segfault caused by
	reading from struct after it had been freed.

2011-07-11  Joe Mistachkin  <[email protected]>

	* generic/tclExecute.c: [Bug 3339502]: Correct cast for CURR_DEPTH to
	silence compiler warning.

2011-07-08  Donal K. Fellows  <[email protected]>

	* doc/http.n: [FRQ 3358415]: State what RFC defines HTTP/1.1.

2011-07-07  Miguel Sofer  <[email protected]>

	* generic/tclBasic.c: Add missing INT2PTR

2011-07-03  Donal K. Fellows  <[email protected]>

	* doc/FileSystem.3: Corrected statements about ctime field of 'struct
	stat'; that was always the time of the last metadata change, not the
	time of creation.

2011-07-02  Kevin B. Kenny  <[email protected]>

	* generic/tclStrToD.c:
	* generic/tclTomMath.decls:
	* generic/tclTomMathDecls.h:
	* macosx/Tcl.xcode/project.pbxproj:
	* macosx/Tcl.xcodeproj/project.pbxproj:
	* tests/util.test:
	* unix/Makefile.in:
	* win/Makefile.in:
	* win/Makefile.vc:
	[Bug 3349507]: Fix a bug where bignum->double conversion is "round up"
	and not "round to nearest" (causing expr double(1[string repeat 0 23])
	not to be 1e+23).

2011-06-28  Reinhard Max  <[email protected]>

	* unix/tclUnixSock.c (CreateClientSocket): [Bug 3325339]: Fix and
	simplify posting of the writable fileevent at the end of an
	asynchronous connection attempt. Improve comments for some of the
	trickery around [socket -async].

	* tests/socket.test: Adjust tests to the async code changes. Add
	more tests for corner cases of async sockets.

2011-06-22  Andreas Kupries  <[email protected]>

	* library/platform/pkgIndex.tcl: Updated to platform 1.0.10. Added
	* library/platform/platform.tcl: handling of the DEB_HOST_MULTIARCH
	* unix/Makefile.in: location change for libc.
	* win/Makefile.in:

	* generic/tclInt.h: Fixed the inadvertently committed disabling of
	  stack checks, see my 2010-11-15 commit.

2011-06-22  Reinhard Max  <[email protected]>

	Merge from rmax-ipv6-branch:
	* unix/tclUnixSock.c: Fix [socket -async], so that all addresses
	returned by getaddrinfo() are tried, not just the first one. This
	requires the event loop to be running while the async connection
	is in progress. ***POTENTIAL INCOMPATIBILITY***
	* tests/socket.test: Add a test for the above.
	* doc/socket: Document the fact that -async needs the event loop
	* generic/tclIOSock.c: AI_ADDRCONFIG is broken on HP-UX

2011-06-21  Don Porter  <[email protected]>

	* generic/tclLink.c:	[Bug 3317466]: Prevent multiple links to a
	single Tcl variable when calling Tcl_LinkVar().

2011-06-13  Don Porter  <[email protected]>

	* generic/tclStrToD.c:  [Bug 3315098]: Mem leak fix from Gustaf Neumann.

2011-06-08  Andreas Kupries  <[email protected]>

	* generic/tclExecute.c: Reverted the fix for [Bug 3274728]
	committed on 2011-04-06 and replaced with one which is
	64bit-safe. The existing fix crashed tclsh on Windows 64bit.

2011-06-08  Donal K. Fellows  <[email protected]>

	* tests/fileSystem.test: Reduce the amount of use of duplication of
	complex code to perform common tests, and convert others to do the
	test result check directly using Tcltest's own primitives.

2011-06-06  Jan Nijtmans  <[email protected]>

	* tests/socket.test: Add test constraint, so 6.2 and 6.3 don't fail
	when the machine does not have support for ip6. Follow-up to checkin
	from 2011-05-11 by rmax.

2011-06-02  Don Porter  <[email protected]>

	* generic/tclBasic.c:	Removed TclCleanupLiteralTable(), and old
	* generic/tclInt.h:	band-aid routine put in place while a fix
	* generic/tclLiteral.c:	for [Bug 994838] took shape.  No longer needed.

2011-06-02  Donal K. Fellows  <[email protected]>

	* generic/tclInt.h (TclInvalidateNsCmdLookup): [Bug 3185407]: Extend
	the set of epochs that are potentially bumped when a command is
	created, for a slight performance drop (in some circumstances) and
	improved semantics.

2011-06-01  Miguel Sofer  <[email protected]>

	* generic/tclBasic.c: Using the two free data elements in NRCommand to
	store objc and objv - useful for debugging.

2011-06-01  Jan Nijtmans  <[email protected]>

	* generic/tclUtil.c:   Fix for [Bug 3309871]: Valgrind finds:
	invalid read in TclMaxListLength()

2011-05-31  Don Porter  <[email protected]>

	* generic/tclInt.h:	Use a complete growth algorithm for lists
	* generic/tclListObj.c:	so that length limits do not overconstrain
	* generic/tclStringObj.c:	by a factor of 2.  [Bug 3293874]:
	* generic/tclUtil.c:	Fix includes rooting all growth routines
	by default on a commone tunable parameter TCL_MIN_GROWTH.

2011-05-25  Don Porter  <[email protected]>

	* library/msgcat/msgcat.tcl:	Bump to msgcat 1.4.4.
	* library/msgcat/pkgIndex.tcl:
	* unix/Makefile.in
	* win/Makefile.in

2011-05-25  Donal K. Fellows  <[email protected]>

	* generic/tclOO.h (TCLOO_VERSION): Bump version.

	IMPLEMENTATION OF TIP#381.

	* doc/next.n, doc/ooInfo.n, doc/self.n, generic/tclOO.c,
	* generic/tclOOBasic.c, generic/tclOOCall.c, generic/tclOOInfo.c,
	* generic/tclOOInt.h, tests/oo.test, tests/ooNext2.test: Added
	introspection of call chains ([self call], [info object call], [info
	class call]) and ability to skip ahead in chain ([nextto]).

2011-05-24  Venkat Iyer <[email protected]>

	* library/tzdata/Africa/Cairo: Update to Olson tzdata2011g

2011-05-24  Donal K. Fellows  <[email protected]>

	* library/msgcat/msgcat.tcl (msgcat::mcset, msgcat::mcmset): Remove
	some useless code; [dict set] builds dictionary levels for us.

2011-05-17  Andreas Kupries  <[email protected]>

	* generic/tclCompile.c (TclFixupForwardJump): Tracked down and fixed
	* generic/tclBasic.c (TclArgumentBCEnter): the cause of a violation
	of my assertion that 'ePtr->nline == objc' in TclArgumentBCEnter.
	When a bytecode was grown during jump fixup the pc -> command line
	mapping was not updated. When things aligned just wrong the mapping
	would direct command A to the data for command B, with a different
	number of arguments.

2011-05-11  Reinhard Max  <[email protected]>

	* unix/tclUnixSock.c (TcpWatchProc): No need to check for server
	sockets here, as the generic server code already takes care of
	that.
	* tests/socket.test (accept): Add tests to make sure that this
	remains so.

2011-05-10  Don Porter  <[email protected]>

	* generic/tclInt.h:     New internal routines TclScanElement() and
	* generic/tclUtil.c:    TclConvertElement() are rewritten guts of
	machinery to produce string rep of lists.  The new routines avoid
	and correct [Bug 3173086].  See comments for much more detail.

	* generic/tclDictObj.c:         Update all callers.
	* generic/tclIndexObj.c:
	* generic/tclListObj.c:
	* generic/tclUtil.c:
	* tests/list.test:

2011-05-09  Donal K. Fellows  <[email protected]>

	* generic/tclNamesp.c (NamespacePathCmd): Convert to use Tcl_Obj API
	* generic/tclPkg.c (Tcl_PackageObjCmd):   for result generation in
	* generic/tclTimer.c (Tcl_AfterObjCmd):   [after info], [namespace
	path] and [package versions].

2011-05-09  Don Porter  <[email protected]>

	* generic/tclListObj.c:	Revise empty string tests so that we avoid
	potentially expensive string rep generations, especially for dicts.

2011-05-07  Donal K. Fellows  <[email protected]>

	* generic/tclLoad.c (TclGetLoadedPackages): Convert to use Tcl_Obj API
	for result generation.

2011-05-07  Miguel Sofer  <[email protected]>

	* generic/tclInt.h: fix USE_TCLALLOC so that it can be enabled
	* unix/Makefile.in: without editing the Makefile

2011-05-05  Don Porter  <[email protected]>

	* generic/tclListObj.c:	Stop generating string rep of dict when
	converting to list.  Tolerate NULL interps more completely.

2011-05-03  Don Porter  <[email protected]>

	* generic/tclUtil.c:	Tighten Tcl_SplitList().
	* generic/tclListObj.c:	Tighten SetListFromAny().
	* generic/tclDictObj.c:	Tighten SetDictFromAny().
	* tests/join.test:
	* tests/mathop.test:

2011-05-02  Don Porter  <[email protected]>

	* generic/tclCmdMZ.c:	Revised TclFindElement() interface.  The
	* generic/tclDictObj.c:	final argument had been bracePtr, the address
	* generic/tclListObj.c:	of a boolean var, where the caller can be told
	* generic/tclParse.c:	whether or not the parsed list element was
	* generic/tclUtil.c:	enclosed in braces.  In practice, no callers
	really care about that.  What the callers really want to know is
	whether the list element value exists as a literal substring of the
	string being parsed, or whether a call to TclCopyAndCollpase() is
	needed to produce the list element value.  Now the final argument
	is changed to do what callers actually need.  This is a better fit
	for the calls in tclParse.c, where now a good deal of post-processing
	checking for "naked backslashes" is no longer necessary.
	***POTENTIAL INCOMPATIBILITY***
	For any callers calling in via the internal stubs table who really
	do use the final argument explicitly to check for the enclosing brace
	scenario.  Simply looking for the braces where they must be is the
	revision available to those callers, and it will backport cleanly.

	* tests/parse.test:	Tests for expanded literals quoting detection.

	* generic/tclCompCmdsSZ.c:	New TclFindElement() is also a better
	fit for the [switch] compiler.

	* generic/tclInt.h:	Replace TclCountSpaceRuns() with
	* generic/tclListObj.c:	TclMaxListLength() which is the function we
	* generic/tclUtil.c:	actually want.
	* generic/tclCompCmdsSZ.c:

	* generic/tclCompCmdsSZ.c: Rewrite of parts of the switch compiler to
	better use the powers of TclFindElement() and do less parsing on
	its own.

2011-04-28  Don Porter  <[email protected]>

	* generic/tclInt.h:	New utility routines:
	* generic/tclParse.c:	TclIsSpaceProc() and
	* generic/tclUtil.c:	TclCountSpaceRuns()

	* generic/tclCmdMZ.c:	Use new routines to replace calls to
	* generic/tclListObj.c:	isspace() and their /* INTL */ risk.
	* generic/tclStrToD.c:
	* generic/tclUtf.c:
	* unix/tclUnixFile.c:

	* generic/tclStringObj.c:	Improved reaction to out of memory.

2011-04-27  Don Porter  <[email protected]>

	* generic/tclCmdMZ.c:	TclFreeIntRep() correction & cleanup.
	* generic/tclExecute.c:
	* generic/tclIndexObj.c:
	* generic/tclInt.h:
	* generic/tclListObj.c:
	* generic/tclNamesp.c:
	* generic/tclResult.c:
	* generic/tclStringObj.c:
	* generic/tclVar.c:

	* generic/tclListObj.c:	FreeListInternalRep() cleanup.

2011-04-21  Don Porter  <[email protected]>

	* generic/tclInt.h:	Use macro to set List intreps.
	* generic/tclListObj.c:

	* generic/tclCmdIL.c:	Limits on list length were too strict.
	* generic/tclInt.h:	Revised panics to errors where possible.
	* generic/tclListObj.c:
	* tests/lrepeat.test:

	* generic/tclCompile.c:	Make sure SetFooFromAny routines react
	* generic/tclIO.c:	reasonably when passed a NULL interp.
	* generic/tclIndexObj.c:
	* generic/tclListObj.c:
	* generic/tclNamesp.c:
	* generic/tclObj.c:
	* generic/tclProc.c:
	* macosx/tclMacOSXFCmd.c:

2011-04-21  Jan Nijtmans  <[email protected]>

	* generic/tcl.h:       fix for [Bug 3288345]: Wrong Tcl_StatBuf
	* generic/tclInt.h:    used on MinGW. Make sure that all _WIN32
	* win/tclWinFile.c:    compilers use exactly the same layout
	* win/configure.in:    for Tcl_StatBuf - the one used by MSVC6 -
	* win/configure:       in all situations.

2011-04-19  Don Porter  <[email protected]>

	* generic/tclConfig.c:	Reduce internals access in the implementation
	of [<foo>::pkgconfig list].

2011-04-18  Don Porter  <[email protected]>

	* generic/tclCmdIL.c:	Use ListRepPtr(.) and other cleanup.
	* generic/tclConfig.c:
	* generic/tclListObj.c:

	* generic/tclInt.h:	Define and use macros that test whether
	* generic/tclBasic.c:	a Tcl list value is canonical.
	* generic/tclUtil.c:

2011-04-18  Donal K. Fellows  <[email protected]>

	* doc/dict.n: [Bug 3288696]: Command summary was confusingly wrong
	when it came to [dict filter] with a 'value' filter.

2011-04-16  Donal K. Fellows  <[email protected]>

	* generic/tclFCmd.c (TclFileAttrsCmd): Add comments to make this code
	easier to understand. Added a panic to handle the case where the VFS
	layer does something odd.

2011-04-13  Don Porter  <[email protected]>

	* generic/tclUtil.c:	[Bug 3285375]: Rewrite of Tcl_Concat*()
	routines to prevent segfaults on buffer overflow.  Build them out of
	existing primitives already coded to handle overflow properly.  Uses
	the new TclTrim*() routines.

	* generic/tclCmdMZ.c:	New internal utility routines TclTrimLeft()
	* generic/tclInt.h:	and TclTrimRight().  Refactor the
	* generic/tclUtil.c:	[string trim*] implementations to use them.

2011-04-13  Miguel Sofer  <[email protected]>

	* generic/tclVar.c: [Bug 2662380]: Fix crash caused by appending to a
	variable with a write trace that unsets it.

2011-04-13  Donal K. Fellows  <[email protected]>

	* generic/tclUtil.c (Tcl_ConcatObj): [Bug 3285375]: Make the crash
	less mysterious through the judicious use of a panic. Not yet properly
	fixed, but at least now clearer what the failure mode is.

2011-04-12  Don Porter  <[email protected]>

	* tests/string.test:	Test for [Bug 3285472]. Not buggy in trunk.

2011-04-12  Venkat Iyer <[email protected]>

	* library/tzdata/Atlantic/Stanley: Update to Olson tzdata2011f

2011-04-12  Miguel Sofer  <[email protected]>

	* generic/tclBasic.c: Fix for [Bug 2440625], kbk's patch

2011-04-11  Miguel Sofer  <[email protected]>

	* generic/tclBasic.c:
	* tests/coroutine.test: [Bug 3282869]: Ensure that 'coroutine eval'
	runs the initial command in the proper context.

2011-04-11  Jan Nijtmans  <[email protected]>

	* generic/tcl.h:    Fix for [Bug 3281728]: Tcl sources from 2011-04-06
	* unix/tcl.m4:      do not build on GCC9 (RH9)
	* unix/configure:

2011-04-08  Jan Nijtmans  <[email protected]>

	* win/tclWinPort.h: Fix for [Bug 3280043]: win2k: unresolved DLL
	* win/configure.in: imports.
	* win/configure

2011-04-06  Miguel Sofer  <[email protected]>

	* generic/tclExecute.c (TclCompileObj): Earlier return if Tip280
	gymnastics not needed.

	* generic/tclExecute.c: Fix for [Bug 3274728]: making *catchTop an
	unsigned long.

2011-04-06  Jan Nijtmans  <[email protected]>

	* unix/tclAppInit.c:  Make symbols "main" and "Tcl_AppInit"
	MODULE_SCOPE: there is absolutely no reason for exporting them.
	* unix/tcl.m4:        Don't use -fvisibility=hidden with static
	* unix/configure      libraries (--disable-shared)

2011-04-06  Donal K. Fellows  <[email protected]>

	* generic/tclFCmd.c, macosx/tclMacOSXFCmd.c, unix/tclUnixChan.c,
	* unix/tclUnixFCmd.c, win/tclWinChan.c, win/tclWinDde.c,
	* win/tclWinFCmd.c, win/tclWinLoad.c, win/tclWinPipe.c,
	* win/tclWinReg.c, win/tclWinSerial.c, win/tclWinSock.c: More
	generation of error codes (most platform-specific parts not already
	using Tcl_PosixError).

2011-04-05  Venkat Iyer <[email protected]>

	* library/tzdata/Africa/Casablanca: Update to Olson's tzdata2011e
	* library/tzdata/America/Santiago:
	* library/tzdata/Pacific/Easter:
	* library/tzdata/America/Metlakatla: (new)
	* library/tzdata/America/North_Dakota/Beulah: (new)
	* library/tzdata/America/Sitka: (new)

2011-04-04  Donal K. Fellows  <[email protected]>

	* generic/tclOO.c, generic/tclOOBasic.c, generic/tclOODefineCmds.c
	* generic/tclOOInfo.c, generic/tclOOMethod.c: More generation of
	error codes (TclOO miscellany).

	* generic/tclCmdAH.c, generic/tclCmdIL.c: More generation of error
	codes (miscellaneous commands mostly already handled).

2011-04-04  Don Porter  <[email protected]>

	* README:	[Bug 3202030]: Updated README files, repairing broken
	* macosx/README:URLs and removing other bits that were clearly wrong.
	* unix/README:	Still could use more eyeballs on the detailed build
	* win/README:	advice on various plaforms.

2011-04-04  Donal K. Fellows  <[email protected]>

	* library/init.tcl (tcl::mathfunc::rmmadwiw): Disable by default to
	make test suite work.

	* generic/tclBasic.c, generic/tclStringObj.c, generic/tclTimer.c,
	* generic/tclTrace.c, generic/tclUtil.c: More generation of error
	codes ([format], [after], [trace], RE optimizer).

2011-04-04  Jan Nijtmans  <[email protected]>

	* generic/tclCmdAH.c:  Better error-message in case of errors
	* generic/tclCmdIL.c:  related to setting a variable. This fixes
	* generic/tclDictObj.c: a warning: "Why make your own error
	* generic/tclScan.c:   message? Why?"
	* generic/tclTest.c:
	* test/error.test:
	* test/info.test:
	* test/scan.test:
	* unix/tclUnixThrd.h:  Remove this unused header file.

2011-04-04 Alexandre Ferrieux  <[email protected]>

	* nacl/...: New branch ferrieux-nacl : a port of Tcl to
	Google's Nacl (Native Client)


2011-04-03  Donal K. Fellows  <[email protected]>

	* generic/tclNamesp.c, generic/tclObj.c, generic/tclPathObj.c:
	* generic/tclPipe.c, generic/tclPkg.c, generic/tclProc.c:
	* generic/tclScan.c: More generation of error codes (namespace
	creation, path normalization, pipeline creation, package handling,
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218

2011-03-09  Donal K. Fellows  <[email protected]>

	* tests/incr.test: Update more of the test suite to use Tcltest 2.

2011-03-09  Don Porter  <[email protected]>

	* generic/tclNamesp.c:	Tighten the detector of nested [namespace code]
	* tests/namespace.test:	quoting that the quoted scripts function
	properly even in a namespace that contains a custom "namespace"
	command.  [Bug 3202171]

	* doc/tclvars.n:	Formatting fix.  Thanks to Pat Thotys.

2011-03-09  Donal K. Fellows  <[email protected]>

	* tests/dstring.test, tests/init.test, tests/link.test: Update more of
	the test suite to use Tcltest 2.







|
|
|
|







1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235

2011-03-09  Donal K. Fellows  <[email protected]>

	* tests/incr.test: Update more of the test suite to use Tcltest 2.

2011-03-09  Don Porter  <[email protected]>

	* generic/tclNamesp.c:	[Bug 3202171]: Tighten the detector of nested
	* tests/namespace.test:	[namespace code] quoting that the quoted
	scripts function properly even in a namespace that contains a custom
	"namespace" command.

	* doc/tclvars.n:	Formatting fix.  Thanks to Pat Thotys.

2011-03-09  Donal K. Fellows  <[email protected]>

	* tests/dstring.test, tests/init.test, tests/link.test: Update more of
	the test suite to use Tcltest 2.
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
	and unsigned integer expressions

2011-03-08  Don Porter  <[email protected]>

	* generic/tclInt.h:	Remove TclMarkList() routine, an experimental
	* generic/tclUtil.c:	dead-end from the 8.5 alpha days.

	* generic/tclResult.c (ResetObjResult):	Correct failure to clear
	invalid intrep.  Thanks to Colin McDonald. [Bug 3202905]

2011-03-08  Donal K. Fellows  <[email protected]>

	* generic/tclAssembly.c, tests/assemble.test: Migrate to use a style
	more consistent with the rest of Tcl.

2011-03-06  Don Porter  <[email protected]>

	* generic/tclBasic.c:	More replacements of Tcl_UtfBackslash() calls
	* generic/tclCompile.c:	with TclParseBackslash() where possible.
	* generic/tclCompCmdsSZ.c:
	* generic/tclParse.c:
	* generic/tclUtil.c:

	* generic/tclUtil.c (TclFindElement):	Guard escape sequence scans
	to not overrun the string end.  [Bug 3192636]

2011-03-05  Don Porter  <[email protected]>

	* generic/tclParse.c (TclParseBackslash): Correct trunction checks in
	* tests/parse.test:	\x and \u substitutions.  [Bug 3200987]

2011-03-05  Miguel Sofer  <[email protected]>

	* generic/tclExecute.c (TclStackFree): insure that the execStack
	satisfies "at most one free stack after the current one" when
	consecutive reallocs caused the creation of intervening stacks.








|
|














|
|



|
|







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
	and unsigned integer expressions

2011-03-08  Don Porter  <[email protected]>

	* generic/tclInt.h:	Remove TclMarkList() routine, an experimental
	* generic/tclUtil.c:	dead-end from the 8.5 alpha days.

	* generic/tclResult.c (ResetObjResult): [Bug 3202905]: Correct failure
	to clear invalid intrep.  Thanks to Colin McDonald.

2011-03-08  Donal K. Fellows  <[email protected]>

	* generic/tclAssembly.c, tests/assemble.test: Migrate to use a style
	more consistent with the rest of Tcl.

2011-03-06  Don Porter  <[email protected]>

	* generic/tclBasic.c:	More replacements of Tcl_UtfBackslash() calls
	* generic/tclCompile.c:	with TclParseBackslash() where possible.
	* generic/tclCompCmdsSZ.c:
	* generic/tclParse.c:
	* generic/tclUtil.c:

	* generic/tclUtil.c (TclFindElement):	[Bug 3192636]: Guard escape
	sequence scans to not overrun the string end.

2011-03-05  Don Porter  <[email protected]>

	* generic/tclParse.c (TclParseBackslash): [Bug 3200987]: Correct
	* tests/parse.test:	trunction checks in \x and \u substitutions.

2011-03-05  Miguel Sofer  <[email protected]>

	* generic/tclExecute.c (TclStackFree): insure that the execStack
	satisfies "at most one free stack after the current one" when
	consecutive reallocs caused the creation of intervening stacks.

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
	* generic/tclInt.h:
	* generic/tclIntDecls.h:
	* generic/tclInterp.c:
	* generic/tclOODecls.h:
	* generic/tclStubInit.c:
	* win/makefile.vc:

	* generic/tclExecute.c (ExprObjCallback): fix object leak

	* generic/tclExecute.c (TEBCresume): store local var array and
	constants in automatic vars to reduce indirection, slight perf
	increase

	* generic/tclOOCall.c (TclOODeleteContext): added missing '*' so
	that trunk compiles.

	* generic/tclBasic.c (TclNRRunCallbacks): don't do the trampoline
	dance for commands that do not have an nreProc, [Patch 3168229]

2011-03-01  Donal K. Fellows  <[email protected]>

	* generic/tclOO.c (Tcl_NewObjectInstance, TclNRNewObjectInstance)
	(TclOOObjectCmdCore, FinalizeObjectCall):
	* generic/tclOOBasic.c (TclOO_Object_Destroy, AfterNRDestructor):
	* generic/tclOOCall.c (TclOODeleteContext, TclOOGetCallContext):







|

|



|


|
|







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
	* generic/tclInt.h:
	* generic/tclIntDecls.h:
	* generic/tclInterp.c:
	* generic/tclOODecls.h:
	* generic/tclStubInit.c:
	* win/makefile.vc:

	* generic/tclExecute.c (ExprObjCallback): Fix object leak

	* generic/tclExecute.c (TEBCresume): Store local var array and
	constants in automatic vars to reduce indirection, slight perf
	increase

	* generic/tclOOCall.c (TclOODeleteContext): Added missing '*' so
	that trunk compiles.

	* generic/tclBasic.c (TclNRRunCallbacks): [Patch 3168229]: Don't do
	the trampoline dance for commands that do not have an nreProc.

2011-03-01  Donal K. Fellows  <[email protected]>

	* generic/tclOO.c (Tcl_NewObjectInstance, TclNRNewObjectInstance)
	(TclOOObjectCmdCore, FinalizeObjectCall):
	* generic/tclOOBasic.c (TclOO_Object_Destroy, AfterNRDestructor):
	* generic/tclOOCall.c (TclOODeleteContext, TclOOGetCallContext):
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
	* generic/tclResult.c (TclMergeReturnOptions): Use memcmp where
	applicable as possible speedup on some libc variants.

2010-09-21  Kevin B. Kenny  <[email protected]>

	[BRANCH: dogeen-assembler-branch]

	* generic/tclAssembly.c (new file): 
	* generic/tclAssembly.h:
	* generic/tclBasic.c (builtInCmds, Tcl_CreateInterp):
	* generic/tclInt.h:
	* tests/assemble.test (new file):
	* tests/assemble1.bench (new file):
	* unix/Makefile.in:
	* win/Makefile.in:







|







2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
	* generic/tclResult.c (TclMergeReturnOptions): Use memcmp where
	applicable as possible speedup on some libc variants.

2010-09-21  Kevin B. Kenny  <[email protected]>

	[BRANCH: dogeen-assembler-branch]

	* generic/tclAssembly.c (new file):
	* generic/tclAssembly.h:
	* generic/tclBasic.c (builtInCmds, Tcl_CreateInterp):
	* generic/tclInt.h:
	* tests/assemble.test (new file):
	* tests/assemble1.bench (new file):
	* unix/Makefile.in:
	* win/Makefile.in:

Changes to README.

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
README:  Tcl
    This is the Tcl 8.6b1 source distribution.
    Tcl/Tk is also available through NetCVS:
	http://tcl.sourceforge.net/
    You can get any source release of Tcl from the file distributions
    link at the above URL.

Contents
--------
    1. Introduction
    2. Documentation
    3. Compiling and installing Tcl
    4. Development tools
    5. Tcl newsgroup
    6. Tcl contributed archive
    7. Tcl Resource Center
    8. Mailing lists
    9. Support and Training

    10. Thank You

1. Introduction
---------------
Tcl provides a powerful platform for creating integration applications that
tie together diverse applications, protocols, devices, and frameworks.
When paired with the Tk toolkit, Tcl provides the fastest and most powerful
way to create GUI applications that run on PCs, Unix, and Mac OS X.
Tcl can also be used for a variety of web-related tasks and for creating
powerful command languages for applications.

Tcl is maintained, enhanced, and distributed freely by the Tcl community.
The home for Tcl/Tk sources and bug/patch database is on SourceForge:

	http://tcl.sourceforge.net/

with the Tcl Developer Xchange hosted at:

	http://www.tcl.tk/


|
<











|
<
|
|
>












|







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
README:  Tcl
    This is the Tcl 8.6b2 source distribution.

	http://tcl.sourceforge.net/
    You can get any source release of Tcl from the file distributions
    link at the above URL.

Contents
--------
    1. Introduction
    2. Documentation
    3. Compiling and installing Tcl
    4. Development tools
    5. Tcl newsgroup
    6. The Tcler's Wiki

    7. Mailing lists
    8. Support and Training
    9. Tracking Development
    10. Thank You

1. Introduction
---------------
Tcl provides a powerful platform for creating integration applications that
tie together diverse applications, protocols, devices, and frameworks.
When paired with the Tk toolkit, Tcl provides the fastest and most powerful
way to create GUI applications that run on PCs, Unix, and Mac OS X.
Tcl can also be used for a variety of web-related tasks and for creating
powerful command languages for applications.

Tcl is maintained, enhanced, and distributed freely by the Tcl community.
The home for Tcl/Tk releases and bug/patch database is on SourceForge:

	http://tcl.sourceforge.net/

with the Tcl Developer Xchange hosted at:

	http://www.tcl.tk/

46
47
48
49
50
51
52
53
54
55
56
57
58
59




60
61
62
63
64
65
66

Extensive documentation is available at our website.
The home page for this release, including new features, is
	http://www.tcl.tk/software/tcltk/8.6.html

Detailed release notes can be found at the file distributions page
by clicking on the relevant version.
	http://sourceforge.net/project/showfiles.php?group_id=10894

Information about Tcl itself can be found at
	http://www.tcl.tk/scripting/

There have been many Tcl books on the market.  Many are mentioned in the Wiki:
	http://wiki.tcl.tk/book





2a. Unix Documentation
----------------------

The "doc" subdirectory in this release contains a complete set of
reference manual entries for Tcl.  Files with extension ".1" are for
programs (for example, tclsh.1); files with extension ".3" are for 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

Extensive documentation is available at our website.
The home page for this release, including new features, is
	http://www.tcl.tk/software/tcltk/8.6.html

Detailed release notes can be found at the file distributions page
by clicking on the relevant version.
	http://sourceforge.net/projects/tcl/files/

Information about Tcl itself can be found at
	http://www.tcl.tk/about/

There have been many Tcl books on the market.  Many are mentioned in the Wiki:
	http://wiki.tcl.tk/_/ref?N=25206

To view the complete set of reference manual entries for Tcl 8.6 online,
visit the URL:
	http://www.tcl.tk/man/tcl8.6/

2a. Unix Documentation
----------------------

The "doc" subdirectory in this release contains a complete set of
reference manual entries for Tcl.  Files with extension ".1" are for
programs (for example, tclsh.1); files with extension ".3" are for C
164
165
166
167
168
169
170






171
172
173
174
175
176
177
for users.  If you need help we suggest that you post questions to
comp.lang.tcl.  We read the newsgroup and will attempt to answer esoteric
questions for which no one else is likely to know the answer.  In addition,
see the following Web site for links to other organizations that offer
Tcl/Tk training:

	http://wiki.tcl.tk/training







10. Thank You
-------------

We'd like to express our thanks to the Tcl community for all the
helpful suggestions, bug reports, and patches we have received.
Tcl/Tk has improved vastly and will continue to do so with your help.







>
>
>
>
>
>







167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
for users.  If you need help we suggest that you post questions to
comp.lang.tcl.  We read the newsgroup and will attempt to answer esoteric
questions for which no one else is likely to know the answer.  In addition,
see the following Web site for links to other organizations that offer
Tcl/Tk training:

	http://wiki.tcl.tk/training

9. Tracking Development
-----------------------

Tcl is developed in public.  To keep an eye on how Tcl is changing, see
	http://core.tcl.tk/

10. Thank You
-------------

We'd like to express our thanks to the Tcl community for all the
helpful suggestions, bug reports, and patches we have received.
Tcl/Tk has improved vastly and will continue to do so with your help.

Changes to changes.

7528
7529
7530
7531
7532
7533
7534
7535
7536
7537
7538
7539
7540
7541
7542

2009-04-30 (bug fix)[2486550] coroutine in [interp invokehidden] (sofer)

2009-05-07 (bug fix)[2785893] find command in deleted namespace (sofer)

2009-05-08 (bug fix)[2414858] tailcall in oo constructor (fellows)

2009-05-14 (new subcommand) [info object namespace] (fellows)

2009-05-29 (platform support) account for ia64_32 (kupries)
=> platform 1.0.5

2009-06-02 (bug fix)[2798543] incorrect [expr] integer ** results (porter)

2009-06-10 (bug fix)[2801413] overflow in [format] (porter)







|







7528
7529
7530
7531
7532
7533
7534
7535
7536
7537
7538
7539
7540
7541
7542

2009-04-30 (bug fix)[2486550] coroutine in [interp invokehidden] (sofer)

2009-05-07 (bug fix)[2785893] find command in deleted namespace (sofer)

2009-05-08 (bug fix)[2414858] tailcall in oo constructor (fellows)

2009-05-14 (new subcommand)[TIP 354] [info object namespace] (fellows)

2009-05-29 (platform support) account for ia64_32 (kupries)
=> platform 1.0.5

2009-06-02 (bug fix)[2798543] incorrect [expr] integer ** results (porter)

2009-06-10 (bug fix)[2801413] overflow in [format] (porter)
7559
7560
7561
7562
7563
7564
7565
7566
7567
7568
7569
7570
7571
7572
7573

2009-07-13 (bug fix)[1605269] NR-related [info frame] fixes (kupries)

2009-07-14 (bug fix)[2821401] NR-enable direct eval [switch] (kenny)

2009-07-16 (bug fix)[2819200] underflow settings on MIPS systems (porter)

2009-07-19 (interface) new public routine Tcl_GetObjectName() (fellows)

2009-07-20 (performance) favor [string is] success cases over empty (fellows)

2009-07-22 (interface) removed TclpPanic() routine (nijtmans)

2009-07-23 (bug fix)[2820349] plug event leak in notifier (mistachkin)








|







7559
7560
7561
7562
7563
7564
7565
7566
7567
7568
7569
7570
7571
7572
7573

2009-07-13 (bug fix)[1605269] NR-related [info frame] fixes (kupries)

2009-07-14 (bug fix)[2821401] NR-enable direct eval [switch] (kenny)

2009-07-16 (bug fix)[2819200] underflow settings on MIPS systems (porter)

2009-07-19 (interface)[TIP 354] new routine Tcl_GetObjectName() (fellows)

2009-07-20 (performance) favor [string is] success cases over empty (fellows)

2009-07-22 (interface) removed TclpPanic() routine (nijtmans)

2009-07-23 (bug fix)[2820349] plug event leak in notifier (mistachkin)

7863
7864
7865
7866
7867
7868
7869






















































































7870

2010-11-04 improved testing of sockets (max)

2010-11-05 (frq)[491789] setargv/unicode cmdline for MSVC (nijtmans)

2010-11-09 (bug fix)[3105999] fixed memleak in OO var resolver (fellows)























































































--- Released 8.6b2, November 15, 2010 --- See ChangeLog for details ---







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
7863
7864
7865
7866
7867
7868
7869
7870
7871
7872
7873
7874
7875
7876
7877
7878
7879
7880
7881
7882
7883
7884
7885
7886
7887
7888
7889
7890
7891
7892
7893
7894
7895
7896
7897
7898
7899
7900
7901
7902
7903
7904
7905
7906
7907
7908
7909
7910
7911
7912
7913
7914
7915
7916
7917
7918
7919
7920
7921
7922
7923
7924
7925
7926
7927
7928
7929
7930
7931
7932
7933
7934
7935
7936
7937
7938
7939
7940
7941
7942
7943
7944
7945
7946
7947
7948
7949
7950
7951
7952
7953
7954
7955
7956

2010-11-04 improved testing of sockets (max)

2010-11-05 (frq)[491789] setargv/unicode cmdline for MSVC (nijtmans)

2010-11-09 (bug fix)[3105999] fixed memleak in OO var resolver (fellows)

2010-11-15 (TIP 378)[3081184] improved TIP 280 performance (kupries)

2010-11-16 (platform) VS 2005 SP1 MSVC compiler (nijtmans)

2010-11-18 (bug fix)[3111059] leak in [namespace delete] w coroutines (sofer)

2010-11-28 [3120139,3105247] Tcl_PrintDouble improvements (kenny)

2010-11-29 (new cmd) [tcl::unsupported::inject] (ferrieux,sofer)

2010-11-30 (enhancement) Restore TclFormatInt for performance (hobbs)

2010-12-09 (new feature) [file] is now a [namespace ensemble] (fellows)

2010-12-19 (bug fix) [fcopy -size 1 -command] asynchronous (ferrieux)

2010-12-12 (platform) OpenBSD build improvements (cassoff)

2010-12-17 (platform) Revisions to support rpm 4.4.2 (cassoff)

2010-12-27 (bug fix) crash in [lsort] w multiple -index options (fellows)

2010-12-30 (bug fix)[3142026] GrowEvaluationStack OBOE (harder,sofer)

2011-01-18 (bug fix)[3001438] [info frame -1] crash (mccormack,fellows)

2011-03-01 (performance)[3168398] optimize [interp cancel] (mistachkin)

2011-03-05 (bug fix)[3185009] crash in OO variables (danckaert,fellows)

2011-03-05 (new cmd) [tcl::unsupported::assemble] (ugurlu,kenny)

2011-03-06 (bug fix)[3200987,3192636] parser buffer overruns (porter)

2011-03-08 (bug fix)[3202905] failed intrep release of interp result (mccormack)

2011-03-09 (bug fix)[3202171] repair [namespace inscope] optimizer (porter)

2011-03-10 (new version) better tcltest reporting from child interps (fellows)
=> tcltest 2.3.3

2011-03-10 (new feature) [namespace] is now a [namespace ensemble] (fellows)

2011-03-12 (interface) reduce casting by ckalloc(), ckfree() callers (fellows)

2011-03-14 (bug fix) Fixes from libtommath 0.42.0 release (fellows)

2011-03-21 (bug fix)[3216070] [load] extension from embed Tcl apps (nijtmans)

2011-03-27 (performance) NRE: LIST lset foreach benchmark (twylite)

2011-04-11 (bug fix)[3282869] coroutine + eval + locals crash (ferrieux,sofer)

2011-04-13 (bug fix)[2662380] crash when variable append trace unsets (sofer)

2011-04-13 (bug fix)[3285375] Buffer overflow in [concat] (porter)

2011-05-02 (internals change) revised TclFindElement() interface (porter)
	*** POTENTIAL INCOMPATIBILITY ***

2011-05-05 (enhancement) dict->list w/o string rep generation (porter)

2011-05-10 (bug fix)[3173086] Crash parsing long lists (rogers,porter)

2011-05-24 (enhancement) msgcat internal improvements (fellows)
=> msgcat 1.4.4

2011-05-25 (TIP 381) [info object|class call] [self call] [nextto] (fellows)

2011-05-31 (bug fix)[3293874] let lists grow all the way to the limit (porter)

2011-06-02 (bug fix)[3185407] cmd resolution epoch flaw (nadkarni,fellows)

2011-06-13 (bug fix)[3315098] mem leak generating double string rep (neumann)

2011-06-22 (new feature) DEB_HOST_MULTIARCH support (kupries)
=> platform 1.0.10

2011-07-15 (bug fix)[3357771] Prevent circular refs in bytecode (porter)

2011-07-28 tzdata updated to Olson's tzdata2011h (porter)

2011-08-01 (bug fix)[3383616] memleak exposed by XOTcl (neumann,sofer)

Many more Tcl built-in command errors now set an -errorcode.

--- Released 8.6b2, August 8, 2011 --- See ChangeLog for details ---

Changes to doc/Class.3.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
'\"
'\" Copyright (c) 2007 Donal K. Fellows
'\"
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\"
.so man.macros
.TH Tcl_Class 3 0.1 TclOO "TclOO Library Functions"
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
Tcl_ClassGetMetadata, Tcl_ClassSetMetadata, Tcl_CopyObjectInstance, Tcl_GetClassAsObject, Tcl_GetObjectAsClass, Tcl_GetObjectCommand, Tcl_GetObjectNamespace, Tcl_NewObjectInstance, Tcl_ObjectDeleted, Tcl_ObjectGetMetadata, Tcl_ObjectGetMethodNameMapper, Tcl_ObjectSetMetadata, Tcl_ObjectSetMethodNameMapper \- manipulate objects and classes
.SH SYNOPSIS
.nf
\fB#include <tclOO.h>\fR
.sp
Tcl_Object
\fBTcl_GetObjectFromObj\fR(\fIinterp, objPtr\fR)
.sp











|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
'\"
'\" Copyright (c) 2007 Donal K. Fellows
'\"
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\"
.so man.macros
.TH Tcl_Class 3 0.1 TclOO "TclOO Library Functions"
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
Tcl_ClassGetMetadata, Tcl_ClassSetMetadata, Tcl_CopyObjectInstance, Tcl_GetClassAsObject, Tcl_GetObjectAsClass, Tcl_GetObjectCommand, Tcl_GetObjectFromObj, Tcl_GetObjectName, Tcl_GetObjectNamespace, Tcl_NewObjectInstance, Tcl_ObjectDeleted, Tcl_ObjectGetMetadata, Tcl_ObjectGetMethodNameMapper, Tcl_ObjectSetMetadata, Tcl_ObjectSetMethodNameMapper \- manipulate objects and classes
.SH SYNOPSIS
.nf
\fB#include <tclOO.h>\fR
.sp
Tcl_Object
\fBTcl_GetObjectFromObj\fR(\fIinterp, objPtr\fR)
.sp

Changes to doc/CrtChnlHdlr.3.

1
2
3
4
5
6

7
8
9
10
11
12
13
'\"
'\" Copyright (c) 1996 Sun Microsystems, Inc.
'\"
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\"

.TH Tcl_CreateChannelHandler 3 7.5 Tcl "Tcl Library Procedures"
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
Tcl_CreateChannelHandler, Tcl_DeleteChannelHandler \- call a procedure when a channel becomes readable or writable
.SH SYNOPSIS
.nf






>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
'\"
'\" Copyright (c) 1996 Sun Microsystems, Inc.
'\"
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\"
.so man.macros
.TH Tcl_CreateChannelHandler 3 7.5 Tcl "Tcl Library Procedures"
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
Tcl_CreateChannelHandler, Tcl_DeleteChannelHandler \- call a procedure when a channel becomes readable or writable
.SH SYNOPSIS
.nf

Changes to doc/CrtCloseHdlr.3.

1
2
3
4
5
6

7
8
9
10
11
12
13
'\"
'\" Copyright (c) 1994-1996 Sun Microsystems, Inc.
'\"
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\"

.TH Tcl_CreateCloseHandler 3 7.5 Tcl "Tcl Library Procedures"
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
Tcl_CreateCloseHandler, Tcl_DeleteCloseHandler \- arrange for callbacks when channels are closed
.SH SYNOPSIS
.nf






>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
'\"
'\" Copyright (c) 1994-1996 Sun Microsystems, Inc.
'\"
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\"
.so man.macros
.TH Tcl_CreateCloseHandler 3 7.5 Tcl "Tcl Library Procedures"
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
Tcl_CreateCloseHandler, Tcl_DeleteCloseHandler \- arrange for callbacks when channels are closed
.SH SYNOPSIS
.nf

Changes to doc/CrtInterp.3.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
'\"
'\" Copyright (c) 1989-1993 The Regents of the University of California.
'\" Copyright (c) 1994-1996 Sun Microsystems, Inc.
'\"
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\" 
.so man.macros
.TH Tcl_CreateInterp 3 7.5 Tcl "Tcl Library Procedures"
.BS
.SH NAME
Tcl_CreateInterp, Tcl_DeleteInterp, Tcl_InterpDeleted \- create and delete Tcl command interpreters
.SH SYNOPSIS
.nf
\fB#include <tcl.h>\fR
.sp
Tcl_Interp *
\fBTcl_CreateInterp\fR()
.sp











|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
'\"
'\" Copyright (c) 1989-1993 The Regents of the University of California.
'\" Copyright (c) 1994-1996 Sun Microsystems, Inc.
'\"
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\" 
.so man.macros
.TH Tcl_CreateInterp 3 7.5 Tcl "Tcl Library Procedures"
.BS
.SH NAME
Tcl_CreateInterp, Tcl_DeleteInterp, Tcl_InterpActive, Tcl_InterpDeleted \- create and delete Tcl command interpreters
.SH SYNOPSIS
.nf
\fB#include <tcl.h>\fR
.sp
Tcl_Interp *
\fBTcl_CreateInterp\fR()
.sp

Changes to doc/Ensemble.3.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
'\"
'\" Copyright (c) 2005 Donal K. Fellows
'\"
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\" 
'\" This documents the C API introduced in TIP#235
'\" 
.so man.macros
.TH Tcl_Ensemble 3 8.5 Tcl "Tcl Library Procedures"
.BS
.SH NAME
Tcl_CreateEnsemble, Tcl_FindEnsemble, Tcl_GetEnsembleFlags, Tcl_GetEnsembleMappingDict, Tcl_GetEnsembleNamespace, Tcl_GetEnsembleUnknownHandler, Tcl_GetEnsembleSubcommandList, Tcl_IsEnsemble, Tcl_SetEnsembleFlags, Tcl_SetEnsembleMappingDict, Tcl_SetEnsembleSubcommandList, Tcl_SetEnsembleUnknownHandler \- manipulate ensemble commands
.SH SYNOPSIS
.nf
\fB#include <tcl.h>\fR
.sp
Tcl_Command
\fBTcl_CreateEnsemble\fR(\fIinterp, name, namespacePtr, ensFlags\fR)
.sp












|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
'\"
'\" Copyright (c) 2005 Donal K. Fellows
'\"
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\" 
'\" This documents the C API introduced in TIP#235
'\" 
.so man.macros
.TH Tcl_Ensemble 3 8.5 Tcl "Tcl Library Procedures"
.BS
.SH NAME
Tcl_CreateEnsemble, Tcl_FindEnsemble, Tcl_GetEnsembleFlags, Tcl_GetEnsembleMappingDict, Tcl_GetEnsembleNamespace, Tcl_GetEnsembleParameterList, Tcl_GetEnsembleUnknownHandler, Tcl_GetEnsembleSubcommandList, Tcl_IsEnsemble, Tcl_SetEnsembleFlags, Tcl_SetEnsembleMappingDict, Tcl_SetEnsembleParameterList, Tcl_SetEnsembleSubcommandList, Tcl_SetEnsembleUnknownHandler \- manipulate ensemble commands
.SH SYNOPSIS
.nf
\fB#include <tcl.h>\fR
.sp
Tcl_Command
\fBTcl_CreateEnsemble\fR(\fIinterp, name, namespacePtr, ensFlags\fR)
.sp

Changes to doc/Eval.3.

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
of arguments.  \fBTcl_VarEval\fR is now deprecated.
.PP
\fBTcl_VarEvalVA\fR is the same as \fBTcl_VarEval\fR except that
instead of taking a variable number of arguments it takes an argument
list. Like \fBTcl_VarEval\fR, \fBTcl_VarEvalVA\fR is deprecated.

.SH "FLAG BITS"

Any ORed combination of the following values may be used for the
\fIflags\fR argument to procedures such as \fBTcl_EvalObjEx\fR:
.TP 23
\fBTCL_EVAL_DIRECT\fR

This flag is only used by \fBTcl_EvalObjEx\fR; it is ignored by
other procedures.  If this flag bit is set, the script is not
compiled to bytecodes; instead it is executed directly
as is done by \fBTcl_EvalEx\fR.  The
\fBTCL_EVAL_DIRECT\fR flag is useful in situations where the
contents of an object are going to change immediately, so the
bytecodes will not be reused in a future execution.  In this case,
it is faster to execute the script directly.
.TP 23
\fBTCL_EVAL_GLOBAL\fR

If this flag is set, the script is processed at global level.  This
means that it is evaluated in the global namespace and its variable
context consists of global variables only (it ignores any Tcl
procedures at are active).

.SH "MISCELLANEOUS DETAILS"
.PP
During the processing of a Tcl command it is legal to make nested
calls to evaluate other commands (this is how procedures and
some control structures are implemented).
If a code other than \fBTCL_OK\fR is returned







>




>










>



|







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
of arguments.  \fBTcl_VarEval\fR is now deprecated.
.PP
\fBTcl_VarEvalVA\fR is the same as \fBTcl_VarEval\fR except that
instead of taking a variable number of arguments it takes an argument
list. Like \fBTcl_VarEval\fR, \fBTcl_VarEvalVA\fR is deprecated.

.SH "FLAG BITS"
.PP
Any ORed combination of the following values may be used for the
\fIflags\fR argument to procedures such as \fBTcl_EvalObjEx\fR:
.TP 23
\fBTCL_EVAL_DIRECT\fR
.
This flag is only used by \fBTcl_EvalObjEx\fR; it is ignored by
other procedures.  If this flag bit is set, the script is not
compiled to bytecodes; instead it is executed directly
as is done by \fBTcl_EvalEx\fR.  The
\fBTCL_EVAL_DIRECT\fR flag is useful in situations where the
contents of an object are going to change immediately, so the
bytecodes will not be reused in a future execution.  In this case,
it is faster to execute the script directly.
.TP 23
\fBTCL_EVAL_GLOBAL\fR
.
If this flag is set, the script is processed at global level.  This
means that it is evaluated in the global namespace and its variable
context consists of global variables only (it ignores any Tcl
procedures that are active).

.SH "MISCELLANEOUS DETAILS"
.PP
During the processing of a Tcl command it is legal to make nested
calls to evaluate other commands (this is how procedures and
some control structures are implemented).
If a code other than \fBTCL_OK\fR is returned

Changes to doc/FileSystem.3.

496
497
498
499
500
501
502
503

504
505
506
507
508
509
510
511
\fBTcl_FSLstat\fR fills the \fITcl_StatBuf\fR structure \fIstatPtr\fR with
information about the specified file. You do not need any access rights to the
file to get this information but you need search rights to all
directories named in the path leading to the file. The \fITcl_StatBuf\fR
structure includes info regarding device, inode (always 0 on Windows),
privilege mode, nlink (always 1 on Windows), user id (always 0 on
Windows), group id (always 0 on Windows), rdev (same as device on
Windows), size, last access time, last modification time, and creation

time. See \fBPORTABLE STAT RESULT API\fR for a description of how to write
portable code to allocate and access the \fITcl_StatBuf\fR structure.
.PP
If \fIpath\fR exists, \fBTcl_FSLstat\fR returns 0 and the stat structure
is filled with data. Otherwise, -1 is returned, and no stat info is
given.
.PP
\fBTcl_FSUtime\fR replaces the library version of utime.







|
>
|







496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
\fBTcl_FSLstat\fR fills the \fITcl_StatBuf\fR structure \fIstatPtr\fR with
information about the specified file. You do not need any access rights to the
file to get this information but you need search rights to all
directories named in the path leading to the file. The \fITcl_StatBuf\fR
structure includes info regarding device, inode (always 0 on Windows),
privilege mode, nlink (always 1 on Windows), user id (always 0 on
Windows), group id (always 0 on Windows), rdev (same as device on
Windows), size, last access time, last modification time, and
last metadata change time.
See \fBPORTABLE STAT RESULT API\fR for a description of how to write
portable code to allocate and access the \fITcl_StatBuf\fR structure.
.PP
If \fIpath\fR exists, \fBTcl_FSLstat\fR returns 0 and the stat structure
is filled with data. Otherwise, -1 is returned, and no stat info is
given.
.PP
\fBTcl_FSUtime\fR replaces the library version of utime.
555
556
557
558
559
560
561
562

563
564
565
566
567
568
569
570
\fBTcl_FSStat\fR fills the \fITcl_StatBuf\fR structure \fIstatPtr\fR with
information about the specified file. You do not need any access rights to the
file to get this information but you need search rights to all
directories named in the path leading to the file. The \fITcl_StatBuf\fR
structure includes info regarding device, inode (always 0 on Windows),
privilege mode, nlink (always 1 on Windows), user id (always 0 on
Windows), group id (always 0 on Windows), rdev (same as device on
Windows), size, last access time, last modification time, and creation

time. See \fBPORTABLE STAT RESULT API\fR for a description of how to write
portable code to allocate and access the \fITcl_StatBuf\fR structure.
.PP
If \fIpath\fR exists, \fBTcl_FSStat\fR returns 0 and the stat structure
is filled with data. Otherwise, -1 is returned, and no stat info is
given.
.PP
\fBTcl_FSOpenFileChannel\fR opens a file specified by \fIpathPtr\fR and







|
>
|







556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
\fBTcl_FSStat\fR fills the \fITcl_StatBuf\fR structure \fIstatPtr\fR with
information about the specified file. You do not need any access rights to the
file to get this information but you need search rights to all
directories named in the path leading to the file. The \fITcl_StatBuf\fR
structure includes info regarding device, inode (always 0 on Windows),
privilege mode, nlink (always 1 on Windows), user id (always 0 on
Windows), group id (always 0 on Windows), rdev (same as device on
Windows), size, last access time, last modification time, and
last metadata change time.
See \fBPORTABLE STAT RESULT API\fR for a description of how to write
portable code to allocate and access the \fITcl_StatBuf\fR structure.
.PP
If \fIpath\fR exists, \fBTcl_FSStat\fR returns 0 and the stat structure
is filled with data. Otherwise, -1 is returned, and no stat info is
given.
.PP
\fBTcl_FSOpenFileChannel\fR opens a file specified by \fIpathPtr\fR and
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
.QW ~
or
.QW ~user
sequences (these have been expanded to their current
representation in the filesystem). The object returned is owned by the
caller, which must store it or call Tcl_DecrRefCount to ensure memory is
freed. This function is of little practical use, and
\fBTcl_FSGetNormalizedPath\fR or \fBTcl_GetNativePath\fR are usually
better functions to use for most purposes.
.PP
\fBTcl_FSGetTranslatedStringPath\fR does the same as
\fBTcl_FSGetTranslatedPath\fR, but returns a character string or NULL.
The string returned is dynamically allocated and owned by the caller,
which must store it or call \fBckfree\fR to ensure it is freed. Again,
\fBTcl_FSGetNormalizedPath\fR or \fBTcl_GetNativePath\fR are usually
better functions to use for most purposes.
.PP
\fBTcl_FSNewNativePath\fR performs something like the reverse of the
usual obj->path->nativerep conversions. If some code retrieves a path
in native form (from, e.g.\ \fBreadlink\fR or a native dialog), and that path
is to be used at the Tcl level, then calling this function is an
efficient way of creating the appropriate path object type.







|






|







714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
.QW ~
or
.QW ~user
sequences (these have been expanded to their current
representation in the filesystem). The object returned is owned by the
caller, which must store it or call Tcl_DecrRefCount to ensure memory is
freed. This function is of little practical use, and
\fBTcl_FSGetNormalizedPath\fR or \fBTcl_FSGetNativePath\fR are usually
better functions to use for most purposes.
.PP
\fBTcl_FSGetTranslatedStringPath\fR does the same as
\fBTcl_FSGetTranslatedPath\fR, but returns a character string or NULL.
The string returned is dynamically allocated and owned by the caller,
which must store it or call \fBckfree\fR to ensure it is freed. Again,
\fBTcl_FSGetNormalizedPath\fR or \fBTcl_FSGetNativePath\fR are usually
better functions to use for most purposes.
.PP
\fBTcl_FSNewNativePath\fR performs something like the reverse of the
usual obj->path->nativerep conversions. If some code retrieves a path
in native form (from, e.g.\ \fBreadlink\fR or a native dialog), and that path
is to be used at the Tcl level, then calling this function is an
efficient way of creating the appropriate path object type.
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
.PP
It returns one of \fBTCL_PATH_ABSOLUTE\fR, \fBTCL_PATH_RELATIVE\fR, or
\fBTCL_PATH_VOLUME_RELATIVE\fR
.SS "PORTABLE STAT RESULT API"
.PP
\fBTcl_AllocStatBuf\fR allocates a \fITcl_StatBuf\fR on the system heap (which
may be deallocated by being passed to \fBckfree\fR). This allows extensions to
invoke \fBTcl_FSStat\fR and \fBTcl_FSLStat\fR without being dependent on the
size of the buffer. That in turn depends on the flags used to build Tcl.
.PP
.VS 8.6
The portable fields of a \fITcl_StatBuf\fR may be read using the following
functions, each of which returns the value of the corresponding field listed
in the table below. Note that on some platforms there may be other fields in
the \fITcl_StatBuf\fR as it is an alias for a suitable system structure, but







|







788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
.PP
It returns one of \fBTCL_PATH_ABSOLUTE\fR, \fBTCL_PATH_RELATIVE\fR, or
\fBTCL_PATH_VOLUME_RELATIVE\fR
.SS "PORTABLE STAT RESULT API"
.PP
\fBTcl_AllocStatBuf\fR allocates a \fITcl_StatBuf\fR on the system heap (which
may be deallocated by being passed to \fBckfree\fR). This allows extensions to
invoke \fBTcl_FSStat\fR and \fBTcl_FSLstat\fR without being dependent on the
size of the buffer. That in turn depends on the flags used to build Tcl.
.PP
.VS 8.6
The portable fields of a \fITcl_StatBuf\fR may be read using the following
functions, each of which returns the value of the corresponding field listed
in the table below. Note that on some platforms there may be other fields in
the \fITcl_StatBuf\fR as it is an alias for a suitable system structure, but
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
The \fBTcl_FSStatProc\fR fills the stat structure \fIstatPtr\fR with
information about the specified file. You do not need any access
rights to the file to get this information but you need search rights
to all directories named in the path leading to the file. The stat
structure includes info regarding device, inode (always 0 on Windows),
privilege mode, nlink (always 1 on Windows), user id (always 0 on
Windows), group id (always 0 on Windows), rdev (same as device on
Windows), size, last access time, last modification time, and creation
time.
.PP
If the file represented by \fIpathPtr\fR exists, the
\fBTcl_FSStatProc\fR returns 0 and the stat structure is filled with
data. Otherwise, -1 is returned, and no stat info is given.
.SS ACCESSPROC
.PP
Function to process a \fBTcl_FSAccess\fR call. Must be implemented for







|
|







1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
The \fBTcl_FSStatProc\fR fills the stat structure \fIstatPtr\fR with
information about the specified file. You do not need any access
rights to the file to get this information but you need search rights
to all directories named in the path leading to the file. The stat
structure includes info regarding device, inode (always 0 on Windows),
privilege mode, nlink (always 1 on Windows), user id (always 0 on
Windows), group id (always 0 on Windows), rdev (same as device on
Windows), size, last access time, last modification time, and
last metadata change time.
.PP
If the file represented by \fIpathPtr\fR exists, the
\fBTcl_FSStatProc\fR returns 0 and the stat structure is filled with
data. Otherwise, -1 is returned, and no stat info is given.
.SS ACCESSPROC
.PP
Function to process a \fBTcl_FSAccess\fR call. Must be implemented for

Changes to doc/FindExec.3.

40
41
42
43
44
45
46







47
48
49
50
51
52
53
\fIargv[0]\fR as its argument.  It is important not to change the
working directory before the invocation.
\fBTcl_FindExecutable\fR uses \fIargv0\fR
along with the \fBPATH\fR environment variable to find the
application's executable, if possible.  If it fails to find
the binary, then future calls to \fBinfo nameofexecutable\fR
will return an empty string.







.PP
\fBTcl_GetNameOfExecutable\fR simply returns a pointer to the
internal full path name of the executable file as computed by
\fBTcl_FindExecutable\fR.  This procedure call is the C API
equivalent to the \fBinfo nameofexecutable\fR command.  NULL
is returned if the internal full path name has not been
computed or unknown.







>
>
>
>
>
>
>







40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
\fIargv[0]\fR as its argument.  It is important not to change the
working directory before the invocation.
\fBTcl_FindExecutable\fR uses \fIargv0\fR
along with the \fBPATH\fR environment variable to find the
application's executable, if possible.  If it fails to find
the binary, then future calls to \fBinfo nameofexecutable\fR
will return an empty string.
.PP
On Windows platforms this procedure is typically invoked as the very
first thing in the application's main program as well; Its \fIargv[0]\fR
argument is only used to indicate wheter the executable has a stderr
channel (any non-null value) or not (the value null). If \fBTcl_SetPanicProc\fR
is never called and no debugger is running, this determines whether
the panic message is sent to stderr or to a standard system dialog.
.PP
\fBTcl_GetNameOfExecutable\fR simply returns a pointer to the
internal full path name of the executable file as computed by
\fBTcl_FindExecutable\fR.  This procedure call is the C API
equivalent to the \fBinfo nameofexecutable\fR command.  NULL
is returned if the internal full path name has not been
computed or unknown.

Changes to doc/Method.3.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
'\"
'\" Copyright (c) 2007 Donal K. Fellows
'\"
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\"
.so man.macros
.TH Tcl_Method 3 0.1 TclOO "TclOO Library Functions"
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
Tcl_ClassSetConstructor, Tcl_ClassSetDestructor, Tcl_MethodDeclarerClass, Tcl_MethodDeclarerObject, Tcl_MethodIsPublic, Tcl_MethodIsType, Tcl_MethodName, Tcl_NewInstanceMethod, Tcl_NewMethod, Tcl_ObjectContextIsFiltering, Tcl_ObjectContextMethod, Tcl_ObjectContextObject, Tcl_ObjectContextSkippedArgs \- manipulate methods and method-call contexts
.SH SYNOPSIS
.nf
\fB#include <tclOO.h>\fR
.sp
Tcl_Method
\fBTcl_NewMethod\fR(\fIinterp, class, nameObj, isPublic,
              methodTypePtr, clientData\fR)











|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
'\"
'\" Copyright (c) 2007 Donal K. Fellows
'\"
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\"
.so man.macros
.TH Tcl_Method 3 0.1 TclOO "TclOO Library Functions"
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
Tcl_ClassSetConstructor, Tcl_ClassSetDestructor, Tcl_MethodDeclarerClass, Tcl_MethodDeclarerObject, Tcl_MethodIsPublic, Tcl_MethodIsType, Tcl_MethodName, Tcl_NewInstanceMethod, Tcl_NewMethod, Tcl_ObjectContextInvokeNext, Tcl_ObjectContextIsFiltering, Tcl_ObjectContextMethod, Tcl_ObjectContextObject, Tcl_ObjectContextSkippedArgs \- manipulate methods and method-call contexts
.SH SYNOPSIS
.nf
\fB#include <tclOO.h>\fR
.sp
Tcl_Method
\fBTcl_NewMethod\fR(\fIinterp, class, nameObj, isPublic,
              methodTypePtr, clientData\fR)

Changes to doc/NRE.3.

137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
invoke a single Tcl command whose words have already been separated
and substituted. The \fIobjc\fR and \fIobjv\fR parameters give the
words of the command to be evaluated when execution reaches the
trampoline.
.PP
\fBTcl_NRCmdSwap\fR allows for trampoline evaluation of a command whose
resolution is already known.  The \fIcmd\fR parameter gives a
\fBTcl_Command\fR object (returned from \fBTcl_CreateObjCmd\fR or
\fBTcl_GetCommandFromObj\fR) identifying the command to be invoked in
the trampoline; this command must match the word in \fIobjv[0]\fR.
The remaining arguments are as for \fBTcl_NREvalObj\fR.
.PP
\fBTcl_NREvalObj\fR, \fBTcl_NREvalObjv\fR and \fBTcl_NRCmdSwap\fR
all accept a \fIflags\fR parameter, which is an OR-ed-together set of
bits to control evaluation. At the present time, the only supported flag







|







137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
invoke a single Tcl command whose words have already been separated
and substituted. The \fIobjc\fR and \fIobjv\fR parameters give the
words of the command to be evaluated when execution reaches the
trampoline.
.PP
\fBTcl_NRCmdSwap\fR allows for trampoline evaluation of a command whose
resolution is already known.  The \fIcmd\fR parameter gives a
\fBTcl_Command\fR object (returned from \fBTcl_CreateObjCommand\fR or
\fBTcl_GetCommandFromObj\fR) identifying the command to be invoked in
the trampoline; this command must match the word in \fIobjv[0]\fR.
The remaining arguments are as for \fBTcl_NREvalObj\fR.
.PP
\fBTcl_NREvalObj\fR, \fBTcl_NREvalObjv\fR and \fBTcl_NRCmdSwap\fR
all accept a \fIflags\fR parameter, which is an OR-ed-together set of
bits to control evaluation. At the present time, the only supported flag

Changes to doc/Namespace.3.

156
157
158
159
160
161
162
163
164
165
\fBTcl_GetNamespaceUnknownHandler\fR returns the unknown command handler
for the namespace, or NULL if none is set.
.PP
\fBTcl_SetNamespaceUnknownHandler\fR sets the unknown command handler for
the namespace. If \fIhandlerPtr\fR is NULL, then the handler is reset to
its default.
.SH "SEE ALSO"
Tcl_CreateCommand(3), Tcl_ListObjAppendElements(3), Tcl_SetVar(3)
.SH KEYWORDS
namespace, command







|


156
157
158
159
160
161
162
163
164
165
\fBTcl_GetNamespaceUnknownHandler\fR returns the unknown command handler
for the namespace, or NULL if none is set.
.PP
\fBTcl_SetNamespaceUnknownHandler\fR sets the unknown command handler for
the namespace. If \fIhandlerPtr\fR is NULL, then the handler is reset to
its default.
.SH "SEE ALSO"
Tcl_CreateCommand(3), Tcl_ListObjAppendList(3), Tcl_SetVar(3)
.SH KEYWORDS
namespace, command

Changes to doc/Notifier.3.

407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
similar manner, except that there is a separate event queue for
each thread containing a Tcl interpreter.
Calling \fBTcl_QueueEvent\fR in a multithreaded application adds
an event to the current thread's queue.
To add an event to another thread's queue, use \fBTcl_ThreadQueueEvent\fR.
\fBTcl_ThreadQueueEvent\fR accepts as an argument a Tcl_ThreadId argument,
which uniquely identifies a thread in a Tcl application.  To obtain the
Tcl_ThreadID for the current thread, use the \fBTcl_GetCurrentThread\fR
procedure.  (A thread would then need to pass this identifier to other
threads for those threads to be able to add events to its queue.)
After adding an event to another thread's queue, you then typically
need to call \fBTcl_ThreadAlert\fR to
.QW "wake up"
that thread's notifier to alert it to the new event.
.PP







|







407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
similar manner, except that there is a separate event queue for
each thread containing a Tcl interpreter.
Calling \fBTcl_QueueEvent\fR in a multithreaded application adds
an event to the current thread's queue.
To add an event to another thread's queue, use \fBTcl_ThreadQueueEvent\fR.
\fBTcl_ThreadQueueEvent\fR accepts as an argument a Tcl_ThreadId argument,
which uniquely identifies a thread in a Tcl application.  To obtain the
Tcl_ThreadId for the current thread, use the \fBTcl_GetCurrentThread\fR
procedure.  (A thread would then need to pass this identifier to other
threads for those threads to be able to add events to its queue.)
After adding an event to another thread's queue, you then typically
need to call \fBTcl_ThreadAlert\fR to
.QW "wake up"
that thread's notifier to alert it to the new event.
.PP

Changes to doc/Panic.3.

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
same formatting rules used by the \fBprintf\fR family of functions.  The
same formatting rules are also used by the built-in Tcl command
\fBformat\fR.
.PP
In a freshly loaded Tcl library, \fBTcl_Panic\fR prints the formatted
error message to the standard error file of the process, and then
calls \fBabort\fR to terminate the process.  \fBTcl_Panic\fR does not
return.



.PP
\fBTcl_SetPanicProc\fR may be used to modify the behavior of
\fBTcl_Panic\fR.  The \fIpanicProc\fR argument should match the
type \fBTcl_PanicProc\fR:
.PP
.CS
typedef void \fBTcl_PanicProc\fR(
        const char *\fBformat\fR,
        \fBarg\fR, \fBarg\fR,...);
.CE
.PP
After \fBTcl_SetPanicProc\fR returns, any future calls to
\fBTcl_Panic\fR will call \fIpanicProc\fR, passing along the
\fIformat\fR and \fIarg\fR arguments.  To maintain consistency with the
callers of \fBTcl_Panic\fR, \fIpanicProc\fR must not return; it must
call \fBabort\fR.  \fIpanicProc\fR should avoid making calls into the
Tcl library, or into other libraries that may call the Tcl library,
since the original call to \fBTcl_Panic\fR indicates the Tcl library is
not in a state of reliable operation.  
.PP
The typical use of \fBTcl_SetPanicProc\fR arranges for the error message
to be displayed or reported in a manner more suitable for the
application or the platform.  As an example, the Windows implementation
of \fBwish\fR calls \fBTcl_SetPanicProc\fR to force all panic messages
to be displayed in a system dialog box, rather than to be printed to the
standard error file (usually not visible under Windows).
.PP
Although the primary callers of \fBTcl_Panic\fR are the procedures of
the Tcl library, \fBTcl_Panic\fR is a public function and may be called
by any extension or application that wishes to abort the process and
have a panic message displayed the same way that panic messages from Tcl
will be displayed.
.PP







|
>
>
>













|
<
<
|
|
|



|
<
<
<







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
same formatting rules used by the \fBprintf\fR family of functions.  The
same formatting rules are also used by the built-in Tcl command
\fBformat\fR.
.PP
In a freshly loaded Tcl library, \fBTcl_Panic\fR prints the formatted
error message to the standard error file of the process, and then
calls \fBabort\fR to terminate the process.  \fBTcl_Panic\fR does not
return. On Windows, when a debugger is running, the formatted error
message is sent to the debugger in stead. If the windows executable
does not have a stderr channel (e.g. \fBwish.exe\fR), then a
system dialog box is used to display the panic message.
.PP
\fBTcl_SetPanicProc\fR may be used to modify the behavior of
\fBTcl_Panic\fR.  The \fIpanicProc\fR argument should match the
type \fBTcl_PanicProc\fR:
.PP
.CS
typedef void \fBTcl_PanicProc\fR(
        const char *\fBformat\fR,
        \fBarg\fR, \fBarg\fR,...);
.CE
.PP
After \fBTcl_SetPanicProc\fR returns, any future calls to
\fBTcl_Panic\fR will call \fIpanicProc\fR, passing along the
\fIformat\fR and \fIarg\fR arguments. \fIpanicProc\fR should avoid


making calls into the Tcl library, or into other libraries that may
call the Tcl library, since the original call to \fBTcl_Panic\fR
indicates the Tcl library is not in a state of reliable operation.  
.PP
The typical use of \fBTcl_SetPanicProc\fR arranges for the error message
to be displayed or reported in a manner more suitable for the
application or the platform.



.PP
Although the primary callers of \fBTcl_Panic\fR are the procedures of
the Tcl library, \fBTcl_Panic\fR is a public function and may be called
by any extension or application that wishes to abort the process and
have a panic message displayed the same way that panic messages from Tcl
will be displayed.
.PP

Changes to doc/SplitList.3.

178
179
180
181
182
183
184


185
186
187
188
hash character by OR-ing the flag value returned by \fBTcl_ScanElement\fR
with \fBTCL_DONT_QUOTE_HASH\fR.
.PP
\fBTcl_ScanCountedElement\fR and \fBTcl_ConvertCountedElement\fR are
the same as \fBTcl_ScanElement\fR and \fBTcl_ConvertElement\fR, except
the length of string \fIsrc\fR is specified by the \fIlength\fR
argument, and the string may contain embedded nulls.


.SH KEYWORDS
backslash, convert, element, list, merge, split, strings
.SH "SEE ALSO"
Tcl_GetListFromObj(3)







>
>


<
<
178
179
180
181
182
183
184
185
186
187
188


hash character by OR-ing the flag value returned by \fBTcl_ScanElement\fR
with \fBTCL_DONT_QUOTE_HASH\fR.
.PP
\fBTcl_ScanCountedElement\fR and \fBTcl_ConvertCountedElement\fR are
the same as \fBTcl_ScanElement\fR and \fBTcl_ConvertElement\fR, except
the length of string \fIsrc\fR is specified by the \fIlength\fR
argument, and the string may contain embedded nulls.
.SH "SEE ALSO"
Tcl_ListObjGetElements(3)
.SH KEYWORDS
backslash, convert, element, list, merge, split, strings


Changes to doc/Tcl.n.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
'\"
'\" Copyright (c) 1993 The Regents of the University of California.
'\" Copyright (c) 1994-1996 Sun Microsystems, Inc.
'\"
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\"
.so man.macros
.TH Tcl n "8.5" Tcl "Tcl Built-In Commands"
.BS
.SH NAME
Tcl \- Tool Command Language
.SH SYNOPSIS
Summary of Tcl language syntax.
.BE
.SH DESCRIPTION








|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
'\"
'\" Copyright (c) 1993 The Regents of the University of California.
'\" Copyright (c) 1994-1996 Sun Microsystems, Inc.
'\"
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\"
.so man.macros
.TH Tcl n "8.6" Tcl "Tcl Built-In Commands"
.BS
.SH NAME
Tcl \- Tool Command Language
.SH SYNOPSIS
Summary of Tcl language syntax.
.BE
.SH DESCRIPTION
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
.TP 7
\e\e
Backslash
.PQ \e "" .
.TP 7
\e\fIooo\fR 
.
The digits \fIooo\fR (one, two, or three of them) give an eight-bit octal 
value for the Unicode character that will be inserted.  The upper bits of the


Unicode character will be 0.
.TP 7
\e\fBx\fIhh\fR 
.
The hexadecimal digits \fIhh\fR give an eight-bit hexadecimal value for the
Unicode character that will be inserted.  Any number of hexadecimal digits
may be present; however, all but the last two are ignored (the result is
always a one-byte quantity).  The upper bits of the Unicode character will
be 0.
.TP 7
\e\fBu\fIhhhh\fR 
.
The hexadecimal digits \fIhhhh\fR (one, two, three, or four of them) give a
sixteen-bit hexadecimal value for the Unicode character that will be
inserted.










.PP
Backslash substitution is not performed on words enclosed in braces,
except for backslash-newline as described above.
.RE
.IP "[10] \fBComments.\fR"
If a hash character
.PQ #







|
|
>
>
|



|
|
<
|
<





|
>
>
>
>
>
>
>
>
>
>







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
.TP 7
\e\e
Backslash
.PQ \e "" .
.TP 7
\e\fIooo\fR 
.
The digits \fIooo\fR (one, two, or three of them) give a eight-bit octal 
value for the Unicode character that will be inserted, in the range \fI000\fR
- \fI377\fR.  The parser will stop just before this range overflows, or when
the maximum of three digits is reached.  The upper bits of the Unicode
character will be 0.
.TP 7
\e\fBx\fIhh\fR 
.
The hexadecimal digits \fIhh\fR (one or two of them) give an eight-bit
hexadecimal value for the Unicode character that will be inserted.  The upper

bits of the Unicode character will be 0.

.TP 7
\e\fBu\fIhhhh\fR 
.
The hexadecimal digits \fIhhhh\fR (one, two, three, or four of them) give a
sixteen-bit hexadecimal value for the Unicode character that will be
inserted.  The upper bits of the Unicode character will be 0.
.TP 7
\e\fBU\fIhhhhhhhh\fR 
.
The hexadecimal digits \fIhhhhhhhh\fR (one up to eight of them) give a
twentiy-one-bit hexadecimal value for the Unicode character that will be
inserted, in the range U+0000..U+10FFFF.  The parser will stop just
before this range overflows, or when the maximum of eight digits
is reached.  The upper bits of the Unicode character will be 0.
.PP
The range U+010000..U+10FFFD is reserved for the future.
.PP
Backslash substitution is not performed on words enclosed in braces,
except for backslash-newline as described above.
.RE
.IP "[10] \fBComments.\fR"
If a hash character
.PQ #

Changes to doc/Translate.3.

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
.QW ~ .
.AP Tcl_DString *bufferPtr in/out
If needed, this dynamic string is used to store the new file name.
At the time of the call it should be uninitialized or free.  The
caller must eventually call \fBTcl_DStringFree\fR to free up
anything stored here.
.BE

.SH DESCRIPTION
.PP
This utility procedure translates a file name to a platform-specific form
which, after being converted to the appropriate encoding, is suitable for
passing to the local operating system.  In particular, it converts
network names into native form and does tilde substitution.  
.PP
However, with the advent of the newer \fBTcl_FSGetNormalizedPath\fR and
\fBTcl_GetNativePath\fR, there is no longer any need to use this
procedure.  In particular, \fBTcl_GetNativePath\fR performs all the
necessary translation and encoding conversion, is virtual-filesystem
aware, and caches the native result for faster repeated calls.
Finally \fBTcl_GetNativePath\fR does not require you to free anything
afterwards.
.PP
If
\fBTcl_TranslateFileName\fR has to do tilde substitution or translate
the name then it uses
the dynamic string at \fI*bufferPtr\fR to hold the new string it
generates.







<








|
|


|







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
.QW ~ .
.AP Tcl_DString *bufferPtr in/out
If needed, this dynamic string is used to store the new file name.
At the time of the call it should be uninitialized or free.  The
caller must eventually call \fBTcl_DStringFree\fR to free up
anything stored here.
.BE

.SH DESCRIPTION
.PP
This utility procedure translates a file name to a platform-specific form
which, after being converted to the appropriate encoding, is suitable for
passing to the local operating system.  In particular, it converts
network names into native form and does tilde substitution.  
.PP
However, with the advent of the newer \fBTcl_FSGetNormalizedPath\fR and
\fBTcl_FSGetNativePath\fR, there is no longer any need to use this
procedure.  In particular, \fBTcl_FSGetNativePath\fR performs all the
necessary translation and encoding conversion, is virtual-filesystem
aware, and caches the native result for faster repeated calls.
Finally \fBTcl_FSGetNativePath\fR does not require you to free anything
afterwards.
.PP
If
\fBTcl_TranslateFileName\fR has to do tilde substitution or translate
the name then it uses
the dynamic string at \fI*bufferPtr\fR to hold the new string it
generates.
62
63
64
65
66
67
68
69
70
71
72
73
74
in the interpreter's result.
When an error occurs, \fBTcl_TranslateFileName\fR
frees the dynamic string itself so that the caller need not call
\fBTcl_DStringFree\fR.
.PP
The caller is responsible for making sure that the interpreter's result
has its default empty value when \fBTcl_TranslateFileName\fR is invoked.

.SH "SEE ALSO"
filename

.SH KEYWORDS
file name, home directory, tilde, translate, user







<

|
<


61
62
63
64
65
66
67

68
69

70
71
in the interpreter's result.
When an error occurs, \fBTcl_TranslateFileName\fR
frees the dynamic string itself so that the caller need not call
\fBTcl_DStringFree\fR.
.PP
The caller is responsible for making sure that the interpreter's result
has its default empty value when \fBTcl_TranslateFileName\fR is invoked.

.SH "SEE ALSO"
filename(n)

.SH KEYWORDS
file name, home directory, tilde, translate, user

Changes to doc/after.n.

45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
The command will be executed exactly once, at the given time.
The delayed command is formed by concatenating all the \fIscript\fR
arguments in the same fashion as the \fBconcat\fR command.
The command will be executed at global level (outside the context
of any Tcl procedure).
If an error occurs while executing the delayed command then 
the background error will be reported by the command
registered with \fB interp bgerror\fR.
The \fBafter\fR command returns an identifier that can be used
to cancel the delayed command using \fBafter cancel\fR.
.TP
\fBafter cancel \fIid\fR
.
Cancels the execution of a delayed command that
was previously scheduled.







|







45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
The command will be executed exactly once, at the given time.
The delayed command is formed by concatenating all the \fIscript\fR
arguments in the same fashion as the \fBconcat\fR command.
The command will be executed at global level (outside the context
of any Tcl procedure).
If an error occurs while executing the delayed command then 
the background error will be reported by the command
registered with \fBinterp bgerror\fR.
The \fBafter\fR command returns an identifier that can be used
to cancel the delayed command using \fBafter cancel\fR.
.TP
\fBafter cancel \fIid\fR
.
Cancels the execution of a delayed command that
was previously scheduled.
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
for the resulting script to be evaluated later as an idle callback.
The script will be run exactly once, the next time the event
loop is entered and there are no events to process.
The command returns an identifier that can be used
to cancel the delayed command using \fBafter cancel\fR.
If an error occurs while executing the script then the
background error will be reported by the command
registered with \fB interp bgerror\fR.
.TP
\fBafter info \fR?\fIid\fR?
.
This command returns information about existing event handlers.
If no \fIid\fR argument is supplied, the command returns
a list of the identifiers for all existing
event handlers created by the \fBafter\fR command for this







|







78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
for the resulting script to be evaluated later as an idle callback.
The script will be run exactly once, the next time the event
loop is entered and there are no events to process.
The command returns an identifier that can be used
to cancel the delayed command using \fBafter cancel\fR.
If an error occurs while executing the script then the
background error will be reported by the command
registered with \fBinterp bgerror\fR.
.TP
\fBafter info \fR?\fIid\fR?
.
This command returns information about existing event handlers.
If no \fIid\fR argument is supplied, the command returns
a list of the identifiers for all existing
event handlers created by the \fBafter\fR command for this

Changes to doc/binary.n.

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
.TH binary n 8.0 Tcl "Tcl Built-In Commands"
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
binary \- Insert and extract fields from binary strings
.SH SYNOPSIS
.VS 8.6
\fBbinary decode \fIformat\fR ?\fI-option value ...\fR? \fIdata\fR
.br
\fBbinary encode \fIformat\fR ?\fI-option value ...\fR? \fIdata\fR
.br
.VE 8.6
\fBbinary format \fIformatString \fR?\fIarg arg ...\fR?
.br
\fBbinary scan \fIstring formatString \fR?\fIvarName varName ...\fR?
.BE
.SH DESCRIPTION







|

|







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
.TH binary n 8.0 Tcl "Tcl Built-In Commands"
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
binary \- Insert and extract fields from binary strings
.SH SYNOPSIS
.VS 8.6
\fBbinary decode \fIformat\fR ?\fI\-option value ...\fR? \fIdata\fR
.br
\fBbinary encode \fIformat\fR ?\fI\-option value ...\fR? \fIdata\fR
.br
.VE 8.6
\fBbinary format \fIformatString \fR?\fIarg arg ...\fR?
.br
\fBbinary scan \fIstring formatString \fR?\fIvarName varName ...\fR?
.BE
.SH DESCRIPTION

Changes to doc/break.n.

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
.SH SYNOPSIS
\fBbreak\fR
.BE
.SH DESCRIPTION
.PP
This command is typically invoked inside the body of a looping command
such as \fBfor\fR or \fBforeach\fR or \fBwhile\fR.
It returns a \fBTCL_BREAK\fR code, which causes a break exception
to occur.
The exception causes the current script to be aborted
out to the innermost containing loop command, which then
aborts its execution and returns normally.
Break exceptions are also handled in a few other situations, such
as the \fBcatch\fR command, Tk event bindings, and the outermost
scripts of procedure bodies.







|







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
.SH SYNOPSIS
\fBbreak\fR
.BE
.SH DESCRIPTION
.PP
This command is typically invoked inside the body of a looping command
such as \fBfor\fR or \fBforeach\fR or \fBwhile\fR.
It returns a 3 (\fBTCL_BREAK\fR) result code, which causes a break exception
to occur.
The exception causes the current script to be aborted
out to the innermost containing loop command, which then
aborts its execution and returns normally.
Break exceptions are also handled in a few other situations, such
as the \fBcatch\fR command, Tk event bindings, and the outermost
scripts of procedure bodies.

Changes to doc/catch.n.

74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
.QW \fBCALL\fR ,
in which case the parameter is a list made of the proc name and arguments at
the corresponding level; or it may be
.QW \fBUP\fR ,
in which case the parameter is
the relative level (as in \fBuplevel\fR) of the previous \fBCALL\fR. The
salient differences wrt \fB\-errorinfo\fR are that:
.IP (1)
it is a machine-readable form that is amenable to processing with
[\fBforeach\fR {tok prm} ...],
.IP (2)
it contains the true (substituted) values passed to the functions, instead of
the static text of the calling sites, and
.IP (3)
it is coarser-grained, with only one element per stack frame (like procs; no
separate elements for \fBforeach\fR constructs for example).
.VE 8.6
.PP
The values of the \fB\-errorinfo\fR and \fB\-errorcode\fR entries of
the most recent error are also available as values of the global
variables \fB::errorInfo\fR and \fB::errorCode\fR respectively.







|


|


|







74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
.QW \fBCALL\fR ,
in which case the parameter is a list made of the proc name and arguments at
the corresponding level; or it may be
.QW \fBUP\fR ,
in which case the parameter is
the relative level (as in \fBuplevel\fR) of the previous \fBCALL\fR. The
salient differences wrt \fB\-errorinfo\fR are that:
.IP [1]
it is a machine-readable form that is amenable to processing with
[\fBforeach\fR {tok prm} ...],
.IP [2]
it contains the true (substituted) values passed to the functions, instead of
the static text of the calling sites, and
.IP [3]
it is coarser-grained, with only one element per stack frame (like procs; no
separate elements for \fBforeach\fR constructs for example).
.VE 8.6
.PP
The values of the \fB\-errorinfo\fR and \fB\-errorcode\fR entries of
the most recent error are also available as values of the global
variables \fB::errorInfo\fR and \fB::errorCode\fR respectively.

Changes to doc/clock.n.

38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
\fBclock clicks\fR ?\fI\-option\fR?
If no \fI\-option\fR argument is supplied, returns a high-resolution
time value as a system-dependent integer value.  The unit of the value
is system-dependent but should be the highest resolution clock available
on the system such as a CPU cycle counter.  See \fBHIGH RESOLUTION TIMERS\fR for a full description.
.RS
.PP
If the \fI\-option\fR argument is \fI\-milliseconds\fR, then the command
is synonymous with \fBclock milliseconds\fR (see below).  This
usage is obsolete, and \fBclock milliseconds\fR is to be
considered the preferred way of obtaining a count of milliseconds.
.PP
If the \fI\-option\fR argument is \fI\-microseconds\fR, then the command
is synonymous with \fBclock microseconds\fR (see below).  This
usage is obsolete, and \fBclock microseconds\fR is to be
considered the preferred way of obtaining a count of microseconds.
.RE
.TP
\fBclock format\fR \fItimeVal\fR ?\fI\-option value\fR...?
Formats a time that is expressed as an integer number of seconds into a format







|




|







38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
\fBclock clicks\fR ?\fI\-option\fR?
If no \fI\-option\fR argument is supplied, returns a high-resolution
time value as a system-dependent integer value.  The unit of the value
is system-dependent but should be the highest resolution clock available
on the system such as a CPU cycle counter.  See \fBHIGH RESOLUTION TIMERS\fR for a full description.
.RS
.PP
If the \fI\-option\fR argument is \fB\-milliseconds\fR, then the command
is synonymous with \fBclock milliseconds\fR (see below).  This
usage is obsolete, and \fBclock milliseconds\fR is to be
considered the preferred way of obtaining a count of milliseconds.
.PP
If the \fI\-option\fR argument is \fB\-microseconds\fR, then the command
is synonymous with \fBclock microseconds\fR (see below).  This
usage is obsolete, and \fBclock microseconds\fR is to be
considered the preferred way of obtaining a count of microseconds.
.RE
.TP
\fBclock format\fR \fItimeVal\fR ?\fI\-option value\fR...?
Formats a time that is expressed as an integer number of seconds into a format
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
.PP
On \fBclock format\fR, the default format is
.PP
.CS
%a %b %d %H:%M:%S %z %Y
.CE
.PP
On \fBclock scan\fR, the lack of a \fI\-format\fR option indicates that a
.QW "free format scan"
is requested; see \fBFREE FORM SCAN\fR for a description of what happens.
.RE
.TP
\fB\-gmt\fR boolean
If \fIboolean\fR is true, specifies that a time specified to \fBclock add\fR,
\fBclock format\fR or \fBclock scan\fR should be processed in







|







112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
.PP
On \fBclock format\fR, the default format is
.PP
.CS
%a %b %d %H:%M:%S %z %Y
.CE
.PP
On \fBclock scan\fR, the lack of a \fB\-format\fR option indicates that a
.QW "free format scan"
is requested; see \fBFREE FORM SCAN\fR for a description of what happens.
.RE
.TP
\fB\-gmt\fR boolean
If \fIboolean\fR is true, specifies that a time specified to \fBclock add\fR,
\fBclock format\fR or \fBclock scan\fR should be processed in
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
.QW T ,
.QW "\fICCyymmdd hhmmss\fR" ,
or
.QW \fICCyymmdd\fBT\fIhh:mm:ss\fR .
Note that only these three formats are accepted.
The command does \fInot\fR accept the full range of point-in-time
specifications specified in ISO8601.  Other formats can be recognized by
giving an explicit \fI\-format\fR option to the \fBclock scan\fR command.
.TP
\fIrelative time\fR
A specification relative to the current time.  The format is \fBnumber
unit\fR. Acceptable units are \fByear\fR, \fBfortnight\fR, 
\fBmonth\fR, \fBweek\fR, \fBday\fR,
\fBhour\fR, \fBminute\fR (or \fBmin\fR), and \fBsecond\fR (or \fBsec\fR).  The
unit can be specified as a singular or plural, as in \fB3 weeks\fR.







|







900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
.QW T ,
.QW "\fICCyymmdd hhmmss\fR" ,
or
.QW \fICCyymmdd\fBT\fIhh:mm:ss\fR .
Note that only these three formats are accepted.
The command does \fInot\fR accept the full range of point-in-time
specifications specified in ISO8601.  Other formats can be recognized by
giving an explicit \fB\-format\fR option to the \fBclock scan\fR command.
.TP
\fIrelative time\fR
A specification relative to the current time.  The format is \fBnumber
unit\fR. Acceptable units are \fByear\fR, \fBfortnight\fR, 
\fBmonth\fR, \fBweek\fR, \fBday\fR,
\fBhour\fR, \fBminute\fR (or \fBmin\fR), and \fBsecond\fR (or \fBsec\fR).  The
unit can be specified as a singular or plural, as in \fB3 weeks\fR.

Changes to doc/continue.n.

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
.SH SYNOPSIS
\fBcontinue\fR
.BE
.SH DESCRIPTION
.PP
This command is typically invoked inside the body of a looping command
such as \fBfor\fR or \fBforeach\fR or \fBwhile\fR.
It returns a \fBTCL_CONTINUE\fR code, which causes a continue exception
to occur.
The exception causes the current script to be aborted
out to the innermost containing loop command, which then
continues with the next iteration of the loop.
Catch exceptions are also handled in a few other situations, such
as the \fBcatch\fR command and the outermost scripts of procedure
bodies.
.SH EXAMPLE







|
|







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
.SH SYNOPSIS
\fBcontinue\fR
.BE
.SH DESCRIPTION
.PP
This command is typically invoked inside the body of a looping command
such as \fBfor\fR or \fBforeach\fR or \fBwhile\fR.
It returns a 4 (\fBTCL_CONTINUE\fR) result code, which causes a continue
exception to occur.
The exception causes the current script to be aborted
out to the innermost containing loop command, which then
continues with the next iteration of the loop.
Catch exceptions are also handled in a few other situations, such
as the \fBcatch\fR command and the outermost scripts of procedure
bodies.
.SH EXAMPLE

Changes to doc/coroutine.n.

107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
for {set i 1} {$i <= 20} {incr i} {
    puts "prime#$i = [\fIeratosthenes\fR]"
}
.CE
.SS "DETAILED SEMANTICS"
.PP
This example demonstrates that coroutines start from the global namespace, and
that\fIcommand\fR resolution happens before the coroutine stack is created.
.PP
.CS
proc report {where level} {
    # Where was the caller called from?
    set ns [uplevel 2 {namespace current}]
    \fByield\fR "made $where $level context=$ns name=[info coroutine]"
}







|







107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
for {set i 1} {$i <= 20} {incr i} {
    puts "prime#$i = [\fIeratosthenes\fR]"
}
.CE
.SS "DETAILED SEMANTICS"
.PP
This example demonstrates that coroutines start from the global namespace, and
that \fIcommand\fR resolution happens before the coroutine stack is created.
.PP
.CS
proc report {where level} {
    # Where was the caller called from?
    set ns [uplevel 2 {namespace current}]
    \fByield\fR "made $where $level context=$ns name=[info coroutine]"
}

Changes to doc/dict.n.

63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
argument after the rule selection word is a two-element list.  If the
\fIscript\fR returns with a condition of \fBTCL_BREAK\fR, no further
key/value pairs are considered for inclusion in the resulting
dictionary, and a condition of \fBTCL_CONTINUE\fR is equivalent to a false
result. The key/value pairs are tested in the order in which the keys
were inserted into the dictionary.
.TP
\fBdict filter \fIdictionaryValue \fBvalue \fIglobPattern\fR
.VS 8.6
The value rule only matches those key/value pairs whose values match any
of the given patterns (in the style of \fBstring match\fR.)
.VE 8.6
.RE
.TP
\fBdict for {\fIkeyVar valueVar\fB} \fIdictionaryValue body\fR







|







63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
argument after the rule selection word is a two-element list.  If the
\fIscript\fR returns with a condition of \fBTCL_BREAK\fR, no further
key/value pairs are considered for inclusion in the resulting
dictionary, and a condition of \fBTCL_CONTINUE\fR is equivalent to a false
result. The key/value pairs are tested in the order in which the keys
were inserted into the dictionary.
.TP
\fBdict filter \fIdictionaryValue \fBvalue \fR?\fIglobPattern ...\fR?
.VS 8.6
The value rule only matches those key/value pairs whose values match any
of the given patterns (in the style of \fBstring match\fR.)
.VE 8.6
.RE
.TP
\fBdict for {\fIkeyVar valueVar\fB} \fIdictionaryValue body\fR

Changes to doc/error.n.

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
Historically, this feature had been most useful in conjunction
with the \fBcatch\fR command:
if a caught error cannot be handled successfully, \fIinfo\fR can be used
to return a stack trace reflecting the original point of occurrence
of the error:
.PP
.CS
\fBcatch {...} errMsg
set savedInfo $::errorInfo
\&...
error $errMsg $savedInfo\fR
.CE
.PP
When working with Tcl 8.5 or later, the following code
should be used instead:
.PP
.CS
\fBcatch {...} errMsg options
\&...
return -options $options $errMsg\fR
.CE
.PP
If the \fIcode\fR argument is present, then its value is stored
in the \fB\-errorcode\fR return option.  The \fB\-errorcode\fR
return option is intended to hold a machine-readable description
of the error in cases where such information is available; see
the \fBreturn\fR manual page for information on the proper format







|


|






|

|







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
Historically, this feature had been most useful in conjunction
with the \fBcatch\fR command:
if a caught error cannot be handled successfully, \fIinfo\fR can be used
to return a stack trace reflecting the original point of occurrence
of the error:
.PP
.CS
catch {...} errMsg
set savedInfo $::errorInfo
\&...
\fBerror\fR $errMsg $savedInfo
.CE
.PP
When working with Tcl 8.5 or later, the following code
should be used instead:
.PP
.CS
catch {...} errMsg options
\&...
return -options $options $errMsg
.CE
.PP
If the \fIcode\fR argument is present, then its value is stored
in the \fB\-errorcode\fR return option.  The \fB\-errorcode\fR
return option is intended to hold a machine-readable description
of the error in cases where such information is available; see
the \fBreturn\fR manual page for information on the proper format
69
70
71
72
73
74
75



    \fBerror\fR "something is very wrong with addition"
}
.CE
.SH "SEE ALSO"
catch(n), return(n)
.SH KEYWORDS
error, exception










>
>
>
69
70
71
72
73
74
75
76
77
78
    \fBerror\fR "something is very wrong with addition"
}
.CE
.SH "SEE ALSO"
catch(n), return(n)
.SH KEYWORDS
error, exception
'\" Local Variables:
'\" mode: nroff
'\" End:

Changes to doc/exec.n.

235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
.PP
Additionally, when calling a 16-bit DOS or Windows 3.X application, all path
names must use the short, cryptic, path format (e.g., using
.QW applba~1.def
instead of
.QW applbakery.default ),
which can be obtained with the
.QW "\fBfile attributes \fIfileName \fB\-shortname\fR"
command.
.PP
Two or more forward or backward slashes in a row in a path refer to a
network path.  For example, a simple concatenation of the root directory
\fBc:/\fR with a subdirectory \fB/windows/system\fR will yield
\fBc://windows/system\fR (two slashes together), which refers to the mount
point called \fBsystem\fR on the machine called \fBwindows\fR (and the







|







235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
.PP
Additionally, when calling a 16-bit DOS or Windows 3.X application, all path
names must use the short, cryptic, path format (e.g., using
.QW applba~1.def
instead of
.QW applbakery.default ),
which can be obtained with the
.QW "\fBfile attributes\fI fileName \fB\-shortname\fR"
command.
.PP
Two or more forward or backward slashes in a row in a path refer to a
network path.  For example, a simple concatenation of the root directory
\fBc:/\fR with a subdirectory \fB/windows/system\fR will yield
\fBc://windows/system\fR (two slashes together), which refers to the mount
point called \fBsystem\fR on the machine called \fBwindows\fR (and the

Changes to doc/expr.n.

24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
common to both Tcl and C, Tcl applies the same meaning and precedence
as the corresponding C operators.
Expressions almost always yield numeric results
(integer or floating-point values).
For example, the expression
.PP
.CS
\fBexpr 8.2 + 6\fR
.CE
.PP
evaluates to 14.2.
Tcl expressions differ from C expressions in the way that
operands are specified.  Also, Tcl expressions support
non-numeric operands and string comparisons, as well as some
additional operators not found in C.







|







24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
common to both Tcl and C, Tcl applies the same meaning and precedence
as the corresponding C operators.
Expressions almost always yield numeric results
(integer or floating-point values).
For example, the expression
.PP
.CS
\fBexpr\fR 8.2 + 6
.CE
.PP
evaluates to 14.2.
Tcl expressions differ from C expressions in the way that
operands are specified.  Also, Tcl expressions support
non-numeric operands and string comparisons, as well as some
additional operators not found in C.
64
65
66
67
68
69
70
71

72
73
74
75
76
77
78
braces or with double quotes), then an operand is left as a string
(and only a limited set of operators may be applied to it).
.PP
Operands may be specified in any of the following ways:
.IP [1]
As a numeric value, either integer or floating-point.
.IP [2]
As a boolean value, using any form understood by \fBstring is boolean\fR.

.IP [3]
As a Tcl variable, using standard \fB$\fR notation.
The variable's value will be used as the operand.
.IP [4]
As a string enclosed in double-quotes.
The expression parser will perform backslash, variable, and
command substitutions on the information between the quotes,







|
>







64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
braces or with double quotes), then an operand is left as a string
(and only a limited set of operators may be applied to it).
.PP
Operands may be specified in any of the following ways:
.IP [1]
As a numeric value, either integer or floating-point.
.IP [2]
As a boolean value, using any form understood by \fBstring is\fR
\fBboolean\fR.
.IP [3]
As a Tcl variable, using standard \fB$\fR notation.
The variable's value will be used as the operand.
.IP [4]
As a string enclosed in double-quotes.
The expression parser will perform backslash, variable, and
command substitutions on the information between the quotes,
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
.PP
The \fB&&\fR, \fB||\fR, and \fB?:\fR operators have
.QW "lazy evaluation" ,
just as in C, which means that operands are not evaluated if they are
not needed to determine the outcome.  For example, in the command
.PP
.CS
\fBexpr {$v ? [a] : [b]}\fR
.CE
.PP
only one of
.QW \fB[a]\fR
or
.QW \fB[b]\fR
will actually be evaluated,







|







222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
.PP
The \fB&&\fR, \fB||\fR, and \fB?:\fR operators have
.QW "lazy evaluation" ,
just as in C, which means that operands are not evaluated if they are
not needed to determine the outcome.  For example, in the command
.PP
.CS
\fBexpr\fR {$v ? [a] : [b]}
.CE
.PP
only one of
.QW \fB[a]\fR
or
.QW \fB[b]\fR
will actually be evaluated,
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
.PP
When the expression parser encounters a mathematical function
such as \fBsin($x)\fR, it replaces it with a call to an ordinary
Tcl function in the \fBtcl::mathfunc\fR namespace.  The processing
of an expression such as:
.PP
.CS
\fBexpr {sin($x+$y)}\fR
.CE
.PP
is the same in every way as the processing of:
.PP
.CS
\fBexpr {[tcl::mathfunc::sin [expr {$x+$y}]]}\fR
.CE
.PP
which in turn is the same as the processing of:
.PP
.CS
\fBtcl::mathfunc::sin [expr {$x+$y}]\fR
.CE
.PP
The executor will search for \fBtcl::mathfunc::sin\fR using the usual
rules for resolving functions in namespaces. Either
\fB::tcl::mathfunc::sin\fR or \fB[namespace
current]::tcl::mathfunc::sin\fR will satisfy the request, and others
may as well (depending on the current \fBnamespace path\fR setting).







|





|





|







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
.PP
When the expression parser encounters a mathematical function
such as \fBsin($x)\fR, it replaces it with a call to an ordinary
Tcl function in the \fBtcl::mathfunc\fR namespace.  The processing
of an expression such as:
.PP
.CS
\fBexpr\fR {sin($x+$y)}
.CE
.PP
is the same in every way as the processing of:
.PP
.CS
\fBexpr\fR {[tcl::mathfunc::sin [\fBexpr\fR {$x+$y}]]}
.CE
.PP
which in turn is the same as the processing of:
.PP
.CS
tcl::mathfunc::sin [\fBexpr\fR {$x+$y}]
.CE
.PP
The executor will search for \fBtcl::mathfunc::sin\fR using the usual
rules for resolving functions in namespaces. Either
\fB::tcl::mathfunc::sin\fR or \fB[namespace
current]::tcl::mathfunc::sin\fR will satisfy the request, and others
may as well (depending on the current \fBnamespace path\fR setting).
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
operand value is generated to compare with the string operand.
Canonical string representation for integer values is a decimal string
format.  Canonical string representation for floating-point values
is that produced by the \fB%g\fR format specifier of Tcl's
\fBformat\fR command.  For example, the commands
.PP
.CS
\fBexpr {"0x03" > "2"}\fR
\fBexpr {"0y" < "0x12"}\fR
.CE
.PP
both return 1.  The first comparison is done using integer
comparison, and the second is done using string comparison after
the second operand is converted to the string \fB18\fR.
Because of Tcl's tendency to treat values as numbers whenever
possible, it is not generally a good idea to use operators like \fB==\fR







|
|







332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
operand value is generated to compare with the string operand.
Canonical string representation for integer values is a decimal string
format.  Canonical string representation for floating-point values
is that produced by the \fB%g\fR format specifier of Tcl's
\fBformat\fR command.  For example, the commands
.PP
.CS
\fBexpr\fR {"0x03" > "2"}
\fBexpr\fR {"0y" < "0x12"}
.CE
.PP
both return 1.  The first comparison is done using integer
comparison, and the second is done using string comparison after
the second operand is converted to the string \fB18\fR.
Because of Tcl's tendency to treat values as numbers whenever
possible, it is not generally a good idea to use operators like \fB==\fR
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
This allows the Tcl bytecode compiler to generate the best code.
.PP
As mentioned above, expressions are substituted twice:
once by the Tcl parser and once by the \fBexpr\fR command.
For example, the commands
.PP
.CS
\fBset a 3\fR
\fBset b {$a + 2}\fR
\fBexpr $b*4\fR
.CE
.PP
return 11, not a multiple of 4.
This is because the Tcl parser will first substitute \fB$a + 2\fR for
the variable \fBb\fR,
then the \fBexpr\fR command will evaluate the expression \fB$a + 2*4\fR.
.PP







|
|
|







355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
This allows the Tcl bytecode compiler to generate the best code.
.PP
As mentioned above, expressions are substituted twice:
once by the Tcl parser and once by the \fBexpr\fR command.
For example, the commands
.PP
.CS
set a 3
set b {$a + 2}
\fBexpr\fR $b*4
.CE
.PP
return 11, not a multiple of 4.
This is because the Tcl parser will first substitute \fB$a + 2\fR for
the variable \fBb\fR,
then the \fBexpr\fR command will evaluate the expression \fB$a + 2*4\fR.
.PP
440
441
442
443
444
445
446



arithmetic, boolean, compare, expression, fuzzy comparison
.SH COPYRIGHT
.nf
Copyright (c) 1993 The Regents of the University of California.
Copyright (c) 1994-2000 Sun Microsystems Incorporated.
Copyright (c) 2005 by Kevin B. Kenny <[email protected]>. All rights reserved.
.fi










>
>
>
441
442
443
444
445
446
447
448
449
450
arithmetic, boolean, compare, expression, fuzzy comparison
.SH COPYRIGHT
.nf
Copyright (c) 1993 The Regents of the University of California.
Copyright (c) 1994-2000 Sun Microsystems Incorporated.
Copyright (c) 2005 by Kevin B. Kenny <[email protected]>. All rights reserved.
.fi
'\" Local Variables:
'\" mode: nroff
'\" End:

Changes to doc/file.n.

100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
overwritten unless the \fB\-force\fR option is specified (when Tcl will
also attempt to adjust permissions on the destination file or directory
if that is necessary to allow the copy to proceed).  When copying
within a single filesystem, \fIfile copy\fR will copy soft links (i.e.
the links themselves are copied, not the things they point to).  Trying
to overwrite a non-empty directory, overwrite a directory with a file,
or overwrite a file with a directory will all result in errors even if
\fI\-force\fR was specified.  Arguments are processed in the order
specified, halting at the first error, if any.  A \fB\-\|\-\fR marks
the end of switches; the argument following the \fB\-\|\-\fR will be
treated as a \fIsource\fR even if it starts with a \fB\-\fR.
.TP
\fBfile delete \fR?\fB\-force\fR? ?\fB\-\|\-\fR? ?\fIpathname\fR ... ?
.
Removes the file or directory specified by each \fIpathname\fR







|







100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
overwritten unless the \fB\-force\fR option is specified (when Tcl will
also attempt to adjust permissions on the destination file or directory
if that is necessary to allow the copy to proceed).  When copying
within a single filesystem, \fIfile copy\fR will copy soft links (i.e.
the links themselves are copied, not the things they point to).  Trying
to overwrite a non-empty directory, overwrite a directory with a file,
or overwrite a file with a directory will all result in errors even if
\fB\-force\fR was specified.  Arguments are processed in the order
specified, halting at the first error, if any.  A \fB\-\|\-\fR marks
the end of switches; the argument following the \fB\-\|\-\fR will be
treated as a \fIsource\fR even if it starts with a \fB\-\fR.
.TP
\fBfile delete \fR?\fB\-force\fR? ?\fB\-\|\-\fR? ?\fIpathname\fR ... ?
.
Removes the file or directory specified by each \fIpathname\fR
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
only contains one path element, then returns
.QW \fB.\fR .
If \fIname\fR refers to a root directory, then the root directory is
returned.  For example,
.RS
.PP
.CS
\fBfile dirname c:/\fR
.CE
.PP
returns \fBc:/\fR. 
.PP
Note that tilde substitution will only be
performed if it is necessary to complete the command. For example,
.PP
.CS
\fBfile dirname ~/src/foo.c\fR
.CE
.PP
returns \fB~/src\fR, whereas
.PP
.CS
\fBfile dirname ~\fR
.CE
.PP
returns \fB/home\fR (or something similar).
.RE
.TP
\fBfile executable \fIname\fR
.







|








|





|







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
only contains one path element, then returns
.QW \fB.\fR .
If \fIname\fR refers to a root directory, then the root directory is
returned.  For example,
.RS
.PP
.CS
\fBfile dirname\fR c:/
.CE
.PP
returns \fBc:/\fR. 
.PP
Note that tilde substitution will only be
performed if it is necessary to complete the command. For example,
.PP
.CS
\fBfile dirname\fR ~/src/foo.c
.CE
.PP
returns \fB~/src\fR, whereas
.PP
.CS
\fBfile dirname\fR ~
.CE
.PP
returns \fB/home\fR (or something similar).
.RE
.TP
\fBfile executable \fIname\fR
.
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
separator for the current platform.  If a particular \fIname\fR is
relative, then it will be joined to the previous file name argument.
Otherwise, any earlier arguments will be discarded, and joining will
proceed from the current argument.  For example,
.RS
.PP
.CS
\fBfile join a b /foo bar\fR
.CE
.PP
returns \fB/foo/bar\fR.
.PP
Note that any of the names can contain separators, and that the result
is always canonical for the current platform: \fB/\fR for Unix and
Windows.







|







189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
separator for the current platform.  If a particular \fIname\fR is
relative, then it will be joined to the previous file name argument.
Otherwise, any earlier arguments will be discarded, and joining will
proceed from the current argument.  For example,
.RS
.PP
.CS
\fBfile join\fR a b /foo bar
.CE
.PP
returns \fB/foo/bar\fR.
.PP
Note that any of the names can contain separators, and that the result
is always canonical for the current platform: \fB/\fR for Unix and
Windows.
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
create a link in a cross-platform way, and does not care what type of
link is created.
.PP
If the user wishes to make a link of a specific type only, (and signal an
error if for some reason that is not possible), then the optional
\fI\-linktype\fR argument should be given.  Accepted values for
\fI\-linktype\fR are
.QW \-symbolic
and
.QW \-hard .
.PP
On Unix, symbolic links can be made to relative paths, and those paths
must be relative to the actual \fIlinkName\fR's location (not to the
cwd), but on all other platforms where relative links are not supported,
target paths will always be converted to absolute, normalized form
before the link is created (and therefore relative paths are interpreted
as relative to the cwd).  Furthermore,







|

|







223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
create a link in a cross-platform way, and does not care what type of
link is created.
.PP
If the user wishes to make a link of a specific type only, (and signal an
error if for some reason that is not possible), then the optional
\fI\-linktype\fR argument should be given.  Accepted values for
\fI\-linktype\fR are
.QW \fB\-symbolic\fR
and
.QW \fB\-hard\fR .
.PP
On Unix, symbolic links can be made to relative paths, and those paths
must be relative to the actual \fIlinkName\fR's location (not to the
cwd), but on all other platforms where relative links are not supported,
target paths will always be converted to absolute, normalized form
before the link is created (and therefore relative paths are interpreted
as relative to the cwd).  Furthermore,
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
first element of the list will have the same path type as \fIname\fR.
All other elements will be relative.  Path separators will be discarded
unless they are needed to ensure that an element is unambiguously relative.
For example, under Unix
.RS
.PP
.CS
file split /foo/~bar/baz
.CE
.PP
returns
.QW \fB/\0\0foo\0\0./~bar\0\0baz\fR
to ensure that later commands
that use the third component do not attempt to perform tilde
substitution.







|







376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
first element of the list will have the same path type as \fIname\fR.
All other elements will be relative.  Path separators will be discarded
unless they are needed to ensure that an element is unambiguously relative.
For example, under Unix
.RS
.PP
.CS
\fBfile split\fR /foo/~bar/baz
.CE
.PP
returns
.QW \fB/\0\0foo\0\0./~bar\0\0baz\fR
to ensure that later commands
that use the third component do not attempt to perform tilde
substitution.

Changes to doc/fileevent.n.

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
    puts "[string length $data] $data"
    if {[eof $chan]} {
        fileevent $chan readable {}
    }
}

fconfigure $chan -blocking 0 -encoding binary
fileevent $chan readable [list GetData $chan]
.CE
.PP
The next example demonstrates use of \fBgets\fR to read line-oriented
data.
.PP
.CS
proc GetData {chan} {
    if {[gets $chan line] >= 0} {
        puts $line
    }
    if {[eof $chan]} {
        close $chan
    }
}

fconfigure $chan -blocking 0 -buffering line -translation crlf
fileevent $chan readable [list GetData $chan]
.CE
.SH CREDITS
.PP
\fBfileevent\fR is based on the \fBaddinput\fR command created
by Mark Diekhans.
.SH "SEE ALSO"
fconfigure(n), gets(n), interp(n), puts(n), read(n), Tcl_StandardChannels(3)
.SH KEYWORDS
asynchronous I/O, blocking, channel, event handler, nonblocking, readable,
script, writable.







|
















|










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
    puts "[string length $data] $data"
    if {[eof $chan]} {
        fileevent $chan readable {}
    }
}

fconfigure $chan -blocking 0 -encoding binary
\fBfileevent\fR $chan readable [list GetData $chan]
.CE
.PP
The next example demonstrates use of \fBgets\fR to read line-oriented
data.
.PP
.CS
proc GetData {chan} {
    if {[gets $chan line] >= 0} {
        puts $line
    }
    if {[eof $chan]} {
        close $chan
    }
}

fconfigure $chan -blocking 0 -buffering line -translation crlf
\fBfileevent\fR $chan readable [list GetData $chan]
.CE
.SH CREDITS
.PP
\fBfileevent\fR is based on the \fBaddinput\fR command created
by Mark Diekhans.
.SH "SEE ALSO"
fconfigure(n), gets(n), interp(n), puts(n), read(n), Tcl_StandardChannels(3)
.SH KEYWORDS
asynchronous I/O, blocking, channel, event handler, nonblocking, readable,
script, writable.

Changes to doc/filename.n.

34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
qualified, either giving the path relative to the root directory on the
current volume, or relative to the current directory of the specified
volume.  The \fBfile pathtype\fR command can be used to determine the
type of a given path.
.SH "PATH SYNTAX"
.PP
The rules for native names depend on the value reported in the Tcl
array element \fBtcl_platform(platform)\fR:
.TP 10
\fBUnix\fR
On Unix and Apple MacOS X platforms, Tcl uses path names where the
components are separated by slashes.  Path names may be relative or
absolute, and file names may contain any character other than slash.
The file names \fB\&.\fR and \fB\&..\fR are special and refer to the
current directory and the parent of the current directory respectively.







|







34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
qualified, either giving the path relative to the root directory on the
current volume, or relative to the current directory of the specified
volume.  The \fBfile pathtype\fR command can be used to determine the
type of a given path.
.SH "PATH SYNTAX"
.PP
The rules for native names depend on the value reported in the Tcl
\fBplatform\fR element of the \fBtcl_platform\fR array:
.TP 10
\fBUnix\fR
On Unix and Apple MacOS X platforms, Tcl uses path names where the
components are separated by slashes.  Path names may be relative or
absolute, and file names may contain any character other than slash.
The file names \fB\&.\fR and \fB\&..\fR are special and refer to the
current directory and the parent of the current directory respectively.

Changes to doc/format.n.

137
138
139
140
141
142
143
144

145
146
147
148
149
150
151
truncated to a 16-bit range before converting.  This option is rarely useful.
If it is \fBl\fR it specifies that the integer value is 
truncated to the same range as that produced by the \fBwide()\fR
function of the \fBexpr\fR command (at least a 64-bit range).
If neither \fBh\fR nor \fBl\fR are present, the integer value is
truncated to the same range as that produced by the \fBint()\fR
function of the \fBexpr\fR command (at least a 32-bit range, but
determined by the value of \fBtcl_platform(wordSize)\fR).

.SS "MANDATORY CONVERSION TYPE"
.PP
The last thing in a conversion specifier is an alphabetic character
that determines what kind of conversion to perform.
The following conversion characters are currently supported:
.TP 10
\fBd\fR







|
>







137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
truncated to a 16-bit range before converting.  This option is rarely useful.
If it is \fBl\fR it specifies that the integer value is 
truncated to the same range as that produced by the \fBwide()\fR
function of the \fBexpr\fR command (at least a 64-bit range).
If neither \fBh\fR nor \fBl\fR are present, the integer value is
truncated to the same range as that produced by the \fBint()\fR
function of the \fBexpr\fR command (at least a 32-bit range, but
determined by the value of the \fBwordSize\fR element of the
\fBtcl_platform\fR array).
.SS "MANDATORY CONVERSION TYPE"
.PP
The last thing in a conversion specifier is an alphabetic character
that determines what kind of conversion to perform.
The following conversion characters are currently supported:
.TP 10
\fBd\fR

Changes to doc/glob.n.

226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
.QW \fI\e*\fR
will match the single character
.QW \fI*\fR
and will not be
interpreted as a wildcard character. One solution to this problem is
to use the Unix style forward slash as a path separator. Windows style
paths can be converted to Unix style paths with the command
.QW "\fBfile join $path\fR"
or
.QW "\fBfile normalize $path\fR" .
.SH EXAMPLES
.PP
Find all the Tcl files in the current directory:
.PP
.CS
\fBglob\fR *.tcl
.CE







|

|







226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
.QW \fI\e*\fR
will match the single character
.QW \fI*\fR
and will not be
interpreted as a wildcard character. One solution to this problem is
to use the Unix style forward slash as a path separator. Windows style
paths can be converted to Unix style paths with the command
.QW "\fBfile join\fR \fB$path\fR"
or
.QW "\fBfile normalize\fR \fB$path\fR" .
.SH EXAMPLES
.PP
Find all the Tcl files in the current directory:
.PP
.CS
\fBglob\fR *.tcl
.CE

Changes to doc/http.n.

12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
http \- Client-side implementation of the HTTP/1.1 protocol
.SH SYNOPSIS
\fBpackage require http ?2.7?\fR
.\" See Also -useragent option documentation in body!
.sp
\fB::http::config ?\fI-option value\fR ...?
.sp
\fB::http::geturl \fIurl\fR ?\fI-option value\fR ...?
.sp
\fB::http::formatQuery\fR \fIkey value\fR ?\fIkey value\fR ...?
.sp
\fB::http::reset\fR \fItoken\fR ?\fIwhy\fR?
.sp
\fB::http::wait \fItoken\fR
.sp







|

|







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
http \- Client-side implementation of the HTTP/1.1 protocol
.SH SYNOPSIS
\fBpackage require http ?2.7?\fR
.\" See Also -useragent option documentation in body!
.sp
\fB::http::config ?\fI\-option value\fR ...?
.sp
\fB::http::geturl \fIurl\fR ?\fI\-option value\fR ...?
.sp
\fB::http::formatQuery\fR \fIkey value\fR ?\fIkey value\fR ...?
.sp
\fB::http::reset\fR \fItoken\fR ?\fIwhy\fR?
.sp
\fB::http::wait \fItoken\fR
.sp
45
46
47
48
49
50
51

52
53
54
55
56
57
58
59
\fB::http::register \fIproto port command\fR
.sp
\fB::http::unregister \fIproto\fR
.BE
.SH DESCRIPTION
.PP
The \fBhttp\fR package provides the client side of the HTTP/1.1

protocol.  The package implements the GET, POST, and HEAD operations
of HTTP/1.1.  It allows configuration of a proxy host to get through
firewalls.  The package is compatible with the \fBSafesock\fR security
policy, so it can be used by untrusted applets to do URL fetching from
a restricted set of hosts. This package can be extended to support
additional HTTP transport protocols, such as HTTPS, by providing
a custom \fBsocket\fR command, via \fB::http::register\fR.
.PP







>
|







45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
\fB::http::register \fIproto port command\fR
.sp
\fB::http::unregister \fIproto\fR
.BE
.SH DESCRIPTION
.PP
The \fBhttp\fR package provides the client side of the HTTP/1.1
protocol, as defined in RFC 2616.
The package implements the GET, POST, and HEAD operations
of HTTP/1.1.  It allows configuration of a proxy host to get through
firewalls.  The package is compatible with the \fBSafesock\fR security
policy, so it can be used by untrusted applets to do URL fetching from
a restricted set of hosts. This package can be extended to support
additional HTTP transport protocols, such as HTTPS, by providing
a custom \fBsocket\fR command, via \fB::http::register\fR.
.PP

Changes to doc/info.n.

394
395
396
397
398
399
400























401
402
403
404
405
406
407
if it has not
been set (e.g. a variable declared but not set by \fBvariable\fR).
.SS "CLASS INTROSPECTION"
.VS 8.6
.PP
The following \fIsubcommand\fR values are supported by \fBinfo class\fR:
.VE 8.6























.TP
\fBinfo class constructor\fI class\fR
.VS 8.6
This subcommand returns a description of the definition of the constructor of
class \fIclass\fR. The defintion is described as a two element list; the first
element is the list of arguments to the constructor in a form suitable for
passing to another call to \fBproc\fR or a method defintion, and the second







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







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
if it has not
been set (e.g. a variable declared but not set by \fBvariable\fR).
.SS "CLASS INTROSPECTION"
.VS 8.6
.PP
The following \fIsubcommand\fR values are supported by \fBinfo class\fR:
.VE 8.6
.TP
\fBinfo class call\fI class method\fR
.VS
Returns a description of the method implementations that are used to provide a
stereotypical instance of \fIclass\fR's implementation of \fImethod\fR
(stereotypical instances being objects instantiated by a class without having
any object-specific definitions added). This consists of a list of lists of
four elements, where each sublist consists of a word that describes the
general type of method implementation (being one of \fBmethod\fR for an
ordinary method, \fBfilter\fR for an applied filter, and \fBunknown\fR for a
method that is invoked as part of unknown method handling), a word giving the
name of the particular method invoked (which is always the same as
\fImethod\fR for the \fBmethod\fR type, and
.QW \fBunknown\fR
for the \fBunknown\fR type), a word giving the fully qualified name of the
class that defined the method, and a word describing the type of method
implementation (see \fBinfo class methodtype\fR).
.RS
.PP
Note that there is no inspection of whether the method implementations
actually use \fBnext\fR to transfer control along the call chain.
.RE
.VE 8.6
.TP
\fBinfo class constructor\fI class\fR
.VS 8.6
This subcommand returns a description of the definition of the constructor of
class \fIclass\fR. The defintion is described as a two element list; the first
element is the list of arguments to the constructor in a form suitable for
passing to another call to \fBproc\fR or a method defintion, and the second
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
class named \fIclass\fR.
.VE 8.6
.TP
\fBinfo class subclasses\fI class\fR ?\fIpattern\fR?
.VS 8.6
This subcommand returns a list of direct subclasses of class \fIclass\fR. If
the optional \fIpattern\fR argument is present, it constrains the list of
returned classes to those that match it according to the rules of \fBstring
match\fR.
.VE 8.6
.TP
\fBinfo class superclasses\fI class\fR
.VS 8.6
This subcommand returns a list of direct superclasses of class \fIclass\fR in
inheritance precedence order.
.VE 8.6
.TP
\fBinfo class variables\fI class\fR
.VS 8.6
This subcommand returns a list of all variables that have been declared for
the class named \fIclass\fR (i.e. that are automatically present in the
class's methods, constructor and destructor).
.SS "OBJECT INTROSPECTION"
.PP
The following \fIsubcommand\fR values are supported by \fBinfo object\fR:






















.VE 8.6
.TP
\fBinfo object class\fI object\fR ?\fIclassName\fR?
.VS 8.6
If \fIclassName\fR is unspecified, this subcommand returns class of the
\fIobject\fR object. If \fIclassName\fR is present, this subcommand returns a
boolean value indicating whether the \fIobject\fR is of that class.







|
|
















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







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
class named \fIclass\fR.
.VE 8.6
.TP
\fBinfo class subclasses\fI class\fR ?\fIpattern\fR?
.VS 8.6
This subcommand returns a list of direct subclasses of class \fIclass\fR. If
the optional \fIpattern\fR argument is present, it constrains the list of
returned classes to those that match it according to the rules of
\fBstring match\fR.
.VE 8.6
.TP
\fBinfo class superclasses\fI class\fR
.VS 8.6
This subcommand returns a list of direct superclasses of class \fIclass\fR in
inheritance precedence order.
.VE 8.6
.TP
\fBinfo class variables\fI class\fR
.VS 8.6
This subcommand returns a list of all variables that have been declared for
the class named \fIclass\fR (i.e. that are automatically present in the
class's methods, constructor and destructor).
.SS "OBJECT INTROSPECTION"
.PP
The following \fIsubcommand\fR values are supported by \fBinfo object\fR:
.VE 8.6
.TP
\fBinfo object call\fI object method\fR
.VS 8.6
Returns a description of the method implementations that are used to provide
\fIobject\fR's implementation of \fImethod\fR.  This consists of a list of
lists of four elements, where each sublist consists of a word that describes
the general type of method implementation (being one of \fBmethod\fR for an
ordinary method, \fBfilter\fR for an applied filter, and \fBunknown\fR for a
method that is invoked as part of unknown method handling), a word giving the
name of the particular method invoked (which is always the same as
\fImethod\fR for the \fBmethod\fR type, and
.QW \fBunknown\fR
for the \fBunknown\fR type), a word giving what defined the method (the fully
qualified name of the class, or the literal string \fBobject\fR if the method
implementation is on an instance), and a word describing the type of method
implementation (see \fBinfo object methodtype\fR).
.RS
.PP
Note that there is no inspection of whether the method implementations
actually use \fBnext\fR to transfer control along the call chain.
.RE
.VE 8.6
.TP
\fBinfo object class\fI object\fR ?\fIclassName\fR?
.VS 8.6
If \fIclassName\fR is unspecified, this subcommand returns class of the
\fIobject\fR object. If \fIclassName\fR is present, this subcommand returns a
boolean value indicating whether the \fIobject\fR is of that class.
666
667
668
669
670
671
672





















673
674
675
676
677
678
679
puts [\fBinfo object class\fR c]
                     \fI\(-> prints "::oo::class"\fR
.CE
.PP
The introspection capabilities can be used to discover what class implements a
method and get how it is defined. This procedure illustrates how:
.PP





















.CS
proc getDef {obj method} {
    if {$method in [\fBinfo object methods\fR $obj]} {
        # Assume no forwards
        return [\fBinfo object definition\fR $obj $method]
    }
    set cls [\fBinfo object class\fR $obj]







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







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
puts [\fBinfo object class\fR c]
                     \fI\(-> prints "::oo::class"\fR
.CE
.PP
The introspection capabilities can be used to discover what class implements a
method and get how it is defined. This procedure illustrates how:
.PP
.CS
proc getDef {obj method} {
    foreach inf [\fBinfo object call\fR $obj $method] {
        lassign $inf calltype name locus methodtype
        # Assume no forwards or filters, and hence no $calltype
        # or $methodtype checks...
        if {$locus eq "object"} {
            return [\fBinfo object definition\fR $obj $name]
        } else {
            return [\fBinfo class definition\fR $locus $name]
        }
    }
    error "no definition for $method"
}
.CE
.PP
This is an alternate way of implementing the definition lookup is by manually
scanning the list of methods up the inheritance tree. This code assumes that
only single inheritance is in use, and that there is no complex use of
mixed-in classes:
.PP
.CS
proc getDef {obj method} {
    if {$method in [\fBinfo object methods\fR $obj]} {
        # Assume no forwards
        return [\fBinfo object definition\fR $obj $method]
    }
    set cls [\fBinfo object class\fR $obj]

Changes to doc/interp.n.

57
58
59
60
61
62
63
64

65



66




67
68
69
70
71
72
73
74
kernel call) between a slave interpreter and its master.
See \fBALIAS INVOCATION\fR, below, for more details
on how the alias mechanism works.
.PP
A qualified interpreter name is a proper Tcl lists containing a subset of its
ancestors in the interpreter hierarchy, terminated by the string naming the
interpreter in its immediate master. Interpreter names are relative to the
interpreter in which they are used. For example, if \fBa\fR is a slave of

the current interpreter and it has a slave \fBa1\fR, which in turn has a



slave \fBa11\fR, the qualified name of \fBa11\fR in \fBa\fR is the list




\fBa1 a11\fR.
.PP
The \fBinterp\fR command, described below, accepts qualified interpreter
names as arguments; the interpreter in which the command is being evaluated
can always be referred to as \fB{}\fR (the empty list or string). Note that
it is impossible to refer to a master (ancestor) interpreter by name in a
slave interpreter except through aliases. Also, there is no global name by
which one can refer to the first interpreter created in an application.







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







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
kernel call) between a slave interpreter and its master.
See \fBALIAS INVOCATION\fR, below, for more details
on how the alias mechanism works.
.PP
A qualified interpreter name is a proper Tcl lists containing a subset of its
ancestors in the interpreter hierarchy, terminated by the string naming the
interpreter in its immediate master. Interpreter names are relative to the
interpreter in which they are used. For example, if
.QW \fBa\fR
is a slave of the current interpreter and it has a slave
.QW \fBa1\fR ,
which in turn has a slave
.QW \fBa11\fR ,
the qualified name of
.QW \fBa11\fR
in
.QW \fBa\fR
is the list
.QW "\fBa1 a11\fR" .
.PP
The \fBinterp\fR command, described below, accepts qualified interpreter
names as arguments; the interpreter in which the command is being evaluated
can always be referred to as \fB{}\fR (the empty list or string). Note that
it is impossible to refer to a master (ancestor) interpreter by name in a
slave interpreter except through aliases. Also, there is no global name by
which one can refer to the first interpreter created in an application.
104
105
106
107
108
109
110

111

112
113
114
115
116
117
118
119
120
121
may be anywhere in the hierarchy of interpreters under the interpreter
invoking the command.
\fISrcPath\fR and \fIsrcCmd\fR identify the source of the alias.
\fISrcPath\fR is a Tcl list whose elements select a particular
interpreter.  For example,
.QW "\fBa b\fR"
identifies an interpreter

\fBb\fR, which is a slave of interpreter \fBa\fR, which is a slave

of the invoking interpreter.  An empty list specifies the interpreter
invoking the command.  \fIsrcCmd\fR gives the name of a new
command, which will be created in the source interpreter.
\fITargetPath\fR and \fItargetCmd\fR specify a target interpreter
and command, and the \fIarg\fR arguments, if any, specify additional
arguments to \fItargetCmd\fR which are prepended to any arguments specified
in the invocation of \fIsrcCmd\fR.
\fITargetCmd\fR may be undefined at the time of this call, or it may
already exist; it is not created by this command.
The alias arranges for the given target command to be invoked







>
|
>
|
|
|







112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
may be anywhere in the hierarchy of interpreters under the interpreter
invoking the command.
\fISrcPath\fR and \fIsrcCmd\fR identify the source of the alias.
\fISrcPath\fR is a Tcl list whose elements select a particular
interpreter.  For example,
.QW "\fBa b\fR"
identifies an interpreter
.QW \fBb\fR ,
which is a slave of interpreter
.QW \fBa\fR ,
which is a slave of the invoking interpreter.  An empty list specifies
the interpreter invoking the command.  \fIsrcCmd\fR gives the name of
a new command, which will be created in the source interpreter.
\fITargetPath\fR and \fItargetCmd\fR specify a target interpreter
and command, and the \fIarg\fR arguments, if any, specify additional
arguments to \fItargetCmd\fR which are prepended to any arguments specified
in the invocation of \fIsrcCmd\fR.
\fITargetCmd\fR may be undefined at the time of this call, or it may
already exist; it is not created by this command.
The alias arranges for the given target command to be invoked
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
value such as \fB\-safe\fR. The result of the command is the name of the
new interpreter. The name of a slave interpreter must be unique among all
the slaves for its master;  an error occurs if a slave interpreter by the
given name already exists in this master.
The initial recursion limit of the slave interpreter is set to the
current recursion limit of its parent interpreter.
.TP
\fBinterp\fR \fBdebug \fIpath\fR ?\fI\-frame\fR ?\fIbool\fR??
.
Controls whether frame-level stack information is captured in the
slave interpreter identified by \fIpath\fR.  If no arguments are
given, option and current setting are returned.  If \fI\-frame\fR
is given, the debug setting is set to the given boolean if provided
and the current setting is returned.
This only effects the output of \fBinfo frame\fR, in that exact
frame-level information for command invocation at the bytecode level
is only captured with this setting on.
.PP
.RS

For example, with code like
.PP
.CS
\fBproc\fR mycontrol {... script} {
  ...
  \fBuplevel\fR 1 $script
  ...







|



|





<

>







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
value such as \fB\-safe\fR. The result of the command is the name of the
new interpreter. The name of a slave interpreter must be unique among all
the slaves for its master;  an error occurs if a slave interpreter by the
given name already exists in this master.
The initial recursion limit of the slave interpreter is set to the
current recursion limit of its parent interpreter.
.TP
\fBinterp\fR \fBdebug \fIpath\fR ?\fB\-frame\fR ?\fIbool\fR??
.
Controls whether frame-level stack information is captured in the
slave interpreter identified by \fIpath\fR.  If no arguments are
given, option and current setting are returned.  If \fB\-frame\fR
is given, the debug setting is set to the given boolean if provided
and the current setting is returned.
This only effects the output of \fBinfo frame\fR, in that exact
frame-level information for command invocation at the bytecode level
is only captured with this setting on.

.RS
.PP
For example, with code like
.PP
.CS
\fBproc\fR mycontrol {... script} {
  ...
  \fBuplevel\fR 1 $script
  ...
216
217
218
219
220
221
222




223
224
225
226
227
228
229
the standard setting will provide a relative line number for the
command \fBsomecode\fR and the relevant frame will be of type
\fBeval\fR. With frame-debug active on the other hand the tracking
extends so far that the system will be able to determine the file and
absolute line number of this command, and return a frame of type
\fBsource\fR. This more exact information is paid for with slower
execution of all commands.




.RE
.TP
\fBinterp\fR \fBdelete \fR?\fIpath ...?\fR
.
Deletes zero or more interpreters given by the optional \fIpath\fR
arguments, and for each interpreter, it also deletes its slaves. The
command also deletes the slave command for each interpreter deleted.







>
>
>
>







226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
the standard setting will provide a relative line number for the
command \fBsomecode\fR and the relevant frame will be of type
\fBeval\fR. With frame-debug active on the other hand the tracking
extends so far that the system will be able to determine the file and
absolute line number of this command, and return a frame of type
\fBsource\fR. This more exact information is paid for with slower
execution of all commands.
.PP
Note that once it is on, this flag cannot be switched back off: such
attempts are silently ignored. This is needed to maintain the
consistency of the underlying interpreter's state.
.RE
.TP
\fBinterp\fR \fBdelete \fR?\fIpath ...?\fR
.
Deletes zero or more interpreters given by the optional \fIpath\fR
arguments, and for each interpreter, it also deletes its slaves. The
command also deletes the slave command for each interpreter deleted.
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
already trusted.
.TP
\fBinterp\fR \fBrecursionlimit\fR \fIpath\fR ?\fInewlimit\fR?
.
Returns the maximum allowable nesting depth for the interpreter
specified by \fIpath\fR.  If \fInewlimit\fR is specified,
the interpreter recursion limit will be set so that nesting
of more than \fInewlimit\fR calls to \fBTcl_Eval()\fR
and related procedures in that interpreter will return an error.
The \fInewlimit\fR value is also returned.
The \fInewlimit\fR value must be a positive integer between 1 and the
maximum value of a non-long integer on the platform.
.RS
.PP
The command sets the maximum size of the Tcl call stack only. It cannot







|







342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
already trusted.
.TP
\fBinterp\fR \fBrecursionlimit\fR \fIpath\fR ?\fInewlimit\fR?
.
Returns the maximum allowable nesting depth for the interpreter
specified by \fIpath\fR.  If \fInewlimit\fR is specified,
the interpreter recursion limit will be set so that nesting
of more than \fInewlimit\fR calls to \fBTcl_Eval\fR
and related procedures in that interpreter will return an error.
The \fInewlimit\fR value is also returned.
The \fInewlimit\fR value must be a positive integer between 1 and the
maximum value of a non-long integer on the platform.
.RS
.PP
The command sets the maximum size of the Tcl call stack only. It cannot

Changes to doc/lassign.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
59
60
unassigned elements is returned.
.SH EXAMPLES
.PP
An illustration of how multiple assignment works, and what happens
when there are either too few or too many elements.
.PP
.CS
lassign {a b c} x y z       ;# Empty return
puts $x                     ;# Prints "a"
puts $y                     ;# Prints "b"
puts $z                     ;# Prints "c"

lassign {d e} x y z         ;# Empty return
puts $x                     ;# Prints "d"
puts $y                     ;# Prints "e"
puts $z                     ;# Prints ""

lassign {f g h i} x y       ;# Returns "h i"
puts $x                     ;# Prints "f"
puts $y                     ;# Prints "g"
.CE
.PP
The \fBlassign\fR command has other uses.  It can be used to create
the analogue of the
.QW shift
command in many shell languages like this:
.PP
.CS
set ::argv [lassign $::argv argumentToReadOff]
.CE
.SH "SEE ALSO"
lindex(n), list(n), lset(n), set(n)
.SH KEYWORDS
assign, element, list, multiple, set, variable
'\"Local Variables:
'\"mode: nroff
'\"End:







|




|




|










|


|





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
unassigned elements is returned.
.SH EXAMPLES
.PP
An illustration of how multiple assignment works, and what happens
when there are either too few or too many elements.
.PP
.CS
\fBlassign\fR {a b c} x y z       ;# Empty return
puts $x                     ;# Prints "a"
puts $y                     ;# Prints "b"
puts $z                     ;# Prints "c"

\fBlassign\fR {d e} x y z         ;# Empty return
puts $x                     ;# Prints "d"
puts $y                     ;# Prints "e"
puts $z                     ;# Prints ""

\fBlassign\fR {f g h i} x y       ;# Returns "h i"
puts $x                     ;# Prints "f"
puts $y                     ;# Prints "g"
.CE
.PP
The \fBlassign\fR command has other uses.  It can be used to create
the analogue of the
.QW shift
command in many shell languages like this:
.PP
.CS
set ::argv [\fBlassign\fR $::argv argumentToReadOff]
.CE
.SH "SEE ALSO"
lindex(n), list(n), lrange(n), lset(n), set(n)
.SH KEYWORDS
assign, element, list, multiple, set, variable
'\"Local Variables:
'\"mode: nroff
'\"End:

Changes to doc/lindex.n.

22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
the list.  The indices may be presented either consecutively on the
command line, or grouped in a
Tcl list and presented as a single argument.
.PP
If no indices are presented, the command takes the form:
.PP
.CS
lindex list
.CE
.PP
or
.PP
.CS
lindex list {}
.CE
.PP
In this case, the return value of \fBlindex\fR is simply the value of the
\fIlist\fR parameter.
.PP
When presented with a single index, the \fBlindex\fR command
treats \fIlist\fR as a Tcl list and returns the







|





|







22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
the list.  The indices may be presented either consecutively on the
command line, or grouped in a
Tcl list and presented as a single argument.
.PP
If no indices are presented, the command takes the form:
.PP
.CS
\fBlindex \fIlist\fR
.CE
.PP
or
.PP
.CS
\fBlindex \fIlist\fR {}
.CE
.PP
In this case, the return value of \fBlindex\fR is simply the value of the
\fIlist\fR parameter.
.PP
When presented with a single index, the \fBlindex\fR command
treats \fIlist\fR as a Tcl list and returns the
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
arithmetic and indices relative to the end of the list.
.PP
If additional \fIindex\fR arguments are supplied, then each argument is
used in turn to select an element from the previous indexing operation,
allowing the script to select elements from sublists.  The command,
.PP
.CS
lindex $a 1 2 3
.CE
.PP
or
.PP
.CS
lindex $a {1 2 3}
.CE
.PP
is synonymous with
.PP
.CS
lindex [lindex [lindex $a 1] 2] 3
.CE
.SH EXAMPLES
.PP
Lists can be indexed into from either end:
.PP
.CS
\fBlindex\fR {a b c} 0







|





|





|







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
arithmetic and indices relative to the end of the list.
.PP
If additional \fIindex\fR arguments are supplied, then each argument is
used in turn to select an element from the previous indexing operation,
allowing the script to select elements from sublists.  The command,
.PP
.CS
\fBlindex\fR $a 1 2 3
.CE
.PP
or
.PP
.CS
\fBlindex\fR $a {1 2 3}
.CE
.PP
is synonymous with
.PP
.CS
\fBlindex\fR [\fBlindex\fR [\fBlindex\fR $a 1] 2] 3
.CE
.SH EXAMPLES
.PP
Lists can be indexed into from either end:
.PP
.CS
\fBlindex\fR {a b c} 0

Changes to doc/lsearch.n.

157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
.TP
\fB\-subindices\fR
.
If this option is given, the index result from this command (or every
index result when \fB\-all\fR is also specified) will be a complete
path (suitable for use with \fBlindex\fR or \fBlset\fR) within the
overall list to the term found.  This option has no effect unless the
\fI\-index\fR is also specified, and is just a convenience short-cut.
.SH EXAMPLES
.PP
Basic searching:
.PP
.CS
\fBlsearch\fR {a b c d e} c
      \fI\(-> 2\fR







|







157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
.TP
\fB\-subindices\fR
.
If this option is given, the index result from this command (or every
index result when \fB\-all\fR is also specified) will be a complete
path (suitable for use with \fBlindex\fR or \fBlset\fR) within the
overall list to the term found.  This option has no effect unless the
\fB\-index\fR is also specified, and is just a convenience short-cut.
.SH EXAMPLES
.PP
Basic searching:
.PP
.CS
\fBlsearch\fR {a b c d e} c
      \fI\(-> 2\fR

Changes to doc/lset.n.

22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
command line, or grouped in a
Tcl list and presented as a single argument.
Finally, it accepts a new value for an element of \fIvarName\fR.
.PP
If no indices are presented, the command takes the form:
.PP
.CS
lset varName newValue
.CE
.PP
or
.PP
.CS
lset varName {} newValue
.CE
.PP
In this case, \fInewValue\fR replaces the old value of the variable
\fIvarName\fR.
.PP
When presented with a single index, the \fBlset\fR command
treats the content of the \fIvarName\fR variable as a Tcl list.







|





|







22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
command line, or grouped in a
Tcl list and presented as a single argument.
Finally, it accepts a new value for an element of \fIvarName\fR.
.PP
If no indices are presented, the command takes the form:
.PP
.CS
\fBlset\fR varName newValue
.CE
.PP
or
.PP
.CS
\fBlset\fR varName {} newValue
.CE
.PP
In this case, \fInewValue\fR replaces the old value of the variable
\fIvarName\fR.
.PP
When presented with a single index, the \fBlset\fR command
treats the content of the \fIvarName\fR variable as a Tcl list.
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
If additional \fIindex\fR arguments are supplied, then each argument is
used in turn to address an element within a sublist designated
by the previous indexing operation,
allowing the script to alter elements in sublists (or append elements
to sublists).  The command,
.PP
.CS
lset a 1 2 newValue
.CE
.PP
or
.PP
.CS
lset a {1 2} newValue
.CE
.PP
replaces element 2 of sublist 1 with \fInewValue\fR.
.PP
The integer appearing in each \fIindex\fR argument must be greater
than or equal to zero.  The integer appearing in each \fIindex\fR
argument must be less than or equal to the length of the corresponding







|





|







64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
If additional \fIindex\fR arguments are supplied, then each argument is
used in turn to address an element within a sublist designated
by the previous indexing operation,
allowing the script to alter elements in sublists (or append elements
to sublists).  The command,
.PP
.CS
\fBlset\fR a 1 2 newValue
.CE
.PP
or
.PP
.CS
\fBlset\fR a {1 2} newValue
.CE
.PP
replaces element 2 of sublist 1 with \fInewValue\fR.
.PP
The integer appearing in each \fIindex\fR argument must be greater
than or equal to zero.  The integer appearing in each \fIindex\fR
argument must be less than or equal to the length of the corresponding

Changes to doc/lsort.n.

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
.
Return a list of indices into \fIlist\fR in sorted order instead of
the values themselves.
.TP
\fB\-index\0\fIindexList\fR
.
If this option is specified, each of the elements of \fIlist\fR must
itself be a proper Tcl sublist (unless \fB-stride\fR is used).
Instead of sorting based on whole sublists, \fBlsort\fR will extract
the \fIindexList\fR'th element from each sublist (as if the overall
element and the \fIindexList\fR were passed to \fBlindex\fR) and sort
based on the given element.
For example,
.RS
.PP
.CS
lsort -integer -index 1 \e
      {{First 24} {Second 18} {Third 30}}
.CE
.PP
returns \fB{Second 18} {First 24} {Third 30}\fR,
.PP
'\"
'\" This example is from the test suite!
'\"
.CS
lsort -index end-1 \e
        {{a 1 e i} {b 2 3 f g} {c 4 5 6 d h}}
.CE
.PP
returns \fB{c 4 5 6 d h} {a 1 e i} {b 2 3 f g}\fR,
and
.PP
.CS
lsort -index {0 1} {
    {{b i g} 12345}
    {{d e m o} 34512}
    {{c o d e} 54321}
}
.CE
.PP
returns \fB{{d e m o} 34512} {{b i g} 12345} {{c o d e} 54321}\fR







|








|









|







|







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
.
Return a list of indices into \fIlist\fR in sorted order instead of
the values themselves.
.TP
\fB\-index\0\fIindexList\fR
.
If this option is specified, each of the elements of \fIlist\fR must
itself be a proper Tcl sublist (unless \fB\-stride\fR is used).
Instead of sorting based on whole sublists, \fBlsort\fR will extract
the \fIindexList\fR'th element from each sublist (as if the overall
element and the \fIindexList\fR were passed to \fBlindex\fR) and sort
based on the given element.
For example,
.RS
.PP
.CS
\fBlsort\fR -integer -index 1 \e
      {{First 24} {Second 18} {Third 30}}
.CE
.PP
returns \fB{Second 18} {First 24} {Third 30}\fR,
.PP
'\"
'\" This example is from the test suite!
'\"
.CS
\fBlsort\fR -index end-1 \e
        {{a 1 e i} {b 2 3 f g} {c 4 5 6 d h}}
.CE
.PP
returns \fB{c 4 5 6 d h} {a 1 e i} {b 2 3 f g}\fR,
and
.PP
.CS
\fBlsort\fR -index {0 1} {
    {{b i g} 12345}
    {{d e m o} 34512}
    {{c o d e} 54321}
}
.CE
.PP
returns \fB{{d e m o} 34512} {{b i g} 12345} {{c o d e} 54321}\fR
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
.PP
The list length must be an integer multiple of \fIstrideLength\fR, which
in turn must be at least 2.
.PP
For example,
.PP
.CS
lsort \-stride 2 {carrot 10 apple 50 banana 25}
.CE
.PP
returns
.QW "apple 50 banana 25 carrot 10" ,
and
.PP
.CS
lsort \-stride 2 \-index 1 \-integer {carrot 10 apple 50 banana 25}
.CE
.PP
returns
.QW "carrot 10 banana 25 apple 50" .
.RE
.TP
\fB\-nocase\fR
.
Causes comparisons to be handled in a case-insensitive manner.  Has no
effect if combined with the \fB\-dictionary\fR, \fB\-integer\fR, or 
\fB\-real\fR options.
.TP
\fB\-unique\fR
.
If this option is specified, then only the last set of duplicate
elements found in the list will be retained.  Note that duplicates are
determined relative to the comparison used in the sort.  Thus if 
\fI\-index 0\fR is used, \fB{1 a}\fR and \fB{1 b}\fR would be
considered duplicates and only the second element, \fB{1 b}\fR, would
be retained.
.SH "NOTES"
.PP
The options to \fBlsort\fR only control what sort of comparison is
used, and do not necessarily constrain what the values themselves
actually are.  This distinction is only noticeable when the list to be







|







|

















|







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
.PP
The list length must be an integer multiple of \fIstrideLength\fR, which
in turn must be at least 2.
.PP
For example,
.PP
.CS
\fBlsort\fR \-stride 2 {carrot 10 apple 50 banana 25}
.CE
.PP
returns
.QW "apple 50 banana 25 carrot 10" ,
and
.PP
.CS
\fBlsort\fR \-stride 2 \-index 1 \-integer {carrot 10 apple 50 banana 25}
.CE
.PP
returns
.QW "carrot 10 banana 25 apple 50" .
.RE
.TP
\fB\-nocase\fR
.
Causes comparisons to be handled in a case-insensitive manner.  Has no
effect if combined with the \fB\-dictionary\fR, \fB\-integer\fR, or 
\fB\-real\fR options.
.TP
\fB\-unique\fR
.
If this option is specified, then only the last set of duplicate
elements found in the list will be retained.  Note that duplicates are
determined relative to the comparison used in the sort.  Thus if 
\fB\-index 0\fR is used, \fB{1 a}\fR and \fB{1 b}\fR would be
considered duplicates and only the second element, \fB{1 b}\fR, would
be retained.
.SH "NOTES"
.PP
The options to \fBlsort\fR only control what sort of comparison is
used, and do not necessarily constrain what the values themselves
actually are.  This distinction is only noticeable when the list to be

Changes to doc/mathfunc.n.

191
192
193
194
195
196
197
198

199


200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
\fBfmod \fIx y\fR
.
Returns the floating-point remainder of the division of \fIx\fR by
\fIy\fR.  If \fIy\fR is 0, an error is returned.
.TP
\fBhypot \fIx y\fR
.
Computes the length of the hypotenuse of a right-angled triangle

.QW "\fBsqrt\fR [\fBexpr\fR {\fIx\fB*\fIx\fB+\fIy\fB*\fIy\fR}]".


.TP
\fBint \fIarg\fR
.
The argument may be any numeric value.  The integer part of \fIarg\fR
is determined, and then the low order bits of that integer value up
to the machine word size are returned as an integer value.  For reference,
the number of bytes in the machine word are stored in
\fBtcl_platform(wordSize)\fR.
.TP
\fBisqrt \fIarg\fR
.
Computes the integer part of the square root of \fIarg\fR.  \fIArg\fR must be
a positive value, either an integer or a floating point number.
Unlike \fBsqrt\fR, which is limited to the precision of a floating point
number, \fIisqrt\fR will return a result of arbitrary precision.







|
>
|
>
>






|
|







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
\fBfmod \fIx y\fR
.
Returns the floating-point remainder of the division of \fIx\fR by
\fIy\fR.  If \fIy\fR is 0, an error is returned.
.TP
\fBhypot \fIx y\fR
.
Computes the length of the hypotenuse of a right-angled triangle,
approximately
.QW "\fBsqrt\fR [\fBexpr\fR {\fIx\fB*\fIx\fB+\fIy\fB*\fIy\fR}]"
except for being more numerically stable when the two arguments have
substantially different magnitudes.
.TP
\fBint \fIarg\fR
.
The argument may be any numeric value.  The integer part of \fIarg\fR
is determined, and then the low order bits of that integer value up
to the machine word size are returned as an integer value.  For reference,
the number of bytes in the machine word are stored in the \fBwordSize\fR
element of the \fBtcl_platform\fR array.
.TP
\fBisqrt \fIarg\fR
.
Computes the integer part of the square root of \fIarg\fR.  \fIArg\fR must be
a positive value, either an integer or a floating point number.
Unlike \fBsqrt\fR, which is limited to the precision of a floating point
number, \fIisqrt\fR will return a result of arbitrary precision.

Changes to doc/mathop.n.

129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
Returns the integral modulus of the first argument with respect to the second.
Each \fInumber\fR must have an integral value. Note that Tcl defines this
operation exactly even for negative numbers, so that the following equality
holds true:
.RS
.PP
.CS
(\fIx \fB/ \fIy\fR) \fB* \fIy \fB== \fIx \fB-\fR (\fIx \fB% \fIy\fR)
.CE
.RE
.TP
\fB**\fR ?\fInumber\fR ...?
.
Returns the result of raising each value to the power of the result of
recursively operating on the result of processing the following arguments, so







|







129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
Returns the integral modulus of the first argument with respect to the second.
Each \fInumber\fR must have an integral value. Note that Tcl defines this
operation exactly even for negative numbers, so that the following equality
holds true:
.RS
.PP
.CS
(\fIx \fB/ \fIy\fR) \fB* \fIy \fB== \fIx \fB\-\fR (\fIx \fB% \fIy\fR)
.CE
.RE
.TP
\fB**\fR ?\fInumber\fR ...?
.
Returns the result of raising each value to the power of the result of
recursively operating on the result of processing the following arguments, so

Changes to doc/next.n.

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
.SH NAME
next \- invoke superclass method implementations
.SH SYNOPSIS
.nf
package require TclOO

\fBnext\fR ?\fIarg ...\fR?

.fi
.BE

.SH DESCRIPTION
.PP
The \fBnext\fR command is used to call implementations of a method by a class,
superclass or mixin that are overridden by the current method. It can only be
used from within a method. It is also used within filters to indicate the
point where a filter calls the actual implementation (the filter may decide to
not go along the chain, and may process the results of going along the chain
of methods as it chooses). The result of the \fBnext\fR command is the result
of the next method in the method chain; if there are no further methods in the
method chain, the result of \fBnext\fR will be an error. The arguments,
\fIarg\fR, to \fBnext\fR are the arguments to pass to the next method in the
chain.







.SH "THE METHOD CHAIN"
.PP
When a method of an object is invoked, things happen in several stages:
.IP [1]
The structure of the object, its class, superclasses, filters, and mixins, are
examined to build a \fImethod chain\fR, which contains a list of method
implementations to invoke.







>















>
>
>
>
>
>
>







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
.SH NAME
next \- invoke superclass method implementations
.SH SYNOPSIS
.nf
package require TclOO

\fBnext\fR ?\fIarg ...\fR?
\fBnextto\fI class\fR ?\fIarg ...\fR?
.fi
.BE

.SH DESCRIPTION
.PP
The \fBnext\fR command is used to call implementations of a method by a class,
superclass or mixin that are overridden by the current method. It can only be
used from within a method. It is also used within filters to indicate the
point where a filter calls the actual implementation (the filter may decide to
not go along the chain, and may process the results of going along the chain
of methods as it chooses). The result of the \fBnext\fR command is the result
of the next method in the method chain; if there are no further methods in the
method chain, the result of \fBnext\fR will be an error. The arguments,
\fIarg\fR, to \fBnext\fR are the arguments to pass to the next method in the
chain.
.PP
The \fBnextto\fR command is the same as the \fBnext\fR command, except that it
takes an additional \fIclass\fR argument that identifies a class whose
implementation of the current method chain (see \fBinfo object\fR \fBcall\fR) should
be used; the method implementation selected will be the one provided by the
given class, and it must refer to an existing non-filter invocation that lies
further along the chain than the current implementation.
.SH "THE METHOD CHAIN"
.PP
When a method of an object is invoked, things happen in several stages:
.IP [1]
The structure of the object, its class, superclasses, filters, and mixins, are
examined to build a \fImethod chain\fR, which contains a list of method
implementations to invoke.

Changes to doc/open.n.

63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
.
Open the file for reading and writing.  If the file does not exist,
create a new empty file.
Set the initial access position  to the end of the file.
.PP
All of the legal \fIaccess\fR values above may have the character
\fBb\fR added as the second or third character in the value to
indicate that the opened channel should be configured with the
\fB\-translation binary\fR option, making the channel suitable for 
reading or writing of binary data.
.PP
In the second form, \fIaccess\fR consists of a list of any of the
following flags, all of which have the standard POSIX meanings.
One of the flags must be either \fBRDONLY\fR, \fBWRONLY\fR or \fBRDWR\fR.
.TP 15
\fBRDONLY\fR







|
|







63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
.
Open the file for reading and writing.  If the file does not exist,
create a new empty file.
Set the initial access position  to the end of the file.
.PP
All of the legal \fIaccess\fR values above may have the character
\fBb\fR added as the second or third character in the value to
indicate that the opened channel should be configured as if with the
\fBfconfigure\fR \fB\-translation binary\fR option, making the channel suitable for 
reading or writing of binary data.
.PP
In the second form, \fIaccess\fR consists of a list of any of the
following flags, all of which have the standard POSIX meanings.
One of the flags must be either \fBRDONLY\fR, \fBWRONLY\fR or \fBRDWR\fR.
.TP 15
\fBRDONLY\fR
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
If a new file is created as part of opening it, \fIpermissions\fR
(an integer) is used to set the permissions for the new file in
conjunction with the process's file mode creation mask.
\fIPermissions\fR defaults to 0666.
.SH "COMMAND PIPELINES"
.PP
If the first character of \fIfileName\fR is
.QW |
then the
remaining characters of \fIfileName\fR are treated as a list of arguments
that describe a command pipeline to invoke, in the same style as the
arguments for \fBexec\fR.
In this case, the channel identifier returned by \fBopen\fR may be used
to write to the command's input pipe or read from its output pipe,
depending on the value of \fIaccess\fR.
If write-only access is used (e.g. \fIaccess\fR is \fBw\fR), then

standard output for the pipeline is directed to the current standard
output unless overridden by the command.
If read-only access is used (e.g. \fIaccess\fR is \fBr\fR),

standard input for the pipeline is taken from the current standard
input unless overridden by the command.
The id of the spawned process is accessible through the \fBpid\fR
command, using the channel id returned by \fBopen\fR as argument.
.PP
If the command (or one of the commands) executed in the command
pipeline returns an error (according to the definition in \fBexec\fR),







|







|
>
|

|
>







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
If a new file is created as part of opening it, \fIpermissions\fR
(an integer) is used to set the permissions for the new file in
conjunction with the process's file mode creation mask.
\fIPermissions\fR defaults to 0666.
.SH "COMMAND PIPELINES"
.PP
If the first character of \fIfileName\fR is
.QW \fB|\fR
then the
remaining characters of \fIfileName\fR are treated as a list of arguments
that describe a command pipeline to invoke, in the same style as the
arguments for \fBexec\fR.
In this case, the channel identifier returned by \fBopen\fR may be used
to write to the command's input pipe or read from its output pipe,
depending on the value of \fIaccess\fR.
If write-only access is used (e.g. \fIaccess\fR is
.QW \fBw\fR ),
then standard output for the pipeline is directed to the current standard
output unless overridden by the command.
If read-only access is used (e.g. \fIaccess\fR is
.QW \fBr\fR ),
standard input for the pipeline is taken from the current standard
input unless overridden by the command.
The id of the spawned process is accessible through the \fBpid\fR
command, using the channel id returned by \fBopen\fR as argument.
.PP
If the command (or one of the commands) executed in the command
pipeline returns an error (according to the definition in \fBexec\fR),
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
in the second form both input and output buffers are defined.
.TP
\fB\-lasterror\fR
.
(Windows only). This option is query only.
In case of a serial communication error, \fBread\fR or \fBputs\fR
returns a general Tcl file I/O error.
\fBfconfigure -lasterror\fR can be called to get a list of error details.
See below for an explanation of the various error codes.
.SH "SERIAL PORT SIGNALS"
.PP
RS-232 is the most commonly used standard electrical interface for serial
communications. A negative voltage (-3V..-12V) define a mark (on=1) bit and
a positive voltage (+3..+12V) define a space (off=0) bit (RS-232C).  The
following signals are specified for incoming and outgoing data, status
lines and handshaking. Here we are using the terms \fIworkstation\fR for
your computer and \fImodem\fR for the external device, because some signal
names (DCD, RI) come from modems. Of course your external device may use
these signal lines for other purposes.
.IP \fBTXD(output)\fR
\fBTransmitted Data:\fR Outgoing serial data.
.IP \fBRXD(input)\fR
\fBReceived Data:\fRIncoming serial data.
.IP \fBRTS(output)\fR
\fBRequest To Send:\fR This hardware handshake line informs the modem that
your workstation is ready to receive data. Your workstation may
automatically reset this signal to indicate that the input buffer is full.
.IP \fBCTS(input)\fR
\fBClear To Send:\fR The complement to RTS. Indicates that the modem is
ready to receive data.
.IP \fBDTR(output)\fR
\fBData Terminal Ready:\fR This signal tells the modem that the workstation
is ready to establish a link. DTR is often enabled automatically whenever a
serial port is opened.
.IP \fBDSR(input)\fR
\fBData Set Ready:\fR The complement to DTR. Tells the workstation that the
modem is ready to establish a link.
.IP \fBDCD(input)\fR
\fBData Carrier Detect:\fR This line becomes active when a modem detects a
.QW Carrier
signal.
.IP \fBRI(input)\fR
\fBRing Indicator:\fR Goes active when the modem detects an incoming call.
.IP \fBBREAK\fR
A BREAK condition is not a hardware signal line, but a logical zero on the
TXD or RXD lines for a long period of time, usually 250 to 500
milliseconds.  Normally a receive or transmit data signal stays at the mark
(on=1) voltage until the next character is transferred. A BREAK is sometimes
used to reset the communications line or change the operating mode of
communications hardware.
.SH "ERROR CODES (Windows only)"
.PP
A lot of different errors may occur during serial read operations or during
event polling in background. The external device may have been switched
off, the data lines may be noisy, system buffers may overrun or your mode
settings may be wrong.  That is why a reliable software should always
\fBcatch\fR serial read operations.  In cases of an error Tcl returns a
general file I/O error.  Then \fBfconfigure -lasterror\fR may help to
locate the problem.  The following error codes may be returned.
.TP 10
\fBRXOVER\fR
.
Windows input buffer overrun. The data comes faster than your scripts reads
it or your system is overloaded. Use \fBfconfigure -sysbuffer\fR to avoid a
temporary bottleneck and/or make your script faster.
.TP 10
\fBTXFULL\fR
.
Windows output buffer overrun. Complement to RXOVER. This error should
practically not happen, because Tcl cares about the output buffer status.
.TP 10
\fBOVERRUN\fR
.
UART buffer overrun (hardware) with data lost.
The data comes faster than the system driver receives it.
Check your advanced serial port settings to enable the FIFO (16550) buffer
and/or setup a lower(1) interrupt threshold value.
.TP 10
\fBRXPARITY\fR
.
A parity error has been detected by your UART.
Wrong parity settings with \fBfconfigure -mode\fR or a noisy data line (RXD)
may cause this error.
.TP 10
\fBFRAME\fR
.
A stop-bit error has been detected by your UART.
Wrong mode settings with \fBfconfigure -mode\fR or a noisy data line (RXD)
may cause this error.
.TP 10
\fBBREAK\fR
.
A BREAK condition has been detected by your UART (see above).
.SH "PORTABILITY ISSUES"
.TP







|











|

|

|



|


|



|


|



|















|





|

















|





|







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
in the second form both input and output buffers are defined.
.TP
\fB\-lasterror\fR
.
(Windows only). This option is query only.
In case of a serial communication error, \fBread\fR or \fBputs\fR
returns a general Tcl file I/O error.
\fBfconfigure\fR \fB\-lasterror\fR can be called to get a list of error details.
See below for an explanation of the various error codes.
.SH "SERIAL PORT SIGNALS"
.PP
RS-232 is the most commonly used standard electrical interface for serial
communications. A negative voltage (-3V..-12V) define a mark (on=1) bit and
a positive voltage (+3..+12V) define a space (off=0) bit (RS-232C).  The
following signals are specified for incoming and outgoing data, status
lines and handshaking. Here we are using the terms \fIworkstation\fR for
your computer and \fImodem\fR for the external device, because some signal
names (DCD, RI) come from modems. Of course your external device may use
these signal lines for other purposes.
.IP \fBTXD\fR(output)
\fBTransmitted Data:\fR Outgoing serial data.
.IP \fBRXD\fR(input)
\fBReceived Data:\fRIncoming serial data.
.IP \fBRTS\fR(output)
\fBRequest To Send:\fR This hardware handshake line informs the modem that
your workstation is ready to receive data. Your workstation may
automatically reset this signal to indicate that the input buffer is full.
.IP \fBCTS\fR(input)
\fBClear To Send:\fR The complement to RTS. Indicates that the modem is
ready to receive data.
.IP \fBDTR\fR(output)
\fBData Terminal Ready:\fR This signal tells the modem that the workstation
is ready to establish a link. DTR is often enabled automatically whenever a
serial port is opened.
.IP \fBDSR\fR(input)
\fBData Set Ready:\fR The complement to DTR. Tells the workstation that the
modem is ready to establish a link.
.IP \fBDCD\fR(input)
\fBData Carrier Detect:\fR This line becomes active when a modem detects a
.QW Carrier
signal.
.IP \fBRI\fR(input)
\fBRing Indicator:\fR Goes active when the modem detects an incoming call.
.IP \fBBREAK\fR
A BREAK condition is not a hardware signal line, but a logical zero on the
TXD or RXD lines for a long period of time, usually 250 to 500
milliseconds.  Normally a receive or transmit data signal stays at the mark
(on=1) voltage until the next character is transferred. A BREAK is sometimes
used to reset the communications line or change the operating mode of
communications hardware.
.SH "ERROR CODES (Windows only)"
.PP
A lot of different errors may occur during serial read operations or during
event polling in background. The external device may have been switched
off, the data lines may be noisy, system buffers may overrun or your mode
settings may be wrong.  That is why a reliable software should always
\fBcatch\fR serial read operations.  In cases of an error Tcl returns a
general file I/O error.  Then \fBfconfigure\fR \fB\-lasterror\fR may help to
locate the problem.  The following error codes may be returned.
.TP 10
\fBRXOVER\fR
.
Windows input buffer overrun. The data comes faster than your scripts reads
it or your system is overloaded. Use \fBfconfigure\fR \fB\-sysbuffer\fR to avoid a
temporary bottleneck and/or make your script faster.
.TP 10
\fBTXFULL\fR
.
Windows output buffer overrun. Complement to RXOVER. This error should
practically not happen, because Tcl cares about the output buffer status.
.TP 10
\fBOVERRUN\fR
.
UART buffer overrun (hardware) with data lost.
The data comes faster than the system driver receives it.
Check your advanced serial port settings to enable the FIFO (16550) buffer
and/or setup a lower(1) interrupt threshold value.
.TP 10
\fBRXPARITY\fR
.
A parity error has been detected by your UART.
Wrong parity settings with \fBfconfigure\fR \fB\-mode\fR or a noisy data line (RXD)
may cause this error.
.TP 10
\fBFRAME\fR
.
A stop-bit error has been detected by your UART.
Wrong mode settings with \fBfconfigure\fR \fB\-mode\fR or a noisy data line (RXD)
may cause this error.
.TP 10
\fBBREAK\fR
.
A BREAK condition has been detected by your UART (see above).
.SH "PORTABILITY ISSUES"
.TP
454
455
456
457
458
459
460



.CE
.SH "SEE ALSO"
file(n), close(n), filename(n), fconfigure(n), gets(n), read(n),
puts(n), exec(n), pid(n), fopen(3)
.SH KEYWORDS
access mode, append, create, file, non-blocking, open, permissions,
pipeline, process, serial










>
>
>
456
457
458
459
460
461
462
463
464
465
.CE
.SH "SEE ALSO"
file(n), close(n), filename(n), fconfigure(n), gets(n), read(n),
puts(n), exec(n), pid(n), fopen(3)
.SH KEYWORDS
access mode, append, create, file, non-blocking, open, permissions,
pipeline, process, serial
'\"Local Variables:
'\"mode: nroff
'\"End:

Changes to doc/package.n.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
.TH package n 7.5 Tcl "Tcl Built-In Commands"
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
package \- Facilities for package loading and version control
.SH SYNOPSIS
.nf
\fBpackage forget ?\fIpackage package ...\fR?
\fBpackage ifneeded \fIpackage version\fR ?\fIscript\fR?
\fBpackage names\fR
\fBpackage present \fIpackage \fR?\fIrequirement...\fR?
\fBpackage present \-exact \fIpackage version\fR
\fBpackage provide \fIpackage \fR?\fIversion\fR?
\fBpackage require \fIpackage \fR?\fIrequirement...\fR?
\fBpackage require \-exact \fIpackage version\fR







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
.TH package n 7.5 Tcl "Tcl Built-In Commands"
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
package \- Facilities for package loading and version control
.SH SYNOPSIS
.nf
\fBpackage forget\fR ?\fIpackage package ...\fR?
\fBpackage ifneeded \fIpackage version\fR ?\fIscript\fR?
\fBpackage names\fR
\fBpackage present \fIpackage \fR?\fIrequirement...\fR?
\fBpackage present \-exact \fIpackage version\fR
\fBpackage provide \fIpackage \fR?\fIversion\fR?
\fBpackage require \fIpackage \fR?\fIrequirement...\fR?
\fBpackage require \-exact \fIpackage version\fR
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
Typically, only the \fBpackage require\fR and \fBpackage provide\fR
commands are invoked in normal Tcl scripts;  the other commands are used
primarily by system scripts that maintain the package database.
.PP
The behavior of the \fBpackage\fR command is determined by its first argument.
The following forms are permitted:
.TP
\fBpackage forget ?\fIpackage package ...\fR?
.
Removes all information about each specified package from this interpreter,
including information provided by both \fBpackage ifneeded\fR and
\fBpackage provide\fR.
.TP
\fBpackage ifneeded \fIpackage version\fR ?\fIscript\fR?
.







|







39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
Typically, only the \fBpackage require\fR and \fBpackage provide\fR
commands are invoked in normal Tcl scripts;  the other commands are used
primarily by system scripts that maintain the package database.
.PP
The behavior of the \fBpackage\fR command is determined by its first argument.
The following forms are permitted:
.TP
\fBpackage forget\fR ?\fIpackage package ...\fR?
.
Removes all information about each specified package from this interpreter,
including information provided by both \fBpackage ifneeded\fR and
\fBpackage provide\fR.
.TP
\fBpackage ifneeded \fIpackage version\fR ?\fIscript\fR?
.
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
If \fIcommand\fR is specified as an empty string, then the current
\fBpackage unknown\fR script is removed, if there is one.
.TP
\fBpackage vcompare \fIversion1 version2\fR
.
Compares the two version numbers given by \fIversion1\fR and \fIversion2\fR.
Returns -1 if \fIversion1\fR is an earlier version than \fIversion2\fR,
0 if they are equal, and 1 if \fIversion1\fR is later than \fBversion2\fR.
.TP
\fBpackage versions \fIpackage\fR
.
Returns a list of all the version numbers of \fIpackage\fR
for which information has been provided by \fBpackage ifneeded\fR
commands.
.TP







|







171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
If \fIcommand\fR is specified as an empty string, then the current
\fBpackage unknown\fR script is removed, if there is one.
.TP
\fBpackage vcompare \fIversion1 version2\fR
.
Compares the two version numbers given by \fIversion1\fR and \fIversion2\fR.
Returns -1 if \fIversion1\fR is an earlier version than \fIversion2\fR,
0 if they are equal, and 1 if \fIversion1\fR is later than \fIversion2\fR.
.TP
\fBpackage versions \fIpackage\fR
.
Returns a list of all the version numbers of \fIpackage\fR
for which information has been provided by \fBpackage ifneeded\fR
commands.
.TP

Changes to doc/packagens.n.

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
'\"
'\" Copyright (c) 1998-2000 by Scriptics Corporation.
'\" All rights reserved.
'\" 
.so man.macros
.TH pkg::create n 8.3 Tcl "Tcl Built-In Commands"
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
pkg::create \- Construct an appropriate 'package ifneeded' command for a given package specification
.SH SYNOPSIS
\fB::pkg::create \fI\-name packageName\fR \fI\-version packageVersion\fR ?\fI\-load filespec\fR? ... ?\fI\-source filespec\fR? ...
.BE

.SH DESCRIPTION
.PP
\fB::pkg::create\fR is a utility procedure that is part of the standard Tcl
library.  It is used to create an appropriate \fBpackage ifneeded\fR
command for a given package specification.  It can be used to construct a
\fBpkgIndex.tcl\fR file for use with the \fBpackage\fR mechanism.

.SH OPTIONS
The parameters supported are:
.TP
\fB\-name\fR\0\fIpackageName\fR
This parameter specifies the name of the package.  It is required.
.TP
\fB\-version\fR\0\fIpackageVersion\fR
This parameter specifies the version of the package.  It is required.
.TP
\fB\-load\fR\0\fIfilespec\fR
This parameter specifies a binary library that must be loaded with the
\fBload\fR command.  \fIfilespec\fR is a list with two elements.  The
first element is the name of the file to load.  The second, optional
element is a list of commands supplied by loading that file.  If the
list of procedures is empty or omitted, \fB::pkg::create\fR will
set up the library for direct loading (see \fBpkg_mkIndex\fR).  Any
number of \fB\-load\fR parameters may be specified.
.TP
\fB\-source\fR\0\fIfilespec\fR
This parameter is similar to the \fB\-load\fR parameter, except that it
specifies a Tcl library that must be loaded with the
\fBsource\fR command.  Any number of \fB\-source\fR parameters may be
specified.
.PP
At least one \fB\-load\fR or \fB\-source\fR parameter must be given.
.SH "SEE ALSO"











|












|


|


|








|







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
'\"
'\" Copyright (c) 1998-2000 by Scriptics Corporation.
'\" All rights reserved.
'\" 
.so man.macros
.TH pkg::create n 8.3 Tcl "Tcl Built-In Commands"
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
pkg::create \- Construct an appropriate 'package ifneeded' command for a given package specification
.SH SYNOPSIS
\fB::pkg::create\fR \fB\-name \fIpackageName \fB\-version \fIpackageVersion\fR ?\fB\-load \fIfilespec\fR? ... ?\fB\-source \fIfilespec\fR? ...
.BE

.SH DESCRIPTION
.PP
\fB::pkg::create\fR is a utility procedure that is part of the standard Tcl
library.  It is used to create an appropriate \fBpackage ifneeded\fR
command for a given package specification.  It can be used to construct a
\fBpkgIndex.tcl\fR file for use with the \fBpackage\fR mechanism.

.SH OPTIONS
The parameters supported are:
.TP
\fB\-name \fIpackageName\fR
This parameter specifies the name of the package.  It is required.
.TP
\fB\-version \fIpackageVersion\fR
This parameter specifies the version of the package.  It is required.
.TP
\fB\-load \fIfilespec\fR
This parameter specifies a binary library that must be loaded with the
\fBload\fR command.  \fIfilespec\fR is a list with two elements.  The
first element is the name of the file to load.  The second, optional
element is a list of commands supplied by loading that file.  If the
list of procedures is empty or omitted, \fB::pkg::create\fR will
set up the library for direct loading (see \fBpkg_mkIndex\fR).  Any
number of \fB\-load\fR parameters may be specified.
.TP
\fB\-source \fIfilespec\fR
This parameter is similar to the \fB\-load\fR parameter, except that it
specifies a Tcl library that must be loaded with the
\fBsource\fR command.  Any number of \fB\-source\fR parameters may be
specified.
.PP
At least one \fB\-load\fR or \fB\-source\fR parameter must be given.
.SH "SEE ALSO"

Changes to doc/pkgMkIndex.n.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
.TH pkg_mkIndex n 8.3 Tcl "Tcl Built-In Commands"
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
pkg_mkIndex \- Build an index for automatic loading of packages
.SH SYNOPSIS
.nf
\fBpkg_mkIndex ?\fIoptions...\fR? \fIdir\fR ?\fIpattern pattern ...\fR?
.fi
.BE
.SH DESCRIPTION
.PP
\fBPkg_mkIndex\fR is a utility procedure that is part of the standard
Tcl library.
It is used to create index files that allow packages to be loaded







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
.TH pkg_mkIndex n 8.3 Tcl "Tcl Built-In Commands"
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
pkg_mkIndex \- Build an index for automatic loading of packages
.SH SYNOPSIS
.nf
\fBpkg_mkIndex\fR ?\fIoptions...\fR? \fIdir\fR ?\fIpattern pattern ...\fR?
.fi
.BE
.SH DESCRIPTION
.PP
\fBPkg_mkIndex\fR is a utility procedure that is part of the standard
Tcl library.
It is used to create index files that allow packages to be loaded
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
evaluates all of the \fBpkgIndex.tcl\fR files in the
\fBauto_path\fR.
The \fBpkgIndex.tcl\fR files contain \fBpackage ifneeded\fR
commands for each version of each available package;  these commands
invoke \fBpackage provide\fR commands to announce the
availability of the package, and they setup auto-loader
information to load the files of the package.
If the \fI\-lazy\fR flag was provided when the \fBpkgIndex.tcl\fR
was generated,
a given file of a given version of a given package is not
actually loaded until the first time one of its commands
is invoked.
Thus, after invoking \fBpackage require\fR you may
not see the package's commands in the interpreter, but you will be able
to invoke the commands and they will be auto-loaded.
.SH "DIRECT LOADING"
.PP
Some packages, for instance packages which use namespaces and export
commands or those which require special initialization, might select
that their package files be loaded immediately upon \fBpackage require\fR
instead of delaying the actual loading to the first use of one of the
package's command. This is the default mode when generating the package
index.  It can be overridden by specifying the \fI\-lazy\fR argument.
.SH "COMPLEX CASES"
Most complex cases of dependencies among scripts
and binary files, and packages being split among scripts and
binary files are handled OK.  However, you may have to adjust
the order in which files are processed by \fBpkg_mkIndex\fR.
These issues are described in detail below.
.PP







|














|







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
evaluates all of the \fBpkgIndex.tcl\fR files in the
\fBauto_path\fR.
The \fBpkgIndex.tcl\fR files contain \fBpackage ifneeded\fR
commands for each version of each available package;  these commands
invoke \fBpackage provide\fR commands to announce the
availability of the package, and they setup auto-loader
information to load the files of the package.
If the \fB\-lazy\fR flag was provided when the \fBpkgIndex.tcl\fR
was generated,
a given file of a given version of a given package is not
actually loaded until the first time one of its commands
is invoked.
Thus, after invoking \fBpackage require\fR you may
not see the package's commands in the interpreter, but you will be able
to invoke the commands and they will be auto-loaded.
.SH "DIRECT LOADING"
.PP
Some packages, for instance packages which use namespaces and export
commands or those which require special initialization, might select
that their package files be loaded immediately upon \fBpackage require\fR
instead of delaying the actual loading to the first use of one of the
package's command. This is the default mode when generating the package
index.  It can be overridden by specifying the \fB\-lazy\fR argument.
.SH "COMPLEX CASES"
Most complex cases of dependencies among scripts
and binary files, and packages being split among scripts and
binary files are handled OK.  However, you may have to adjust
the order in which files are processed by \fBpkg_mkIndex\fR.
These issues are described in detail below.
.PP
224
225
226
227
228
229
230



If you must use \fB\-load\fR,
then you must specify the scripts first; otherwise the package loaded from
the binary file may mask the package defined by the scripts.
.SH "SEE ALSO"
package(n)
.SH KEYWORDS
auto-load, index, package, version










>
>
>
224
225
226
227
228
229
230
231
232
233
If you must use \fB\-load\fR,
then you must specify the scripts first; otherwise the package loaded from
the binary file may mask the package defined by the scripts.
.SH "SEE ALSO"
package(n)
.SH KEYWORDS
auto-load, index, package, version
'\"Local Variables:
'\"mode: nroff
'\"End:

Changes to doc/re_syntax.n.

1
2
3
4
5
6
7
8


9
10
11
12
13
14
15
'\"
'\" Copyright (c) 1998 Sun Microsystems, Inc.
'\" Copyright (c) 1999 Scriptics Corporation
'\"
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\"
.so man.macros


.TH re_syntax n "8.1" Tcl "Tcl Built-In Commands"
.BS
.SH NAME
re_syntax \- Syntax of Tcl regular expressions
.BE
.SH DESCRIPTION
.PP








>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
'\"
'\" Copyright (c) 1998 Sun Microsystems, Inc.
'\" Copyright (c) 1999 Scriptics Corporation
'\"
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\"
.so man.macros
.ie '\w'o''\w'\C'^o''' .ds qo \C'^o'
.el .ds qo u
.TH re_syntax n "8.1" Tcl "Tcl Built-In Commands"
.BS
.SH NAME
re_syntax \- Syntax of Tcl regular expressions
.BE
.SH DESCRIPTION
.PP
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
and \fB=]\fR is an equivalence class, standing for the sequences of
characters of all collating elements equivalent to that one, including
itself. (If there are no other equivalent collating elements, the
treatment is as if the enclosing delimiters were
.QW \fB[.\fR \&
and
.QW \fB.]\fR .)
For example, if \fBo\fR and \fB\N'244'\fR are the members of an
equivalence class, then
.QW \fB[[=o=]]\fR ,
.QW \fB[[=\N'244'=]]\fR ,
and
.QW \fB[o\N'244']\fR \&
are all synonymous. An equivalence class may not be an endpoint of a range.
.RS
.PP
(\fINote:\fR Tcl implements only the Unicode locale. It does not define any
equivalence classes. The examples above are just illustrations.)
.RE
.SH ESCAPES







|


|

|







288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
and \fB=]\fR is an equivalence class, standing for the sequences of
characters of all collating elements equivalent to that one, including
itself. (If there are no other equivalent collating elements, the
treatment is as if the enclosing delimiters were
.QW \fB[.\fR \&
and
.QW \fB.]\fR .)
For example, if \fBo\fR and \fB\*(qo\fR are the members of an
equivalence class, then
.QW \fB[[=o=]]\fR ,
.QW \fB[[=\*(qo=]]\fR ,
and
.QW \fB[o\*(qo]\fR \&
are all synonymous. An equivalence class may not be an endpoint of a range.
.RS
.PP
(\fINote:\fR Tcl implements only the Unicode locale. It does not define any
equivalence classes. The examples above are just illustrations.)
.RE
.SH ESCAPES
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
.TP
\fB\et\fR
.
horizontal tab, as in C
.TP
\fB\eu\fIwxyz\fR
.
(where \fIwxyz\fR is exactly four hexadecimal digits) the Unicode
character \fBU+\fIwxyz\fR in the local byte ordering
.TP
\fB\eU\fIstuvwxyz\fR
.
(where \fIstuvwxyz\fR is exactly eight hexadecimal digits) reserved
for a somewhat-hypothetical Unicode extension to 32 bits



.TP
\fB\ev\fR
.
vertical tab, as in C are all available.
.TP
\fB\ex\fIhhh\fR
.
(where \fIhhh\fR is any sequence of hexadecimal digits) the character
whose hexadecimal value is \fB0x\fIhhh\fR (a single character no
matter how many hexadecimal digits are used).
.TP
\fB\e0\fR
.
the character whose value is \fB0\fR
.TP







\fB\e\fIxy\fR
.
(where \fIxy\fR is exactly two octal digits, and is not a \fIback
reference\fR (see below)) the character whose octal value is
\fB0\fIxy\fR
.TP
\fB\e\fIxyz\fR
.
(where \fIxyz\fR is exactly three octal digits, and is not a back
reference (see below)) the character whose octal value is
\fB0\fIxyz\fR
.RE
.PP
Hexadecimal digits are
.QR \fB0\fR \fB9\fR ,
.QR \fBa\fR \fBf\fR ,
and
.QR \fBA\fR \fBF\fR .







|




|
|
>
>
>





|

|
|
<





>
>
>
>
>
>
>





<
<
<
<
<
<







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
.TP
\fB\et\fR
.
horizontal tab, as in C
.TP
\fB\eu\fIwxyz\fR
.
(where \fIwxyz\fR is one up to four hexadecimal digits) the Unicode
character \fBU+\fIwxyz\fR in the local byte ordering
.TP
\fB\eU\fIstuvwxyz\fR
.
(where \fIstuvwxyz\fR is one up to eight hexadecimal digits) reserved
for a Unicode extension up to 21 bits. The digits are parsed until the
first non-hexadecimal character is encountered, the maximun of eight
hexadecimal digits are reached, or an overflow would occur in the maximum
value of \fBU+\fI10ffff\fR.
.TP
\fB\ev\fR
.
vertical tab, as in C are all available.
.TP
\fB\ex\fIhh\fR
.
(where \fIhh\fR is one or two hexadecimal digits) the character
whose hexadecimal value is \fB0x\fIhh\fR.

.TP
\fB\e0\fR
.
the character whose value is \fB0\fR
.TP
\fB\e\fIxyz\fR
.
(where \fIxyz\fR is exactly three octal digits, and is not a \fIback
reference\fR (see below)) the character whose octal value is
\fB0\fIxyz\fR. The first digit must be in the range 0-3, otherwise
the two-digit form is assumed.
.TP
\fB\e\fIxy\fR
.
(where \fIxy\fR is exactly two octal digits, and is not a \fIback
reference\fR (see below)) the character whose octal value is
\fB0\fIxy\fR






.RE
.PP
Hexadecimal digits are
.QR \fB0\fR \fB9\fR ,
.QR \fBa\fR \fBf\fR ,
and
.QR \fBA\fR \fBF\fR .

Changes to doc/read.n.

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



for the channel.
See the \fBfconfigure\fR manual entry for a discussion on ways in
which \fBfconfigure\fR will alter input.
.SH "USE WITH SERIAL PORTS"
'\" Note:  this advice actually applies to many versions of Tcl
.PP
For most applications a channel connected to a serial port should be
configured to be nonblocking: \fBfconfigure \fIchannelId \fB\-blocking
\fI0\fR.  Then \fBread\fR behaves much like described above.  Care
must be taken when using \fBread\fR on blocking serial ports:
.TP
\fBread \fIchannelId numChars\fR 
.
In this form \fBread\fR blocks until \fInumChars\fR have been received
from the serial port.
.TP
\fBread \fIchannelId\fR 
.
In this form \fBread\fR blocks until the reception of the end-of-file
character, see \fBfconfigure -eofchar\fR. If there no end-of-file
character has been configured for the channel, then \fBread\fR will
block forever.
.SH "EXAMPLE"
.PP
This example code reads a file all at once, and splits it into a list,
with each line in the file corresponding to an element in the list:
.PP
.CS
set fl [open /proc/meminfo]
set data [\fBread\fR $fl]
close $fl
set lines [split $data \en]
.CE
.SH "SEE ALSO"
file(n), eof(n), fblocked(n), fconfigure(n), Tcl_StandardChannels(3)
.SH KEYWORDS
blocking, channel, end of line, end of file, nonblocking, read, translation, encoding










|











|

















>
>
>
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
for the channel.
See the \fBfconfigure\fR manual entry for a discussion on ways in
which \fBfconfigure\fR will alter input.
.SH "USE WITH SERIAL PORTS"
'\" Note:  this advice actually applies to many versions of Tcl
.PP
For most applications a channel connected to a serial port should be
configured to be nonblocking: \fBfconfigure\fI channelId \fB\-blocking
\fI0\fR.  Then \fBread\fR behaves much like described above.  Care
must be taken when using \fBread\fR on blocking serial ports:
.TP
\fBread \fIchannelId numChars\fR 
.
In this form \fBread\fR blocks until \fInumChars\fR have been received
from the serial port.
.TP
\fBread \fIchannelId\fR 
.
In this form \fBread\fR blocks until the reception of the end-of-file
character, see \fBfconfigure\fR \fB\-eofchar\fR. If there no end-of-file
character has been configured for the channel, then \fBread\fR will
block forever.
.SH "EXAMPLE"
.PP
This example code reads a file all at once, and splits it into a list,
with each line in the file corresponding to an element in the list:
.PP
.CS
set fl [open /proc/meminfo]
set data [\fBread\fR $fl]
close $fl
set lines [split $data \en]
.CE
.SH "SEE ALSO"
file(n), eof(n), fblocked(n), fconfigure(n), Tcl_StandardChannels(3)
.SH KEYWORDS
blocking, channel, end of line, end of file, nonblocking, read, translation, encoding
'\"Local Variables:
'\"mode: nroff
'\"End:

Changes to doc/refchan.n.

13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
.SH SYNOPSIS
\fBcmdPrefix \fIoption\fR ?\fIarg arg ...\fR?
.BE
.SH DESCRIPTION
.PP
The Tcl-level handler for a reflected channel has to be a command with
subcommands (termed an \fIensemble\fR, as it is a command such as that
created by \fBnamespace ensemble create\fR, though the implementation
of handlers for reflected channel \fIis not\fR tied to \fBnamespace
ensemble\fRs in any way; see \fBEXAMPLE\fR below for how to build a
\fBclass\fR that supports the API). Note that \fIcmdPrefix\fR is whatever was
specified in the call to \fBchan create\fR, and may consist of
multiple arguments; this will be expanded to multiple words in place
of the prefix.
.PP
Of all the possible subcommands, the handler \fImust\fR support
\fBinitialize\fR, \fBfinalize\fR, and \fBwatch\fR. Support for the
other subcommands is optional.







|

|
|







13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
.SH SYNOPSIS
\fBcmdPrefix \fIoption\fR ?\fIarg arg ...\fR?
.BE
.SH DESCRIPTION
.PP
The Tcl-level handler for a reflected channel has to be a command with
subcommands (termed an \fIensemble\fR, as it is a command such as that
created by \fBnamespace ensemble\fR \fBcreate\fR, though the implementation
of handlers for reflected channel \fIis not\fR tied to \fBnamespace
ensemble\fRs in any way; see \fBEXAMPLE\fR below for how to build an
\fBoo::class\fR that supports the API). Note that \fIcmdPrefix\fR is whatever was
specified in the call to \fBchan create\fR, and may consist of
multiple arguments; this will be expanded to multiple words in place
of the prefix.
.PP
Of all the possible subcommands, the handler \fImust\fR support
\fBinitialize\fR, \fBfinalize\fR, and \fBwatch\fR. Support for the
other subcommands is optional.

Changes to doc/registry.n.

99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
data, see \fBSUPPORTED TYPES\fR, below.
.TP
\fBregistry keys \fIkeyName\fR ?\fIpattern\fR?
.
If \fIpattern\fR is not specified, returns a list of names of all the
subkeys of \fIkeyName\fR.  If \fIpattern\fR is specified, only those
names matching \fIpattern\fR are returned.  Matching is determined
using the same rules as for \fBstring\fR \fBmatch\fR.  If the
specified \fIkeyName\fR does not exist, then an error is generated.
.TP
\fBregistry set \fIkeyName\fR ?\fIvalueName data \fR?\fItype\fR??
.
If \fIvalueName\fR is not specified, creates the key \fIkeyName\fR if
it does not already exist.  If \fIvalueName\fR is specified, creates
the key \fIkeyName\fR and value \fIvalueName\fR if necessary.  The







|







99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
data, see \fBSUPPORTED TYPES\fR, below.
.TP
\fBregistry keys \fIkeyName\fR ?\fIpattern\fR?
.
If \fIpattern\fR is not specified, returns a list of names of all the
subkeys of \fIkeyName\fR.  If \fIpattern\fR is specified, only those
names matching \fIpattern\fR are returned.  Matching is determined
using the same rules as for \fBstring match\fR.  If the
specified \fIkeyName\fR does not exist, then an error is generated.
.TP
\fBregistry set \fIkeyName\fR ?\fIvalueName data \fR?\fItype\fR??
.
If \fIvalueName\fR is not specified, creates the key \fIkeyName\fR if
it does not already exist.  If \fIvalueName\fR is specified, creates
the key \fIkeyName\fR and value \fIvalueName\fR if necessary.  The
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
\fBSUPPORTED TYPES\fR, below.
.TP
\fBregistry values \fIkeyName\fR ?\fIpattern\fR?
.
If \fIpattern\fR is not specified, returns a list of names of all the
values of \fIkeyName\fR.  If \fIpattern\fR is specified, only those
names matching \fIpattern\fR are returned.  Matching is determined
using the same rules as for \fBstring\fR \fBmatch\fR.
.SH "SUPPORTED TYPES"
Each value under a key in the registry contains some data of a
particular type in a type-specific representation.  The \fBregistry\fR
command converts between this internal representation and one that can
be manipulated by Tcl scripts.  In most cases, the data is simply
returned as a Tcl string.  The type indicates the intended use for the
data, but does not actually change the representation.  For some







|







123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
\fBSUPPORTED TYPES\fR, below.
.TP
\fBregistry values \fIkeyName\fR ?\fIpattern\fR?
.
If \fIpattern\fR is not specified, returns a list of names of all the
values of \fIkeyName\fR.  If \fIpattern\fR is specified, only those
names matching \fIpattern\fR are returned.  Matching is determined
using the same rules as for \fBstring match\fR.
.SH "SUPPORTED TYPES"
Each value under a key in the registry contains some data of a
particular type in a type-specific representation.  The \fBregistry\fR
command converts between this internal representation and one that can
be manipulated by Tcl scripts.  In most cases, the data is simply
returned as a Tcl string.  The type indicates the intended use for the
data, but does not actually change the representation.  For some

Changes to doc/return.n.

313
314
315
316
317
318
319
320

321
322
323
324
325
    }
    set options [dict merge {-level 1} $args]
    dict incr options -level
    \fBreturn\fR -options $options $result
}
.CE
.SH "SEE ALSO"
break(n), catch(n), continue(n), dict(n), error(n), proc(n), source(n), tclvars(n)

.SH KEYWORDS
break, catch, continue, error, exception, procedure, result, return
.\" Local Variables:
.\" mode: nroff
.\" End:







|
>





313
314
315
316
317
318
319
320
321
322
323
324
325
326
    }
    set options [dict merge {-level 1} $args]
    dict incr options -level
    \fBreturn\fR -options $options $result
}
.CE
.SH "SEE ALSO"
break(n), catch(n), continue(n), dict(n), error(n), proc(n),
source(n), tclvars(n), throw(n), try(n)
.SH KEYWORDS
break, catch, continue, error, exception, procedure, result, return
.\" Local Variables:
.\" mode: nroff
.\" End:

Changes to doc/safe.n.

72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
optional arguments.
If the \fIslave\fR argument is omitted, a name will be generated.
\fB::safe::interpCreate\fR always returns the interpreter name.
.TP
\fB::safe::interpInit\fR \fIslave\fR ?\fIoptions...\fR?
This command is similar to \fBinterpCreate\fR except it that does not
create the safe interpreter. \fIslave\fR must have been created by some
other means, like \fBinterp create \-safe\fR.
.TP
\fB::safe::interpConfigure\fR \fIslave\fR ?\fIoptions...\fR?
If no \fIoptions\fR are given, returns the settings for all options for the
named safe interpreter as a list of options and their current values
for that \fIslave\fR. 
If a single additional argument is provided,
it will return a list of 2 elements \fIname\fR and \fIvalue\fR where







|







72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
optional arguments.
If the \fIslave\fR argument is omitted, a name will be generated.
\fB::safe::interpCreate\fR always returns the interpreter name.
.TP
\fB::safe::interpInit\fR \fIslave\fR ?\fIoptions...\fR?
This command is similar to \fBinterpCreate\fR except it that does not
create the safe interpreter. \fIslave\fR must have been created by some
other means, like \fBinterp create\fR \fB\-safe\fR.
.TP
\fB::safe::interpConfigure\fR \fIslave\fR ?\fIoptions...\fR?
If no \fIoptions\fR are given, returns the settings for all options for the
named safe interpreter as a list of options and their current values
for that \fIslave\fR. 
If a single additional argument is provided,
it will return a list of 2 elements \fIname\fR and \fIvalue\fR where
350
351
352
353
354
355
356



an \fBauto_reset\fR is automatically evaluated in the safe interpreter
to synchronize its \fBauto_index\fR with the new token list.
.SH "SEE ALSO"
interp(n), library(n), load(n), package(n), source(n), unknown(n)
.SH KEYWORDS
alias, auto\-loading, auto_mkindex, load, master interpreter, safe
interpreter, slave interpreter, source










>
>
>
350
351
352
353
354
355
356
357
358
359
an \fBauto_reset\fR is automatically evaluated in the safe interpreter
to synchronize its \fBauto_index\fR with the new token list.
.SH "SEE ALSO"
interp(n), library(n), load(n), package(n), source(n), unknown(n)
.SH KEYWORDS
alias, auto\-loading, auto_mkindex, load, master interpreter, safe
interpreter, slave interpreter, source
'\" Local Variables:
'\" mode: nroff
'\" End:

Changes to doc/self.n.

21
22
23
24
25
26
27











28
29
30
31
32
33
34
The \fBself\fR command, which should only be used from within the context of a
call to a method (i.e. inside a method, constructor or destructor body) is
used to allow the method to discover information about how it was called. It
takes an argument, \fIsubcommand\fR, that tells it what sort of information is
actually desired; if omitted the result will be the same as if \fBself
object\fR was invoked. The supported subcommands are:
.TP











\fBself caller\fR
.
When the method was invoked from inside another object method, this subcommand
returns a three element list describing the containing object and method. The
first element describes the declaring object or class of the method, the
second element is the name of the object on which the containing method was
invoked, and the third element is the name of the method (with the strings







>
>
>
>
>
>
>
>
>
>
>







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
The \fBself\fR command, which should only be used from within the context of a
call to a method (i.e. inside a method, constructor or destructor body) is
used to allow the method to discover information about how it was called. It
takes an argument, \fIsubcommand\fR, that tells it what sort of information is
actually desired; if omitted the result will be the same as if \fBself
object\fR was invoked. The supported subcommands are:
.TP
\fBself call\fR
.
This returns a two-element list describing the method implementations used to
implement the current call chain. The first element is the same as would be
reported by \fBinfo object\fR \fBcall\fR for the current method (except that this
also reports useful values from within constructors and destructors, whose
names are reported as \fB<constructor>\fR and \fB<destructor>\fR
respectively), and the second element is an index into the first element's
list that indicates which actual implementation is currently executing (the
first implementation to execute is always at index 0).
.TP
\fBself caller\fR
.
When the method was invoked from inside another object method, this subcommand
returns a three element list describing the containing object and method. The
first element describes the declaring object or class of the method, the
second element is the name of the object on which the containing method was
invoked, and the third element is the name of the method (with the strings
105
106
107
108
109
110
111






















112
113
114
115
116
117
118
119
    }
}
c create a
c create b
a foo                \fI\(-> prints "this is the ::a object"\fR
b foo                \fI\(-> prints "this is the ::b object"\fR
.CE






















.SH "SEE ALSO"
info(n), next(n)
.SH KEYWORDS
call, introspection, object
.\" Local variables:
.\" mode: nroff
.\" fill-column: 78
.\" End:







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








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
    }
}
c create a
c create b
a foo                \fI\(-> prints "this is the ::a object"\fR
b foo                \fI\(-> prints "this is the ::b object"\fR
.CE
.PP
This demonstrates what a method call chain looks like, and how traversing
along it changes the index into it:
.PP
.CS
oo::class create c {
    method x {} {
        puts "Cls: [\fBself call\fR]"
    }
}
c create a
oo::objdefine a {
    method x {} {
        puts "Obj: [\fBself call\fR]"
        next
        puts "Obj: [\fBself call\fR]"
    }
}
a x     \fI\(-> Obj: {{method x object method} {method x ::c method}} 0\fR
        \fI\(-> Cls: {{method x object method} {method x ::c method}} 1\fR
        \fI\(-> Obj: {{method x object method} {method x ::c method}} 0\fR
.CE
.SH "SEE ALSO"
info(n), next(n)
.SH KEYWORDS
call, introspection, object
.\" Local variables:
.\" mode: nroff
.\" fill-column: 78
.\" End:

Changes to doc/socket.n.

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
port number will be chosen at random by the system software.
.TP
\fB\-async\fR
.
This option will cause the client socket to be connected
asynchronously. This means that the socket will be created immediately
but may not yet be connected to the server, when the call to


\fBsocket\fR returns. When a \fBgets\fR or \fBflush\fR is done on the
socket before the connection attempt succeeds or fails, if the socket
is in blocking mode, the operation will wait until the connection is
completed or fails. If the socket is in nonblocking mode and a
\fBgets\fR or \fBflush\fR is done on the socket before the connection
attempt succeeds or fails, the operation returns immediately and
\fBfblocked\fR on the socket returns 1. Synchronous client sockets may
be switched (after they have connected) to operating in asynchronous
mode using:
.RS
.PP
.CS
\fBchan configure \fIchan \fB\-blocking 0\fR
.CE
.PP
See the \fBchan\fR \fBconfigure\fR command for more details.









.RE
.SH "SERVER SOCKETS"
.PP
If the \fB\-server\fR option is specified then the new socket will be
a server that listens on the given \fIport\fR (either an integer or a
service name, where supported and understood by the host operating
system; if \fIport\fR is zero, the operating system will allocate a







>
>
|
|
|
|
|
|









|
>
>
>
>
>
>
>
>
>







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
port number will be chosen at random by the system software.
.TP
\fB\-async\fR
.
This option will cause the client socket to be connected
asynchronously. This means that the socket will be created immediately
but may not yet be connected to the server, when the call to
\fBsocket\fR returns.

When a \fBgets\fR or \fBflush\fR is done on the socket before the
connection attempt succeeds or fails, if the socket is in blocking
mode, the operation will wait until the connection is completed or
fails. If the socket is in nonblocking mode and a \fBgets\fR or
\fBflush\fR is done on the socket before the connection attempt
succeeds or fails, the operation returns immediately and
\fBfblocked\fR on the socket returns 1. Synchronous client sockets may
be switched (after they have connected) to operating in asynchronous
mode using:
.RS
.PP
.CS
\fBchan configure \fIchan \fB\-blocking 0\fR
.CE
.PP
See the \fBchan configure\fR command for more details.

The Tcl event loop should be running while an asynchronous connection
is in progress, because it may have to do several connection attempts
in the background. Runnig the event loop also allows you to set up a
writable channel event on the socket to get notified when the
asyncronous connection has succeeded or failed. See the \fBvwait\fR
and the \fBchan\fR comands for more details on the event loop and
channel events.

.RE
.SH "SERVER SOCKETS"
.PP
If the \fB\-server\fR option is specified then the new socket will be
a server that listens on the given \fIport\fR (either an integer or a
service name, where supported and understood by the host operating
system; if \fIport\fR is zero, the operating system will allocate a
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
three elements, the address, the host name and the port number for the
socket. If the host name cannot be computed, the second element is
identical to the address, the first element of the list.

For server sockets this option returns a list of a multiple of three
elements each group of which have the same meaning as described
above. The list contains more than one group when the server socket
was created without \fB-myaddr\fR or with the argument to
\fB-myaddr\fR being a domain name that resolves multiple IP addresses
that are local to the invoking host.

.TP
\fB\-peername\fR
.
This option is not supported by server sockets. For client and accepted
sockets, this option returns a list of three elements; these are the







|
|







165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
three elements, the address, the host name and the port number for the
socket. If the host name cannot be computed, the second element is
identical to the address, the first element of the list.

For server sockets this option returns a list of a multiple of three
elements each group of which have the same meaning as described
above. The list contains more than one group when the server socket
was created without \fB\-myaddr\fR or with the argument to
\fB\-myaddr\fR being a domain name that resolves multiple IP addresses
that are local to the invoking host.

.TP
\fB\-peername\fR
.
This option is not supported by server sockets. For client and accepted
sockets, this option returns a list of three elements; these are the

Changes to doc/tcltest.n.

28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
\fBtcltest::removeFile \fIname\fR ?\fIdirectory\fR?
\fBtcltest::viewFile \fIname\fR ?\fIdirectory\fR?
\fBtcltest::cleanupTests \fR?\fIrunningMultipleTests\fR?
\fBtcltest::runAllTests\fR

\fBtcltest::configure\fR
\fBtcltest::configure \fI\-option\fR
\fBtcltest::configure \fI\-option value\fR ?\fI-option value ...\fR?
\fBtcltest::customMatch \fImode command\fR
\fBtcltest::testConstraint \fIconstraint\fR ?\fIvalue\fR?
\fBtcltest::outputChannel \fR?\fIchannelID\fR?
\fBtcltest::errorChannel \fR?\fIchannelID\fR?
\fBtcltest::interpreter \fR?\fIinterp\fR?

\fBtcltest::debug \fR?\fIlevel\fR?







|







28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
\fBtcltest::removeFile \fIname\fR ?\fIdirectory\fR?
\fBtcltest::viewFile \fIname\fR ?\fIdirectory\fR?
\fBtcltest::cleanupTests \fR?\fIrunningMultipleTests\fR?
\fBtcltest::runAllTests\fR

\fBtcltest::configure\fR
\fBtcltest::configure \fI\-option\fR
\fBtcltest::configure \fI\-option value\fR ?\fI\-option value ...\fR?
\fBtcltest::customMatch \fImode command\fR
\fBtcltest::testConstraint \fIconstraint\fR ?\fIvalue\fR?
\fBtcltest::outputChannel \fR?\fIchannelID\fR?
\fBtcltest::errorChannel \fR?\fIchannelID\fR?
\fBtcltest::interpreter \fR?\fIinterp\fR?

\fBtcltest::debug \fR?\fIlevel\fR?
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
test suites.
.PP
See \fBCREATING TEST SUITES WITH TCLTEST\fR below for an extended example
of how to use the commands of \fBtcltest\fR to produce test suites
for your Tcl-enabled code.
.SH COMMANDS
.TP
\fBtest\fR \fIname description\fR ?\fI-option value ...\fR?
.
Defines and possibly runs a test with the name \fIname\fR and
description \fIdescription\fR.  The name and description of a test
are used in messages reported by \fBtest\fR during the
test, as configured by the options of \fBtcltest\fR.  The
remaining \fIoption value\fR arguments to \fBtest\fR
define the test, including the scripts to run, the conditions







|







86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
test suites.
.PP
See \fBCREATING TEST SUITES WITH TCLTEST\fR below for an extended example
of how to use the commands of \fBtcltest\fR to produce test suites
for your Tcl-enabled code.
.SH COMMANDS
.TP
\fBtest\fR \fIname description\fR ?\fI\-option value ...\fR?
.
Defines and possibly runs a test with the name \fIname\fR and
description \fIdescription\fR.  The name and description of a test
are used in messages reported by \fBtest\fR during the
test, as configured by the options of \fBtcltest\fR.  The
remaining \fIoption value\fR arguments to \fBtest\fR
define the test, including the scripts to run, the conditions

Changes to doc/tclvars.n.

98
99
100
101
102
103
104
105

106
107
108
109
110
111
112
Tcl format, using
.QW /
as the path separator, regardless of platform.
This variable is only used when initializing the \fBauto_path\fR variable.
.TP
\fBenv(TCL_INTERP_DEBUG_FRAME)\fR
.
If existing, it has the same effect as running \fBinterp debug {} -frame 1\fR

as the very first command of each new Tcl interpreter.
.RE
.TP
\fBerrorCode\fR
.
This variable holds the value of the \fB\-errorcode\fR return option
set by the most recent error that occurred in this interpreter.







|
>







98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
Tcl format, using
.QW /
as the path separator, regardless of platform.
This variable is only used when initializing the \fBauto_path\fR variable.
.TP
\fBenv(TCL_INTERP_DEBUG_FRAME)\fR
.
If existing, it has the same effect as running \fBinterp debug\fR
\fB{} -frame 1\fR
as the very first command of each new Tcl interpreter.
.RE
.TP
\fBerrorCode\fR
.
This variable holds the value of the \fB\-errorcode\fR return option
set by the most recent error that occurred in this interpreter.
480
481
482
483
484
485
486

487
488
489
490
491
492
493
hold the version number for this version of Tcl in the form \fIx.y\fR.
Changes to \fIx\fR represent major changes with probable
incompatibilities and changes to \fIy\fR represent small enhancements and
bug fixes that retain backward compatibility.
The value of this variable is returned by the \fBinfo tclversion\fR
command.
.SH "OTHER GLOBAL VARIABLES"

The following variables are only guaranteed to exist in \fBtclsh\fR
and \fBwish\fR executables; the Tcl library does not define them
itself but many Tcl environments do.
.TP 6
\fBargc\fR
.
The number of arguments to \fBtclsh\fR or \fBwish\fR.







>







481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
hold the version number for this version of Tcl in the form \fIx.y\fR.
Changes to \fIx\fR represent major changes with probable
incompatibilities and changes to \fIy\fR represent small enhancements and
bug fixes that retain backward compatibility.
The value of this variable is returned by the \fBinfo tclversion\fR
command.
.SH "OTHER GLOBAL VARIABLES"
.PP
The following variables are only guaranteed to exist in \fBtclsh\fR
and \fBwish\fR executables; the Tcl library does not define them
itself but many Tcl environments do.
.TP 6
\fBargc\fR
.
The number of arguments to \fBtclsh\fR or \fBwish\fR.
503
504
505
506
507
508
509




































510
511
512
513
514
515
516
517
was invoked.
.TP 6
\fBtcl_interactive\fR
.
Contains 1 if \fBtclsh\fR or \fBwish\fR is running interactively (no
script was specified and standard input is a terminal-like device), 0
otherwise.




































.SH "SEE ALSO"
eval(n), library(n), tclsh(1), tkvars(n), wish(1)
.SH KEYWORDS
arithmetic, bytecode, compiler, error, environment, POSIX, precision,
subprocess, user, variables
'\" Local Variables:
'\" mode: nroff
'\" End:







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








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
was invoked.
.TP 6
\fBtcl_interactive\fR
.
Contains 1 if \fBtclsh\fR or \fBwish\fR is running interactively (no
script was specified and standard input is a terminal-like device), 0
otherwise.
.SH EXAMPLES
.PP
To add a directory to the collection of locations searched by
\fBpackage require\fR, e.g., because of some application-specific
packages that are used, the \fBauto_path\fR variable needs to be
updated:
.PP
.CS
lappend ::\fBauto_path\fR [file join [pwd] "theLibDir"]
.CE
.PP
A simple though not very robust way to handle command line arguments
of the form
.QW "\-foo 1 \-bar 2"
is to load them into an array having first loaded in the default settings:
.CS
array set arguments {-foo 0 -bar 0 -grill 0}
array set arguments $::\fBargv\fR
puts "foo is $arguments(-foo)"
puts "bar is $arguments(-bar)"
puts "grill is $arguments(-grill)"
.CE
.PP
The \fBargv0\fR global variable can be used (in conjunction with the
\fBinfo script\fR command) to determine whether the current script is
being executed as the main script or loaded as a library.  This is
useful because it allows a single script to be used as both a library
and a demonstration of that library:
.PP
.CS
if {$::\fBargv0\fR eq [info script]} {
    # running as: tclsh example.tcl
} else {
    package provide Example 1.0
}
.CE
.SH "SEE ALSO"
eval(n), library(n), tclsh(1), tkvars(n), wish(1)
.SH KEYWORDS
arithmetic, bytecode, compiler, error, environment, POSIX, precision,
subprocess, user, variables
'\" Local Variables:
'\" mode: nroff
'\" End:

Changes to doc/throw.n.

36
37
38
39
40
41
42
43
44
45
46
47
48
The following produces an error that is identical to that produced by
\fBexpr\fR when trying to divide a value by zero.
.PP
.CS
\fBthrow\fR {ARITH DIVZERO {divide by zero}} {divide by zero}
.CE
.SH "SEE ALSO"
catch(n), error(n), return(n), try(n)
.SH "KEYWORDS"
error, exception
'\" Local Variables:
'\" mode: nroff
'\" End:







|





36
37
38
39
40
41
42
43
44
45
46
47
48
The following produces an error that is identical to that produced by
\fBexpr\fR when trying to divide a value by zero.
.PP
.CS
\fBthrow\fR {ARITH DIVZERO {divide by zero}} {divide by zero}
.CE
.SH "SEE ALSO"
catch(n), error(n), return(n), tclvars(n), try(n)
.SH "KEYWORDS"
error, exception
'\" Local Variables:
'\" mode: nroff
'\" End:

Changes to doc/transchan.n.

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
if the interpreter is deleted.
.TP
\fIcmdPrefix \fBinitialize \fIhandle mode\fR
.
This mandatory subcommand is called first, and then never again (for the given
\fIhandle\fR). Its responsibility is to initialize all parts of the
transformation at the Tcl level. The \fImode\fR is a list containing any of
\fBread\fR and \fBwrite\fR.
.RS
.TP
\fBwrite\fR
.
implies that the channel is writable.
.TP
\fBread\fR
.
implies that the channel is readable.
.PP
The return value of the subcommand should be a list containing the names of
all subcommands supported by this handler. Any error thrown by the subcommand
will prevent the creation of the transformation. The thrown error will appear
as error thrown by \fBchan push\fR.
.RE
.SS "READ-RELATED SUBCOMMANDS"
.PP
These subcommands are used for handling transformations applied to readable
channels; though strictly \fBread\fR is optional, it must be supported if any
of the others is or the channel will be made non-readable.
.TP
\fIcmdPrefix \fBdrain \fIhandle\fR
.
This optional subcommand is called whenever data in the transformation input
(i.e. read) buffer has to be forced upward, i.e. towards the user or script.
The result returned by the method is taken as the \fIbinary\fR data to push







|


















|







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
if the interpreter is deleted.
.TP
\fIcmdPrefix \fBinitialize \fIhandle mode\fR
.
This mandatory subcommand is called first, and then never again (for the given
\fIhandle\fR). Its responsibility is to initialize all parts of the
transformation at the Tcl level. The \fImode\fR is a list containing any of
\fBread \fRand \fBwrite\fR.
.RS
.TP
\fBwrite\fR
.
implies that the channel is writable.
.TP
\fBread\fR
.
implies that the channel is readable.
.PP
The return value of the subcommand should be a list containing the names of
all subcommands supported by this handler. Any error thrown by the subcommand
will prevent the creation of the transformation. The thrown error will appear
as error thrown by \fBchan push\fR.
.RE
.SS "READ-RELATED SUBCOMMANDS"
.PP
These subcommands are used for handling transformations applied to readable
channels; though strictly \fBread \fRis optional, it must be supported if any
of the others is or the channel will be made non-readable.
.TP
\fIcmdPrefix \fBdrain \fIhandle\fR
.
This optional subcommand is called whenever data in the transformation input
(i.e. read) buffer has to be forced upward, i.e. towards the user or script.
The result returned by the method is taken as the \fIbinary\fR data to push

Changes to doc/unset.n.

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
.so man.macros
.TH unset n 8.4 Tcl "Tcl Built-In Commands"
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
unset \- Delete variables
.SH SYNOPSIS
\fBunset \fR?\fI\-nocomplain\fR? ?\fI\-\-\fR? ?\fIname name name ...\fR?
.BE
.SH DESCRIPTION
.PP
This command removes one or more variables.
Each \fIname\fR is a variable name, specified in any of the
ways acceptable to the \fBset\fR command.
If a \fIname\fR refers to an element of an array then that
element is removed without affecting the rest of the array.
If a \fIname\fR consists of an array name with no parenthesized
index, then the entire array is deleted.
The \fBunset\fR command returns an empty string as result.
If \fI\-nocomplain\fR is specified as the first argument, any possible
errors are suppressed.  The option may not be abbreviated, in order to
disambiguate it from possible variable names.  The option \fI\-\-\fR
indicates the end of the options, and should be used if you wish to
remove a variable with the same name as any of the options.
If an error occurs during variable deletion, any variables after the named one
causing the error are not
deleted.  An error can occur when the named variable does not exist, or the
name refers to an array element but the variable is a scalar, or the name
refers to a variable in a non-existent namespace.







|











|

|







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
.so man.macros
.TH unset n 8.4 Tcl "Tcl Built-In Commands"
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
unset \- Delete variables
.SH SYNOPSIS
\fBunset \fR?\fB\-nocomplain\fR? ?\fB\-\-\fR? ?\fIname name name ...\fR?
.BE
.SH DESCRIPTION
.PP
This command removes one or more variables.
Each \fIname\fR is a variable name, specified in any of the
ways acceptable to the \fBset\fR command.
If a \fIname\fR refers to an element of an array then that
element is removed without affecting the rest of the array.
If a \fIname\fR consists of an array name with no parenthesized
index, then the entire array is deleted.
The \fBunset\fR command returns an empty string as result.
If \fB\-nocomplain\fR is specified as the first argument, any possible
errors are suppressed.  The option may not be abbreviated, in order to
disambiguate it from possible variable names.  The option \fB\-\-\fR
indicates the end of the options, and should be used if you wish to
remove a variable with the same name as any of the options.
If an error occurs during variable deletion, any variables after the named one
causing the error are not
deleted.  An error can occur when the named variable does not exist, or the
name refers to an array element but the variable is a scalar, or the name
refers to a variable in a non-existent namespace.

Changes to doc/upvar.n.

17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

.SH DESCRIPTION
.PP
This command arranges for one or more local variables in the current
procedure to refer to variables in an enclosing procedure call or
to global variables.
\fILevel\fR may have any of the forms permitted for the \fBuplevel\fR
command, and may be omitted if the first letter of the first \fIotherVar\fR
is not \fB#\fR or a digit (it defaults to \fB1\fR).
For each \fIotherVar\fR argument, \fBupvar\fR makes the variable
by that name in the procedure frame given by \fIlevel\fR (or at
global level, if \fIlevel\fR is \fB#0\fR) accessible
in the current procedure by the name given in the corresponding
\fImyVar\fR argument.
The variable named by \fIotherVar\fR need not exist at the time of the
call;  it will be created the first time \fImyVar\fR is referenced, just like







|
<







17
18
19
20
21
22
23
24

25
26
27
28
29
30
31

.SH DESCRIPTION
.PP
This command arranges for one or more local variables in the current
procedure to refer to variables in an enclosing procedure call or
to global variables.
\fILevel\fR may have any of the forms permitted for the \fBuplevel\fR
command, and may be omitted (it defaults to \fB1\fR).

For each \fIotherVar\fR argument, \fBupvar\fR makes the variable
by that name in the procedure frame given by \fIlevel\fR (or at
global level, if \fIlevel\fR is \fB#0\fR) accessible
in the current procedure by the name given in the corresponding
\fImyVar\fR argument.
The variable named by \fIotherVar\fR need not exist at the time of the
call;  it will be created the first time \fImyVar\fR is referenced, just like

Changes to generic/regc_lex.c.

738
739
740
741
742
743
744

745
746
747
748
749
750
751
 ^ static int lexescape(struct vars *);
 */
static int			/* not actually used, but convenient for RETV */
lexescape(
    struct vars *v)
{
    chr c;

    static const chr alert[] = {
	CHR('a'), CHR('l'), CHR('e'), CHR('r'), CHR('t')
    };
    static const chr esc[] = {
	CHR('E'), CHR('S'), CHR('C')
    };
    const chr *save;







>







738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
 ^ static int lexescape(struct vars *);
 */
static int			/* not actually used, but convenient for RETV */
lexescape(
    struct vars *v)
{
    chr c;
    int i;
    static const chr alert[] = {
	CHR('a'), CHR('l'), CHR('e'), CHR('r'), CHR('t')
    };
    static const chr esc[] = {
	CHR('E'), CHR('S'), CHR('C')
    };
    const chr *save;
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
	NOTE(REG_ULOCALE);
	RETV(CCLASS, 'S');
	break;
    case CHR('t'):
	RETV(PLAIN, CHR('\t'));
	break;
    case CHR('u'):
	c = lexdigits(v, 16, 4, 4);
	if (ISERR()) {
	    FAILW(REG_EESCAPE);
	}
	RETV(PLAIN, c);
	break;
    case CHR('U'):
	c = lexdigits(v, 16, 8, 8);
	if (ISERR()) {
	    FAILW(REG_EESCAPE);
	}





	RETV(PLAIN, c);
	break;
    case CHR('v'):
	RETV(PLAIN, CHR('\v'));
	break;
    case CHR('w'):
	NOTE(REG_ULOCALE);
	RETV(CCLASS, 'w');
	break;
    case CHR('W'):
	NOTE(REG_ULOCALE);
	RETV(CCLASS, 'W');
	break;
    case CHR('x'):
	NOTE(REG_UUNPORT);
	c = lexdigits(v, 16, 1, 255);	/* REs >255 long outside spec */
	if (ISERR()) {
	    FAILW(REG_EESCAPE);
	}
	RETV(PLAIN, c);
	break;
    case CHR('y'):
	NOTE(REG_ULOCALE);







|






|



>
>
>
>
>
|














|







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
	NOTE(REG_ULOCALE);
	RETV(CCLASS, 'S');
	break;
    case CHR('t'):
	RETV(PLAIN, CHR('\t'));
	break;
    case CHR('u'):
	c = (uchr) lexdigits(v, 16, 1, 4);
	if (ISERR()) {
	    FAILW(REG_EESCAPE);
	}
	RETV(PLAIN, c);
	break;
    case CHR('U'):
	i = lexdigits(v, 16, 1, 8);
	if (ISERR()) {
	    FAILW(REG_EESCAPE);
	}
	if (i > 0xFFFF) {
	    /* TODO: output a Surrogate pair
	     */
	    i = 0xFFFD;
	}
	RETV(PLAIN, (uchr) i);
	break;
    case CHR('v'):
	RETV(PLAIN, CHR('\v'));
	break;
    case CHR('w'):
	NOTE(REG_ULOCALE);
	RETV(CCLASS, 'w');
	break;
    case CHR('W'):
	NOTE(REG_ULOCALE);
	RETV(CCLASS, 'W');
	break;
    case CHR('x'):
	NOTE(REG_UUNPORT);
	c = (uchr) lexdigits(v, 16, 1, 2);
	if (ISERR()) {
	    FAILW(REG_EESCAPE);
	}
	RETV(PLAIN, c);
	break;
    case CHR('y'):
	NOTE(REG_ULOCALE);
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
	RETV(SEND, 0);
	break;
    case CHR('1'): case CHR('2'): case CHR('3'): case CHR('4'):
    case CHR('5'): case CHR('6'): case CHR('7'): case CHR('8'):
    case CHR('9'):
	save = v->now;
	v->now--;		/* put first digit back */
	c = lexdigits(v, 10, 1, 255);	/* REs >255 long outside spec */
	if (ISERR()) {
	    FAILW(REG_EESCAPE);
	}

	/*
	 * Ugly heuristic (first test is "exactly 1 digit?")
	 */







|







868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
	RETV(SEND, 0);
	break;
    case CHR('1'): case CHR('2'): case CHR('3'): case CHR('4'):
    case CHR('5'): case CHR('6'): case CHR('7'): case CHR('8'):
    case CHR('9'):
	save = v->now;
	v->now--;		/* put first digit back */
	c = (uchr) lexdigits(v, 10, 1, 255);	/* REs >255 long outside spec */
	if (ISERR()) {
	    FAILW(REG_EESCAPE);
	}

	/*
	 * Ugly heuristic (first test is "exactly 1 digit?")
	 */
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
	/*
	 * And fall through into octal number.
	 */

    case CHR('0'):
	NOTE(REG_UUNPORT);
	v->now--;		/* put first digit back */
	c = lexdigits(v, 8, 1, 3);
	if (ISERR()) {
	    FAILW(REG_EESCAPE);





	}
	RETV(PLAIN, c);
	break;
    default:
	assert(iscalpha(c));
	FAILW(REG_EESCAPE);	/* unknown alphabetic escape */
	break;
    }
    assert(NOTREACHED);
}

/*
 - lexdigits - slurp up digits and return chr value
 ^ static chr lexdigits(struct vars *, int, int, int);
 */
static chr			/* chr value; errors signalled via ERR */
lexdigits(
    struct vars *v,
    int base,
    int minlen,
    int maxlen)
{
    uchr n;			/* unsigned to avoid overflow misbehavior */
    int len;
    chr c;
    int d;
    const uchr ub = (uchr) base;

    n = 0;
    for (len = 0; len < maxlen && !ATEOS(); len++) {




	c = *v->now++;
	switch (c) {
	case CHR('0'): case CHR('1'): case CHR('2'): case CHR('3'):
	case CHR('4'): case CHR('5'): case CHR('6'): case CHR('7'):
	case CHR('8'): case CHR('9'):
	    d = DIGITVAL(c);
	    break;







|


>
>
>
>
>













|

|






|







>
>
>
>







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
	/*
	 * And fall through into octal number.
	 */

    case CHR('0'):
	NOTE(REG_UUNPORT);
	v->now--;		/* put first digit back */
	c = (uchr) lexdigits(v, 8, 1, 3);
	if (ISERR()) {
	    FAILW(REG_EESCAPE);
	}
	if (c > 0xff) {
	    /* out of range, so we handled one digit too much */
	    v->now--;
	    c >>= 3;
	}
	RETV(PLAIN, c);
	break;
    default:
	assert(iscalpha(c));
	FAILW(REG_EESCAPE);	/* unknown alphabetic escape */
	break;
    }
    assert(NOTREACHED);
}

/*
 - lexdigits - slurp up digits and return chr value
 ^ static int lexdigits(struct vars *, int, int, int);
 */
static int			/* chr value; errors signalled via ERR */
lexdigits(
    struct vars *v,
    int base,
    int minlen,
    int maxlen)
{
    int n;
    int len;
    chr c;
    int d;
    const uchr ub = (uchr) base;

    n = 0;
    for (len = 0; len < maxlen && !ATEOS(); len++) {
	if (n > 0x10fff) {
	    /* Stop when continuing would otherwise overflow */
	    break;
	}
	c = *v->now++;
	switch (c) {
	case CHR('0'): case CHR('1'): case CHR('2'): case CHR('3'):
	case CHR('4'): case CHR('5'): case CHR('6'): case CHR('7'):
	case CHR('8'): case CHR('9'):
	    d = DIGITVAL(c);
	    break;
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
	}
	n = n*ub + (uchr)d;
    }
    if (len < minlen) {
	ERR(REG_EESCAPE);
    }

    return (chr)n;
}

/*
 - brenext - get next BRE token
 * This is much like EREs except for all the stupid backslashes and the
 * context-dependency of some things.
 ^ static int brenext(struct vars *, pchr);







|







969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
	}
	n = n*ub + (uchr)d;
    }
    if (len < minlen) {
	ERR(REG_EESCAPE);
    }

    return n;
}

/*
 - brenext - get next BRE token
 * This is much like EREs except for all the stupid backslashes and the
 * context-dependency of some things.
 ^ static int brenext(struct vars *, pchr);

Changes to generic/regcomp.c.

75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
/* === regc_lex.c === */
static void lexstart(struct vars *);
static void prefixes(struct vars *);
static void lexnest(struct vars *, const chr *, const chr *);
static void lexword(struct vars *);
static int next(struct vars *);
static int lexescape(struct vars *);
static chr lexdigits(struct vars *, int, int, int);
static int brenext(struct vars *, pchr);
static void skip(struct vars *);
static chr newline(NOPARMS);
#ifdef REG_DEBUG
static const chr *ch(NOPARMS);
#endif
static chr chrnamed(struct vars *, const chr *, const chr *, pchr);







|







75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
/* === regc_lex.c === */
static void lexstart(struct vars *);
static void prefixes(struct vars *);
static void lexnest(struct vars *, const chr *, const chr *);
static void lexword(struct vars *);
static int next(struct vars *);
static int lexescape(struct vars *);
static int lexdigits(struct vars *, int, int, int);
static int brenext(struct vars *, pchr);
static void skip(struct vars *);
static chr newline(NOPARMS);
#ifdef REG_DEBUG
static const chr *ch(NOPARMS);
#endif
static chr chrnamed(struct vars *, const chr *, const chr *, pchr);

Changes to generic/regcustom.h.

93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
typedef Tcl_UniChar chr;	/* The type itself. */
typedef int pchr;		/* What it promotes to. */
typedef unsigned uchr;		/* Unsigned type that will hold a chr. */
typedef int celt;		/* Type to hold chr, or NOCELT */
#define	NOCELT (-1)		/* Celt value which is not valid chr */
#define	CHR(c) (UCHAR(c))	/* Turn char literal into chr literal */
#define	DIGITVAL(c) ((c)-'0')	/* Turn chr digit into its value */
#if TCL_UTF_MAX > 3
#define	CHRBITS	32		/* Bits in a chr; must not use sizeof */
#define	CHR_MIN	0x00000000	/* Smallest and largest chr; the value */
#define	CHR_MAX	0xffffffff	/* CHR_MAX-CHR_MIN+1 should fit in uchr */
#else
#define	CHRBITS	16		/* Bits in a chr; must not use sizeof */
#define	CHR_MIN	0x0000		/* Smallest and largest chr; the value */
#define	CHR_MAX	0xffff		/* CHR_MAX-CHR_MIN+1 should fit in uchr */







|







93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
typedef Tcl_UniChar chr;	/* The type itself. */
typedef int pchr;		/* What it promotes to. */
typedef unsigned uchr;		/* Unsigned type that will hold a chr. */
typedef int celt;		/* Type to hold chr, or NOCELT */
#define	NOCELT (-1)		/* Celt value which is not valid chr */
#define	CHR(c) (UCHAR(c))	/* Turn char literal into chr literal */
#define	DIGITVAL(c) ((c)-'0')	/* Turn chr digit into its value */
#if TCL_UTF_MAX > 4
#define	CHRBITS	32		/* Bits in a chr; must not use sizeof */
#define	CHR_MIN	0x00000000	/* Smallest and largest chr; the value */
#define	CHR_MAX	0xffffffff	/* CHR_MAX-CHR_MIN+1 should fit in uchr */
#else
#define	CHRBITS	16		/* Bits in a chr; must not use sizeof */
#define	CHR_MIN	0x0000		/* Smallest and largest chr; the value */
#define	CHR_MAX	0xffff		/* CHR_MAX-CHR_MIN+1 should fit in uchr */

Changes to generic/tcl.decls.

770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
}
declare 216 {
    void Tcl_Release(ClientData clientData)
}
declare 217 {
    void Tcl_ResetResult(Tcl_Interp *interp)
}
declare 218 {
    int Tcl_ScanElement(const char *str, int *flagPtr)
}
declare 219 {
    int Tcl_ScanCountedElement(const char *str, int length, int *flagPtr)
}
# Obsolete
declare 220 {
    int Tcl_SeekOld(Tcl_Channel chan, int offset, int mode)
}
declare 221 {
    int Tcl_ServiceAll(void)







|
|

|
|







770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
}
declare 216 {
    void Tcl_Release(ClientData clientData)
}
declare 217 {
    void Tcl_ResetResult(Tcl_Interp *interp)
}
declare 218 generic {
    int Tcl_ScanElement(const char *src, int *flagPtr)
}
declare 219 generic {
    int Tcl_ScanCountedElement(const char *src, int length, int *flagPtr)
}
# Obsolete
declare 220 {
    int Tcl_SeekOld(Tcl_Channel chan, int offset, int mode)
}
declare 221 {
    int Tcl_ServiceAll(void)

Changes to generic/tcl.h.

54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
 * tools/tcl.wse.in	(for windows installer)
 * tools/tclSplash.bmp	(not patchlevel)
 */

#define TCL_MAJOR_VERSION   8
#define TCL_MINOR_VERSION   6
#define TCL_RELEASE_LEVEL   TCL_BETA_RELEASE
#define TCL_RELEASE_SERIAL  1

#define TCL_VERSION	    "8.6"
#define TCL_PATCH_LEVEL	    "8.6b1.2"

/*
 *----------------------------------------------------------------------------
 * The following definitions set up the proper options for Windows compilers.
 * We use this method because there is no autoconf equivalent.
 */








|


|







54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
 * tools/tcl.wse.in	(for windows installer)
 * tools/tclSplash.bmp	(not patchlevel)
 */

#define TCL_MAJOR_VERSION   8
#define TCL_MINOR_VERSION   6
#define TCL_RELEASE_LEVEL   TCL_BETA_RELEASE
#define TCL_RELEASE_SERIAL  2

#define TCL_VERSION	    "8.6"
#define TCL_PATCH_LEVEL	    "8.6b2"

/*
 *----------------------------------------------------------------------------
 * The following definitions set up the proper options for Windows compilers.
 * We use this method because there is no autoconf equivalent.
 */

189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
#   else
#       define DLLIMPORT __declspec(dllimport)
#       define DLLEXPORT __declspec(dllexport)
#       define CRTIMPORT __declspec(dllimport)
#   endif
#else
#   define DLLIMPORT
#   if defined(__GNUC__) && !defined(NO_VIZ) && !defined(STATIC_BUILD)
#       define DLLEXPORT __attribute__ ((visibility("default")))
#   else
#       define DLLEXPORT
#   endif
#   define CRTIMPORT
#endif








|







189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
#   else
#       define DLLIMPORT __declspec(dllimport)
#       define DLLEXPORT __declspec(dllexport)
#       define CRTIMPORT __declspec(dllimport)
#   endif
#else
#   define DLLIMPORT
#   if defined(__GNUC__) && __GNUC__ > 3
#       define DLLEXPORT __attribute__ ((visibility("default")))
#   else
#       define DLLEXPORT
#   endif
#   define CRTIMPORT
#endif

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
 *
 * Note on converting between Tcl_WideInt and strings. This implementation (in
 * tclObj.c) depends on the function
 * sprintf(...,"%" TCL_LL_MODIFIER "d",...).
 */

#if !defined(TCL_WIDE_INT_TYPE)&&!defined(TCL_WIDE_INT_IS_LONG)
#   if defined(__GNUC__)
#      define TCL_WIDE_INT_TYPE long long
#      if defined(__WIN32__) && !defined(__CYGWIN__)
#         define TCL_LL_MODIFIER        "I64"
#      else
#         define TCL_LL_MODIFIER	"ll"
#      endif
typedef struct stat	Tcl_StatBuf;
#   elif defined(__WIN32__)
#      define TCL_WIDE_INT_TYPE __int64
#      ifdef __BORLANDC__
typedef struct stati64 Tcl_StatBuf;
#         define TCL_LL_MODIFIER	"L"
#      else /* __BORLANDC__ */
#         if _MSC_VER < 1400 || !defined(_M_IX86)


typedef struct _stati64	Tcl_StatBuf;
#         else
typedef struct _stat64	Tcl_StatBuf;
#         endif /* _MSC_VER < 1400 */
#         define TCL_LL_MODIFIER	"I64"
#      endif /* __BORLANDC__ */








#   else /* __WIN32__ */
/*
 * Don't know what platform it is and configure hasn't discovered what is
 * going on for us. Try to guess...
 */
#      ifdef NO_LIMITS_H
#	  error please define either TCL_WIDE_INT_TYPE or TCL_WIDE_INT_IS_LONG
#      else /* !NO_LIMITS_H */







<
<
|
<
<
<
<
<
<





|
>
>


|



>
>
>
>
>
>
>
>
|







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
 *
 * Note on converting between Tcl_WideInt and strings. This implementation (in
 * tclObj.c) depends on the function
 * sprintf(...,"%" TCL_LL_MODIFIER "d",...).
 */

#if !defined(TCL_WIDE_INT_TYPE)&&!defined(TCL_WIDE_INT_IS_LONG)


#   if defined(__WIN32__) && !defined(__CYGWIN__)






#      define TCL_WIDE_INT_TYPE __int64
#      ifdef __BORLANDC__
typedef struct stati64 Tcl_StatBuf;
#         define TCL_LL_MODIFIER	"L"
#      else /* __BORLANDC__ */
#         if defined(_WIN64)
typedef struct __stat64 Tcl_StatBuf;
#         elif (defined(_MSC_VER) && (_MSC_VER < 1400))
typedef struct _stati64	Tcl_StatBuf;
#         else
typedef struct _stat32i64 Tcl_StatBuf;
#         endif /* _MSC_VER < 1400 */
#         define TCL_LL_MODIFIER	"I64"
#      endif /* __BORLANDC__ */
#   elif defined(__GNUC__)
#      define TCL_WIDE_INT_TYPE long long
#      define TCL_LL_MODIFIER	"ll"
#      if defined(__WIN32__)
typedef struct _stat32i64 Tcl_StatBuf;
#      else
typedef struct stat	Tcl_StatBuf;
#      endif
#   else /* ! __WIN32__ && ! __GNUC__ */
/*
 * Don't know what platform it is and configure hasn't discovered what is
 * going on for us. Try to guess...
 */
#      ifdef NO_LIMITS_H
#	  error please define either TCL_WIDE_INT_TYPE or TCL_WIDE_INT_IS_LONG
#      else /* !NO_LIMITS_H */
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
 * Flag values passed to Tcl_ConvertElement.
 * TCL_DONT_USE_BRACES forces it not to enclose the element in braces, but to
 *	use backslash quoting instead.
 * TCL_DONT_QUOTE_HASH disables the default quoting of the '#' character. It
 *	is safe to leave the hash unquoted when the element is not the first
 *	element of a list, and this flag can be used by the caller to indicate
 *	that condition.
 * (Careful! If you change these flag values be sure to change the definitions
 * at the front of tclUtil.c).
 */

#define TCL_DONT_USE_BRACES	1
#define TCL_DONT_QUOTE_HASH	8

/*
 * Flag that may be passed to Tcl_GetIndexFromObj to force it to disallow







<
<







991
992
993
994
995
996
997


998
999
1000
1001
1002
1003
1004
 * Flag values passed to Tcl_ConvertElement.
 * TCL_DONT_USE_BRACES forces it not to enclose the element in braces, but to
 *	use backslash quoting instead.
 * TCL_DONT_QUOTE_HASH disables the default quoting of the '#' character. It
 *	is safe to leave the hash unquoted when the element is not the first
 *	element of a list, and this flag can be used by the caller to indicate
 *	that condition.


 */

#define TCL_DONT_USE_BRACES	1
#define TCL_DONT_QUOTE_HASH	8

/*
 * Flag that may be passed to Tcl_GetIndexFromObj to force it to disallow
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
#define TCL_CONVERT_MULTIBYTE	(-1)
#define TCL_CONVERT_SYNTAX	(-2)
#define TCL_CONVERT_UNKNOWN	(-3)
#define TCL_CONVERT_NOSPACE	(-4)

/*
 * The maximum number of bytes that are necessary to represent a single
 * Unicode character in UTF-8. The valid values should be 3 or 6 (or perhaps 1
 * if we want to support a non-unicode enabled core). If 3, then Tcl_UniChar
 * must be 2-bytes in size (UCS-2) (the default). If 6, then Tcl_UniChar must
 * be 4-bytes in size (UCS-4). At this time UCS-2 mode is the default and
 * recommended mode. UCS-4 is experimental and not recommended. It works for
 * the core, but most extensions expect UCS-2.
 */

#ifndef TCL_UTF_MAX
#define TCL_UTF_MAX		3
#endif

/*
 * This represents a Unicode character. Any changes to this should also be
 * reflected in regcustom.h.
 */

#if TCL_UTF_MAX > 3
    /*
     * unsigned int isn't 100% accurate as it should be a strict 4-byte value
     * (perhaps wchar_t). 64-bit systems may have troubles. The size of this
     * value must be reflected correctly in regcustom.h and
     * in tclEncoding.c.
     * XXX: Tcl is currently UCS-2 and planning UTF-16 for the Unicode
     * XXX: string rep that Tcl_UniChar represents.  Changing the size







|
|
|
|
|
|











|







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
#define TCL_CONVERT_MULTIBYTE	(-1)
#define TCL_CONVERT_SYNTAX	(-2)
#define TCL_CONVERT_UNKNOWN	(-3)
#define TCL_CONVERT_NOSPACE	(-4)

/*
 * The maximum number of bytes that are necessary to represent a single
 * Unicode character in UTF-8. The valid values should be 3, 4 or 6
 * (or perhaps 1 if we want to support a non-unicode enabled core). If 3 or
 * 4, then Tcl_UniChar must be 2-bytes in size (UCS-2) (the default). If 6,
 * then Tcl_UniChar must be 4-bytes in size (UCS-4). At this time UCS-2 mode
 * is the default and recommended mode. UCS-4 is experimental and not
 * recommended. It works for the core, but most extensions expect UCS-2.
 */

#ifndef TCL_UTF_MAX
#define TCL_UTF_MAX		3
#endif

/*
 * This represents a Unicode character. Any changes to this should also be
 * reflected in regcustom.h.
 */

#if TCL_UTF_MAX > 4
    /*
     * unsigned int isn't 100% accurate as it should be a strict 4-byte value
     * (perhaps wchar_t). 64-bit systems may have troubles. The size of this
     * value must be reflected correctly in regcustom.h and
     * in tclEncoding.c.
     * XXX: Tcl is currently UCS-2 and planning UTF-16 for the Unicode
     * XXX: string rep that Tcl_UniChar represents.  Changing the size
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291

/*
 * Shorthand for commonly used argTable entries.
 */

#define TCL_ARGV_AUTO_HELP \
    {TCL_ARGV_HELP,	"-help",	NULL,	NULL, \
	    "Print summary of command-line options and abort"}
#define TCL_ARGV_AUTO_REST \
    {TCL_ARGV_REST,	"--",		NULL,	NULL, \
	    "Marks the end of the options"}
#define TCL_ARGV_TABLE_END \
    {TCL_ARGV_END}

/*
 *----------------------------------------------------------------------------
 * Definitions needed for Tcl_Zlib routines. [TIP #234]
 *
 * Constants for the format flags describing what sort of data format is
 * desired/expected for the Tcl_ZlibDeflate, Tcl_ZlibInflate and







|


|

|







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

/*
 * Shorthand for commonly used argTable entries.
 */

#define TCL_ARGV_AUTO_HELP \
    {TCL_ARGV_HELP,	"-help",	NULL,	NULL, \
	    "Print summary of command-line options and abort", NULL}
#define TCL_ARGV_AUTO_REST \
    {TCL_ARGV_REST,	"--",		NULL,	NULL, \
	    "Marks the end of the options", NULL}
#define TCL_ARGV_TABLE_END \
    {TCL_ARGV_END, NULL, NULL, NULL, NULL, NULL}

/*
 *----------------------------------------------------------------------------
 * Definitions needed for Tcl_Zlib routines. [TIP #234]
 *
 * Constants for the format flags describing what sort of data format is
 * desired/expected for the Tcl_ZlibDeflate, Tcl_ZlibInflate and
2369
2370
2371
2372
2373
2374
2375


2376
2377
2378
2379
2380
2381
2382
2383
2384
 */

/*
 * Public functions that are not accessible via the stubs table.
 * Tcl_GetMemoryInfo is needed for AOLserver. [Bug 1868171]
 */



EXTERN void		Tcl_Main(int argc, char **argv,
			    Tcl_AppInitProc *appInitProc);
EXTERN const char *	Tcl_PkgInitStubsCheck(Tcl_Interp *interp,
			    const char *version, int exact);
#if defined(TCL_THREADS) && defined(USE_THREAD_ALLOC)
EXTERN void		Tcl_GetMemoryInfo(Tcl_DString *dsPtr);
#endif

/*







>
>
|
|







2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
 */

/*
 * Public functions that are not accessible via the stubs table.
 * Tcl_GetMemoryInfo is needed for AOLserver. [Bug 1868171]
 */

#define Tcl_Main(argc, argv, proc) Tcl_MainEx(argc, argv, proc, \
	    (Tcl_FindExecutable(argv[0]), (Tcl_CreateInterp)()))
EXTERN void		Tcl_MainEx(int argc, char **argv,
			    Tcl_AppInitProc *appInitProc, Tcl_Interp *interp);
EXTERN const char *	Tcl_PkgInitStubsCheck(Tcl_Interp *interp,
			    const char *version, int exact);
#if defined(TCL_THREADS) && defined(USE_THREAD_ALLOC)
EXTERN void		Tcl_GetMemoryInfo(Tcl_DString *dsPtr);
#endif

/*

Changes to generic/tclAssembly.c.

1
2
3
4
5
6
7
8
9
/*
 * tclAssembly,c --
 *
 *	Assembler for Tcl bytecodes.
 *
 * This file contains the procedures that convert Tcl Assembly Language (TAL)
 * to a sequence of bytecode instructions for the Tcl execution engine.
 *
 * Copyright (c) 2010 by Ozgur Dogan Ugurlu.

|







1
2
3
4
5
6
7
8
9
/*
 * tclAssembly.c --
 *
 *	Assembler for Tcl bytecodes.
 *
 * This file contains the procedures that convert Tcl Assembly Language (TAL)
 * to a sequence of bytecode instructions for the Tcl execution engine.
 *
 * Copyright (c) 2010 by Ozgur Dogan Ugurlu.
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
				/* BasicBlock structure of the following
				 * block: NULL at the end of the bytecode
				 * sequence. */
    Tcl_Obj* jumpTarget;	/* Jump target label if the jump target is
				 * unresolved */
    int initialStackDepth;	/* Absolute stack depth on entry */
    int minStackDepth;		/* Low-water relative stack depth */
    int maxStackDepth; 		/* High-water relative stack depth */
    int finalStackDepth;	/* Relative stack depth on exit */
    enum BasicBlockCatchState catchState;
				/* State of the block for 'catch' analysis */
    int catchDepth;		/* Number of nested catches in which the basic
				 * block appears */
    struct BasicBlock* enclosingCatch;
				/* BasicBlock structure of the last startCatch







|







80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
				/* BasicBlock structure of the following
				 * block: NULL at the end of the bytecode
				 * sequence. */
    Tcl_Obj* jumpTarget;	/* Jump target label if the jump target is
				 * unresolved */
    int initialStackDepth;	/* Absolute stack depth on entry */
    int minStackDepth;		/* Low-water relative stack depth */
    int maxStackDepth;		/* High-water relative stack depth */
    int finalStackDepth;	/* Relative stack depth on exit */
    enum BasicBlockCatchState catchState;
				/* State of the block for 'catch' analysis */
    int catchDepth;		/* Number of nested catches in which the basic
				 * block appears */
    struct BasicBlock* enclosingCatch;
				/* BasicBlock structure of the last startCatch
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203

/*
 * Description of an instruction recognized by the assembler.
 */

typedef struct TalInstDesc {
    const char *name;		/* Name of instruction. */
    TalInstType instType; 	/* The type of instruction */
    int tclInstCode;		/* Instruction code. For instructions having
				 * 1- and 4-byte variables, tclInstCode is
				 * ((1byte)<<8) || (4byte) */
    int operandsConsumed;	/* Number of operands consumed by the
				 * operation, or INT_MIN if the operation is
				 * variadic */
    int operandsProduced;	/* Number of operands produced by the







|







189
190
191
192
193
194
195
196
197
198
199
200
201
202
203

/*
 * Description of an instruction recognized by the assembler.
 */

typedef struct TalInstDesc {
    const char *name;		/* Name of instruction. */
    TalInstType instType;	/* The type of instruction */
    int tclInstCode;		/* Instruction code. For instructions having
				 * 1- and 4-byte variables, tclInstCode is
				 * ((1byte)<<8) || (4byte) */
    int operandsConsumed;	/* Number of operands consumed by the
				 * operation, or INT_MIN if the operation is
				 * variadic */
    int operandsProduced;	/* Number of operands produced by the
366
367
368
369
370
371
372

373
374
375
376


377
378
379
380
381
382
383
					INST_BEGIN_CATCH4,	0,	0},
    {"bitand",		ASSEM_1BYTE,	INST_BITAND,		2,	1},
    {"bitnot",		ASSEM_1BYTE,	INST_BITNOT,		1,	1},
    {"bitor",		ASSEM_1BYTE,	INST_BITOR,		2,	1},
    {"bitxor",		ASSEM_1BYTE,	INST_BITXOR,		2,	1},
    {"concat",		ASSEM_CONCAT1,	INST_CONCAT1,		INT_MIN,1},
    {"dictAppend",	ASSEM_LVT4,	INST_DICT_APPEND,	2,	1},

    {"dictGet",		ASSEM_DICT_GET, INST_DICT_GET,		INT_MIN,1},
    {"dictIncrImm",	ASSEM_SINT4_LVT4,
					INST_DICT_INCR_IMM,	1,	1},
    {"dictLappend",	ASSEM_LVT4,	INST_DICT_LAPPEND,	2,	1},


    {"dictSet",		ASSEM_DICT_SET, INST_DICT_SET,		INT_MIN,1},
    {"dictUnset",	ASSEM_DICT_UNSET,
					INST_DICT_UNSET,	INT_MIN,1},
    {"div",		ASSEM_1BYTE,	INST_DIV,		2,	1},
    {"dup",		ASSEM_1BYTE,	INST_DUP,		1,	2},
    {"endCatch",	ASSEM_END_CATCH,INST_END_CATCH,		0,	0},
    {"eq",		ASSEM_1BYTE,	INST_EQ,		2,	1},







>




>
>







366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
					INST_BEGIN_CATCH4,	0,	0},
    {"bitand",		ASSEM_1BYTE,	INST_BITAND,		2,	1},
    {"bitnot",		ASSEM_1BYTE,	INST_BITNOT,		1,	1},
    {"bitor",		ASSEM_1BYTE,	INST_BITOR,		2,	1},
    {"bitxor",		ASSEM_1BYTE,	INST_BITXOR,		2,	1},
    {"concat",		ASSEM_CONCAT1,	INST_CONCAT1,		INT_MIN,1},
    {"dictAppend",	ASSEM_LVT4,	INST_DICT_APPEND,	2,	1},
    {"dictExpand",	ASSEM_1BYTE,	INST_DICT_EXPAND,	3,	1},
    {"dictGet",		ASSEM_DICT_GET, INST_DICT_GET,		INT_MIN,1},
    {"dictIncrImm",	ASSEM_SINT4_LVT4,
					INST_DICT_INCR_IMM,	1,	1},
    {"dictLappend",	ASSEM_LVT4,	INST_DICT_LAPPEND,	2,	1},
    {"dictRecombineStk",ASSEM_1BYTE,	INST_DICT_RECOMBINE_STK,3,	0},
    {"dictRecombineImm",ASSEM_LVT4,	INST_DICT_RECOMBINE_IMM,2,	0},
    {"dictSet",		ASSEM_DICT_SET, INST_DICT_SET,		INT_MIN,1},
    {"dictUnset",	ASSEM_DICT_UNSET,
					INST_DICT_UNSET,	INT_MIN,1},
    {"div",		ASSEM_1BYTE,	INST_DIV,		2,	1},
    {"dup",		ASSEM_1BYTE,	INST_DUP,		1,	2},
    {"endCatch",	ASSEM_END_CATCH,INST_END_CATCH,		0,	0},
    {"eq",		ASSEM_1BYTE,	INST_EQ,		2,	1},
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
	return TCL_ERROR;
    }

    /*
     * Use NRE to evaluate the bytecode from the trampoline.
     */

#if 0
    Tcl_NRAddCallback(interp, NRCallTEBC, INT2PTR(TCL_NR_BC_TYPE), codePtr,
	    NULL, NULL);
    return TCL_OK;
#endif
    return TclNRExecuteByteCode(interp, codePtr);
}

/*
 *-----------------------------------------------------------------------------
 *
 * CompileAssembleObj --







<
<
<
<
<







782
783
784
785
786
787
788





789
790
791
792
793
794
795
	return TCL_ERROR;
    }

    /*
     * Use NRE to evaluate the bytecode from the trampoline.
     */






    return TclNRExecuteByteCode(interp, codePtr);
}

/*
 *-----------------------------------------------------------------------------
 *
 * CompileAssembleObj --
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
    Tcl_Obj *objPtr)		/* Source code to assemble */
{
    Interp *iPtr = (Interp *) interp;
				/* Internals of the interpreter */
    CompileEnv compEnv;		/* Compilation environment structure */
    register ByteCode *codePtr = NULL;
				/* Bytecode resulting from the assembly */




    Namespace* namespacePtr;	/* Namespace in which variable and command
				 * names in the bytecode resolve */
    int status;			/* Status return from Tcl_AssembleCode */
    const char* source;		/* String representation of the source code */
    int sourceLen;		/* Length of the source code in bytes */



    /*
     * Get the expression ByteCode from the object. If it exists, make sure it
     * is valid in the current context.
     */

    if (objPtr->typePtr == &assembleCodeType) {
	namespacePtr = iPtr->varFramePtr->nsPtr;
	codePtr = objPtr->internalRep.otherValuePtr;
	if (((Interp *) *codePtr->interpHandle != iPtr)
		|| (codePtr->compileEpoch != iPtr->compileEpoch)
		|| (codePtr->nsPtr != namespacePtr)
		|| (codePtr->nsEpoch != namespacePtr->resolverEpoch)
		|| (codePtr->localCachePtr
			!= iPtr->varFramePtr->localCachePtr)) {
	    FreeAssembleCodeInternalRep(objPtr);
	} else {
	    return codePtr;
	}






    }

    /*
     * Set up the compilation environment, and assemble the code.
     */

    source = TclGetStringFromObj(objPtr, &sourceLen);
    TclInitCompileEnv(interp, &compEnv, source, sourceLen, NULL, 0);
    status = TclAssembleCode(&compEnv, source, sourceLen, TCL_EVAL_DIRECT);
    if (status != TCL_OK) {
	/*
	 * Assembly failed. Clean up and report the error.
	 */






































	TclFreeCompileEnv(&compEnv);
	return NULL;
    }

    /*
     * Add a "done" instruction as the last instruction and change the object







>
>
>
>





>
>









|
|
|
|
|
|
<
<


>
>
>
>
>
>













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







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
    Tcl_Obj *objPtr)		/* Source code to assemble */
{
    Interp *iPtr = (Interp *) interp;
				/* Internals of the interpreter */
    CompileEnv compEnv;		/* Compilation environment structure */
    register ByteCode *codePtr = NULL;
				/* Bytecode resulting from the assembly */
    register const AuxData * auxDataPtr;
				/* Pointer to an auxiliary data element
				 * in a compilation environment being
				 * destroyed. */
    Namespace* namespacePtr;	/* Namespace in which variable and command
				 * names in the bytecode resolve */
    int status;			/* Status return from Tcl_AssembleCode */
    const char* source;		/* String representation of the source code */
    int sourceLen;		/* Length of the source code in bytes */
    int i;


    /*
     * Get the expression ByteCode from the object. If it exists, make sure it
     * is valid in the current context.
     */

    if (objPtr->typePtr == &assembleCodeType) {
	namespacePtr = iPtr->varFramePtr->nsPtr;
	codePtr = objPtr->internalRep.otherValuePtr;
	if (((Interp *) *codePtr->interpHandle == iPtr)
		&& (codePtr->compileEpoch == iPtr->compileEpoch)
		&& (codePtr->nsPtr == namespacePtr)
		&& (codePtr->nsEpoch == namespacePtr->resolverEpoch)
		&& (codePtr->localCachePtr
			== iPtr->varFramePtr->localCachePtr)) {


	    return codePtr;
	}

	/*
	 * Not valid, so free it and regenerate.
	 */

	FreeAssembleCodeInternalRep(objPtr);
    }

    /*
     * Set up the compilation environment, and assemble the code.
     */

    source = TclGetStringFromObj(objPtr, &sourceLen);
    TclInitCompileEnv(interp, &compEnv, source, sourceLen, NULL, 0);
    status = TclAssembleCode(&compEnv, source, sourceLen, TCL_EVAL_DIRECT);
    if (status != TCL_OK) {
	/*
	 * Assembly failed. Clean up and report the error.
	 */

	/*
	 * Free any literals that were constructed for the assembly.
	 */
	for (i = 0; i < compEnv.literalArrayNext; i++) {
	    TclReleaseLiteral(interp, compEnv.literalArrayPtr[i].objPtr);
	}

	/*
	 * Free any auxiliary data that was attached to the bytecode
	 * under construction.
	 */

	for (i = 0; i < compEnv.auxDataArrayNext; i++) {
	    auxDataPtr = compEnv.auxDataArrayPtr + i;
	    if (auxDataPtr->type->freeProc != NULL) {
		(auxDataPtr->type->freeProc)(auxDataPtr->clientData);
	    }
	}

	/*
	 * TIP 280. If there is extended command line information,
	 * we need to clean it up.
	 */

	if (compEnv.extCmdMapPtr != NULL) {
	    if (compEnv.extCmdMapPtr->type == TCL_LOCATION_SOURCE) {
		Tcl_DecrRefCount(compEnv.extCmdMapPtr->path);
	    }
	    for (i = 0; i < compEnv.extCmdMapPtr->nuloc; ++i) {
		ckfree(compEnv.extCmdMapPtr->loc[i].line);
	    }
	    if (compEnv.extCmdMapPtr->loc != NULL) {
		ckfree(compEnv.extCmdMapPtr->loc);
	    }
	    Tcl_DeleteHashTable(&(compEnv.extCmdMapPtr->litInfo));
	}

	TclFreeCompileEnv(&compEnv);
	return NULL;
    }

    /*
     * Add a "done" instruction as the last instruction and change the object
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
 *	environment's stack depth.
 *
 *-----------------------------------------------------------------------------
 */

static int
TclAssembleCode(
    CompileEnv *envPtr, 	/* Compilation environment that is to receive
				 * the generated bytecode */
    const char* codePtr,	/* Assembly-language code to be processed */
    int codeLen,		/* Length of the code */
    int flags)			/* OR'ed combination of flags */
{
    Tcl_Interp* interp = (Tcl_Interp*) envPtr->iPtr;
				/* Tcl interpreter */







|







1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
 *	environment's stack depth.
 *
 *-----------------------------------------------------------------------------
 */

static int
TclAssembleCode(
    CompileEnv *envPtr,		/* Compilation environment that is to receive
				 * the generated bytecode */
    const char* codePtr,	/* Assembly-language code to be processed */
    int codeLen,		/* Length of the code */
    int flags)			/* OR'ed combination of flags */
{
    Tcl_Interp* interp = (Tcl_Interp*) envPtr->iPtr;
				/* Tcl interpreter */
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
	if (parsePtr->numWords > 0) {
	    /*
	     * If tracing, show each line assembled as it happens.
	     */

#ifdef TCL_COMPILE_DEBUG
	    if ((tclTraceCompile >= 2) && (envPtr->procPtr == NULL)) {
		printf("  %4d Assembling: ",
			envPtr->codeNext - envPtr->codeStart);
		TclPrintSource(stdout, parsePtr->commandStart,
			TclMin(instLen, 55));
		printf("\n");
	    }
#endif
	    if (AssembleOneLine(assemEnvPtr) != TCL_OK) {
		if (flags & TCL_EVAL_DIRECT) {







|
|







1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
	if (parsePtr->numWords > 0) {
	    /*
	     * If tracing, show each line assembled as it happens.
	     */

#ifdef TCL_COMPILE_DEBUG
	    if ((tclTraceCompile >= 2) && (envPtr->procPtr == NULL)) {
		printf("  %4ld Assembling: ",
			(long)(envPtr->codeNext - envPtr->codeStart));
		TclPrintSource(stdout, parsePtr->commandStart,
			TclMin(instLen, 55));
		printf("\n");
	    }
#endif
	    if (AssembleOneLine(assemEnvPtr) != TCL_OK) {
		if (flags & TCL_EVAL_DIRECT) {
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
	if (thisBB->jtPtr != NULL) {
	    DeleteMirrorJumpTable(thisBB->jtPtr);
	    thisBB->jtPtr = NULL;
	}
	ckfree(thisBB);
    }

    /*
     * Free the label hash.
     */

    while (1) {
	Tcl_HashEntry* hashEntry;
	Tcl_HashSearch hashSearch;

	hashEntry = Tcl_FirstHashEntry(&assemEnvPtr->labelHash, &hashSearch);
	if (hashEntry == NULL) {
	    break;
	}
	Tcl_DeleteHashEntry(hashEntry);
    }

    /*
     * Dispose what's left.
     */


    TclStackFree(interp, assemEnvPtr->parsePtr);
    TclStackFree(interp, assemEnvPtr);
}

/*
 *-----------------------------------------------------------------------------
 *







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




>







1213
1214
1215
1216
1217
1218
1219















1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
	if (thisBB->jtPtr != NULL) {
	    DeleteMirrorJumpTable(thisBB->jtPtr);
	    thisBB->jtPtr = NULL;
	}
	ckfree(thisBB);
    }
















    /*
     * Dispose what's left.
     */

    Tcl_DeleteHashTable(&assemEnvPtr->labelHash);
    TclStackFree(interp, assemEnvPtr->parsePtr);
    TclStackFree(interp, assemEnvPtr);
}

/*
 *-----------------------------------------------------------------------------
 *
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
				/* Compilation environment being used for code
				 * gen */
    Tcl_Interp* interp = (Tcl_Interp*) envPtr->iPtr;
				/* Tcl interpreter */
    Tcl_Parse* parsePtr = assemEnvPtr->parsePtr;
				/* Parse of the line of code */
    Tcl_Token* tokenPtr;	/* Current token within the line of code */
    Tcl_Obj* instNameObj = NULL;
				/* Name of the instruction */
    int tblIdx;			/* Index in TalInstructionTable of the
				 * instruction */
    enum TalInstType instType;	/* Type of the instruction */
    Tcl_Obj* operand1Obj = NULL;
    				/* First operand to the instruction */
    const char* operand1;	/* String rep of the operand */
    int operand1Len;		/* String length of the operand */
    int opnd;			/* Integer representation of an operand */
    int litIndex;		/* Literal pool index of a constant */
    int localVar;		/* LVT index of a local variable */
    int flags;			/* Flags for a basic block */
    JumptableInfo* jtPtr;	/* Pointer to a jumptable */
    int infoIndex;		/* Index of the jumptable in auxdata */
    int status = TCL_ERROR;	/* Return value from this function */

    /*
     * Make sure that the instruction name is known at compile time.
     */

    tokenPtr = parsePtr->tokenPtr;
    instNameObj = Tcl_NewObj();
    Tcl_IncrRefCount(instNameObj);
    if (GetNextOperand(assemEnvPtr, &tokenPtr, &instNameObj) != TCL_OK) {
	return TCL_ERROR;
    }

    /*
     * Look up the instruction name.
     */

    if (Tcl_GetIndexFromObjStruct(interp, instNameObj,
	    &TalInstructionTable[0].name, sizeof(TalInstDesc), "instruction",
	    TCL_EXACT, &tblIdx) != TCL_OK) {
	return TCL_ERROR;
    }

    /*
     * Vector on the type of instruction being processed.
     */

    instType = TalInstructionTable[tblIdx].instType;







|
<




|















<
<











|







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
				/* Compilation environment being used for code
				 * gen */
    Tcl_Interp* interp = (Tcl_Interp*) envPtr->iPtr;
				/* Tcl interpreter */
    Tcl_Parse* parsePtr = assemEnvPtr->parsePtr;
				/* Parse of the line of code */
    Tcl_Token* tokenPtr;	/* Current token within the line of code */
    Tcl_Obj* instNameObj;	/* Name of the instruction */

    int tblIdx;			/* Index in TalInstructionTable of the
				 * instruction */
    enum TalInstType instType;	/* Type of the instruction */
    Tcl_Obj* operand1Obj = NULL;
				/* First operand to the instruction */
    const char* operand1;	/* String rep of the operand */
    int operand1Len;		/* String length of the operand */
    int opnd;			/* Integer representation of an operand */
    int litIndex;		/* Literal pool index of a constant */
    int localVar;		/* LVT index of a local variable */
    int flags;			/* Flags for a basic block */
    JumptableInfo* jtPtr;	/* Pointer to a jumptable */
    int infoIndex;		/* Index of the jumptable in auxdata */
    int status = TCL_ERROR;	/* Return value from this function */

    /*
     * Make sure that the instruction name is known at compile time.
     */

    tokenPtr = parsePtr->tokenPtr;


    if (GetNextOperand(assemEnvPtr, &tokenPtr, &instNameObj) != TCL_OK) {
	return TCL_ERROR;
    }

    /*
     * Look up the instruction name.
     */

    if (Tcl_GetIndexFromObjStruct(interp, instNameObj,
	    &TalInstructionTable[0].name, sizeof(TalInstDesc), "instruction",
	    TCL_EXACT, &tblIdx) != TCL_OK) {
	goto cleanup;
    }

    /*
     * Vector on the type of instruction being processed.
     */

    instType = TalInstructionTable[tblIdx].instType;
1322
1323
1324
1325
1326
1327
1328
1329


1330

1331
1332
1333
1334
1335
1336
1337
	break;

    case ASSEM_BOOL_LVT4:
	if (parsePtr->numWords != 3) {
	    Tcl_WrongNumArgs(interp, 1, &instNameObj, "boolean varName");
	    goto cleanup;
	}
	if (GetBooleanOperand(assemEnvPtr, &tokenPtr, &opnd) != TCL_OK


		|| (localVar = FindLocalVar(assemEnvPtr, &tokenPtr)) < 0) {

	    goto cleanup;
	}
	BBEmitInstInt1(assemEnvPtr, tblIdx, opnd, 0);
	TclEmitInt4(localVar, envPtr);
	break;

    case ASSEM_CONCAT1:







|
>
>
|
>







1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
	break;

    case ASSEM_BOOL_LVT4:
	if (parsePtr->numWords != 3) {
	    Tcl_WrongNumArgs(interp, 1, &instNameObj, "boolean varName");
	    goto cleanup;
	}
	if (GetBooleanOperand(assemEnvPtr, &tokenPtr, &opnd) != TCL_OK) {
	    goto cleanup;
	}
	localVar = FindLocalVar(assemEnvPtr, &tokenPtr);
	if (localVar < 0) {
	    goto cleanup;
	}
	BBEmitInstInt1(assemEnvPtr, tblIdx, opnd, 0);
	TclEmitInt4(localVar, envPtr);
	break;

    case ASSEM_CONCAT1:
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

    case ASSEM_DICT_SET:
	if (parsePtr->numWords != 3) {
	    Tcl_WrongNumArgs(interp, 1, &instNameObj, "count varName");
	    goto cleanup;
	}
	if (GetIntegerOperand(assemEnvPtr, &tokenPtr, &opnd) != TCL_OK
		|| CheckStrictlyPositive(interp, opnd) != TCL_OK


		|| (localVar = FindLocalVar(assemEnvPtr, &tokenPtr)) == -1) {

	    goto cleanup;
	}
	BBEmitInstInt4(assemEnvPtr, tblIdx, opnd, opnd+1);
	TclEmitInt4(localVar, envPtr);
	break;

    case ASSEM_DICT_UNSET:
	if (parsePtr->numWords != 3) {
	    Tcl_WrongNumArgs(interp, 1, &instNameObj, "count varName");
	    goto cleanup;
	}
	if (GetIntegerOperand(assemEnvPtr, &tokenPtr, &opnd) != TCL_OK
		|| CheckStrictlyPositive(interp, opnd) != TCL_OK


		|| (localVar = FindLocalVar(assemEnvPtr, &tokenPtr)) == -1) {

	    goto cleanup;
	}
	BBEmitInstInt4(assemEnvPtr, tblIdx, opnd, opnd);
	TclEmitInt4(localVar, envPtr);
	break;

    case ASSEM_END_CATCH:







|
>
>
|
>












|
>
>
|
>







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

    case ASSEM_DICT_SET:
	if (parsePtr->numWords != 3) {
	    Tcl_WrongNumArgs(interp, 1, &instNameObj, "count varName");
	    goto cleanup;
	}
	if (GetIntegerOperand(assemEnvPtr, &tokenPtr, &opnd) != TCL_OK
		|| CheckStrictlyPositive(interp, opnd) != TCL_OK) {
	    goto cleanup;
	}
	localVar = FindLocalVar(assemEnvPtr, &tokenPtr);
	if (localVar < 0) {
	    goto cleanup;
	}
	BBEmitInstInt4(assemEnvPtr, tblIdx, opnd, opnd+1);
	TclEmitInt4(localVar, envPtr);
	break;

    case ASSEM_DICT_UNSET:
	if (parsePtr->numWords != 3) {
	    Tcl_WrongNumArgs(interp, 1, &instNameObj, "count varName");
	    goto cleanup;
	}
	if (GetIntegerOperand(assemEnvPtr, &tokenPtr, &opnd) != TCL_OK
		|| CheckStrictlyPositive(interp, opnd) != TCL_OK) {
	    goto cleanup;
	}
	localVar = FindLocalVar(assemEnvPtr, &tokenPtr);
	if (localVar < 0) {
	    goto cleanup;
	}
	BBEmitInstInt4(assemEnvPtr, tblIdx, opnd, opnd);
	TclEmitInt4(localVar, envPtr);
	break;

    case ASSEM_END_CATCH:
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
	break;

    case ASSEM_LVT:
	if (parsePtr->numWords != 2) {
	    Tcl_WrongNumArgs(interp, 1, &instNameObj, "varname");
	    goto cleanup;
	}
	if ((localVar = FindLocalVar(assemEnvPtr, &tokenPtr)) < 0) {

	    goto cleanup;
	}
	BBEmitInst1or4(assemEnvPtr, tblIdx, localVar, 0);
	break;

    case ASSEM_LVT1:
	if (parsePtr->numWords != 2) {
	    Tcl_WrongNumArgs(interp, 1, &instNameObj, "varname");
	    goto cleanup;
	}
	if ((localVar = FindLocalVar(assemEnvPtr, &tokenPtr)) < 0
		|| CheckOneByte(interp, localVar)) {
	    goto cleanup;
	}
	BBEmitInstInt1(assemEnvPtr, tblIdx, localVar, 0);
	break;

    case ASSEM_LVT1_SINT1:
	if (parsePtr->numWords != 3) {
	    Tcl_WrongNumArgs(interp, 1, &instNameObj, "varName imm8");
	    goto cleanup;
	}
	if ((localVar = FindLocalVar(assemEnvPtr, &tokenPtr)) < 0
		|| CheckOneByte(interp, localVar)
		|| GetIntegerOperand(assemEnvPtr, &tokenPtr, &opnd) != TCL_OK
		|| CheckSignedOneByte(interp, opnd)) {
	    goto cleanup;
	}
	BBEmitInstInt1(assemEnvPtr, tblIdx, localVar, 0);
	TclEmitInt1(opnd, envPtr);
	break;

    case ASSEM_LVT4:
	if (parsePtr->numWords != 2) {
	    Tcl_WrongNumArgs(interp, 1, &instNameObj, "varname");
	    goto cleanup;
	}
	if ((localVar = FindLocalVar(assemEnvPtr, &tokenPtr)) < 0) {

	    goto cleanup;
	}
	BBEmitInstInt4(assemEnvPtr, tblIdx, localVar, 0);
	break;

    case ASSEM_OVER:
	if (parsePtr->numWords != 2) {







|
>










|
|










|
|













|
>







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
	break;

    case ASSEM_LVT:
	if (parsePtr->numWords != 2) {
	    Tcl_WrongNumArgs(interp, 1, &instNameObj, "varname");
	    goto cleanup;
	}
	localVar = FindLocalVar(assemEnvPtr, &tokenPtr);
	if (localVar < 0) {
	    goto cleanup;
	}
	BBEmitInst1or4(assemEnvPtr, tblIdx, localVar, 0);
	break;

    case ASSEM_LVT1:
	if (parsePtr->numWords != 2) {
	    Tcl_WrongNumArgs(interp, 1, &instNameObj, "varname");
	    goto cleanup;
	}
	localVar = FindLocalVar(assemEnvPtr, &tokenPtr);
	if (localVar < 0 || CheckOneByte(interp, localVar)) {
	    goto cleanup;
	}
	BBEmitInstInt1(assemEnvPtr, tblIdx, localVar, 0);
	break;

    case ASSEM_LVT1_SINT1:
	if (parsePtr->numWords != 3) {
	    Tcl_WrongNumArgs(interp, 1, &instNameObj, "varName imm8");
	    goto cleanup;
	}
	localVar = FindLocalVar(assemEnvPtr, &tokenPtr);
	if (localVar < 0 || CheckOneByte(interp, localVar)
		|| GetIntegerOperand(assemEnvPtr, &tokenPtr, &opnd) != TCL_OK
		|| CheckSignedOneByte(interp, opnd)) {
	    goto cleanup;
	}
	BBEmitInstInt1(assemEnvPtr, tblIdx, localVar, 0);
	TclEmitInt1(opnd, envPtr);
	break;

    case ASSEM_LVT4:
	if (parsePtr->numWords != 2) {
	    Tcl_WrongNumArgs(interp, 1, &instNameObj, "varname");
	    goto cleanup;
	}
	localVar = FindLocalVar(assemEnvPtr, &tokenPtr);
	if (localVar < 0) {
	    goto cleanup;
	}
	BBEmitInstInt4(assemEnvPtr, tblIdx, localVar, 0);
	break;

    case ASSEM_OVER:
	if (parsePtr->numWords != 2) {
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
	break;

    case ASSEM_SINT4_LVT4:
	if (parsePtr->numWords != 3) {
	    Tcl_WrongNumArgs(interp, 1, &instNameObj, "count varName");
	    goto cleanup;
	}
	if (GetIntegerOperand(assemEnvPtr, &tokenPtr, &opnd) != TCL_OK


		|| (localVar = FindLocalVar(assemEnvPtr, &tokenPtr)) == -1) {

	    goto cleanup;
	}
	BBEmitInstInt4(assemEnvPtr, tblIdx, opnd, 0);
	TclEmitInt4(localVar, envPtr);
	break;

    default:
	Tcl_Panic("Instruction \"%s\" could not be found, can't happen\n",
		Tcl_GetString(instNameObj));
    }

    status = TCL_OK;
 cleanup:
    if (instNameObj) {
	Tcl_DecrRefCount(instNameObj);
    }
    if (operand1Obj) {
	Tcl_DecrRefCount(operand1Obj);
    }
    return status;
}

/*







|
>
>
|
>













<
|
<







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
	break;

    case ASSEM_SINT4_LVT4:
	if (parsePtr->numWords != 3) {
	    Tcl_WrongNumArgs(interp, 1, &instNameObj, "count varName");
	    goto cleanup;
	}
	if (GetIntegerOperand(assemEnvPtr, &tokenPtr, &opnd) != TCL_OK) {
	    goto cleanup;
	}
	localVar = FindLocalVar(assemEnvPtr, &tokenPtr);
	if (localVar < 0) {
	    goto cleanup;
	}
	BBEmitInstInt4(assemEnvPtr, tblIdx, opnd, 0);
	TclEmitInt4(localVar, envPtr);
	break;

    default:
	Tcl_Panic("Instruction \"%s\" could not be found, can't happen\n",
		Tcl_GetString(instNameObj));
    }

    status = TCL_OK;
 cleanup:

    Tcl_DecrRefCount(instNameObj);

    if (operand1Obj) {
	Tcl_DecrRefCount(operand1Obj);
    }
    return status;
}

/*
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
     * once flow analysis has determined the actual stack depth of the block.
     */

    DEBUG_PRINT("basic block %p has %d exceptions starting at %d\n",
	    curr_bb, exceptionCount, savedExceptArrayNext);
    curr_bb->foreignExceptionBase = savedExceptArrayNext;
    curr_bb->foreignExceptionCount = exceptionCount;
    curr_bb->foreignExceptions = 
	    ckalloc(exceptionCount * sizeof(ExceptionRange));
    memcpy(curr_bb->foreignExceptions,
	    envPtr->exceptArrayPtr + savedExceptArrayNext,
	    exceptionCount * sizeof(ExceptionRange));
    for (i = 0; i < exceptionCount; ++i) {
	curr_bb->foreignExceptions[i].nestingLevel -= envPtr->exceptDepth;
    }







|







1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
     * once flow analysis has determined the actual stack depth of the block.
     */

    DEBUG_PRINT("basic block %p has %d exceptions starting at %d\n",
	    curr_bb, exceptionCount, savedExceptArrayNext);
    curr_bb->foreignExceptionBase = savedExceptArrayNext;
    curr_bb->foreignExceptionCount = exceptionCount;
    curr_bb->foreignExceptions =
	    ckalloc(exceptionCount * sizeof(ExceptionRange));
    memcpy(curr_bb->foreignExceptions,
	    envPtr->exceptArrayPtr + savedExceptArrayNext,
	    exceptionCount * sizeof(ExceptionRange));
    for (i = 0; i < exceptionCount; ++i) {
	curr_bb->foreignExceptions[i].nestingLevel -= envPtr->exceptDepth;
    }
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
    BasicBlock* bbPtr = assemEnvPtr->curr_bb;
				/* Current basic block */
    JumptableInfo* jtPtr;
    Tcl_HashTable* jtHashPtr;	/* Hashtable in the JumptableInfo */
    Tcl_HashEntry* hashEntry;	/* Entry for a key in the hashtable */
    int isNew;			/* Flag==1 if the key is not yet in the
				 * table. */
    Tcl_Obj* result;		/* Error message */
    int i;

    if (Tcl_ListObjGetElements(interp, jumps, &objc, &objv) != TCL_OK) {
	return TCL_ERROR;
    }
    if (objc % 2 != 0) {
	if (assemEnvPtr->flags & TCL_EVAL_DIRECT) {







<







1956
1957
1958
1959
1960
1961
1962

1963
1964
1965
1966
1967
1968
1969
    BasicBlock* bbPtr = assemEnvPtr->curr_bb;
				/* Current basic block */
    JumptableInfo* jtPtr;
    Tcl_HashTable* jtHashPtr;	/* Hashtable in the JumptableInfo */
    Tcl_HashEntry* hashEntry;	/* Entry for a key in the hashtable */
    int isNew;			/* Flag==1 if the key is not yet in the
				 * table. */

    int i;

    if (Tcl_ListObjGetElements(interp, jumps, &objc, &objv) != TCL_OK) {
	return TCL_ERROR;
    }
    if (objc % 2 != 0) {
	if (assemEnvPtr->flags & TCL_EVAL_DIRECT) {
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
    for (i = 0; i < objc; i+=2) {
	DEBUG_PRINT("  %s -> %s\n", Tcl_GetString(objv[i]),
		Tcl_GetString(objv[i+1]));
	hashEntry = Tcl_CreateHashEntry(jtHashPtr, Tcl_GetString(objv[i]),
		&isNew);
	if (!isNew) {
	    if (assemEnvPtr->flags & TCL_EVAL_DIRECT) {
		result = Tcl_NewStringObj(
			"duplicate entry in jump table for \"", -1);
		Tcl_AppendObjToObj(result, objv[i]);
		Tcl_AppendToObj(result, "\"", -1);
		Tcl_SetObjResult(interp, result);
		Tcl_SetErrorCode(interp, "TCL", "ASSEM", "DUPJUMPTABLEENTRY");
		DeleteMirrorJumpTable(jtPtr);
		return TCL_ERROR;
	    }
	}
	Tcl_SetHashValue(hashEntry, (ClientData) objv[i+1]);
	Tcl_IncrRefCount(objv[i+1]);
    }
    DEBUG_PRINT("}\n");

    /*
     * Put the mirror jumptable in the basic block struct.
     */







|
|
|
<
<





|







1991
1992
1993
1994
1995
1996
1997
1998
1999
2000


2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
    for (i = 0; i < objc; i+=2) {
	DEBUG_PRINT("  %s -> %s\n", Tcl_GetString(objv[i]),
		Tcl_GetString(objv[i+1]));
	hashEntry = Tcl_CreateHashEntry(jtHashPtr, Tcl_GetString(objv[i]),
		&isNew);
	if (!isNew) {
	    if (assemEnvPtr->flags & TCL_EVAL_DIRECT) {
		Tcl_SetObjResult(interp, Tcl_ObjPrintf(
			"duplicate entry in jump table for \"%s\"",
			Tcl_GetString(objv[i])));


		Tcl_SetErrorCode(interp, "TCL", "ASSEM", "DUPJUMPTABLEENTRY");
		DeleteMirrorJumpTable(jtPtr);
		return TCL_ERROR;
	    }
	}
	Tcl_SetHashValue(hashEntry, objv[i+1]);
	Tcl_IncrRefCount(objv[i+1]);
    }
    DEBUG_PRINT("}\n");

    /*
     * Put the mirror jumptable in the basic block struct.
     */
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
    CompileEnv* envPtr = assemEnvPtr->envPtr;
				/* Compilation environment */
    Tcl_Interp* interp = (Tcl_Interp*) envPtr->iPtr;
				/* Tcl interpreter */
    Tcl_Token* tokenPtr = *tokenPtrPtr;
				/* INOUT: Pointer to the next token in the
				 * source code */
    Tcl_Obj* intObj = Tcl_NewObj();
				/* Integer from the source code */
    int status;			/* Tcl status return */

    /*
     * Extract the next token as a string.
     */

    Tcl_IncrRefCount(intObj);
    if (GetNextOperand(assemEnvPtr, tokenPtrPtr, &intObj) != TCL_OK) {
	Tcl_DecrRefCount(intObj);
	return TCL_ERROR;
    }

    /*
     * Convert to an integer, advance to the next token and return.
     */








<
|






<

<







2120
2121
2122
2123
2124
2125
2126

2127
2128
2129
2130
2131
2132
2133

2134

2135
2136
2137
2138
2139
2140
2141
    CompileEnv* envPtr = assemEnvPtr->envPtr;
				/* Compilation environment */
    Tcl_Interp* interp = (Tcl_Interp*) envPtr->iPtr;
				/* Tcl interpreter */
    Tcl_Token* tokenPtr = *tokenPtrPtr;
				/* INOUT: Pointer to the next token in the
				 * source code */

    Tcl_Obj* intObj;		/* Integer from the source code */
    int status;			/* Tcl status return */

    /*
     * Extract the next token as a string.
     */


    if (GetNextOperand(assemEnvPtr, tokenPtrPtr, &intObj) != TCL_OK) {

	return TCL_ERROR;
    }

    /*
     * Convert to an integer, advance to the next token and return.
     */

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
    CompileEnv* envPtr = assemEnvPtr->envPtr;
				/* Compilation environment */
    Tcl_Interp* interp = (Tcl_Interp*) envPtr->iPtr;
				/* Tcl interpreter */
    Tcl_Token* tokenPtr = *tokenPtrPtr;
				/* INOUT: Pointer to the next token in the
				 * source code */
    Tcl_Obj* intObj = Tcl_NewObj();
				/* Integer from the source code */
    int status;			/* Tcl status return */

    /*
     * Extract the next token as a string.
     */

    Tcl_IncrRefCount(intObj);
    if (GetNextOperand(assemEnvPtr, tokenPtrPtr, &intObj) != TCL_OK) {
	Tcl_DecrRefCount(intObj);
	return TCL_ERROR;
    }

    /*
     * Convert to an integer, advance to the next token and return.
     */








<
|






<

<







2173
2174
2175
2176
2177
2178
2179

2180
2181
2182
2183
2184
2185
2186

2187

2188
2189
2190
2191
2192
2193
2194
    CompileEnv* envPtr = assemEnvPtr->envPtr;
				/* Compilation environment */
    Tcl_Interp* interp = (Tcl_Interp*) envPtr->iPtr;
				/* Tcl interpreter */
    Tcl_Token* tokenPtr = *tokenPtrPtr;
				/* INOUT: Pointer to the next token in the
				 * source code */

    Tcl_Obj* intObj;		/* Integer from the source code */
    int status;			/* Tcl status return */

    /*
     * Extract the next token as a string.
     */


    if (GetNextOperand(assemEnvPtr, tokenPtrPtr, &intObj) != TCL_OK) {

	return TCL_ERROR;
    }

    /*
     * Convert to an integer, advance to the next token and return.
     */

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
    CompileEnv* envPtr = assemEnvPtr->envPtr;
				/* Compilation environment */
    Tcl_Interp* interp = (Tcl_Interp*) envPtr->iPtr;
				/* Tcl interpreter */
    Tcl_Token* tokenPtr = *tokenPtrPtr;
				/* INOUT: Pointer to the next token in the
				 * source code */
    Tcl_Obj* intObj = Tcl_NewObj();
				/* Integer from the source code */
    int status;			/* Tcl status return */

    /*
     * Extract the next token as a string.
     */

    Tcl_IncrRefCount(intObj);
    if (GetNextOperand(assemEnvPtr, tokenPtrPtr, &intObj) != TCL_OK) {
	Tcl_DecrRefCount(intObj);
	return TCL_ERROR;
    }

    /*
     * Convert to an integer, advance to the next token and return.
     */








<
|






<

<







2226
2227
2228
2229
2230
2231
2232

2233
2234
2235
2236
2237
2238
2239

2240

2241
2242
2243
2244
2245
2246
2247
    CompileEnv* envPtr = assemEnvPtr->envPtr;
				/* Compilation environment */
    Tcl_Interp* interp = (Tcl_Interp*) envPtr->iPtr;
				/* Tcl interpreter */
    Tcl_Token* tokenPtr = *tokenPtrPtr;
				/* INOUT: Pointer to the next token in the
				 * source code */

    Tcl_Obj* intObj;		/* Integer from the source code */
    int status;			/* Tcl status return */

    /*
     * Extract the next token as a string.
     */


    if (GetNextOperand(assemEnvPtr, tokenPtrPtr, &intObj) != TCL_OK) {

	return TCL_ERROR;
    }

    /*
     * Convert to an integer, advance to the next token and return.
     */

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
    Tcl_Token** tokenPtrPtr)
{
    CompileEnv* envPtr = assemEnvPtr->envPtr;
				/* Compilation environment */
    Tcl_Interp* interp = (Tcl_Interp*) envPtr->iPtr;
				/* Tcl interpreter */
    Tcl_Token* tokenPtr = *tokenPtrPtr;
				/* INOUT: Pointer to the next token
				 * in the source code */
    Tcl_Obj* varNameObj = Tcl_NewObj();
				/* Name of the variable */
    const char* varNameStr;
    int varNameLen;
    int localVar;		/* Index of the variable in the LVT */

    Tcl_IncrRefCount(varNameObj);
    if (GetNextOperand(assemEnvPtr, tokenPtrPtr, &varNameObj) != TCL_OK) {
	Tcl_DecrRefCount(varNameObj);
	return -1;
    }
    varNameStr = Tcl_GetStringFromObj(varNameObj, &varNameLen);
    if (CheckNamespaceQualifiers(interp, varNameStr, varNameLen)) {

	return -1;
    }
    localVar = TclFindCompiledLocal(varNameStr, varNameLen, 1, envPtr);
    Tcl_DecrRefCount(varNameObj);
    if (localVar == -1) {
	if (assemEnvPtr->flags & TCL_EVAL_DIRECT) {
	    Tcl_SetObjResult(interp, Tcl_NewStringObj(







|
|
<
|




<

<




>







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
    Tcl_Token** tokenPtrPtr)
{
    CompileEnv* envPtr = assemEnvPtr->envPtr;
				/* Compilation environment */
    Tcl_Interp* interp = (Tcl_Interp*) envPtr->iPtr;
				/* Tcl interpreter */
    Tcl_Token* tokenPtr = *tokenPtrPtr;
				/* INOUT: Pointer to the next token in the
				 * source code. */

    Tcl_Obj* varNameObj;	/* Name of the variable */
    const char* varNameStr;
    int varNameLen;
    int localVar;		/* Index of the variable in the LVT */


    if (GetNextOperand(assemEnvPtr, tokenPtrPtr, &varNameObj) != TCL_OK) {

	return -1;
    }
    varNameStr = Tcl_GetStringFromObj(varNameObj, &varNameLen);
    if (CheckNamespaceQualifiers(interp, varNameStr, varNameLen)) {
	Tcl_DecrRefCount(varNameObj);
	return -1;
    }
    localVar = TclFindCompiledLocal(varNameStr, varNameLen, 1, envPtr);
    Tcl_DecrRefCount(varNameObj);
    if (localVar == -1) {
	if (assemEnvPtr->flags & TCL_EVAL_DIRECT) {
	    Tcl_SetObjResult(interp, Tcl_NewStringObj(
2303
2304
2305
2306
2307
2308
2309
2310
2311

2312
2313
2314
2315
2316
2317

2318
2319
2320
2321
2322
2323
2324

static int
CheckNamespaceQualifiers(
    Tcl_Interp* interp,		/* Tcl interpreter for error reporting */
    const char* name,		/* Variable name to check */
    int nameLen)		/* Length of the variable */
{
    Tcl_Obj* result;		/* Error message */
    const char* p;

    for (p = name; p+2 < name+nameLen;  p++) {
	if ((*p == ':') && (p[1] == ':')) {
	    result = Tcl_NewStringObj("variable \"", -1);
	    Tcl_AppendToObj(result, name, -1);
	    Tcl_AppendToObj(result, "\" is not local", -1);
	    Tcl_SetObjResult(interp, result);

	    Tcl_SetErrorCode(interp, "TCL", "ASSEM", "NONLOCAL", name, NULL);
	    return TCL_ERROR;
	}
    }
    return TCL_OK;
}








<

>


<
<
<
|
>







2329
2330
2331
2332
2333
2334
2335

2336
2337
2338
2339



2340
2341
2342
2343
2344
2345
2346
2347
2348

static int
CheckNamespaceQualifiers(
    Tcl_Interp* interp,		/* Tcl interpreter for error reporting */
    const char* name,		/* Variable name to check */
    int nameLen)		/* Length of the variable */
{

    const char* p;

    for (p = name; p+2 < name+nameLen;  p++) {
	if ((*p == ':') && (p[1] == ':')) {



	    Tcl_SetObjResult(interp, Tcl_ObjPrintf(
		    "variable \"%s\" is not local", name));
	    Tcl_SetErrorCode(interp, "TCL", "ASSEM", "NONLOCAL", name, NULL);
	    return TCL_ERROR;
	}
    }
    return TCL_OK;
}

2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
    CompileEnv* envPtr = assemEnvPtr->envPtr;
				/* Compilation environment */
    Tcl_Interp* interp = (Tcl_Interp*) envPtr->iPtr;
				/* Tcl interpreter */
    Tcl_HashEntry* entry;	/* Label's entry in the symbol table */
    int isNew;			/* Flag == 1 iff the label was previously
				 * undefined */
    Tcl_Obj* result;		/* Error message */

    /* TODO - This can now be simplified! */

    StartBasicBlock(assemEnvPtr, BB_FALLTHRU, NULL);

    /*
     * Look up the newly-defined label in the symbol table.
     */

    entry = Tcl_CreateHashEntry(&assemEnvPtr->labelHash, labelName, &isNew);
    if (!isNew) {
	/*
	 * This is a duplicate label.
	 */

	if (assemEnvPtr-> flags & (TCL_EVAL_DIRECT)) {
	    result = Tcl_NewStringObj(
		    "duplicate definition of label \"", -1);
	    Tcl_AppendToObj(result, labelName, -1);
	    Tcl_AppendToObj(result, "\"", -1);
	    Tcl_SetObjResult(interp, result);
	    Tcl_SetErrorCode(interp, "TCL", "ASSEM", "DUPLABEL",
		    labelName, NULL);
	}
	return TCL_ERROR;
    }

    /*
     * This is the first appearance of the label in the code.
     */







<















|
|
|
<
<
<
|
|







2505
2506
2507
2508
2509
2510
2511

2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529



2530
2531
2532
2533
2534
2535
2536
2537
2538
    CompileEnv* envPtr = assemEnvPtr->envPtr;
				/* Compilation environment */
    Tcl_Interp* interp = (Tcl_Interp*) envPtr->iPtr;
				/* Tcl interpreter */
    Tcl_HashEntry* entry;	/* Label's entry in the symbol table */
    int isNew;			/* Flag == 1 iff the label was previously
				 * undefined */


    /* TODO - This can now be simplified! */

    StartBasicBlock(assemEnvPtr, BB_FALLTHRU, NULL);

    /*
     * Look up the newly-defined label in the symbol table.
     */

    entry = Tcl_CreateHashEntry(&assemEnvPtr->labelHash, labelName, &isNew);
    if (!isNew) {
	/*
	 * This is a duplicate label.
	 */

	if (assemEnvPtr->flags & TCL_EVAL_DIRECT) {
	    Tcl_SetObjResult(interp, Tcl_ObjPrintf(
		    "duplicate definition of label \"%s\"", labelName));



	    Tcl_SetErrorCode(interp, "TCL", "ASSEM", "DUPLABEL", labelName,
		    NULL);
	}
	return TCL_ERROR;
    }

    /*
     * This is the first appearance of the label in the code.
     */
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
    int flags,			/* Flags to apply to the basic block being
				 * closed, if there is one. */
    Tcl_Obj* jumpLabel)		/* Label of the location that the block jumps
				 * to, or NULL if the block does not jump */
{
    CompileEnv* envPtr = assemEnvPtr->envPtr;
				/* Compilation environment */
    BasicBlock* newBB;	 	/* BasicBlock structure for the new block */
    BasicBlock* currBB = assemEnvPtr->curr_bb;

    /*
     * Coalesce zero-length blocks.
     */

    if (currBB->startOffset == envPtr->codeNext - envPtr->codeStart) {







|







2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
    int flags,			/* Flags to apply to the basic block being
				 * closed, if there is one. */
    Tcl_Obj* jumpLabel)		/* Label of the location that the block jumps
				 * to, or NULL if the block does not jump */
{
    CompileEnv* envPtr = assemEnvPtr->envPtr;
				/* Compilation environment */
    BasicBlock* newBB;		/* BasicBlock structure for the new block */
    BasicBlock* currBB = assemEnvPtr->curr_bb;

    /*
     * Coalesce zero-length blocks.
     */

    if (currBB->startOffset == envPtr->codeNext - envPtr->codeStart) {
2703
2704
2705
2706
2707
2708
2709

2710
2711

2712
2713
2714
2715
2716
2717
2718
     * Compute stack balance throughout the program.
     */

    if (CheckStack(assemEnvPtr) != TCL_OK) {
	return TCL_ERROR;
    }


    /* TODO - Check for unreachable code */
    /* Maybe not - unreachable code is Mostly Harmless. */


    return TCL_OK;
}

/*
 *-----------------------------------------------------------------------------
 *







>
|
|
>







2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
     * Compute stack balance throughout the program.
     */

    if (CheckStack(assemEnvPtr) != TCL_OK) {
	return TCL_ERROR;
    }

    /*
     * TODO - Check for unreachable code. Or maybe not; unreachable code is
     * Mostly Harmless.
     */

    return TCL_OK;
}

/*
 *-----------------------------------------------------------------------------
 *
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
     */

    *mustMove = 0;
    do {
	motion = 0;
	for (bbPtr = assemEnvPtr->head_bb;
		bbPtr != NULL;
		bbPtr=bbPtr->successor1) {
	    /*
	     * Advance the basic block start offset by however many bytes we
	     * have inserted in the code up to this point
	     */

	    bbPtr->startOffset += motion;








|







2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
     */

    *mustMove = 0;
    do {
	motion = 0;
	for (bbPtr = assemEnvPtr->head_bb;
		bbPtr != NULL;
		bbPtr = bbPtr->successor1) {
	    /*
	     * Advance the basic block start offset by however many bytes we
	     * have inserted in the code up to this point
	     */

	    bbPtr->startOffset += motion;

2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
	    symEntryPtr != NULL;
	    symEntryPtr = Tcl_NextHashEntry(&search)) {
	symbolObj = Tcl_GetHashValue(symEntryPtr);
	valEntryPtr = Tcl_FindHashEntry(&assemEnvPtr->labelHash,
		Tcl_GetString(symbolObj));
	DEBUG_PRINT("  %s -> %s (%d)\n",
		(char*) Tcl_GetHashKey(symHash, symEntryPtr),
		Tcl_GetString(symbolObj),
		(valEntryPtr != NULL));
	if (valEntryPtr == NULL) {
	    ReportUndefinedLabel(assemEnvPtr, bbPtr, symbolObj);
	    return TCL_ERROR;
	}
    }
    DEBUG_PRINT("}\n");
    return TCL_OK;







|
<







2884
2885
2886
2887
2888
2889
2890
2891

2892
2893
2894
2895
2896
2897
2898
	    symEntryPtr != NULL;
	    symEntryPtr = Tcl_NextHashEntry(&search)) {
	symbolObj = Tcl_GetHashValue(symEntryPtr);
	valEntryPtr = Tcl_FindHashEntry(&assemEnvPtr->labelHash,
		Tcl_GetString(symbolObj));
	DEBUG_PRINT("  %s -> %s (%d)\n",
		(char*) Tcl_GetHashKey(symHash, symEntryPtr),
		Tcl_GetString(symbolObj), (valEntryPtr != NULL));

	if (valEntryPtr == NULL) {
	    ReportUndefinedLabel(assemEnvPtr, bbPtr, symbolObj);
	    return TCL_ERROR;
	}
    }
    DEBUG_PRINT("}\n");
    return TCL_OK;
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
 *
 * Side effects:
 *	Stores an error message, error code, and line number information in
 *	the assembler's Tcl interpreter.
 *
 *-----------------------------------------------------------------------------
 */

static void
ReportUndefinedLabel(
    AssemblyEnv* assemEnvPtr,	/* Assembly environment */
    BasicBlock* bbPtr,		/* Basic block that contains the undefined
				 * label */
    Tcl_Obj* jumpTarget)	/* Label of a jump target */
{
    CompileEnv* envPtr = assemEnvPtr->envPtr;
				/* Compilation environment */
    Tcl_Interp* interp = (Tcl_Interp*) envPtr->iPtr;
				/* Tcl interpreter */
    Tcl_Obj* result;		/* Error message */

    if (assemEnvPtr->flags & TCL_EVAL_DIRECT) {
	result = Tcl_NewStringObj("undefined label \"", -1);
	Tcl_AppendObjToObj(result, jumpTarget);
	Tcl_AppendToObj(result, "\"", -1);
	Tcl_SetObjResult(interp, result);

	Tcl_SetErrorCode(interp, "TCL", "ASSEM", "NOLABEL",
		Tcl_GetString(jumpTarget), NULL);
	Tcl_SetErrorLine(interp, bbPtr->jumpLine);
    }
}

/*







>











<


<
<
<
|
>







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
 *
 * Side effects:
 *	Stores an error message, error code, and line number information in
 *	the assembler's Tcl interpreter.
 *
 *-----------------------------------------------------------------------------
 */

static void
ReportUndefinedLabel(
    AssemblyEnv* assemEnvPtr,	/* Assembly environment */
    BasicBlock* bbPtr,		/* Basic block that contains the undefined
				 * label */
    Tcl_Obj* jumpTarget)	/* Label of a jump target */
{
    CompileEnv* envPtr = assemEnvPtr->envPtr;
				/* Compilation environment */
    Tcl_Interp* interp = (Tcl_Interp*) envPtr->iPtr;
				/* Tcl interpreter */


    if (assemEnvPtr->flags & TCL_EVAL_DIRECT) {



	Tcl_SetObjResult(interp, Tcl_ObjPrintf(
		"undefined label \"%s\"", Tcl_GetString(jumpTarget)));
	Tcl_SetErrorCode(interp, "TCL", "ASSEM", "NOLABEL",
		Tcl_GetString(jumpTarget), NULL);
	Tcl_SetErrorLine(interp, bbPtr->jumpLine);
    }
}

/*
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
    BasicBlock* jumpTargetBBPtr;
				/* Basic block that the jump proceeds to */
    int junk;

    auxDataIndex = TclGetInt4AtPtr(envPtr->codeStart + bbPtr->jumpOffset + 1);
    DEBUG_PRINT("bbPtr = %p jumpOffset = %d auxDataIndex = %d\n",
	    bbPtr, bbPtr->jumpOffset, auxDataIndex);
    realJumpTablePtr = (JumptableInfo*)
	    envPtr->auxDataArrayPtr[auxDataIndex].clientData;
    realJumpHashPtr = &realJumpTablePtr->hashTable;

    /*
     * Look up every jump target in the jump hash.
     */

    DEBUG_PRINT("resolve jump table {\n");







<
|







3067
3068
3069
3070
3071
3072
3073

3074
3075
3076
3077
3078
3079
3080
3081
    BasicBlock* jumpTargetBBPtr;
				/* Basic block that the jump proceeds to */
    int junk;

    auxDataIndex = TclGetInt4AtPtr(envPtr->codeStart + bbPtr->jumpOffset + 1);
    DEBUG_PRINT("bbPtr = %p jumpOffset = %d auxDataIndex = %d\n",
	    bbPtr, bbPtr->jumpOffset, auxDataIndex);

    realJumpTablePtr = envPtr->auxDataArrayPtr[auxDataIndex].clientData;
    realJumpHashPtr = &realJumpTablePtr->hashTable;

    /*
     * Look up every jump target in the jump hash.
     */

    DEBUG_PRINT("resolve jump table {\n");
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
				/* Tcl interpreter */
    BasicBlock* nextPtr;	/* Pointer to the succeeding basic block */
    int offset;			/* Bytecode offset of the current
				 * instruction */
    int bound;			/* Bytecode offset following the last
				 * instruction of the block. */
    unsigned char opcode;	/* Current bytecode instruction */
    Tcl_Obj* retval;		/* Error message */

    /*
     * Determine where in the code array the basic block ends.
     */

    nextPtr = blockPtr->successor1;
    if (nextPtr == NULL) {







<







3175
3176
3177
3178
3179
3180
3181

3182
3183
3184
3185
3186
3187
3188
				/* Tcl interpreter */
    BasicBlock* nextPtr;	/* Pointer to the succeeding basic block */
    int offset;			/* Bytecode offset of the current
				 * instruction */
    int bound;			/* Bytecode offset following the last
				 * instruction of the block. */
    unsigned char opcode;	/* Current bytecode instruction */


    /*
     * Determine where in the code array the basic block ends.
     */

    nextPtr = blockPtr->successor1;
    if (nextPtr == NULL) {
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198

3199
3200
3201
3202
3203
3204
3205
3206
3207
	opcode = (envPtr->codeStart)[offset];
	if (BytecodeMightThrow(opcode)) {
	    /*
	     * Report an error for a throw in the wrong context.
	     */

	    if (assemEnvPtr->flags & TCL_EVAL_DIRECT) {
		retval = Tcl_NewStringObj("\"", -1);
		Tcl_AppendToObj(retval, tclInstructionTable[opcode].name, -1);
		Tcl_AppendToObj(retval, "\" instruction may not appear in "
			"a context where an exception has been "
			"caught and not disposed of.", -1);

		Tcl_SetErrorCode(interp, "TCL", "ASSEM", "BADTHROW", NULL);
		Tcl_SetObjResult(interp, retval);
		AddBasicBlockRangeToErrorInfo(assemEnvPtr, blockPtr);
	    }
	    return TCL_ERROR;
	}
	offset += tclInstructionTable[opcode].numBytes;
    }
    return TCL_OK;







|
<
|

|
>

<







3204
3205
3206
3207
3208
3209
3210
3211

3212
3213
3214
3215
3216

3217
3218
3219
3220
3221
3222
3223
	opcode = (envPtr->codeStart)[offset];
	if (BytecodeMightThrow(opcode)) {
	    /*
	     * Report an error for a throw in the wrong context.
	     */

	    if (assemEnvPtr->flags & TCL_EVAL_DIRECT) {
		Tcl_SetObjResult(interp, Tcl_ObjPrintf(

			"\"%s\" instruction may not appear in "
			"a context where an exception has been "
			"caught and not disposed of.",
			tclInstructionTable[opcode].name));
		Tcl_SetErrorCode(interp, "TCL", "ASSEM", "BADTHROW", NULL);

		AddBasicBlockRangeToErrorInfo(assemEnvPtr, blockPtr);
	    }
	    return TCL_ERROR;
	}
	offset += tclInstructionTable[opcode].numBytes;
    }
    return TCL_OK;
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
    unsigned char opcode)
{
    /*
     * Binary search on the non-throwing bytecode list.
     */

    int min = 0;
    int max = sizeof(NonThrowingByteCodes)-1;
    int mid;
    unsigned char c;

    while (max >= min) {
	mid = (min + max) / 2;
	c = NonThrowingByteCodes[mid];
	if (opcode < c) {







|







3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
    unsigned char opcode)
{
    /*
     * Binary search on the non-throwing bytecode list.
     */

    int min = 0;
    int max = sizeof(NonThrowingByteCodes) - 1;
    int mid;
    unsigned char c;

    while (max >= min) {
	mid = (min + max) / 2;
	c = NonThrowingByteCodes[mid];
	if (opcode < c) {
3367
3368
3369
3370
3371
3372
3373


3374


3375
3376
3377
3378
3379
3380
3381

	if (blockPtr->initialStackDepth == initialStackDepth) {
	    return TCL_OK;
	}
	if (assemEnvPtr->flags & TCL_EVAL_DIRECT) {
	    Tcl_SetObjResult(interp, Tcl_NewStringObj(
		    "inconsistent stack depths on two execution paths", -1));


	    /* TODO - add execution trace of both paths */


	    Tcl_SetErrorLine(interp, blockPtr->startLine);
	    Tcl_SetErrorCode(interp, "TCL", "ASSEM", "BADSTACK", NULL);
	}
	return TCL_ERROR;
    }

    /*







>
>
|
>
>







3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401

	if (blockPtr->initialStackDepth == initialStackDepth) {
	    return TCL_OK;
	}
	if (assemEnvPtr->flags & TCL_EVAL_DIRECT) {
	    Tcl_SetObjResult(interp, Tcl_NewStringObj(
		    "inconsistent stack depths on two execution paths", -1));

	    /*
	     * TODO - add execution trace of both paths
	     */

	    Tcl_SetErrorLine(interp, blockPtr->startLine);
	    Tcl_SetErrorCode(interp, "TCL", "ASSEM", "BADSTACK", NULL);
	}
	return TCL_ERROR;
    }

    /*
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568
3569
3570
    CompileEnv* envPtr = assemEnvPtr->envPtr;
				/* Compilation environment */
    Tcl_Interp* interp = (Tcl_Interp*) envPtr->iPtr;
				/* Tcl interpreter */
    int depth;			/* Net stack effect */
    int litIndex;		/* Index in the literal pool of the empty
				 * string */
    Tcl_Obj* depthObj;		/* Net stack effect for an error message */
    Tcl_Obj* resultObj;		/* Error message from this procedure */
    BasicBlock* curr_bb = assemEnvPtr->curr_bb;
				/* Final basic block in the assembly */

    /*
     * Don't perform these checks if execution doesn't reach the exit (either
     * because of an infinite loop or because the only return is from the
     * middle.
     */

    if (curr_bb->flags & BB_VISITED) {
    	/*
	 * Exit with no operands; push an empty one.
	 */

    	depth = curr_bb->finalStackDepth + curr_bb->initialStackDepth;
    	if (depth == 0) {
    	    /*
	     * Emit a 'push' of the empty literal.
	     */

    	    litIndex = TclRegisterNewLiteral(envPtr, "", 0);

    	    /*
	     * Assumes that 'push' is at slot 0 in TalInstructionTable.
	     */

    	    BBEmitInst1or4(assemEnvPtr, 0, litIndex, 0);
    	    ++depth;
    	}

    	/*
	 * Exit with unbalanced stack.
	 */

    	if (depth != 1) {
    	    if (assemEnvPtr->flags & TCL_EVAL_DIRECT) {
    		depthObj = Tcl_NewIntObj(depth);
    		Tcl_IncrRefCount(depthObj);
    		resultObj = Tcl_NewStringObj(
			"stack is unbalanced on exit from the code (depth=",
			-1);
    		Tcl_AppendObjToObj(resultObj, depthObj);
    		Tcl_DecrRefCount(depthObj);
    		Tcl_AppendToObj(resultObj, ")", -1);
    		Tcl_SetObjResult(interp, resultObj);
    		Tcl_SetErrorCode(interp, "TCL", "ASSEM", "BADSTACK", NULL);
    	    }
    	    return TCL_ERROR;
    	}

    	/*
	 * Record stack usage.
	 */

    	envPtr->currStackDepth += depth;
    }

    return TCL_OK;
}

/*
 *-----------------------------------------------------------------------------







<
<










|



|
|
|



|

|



|
|
|

|



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

|



|







3520
3521
3522
3523
3524
3525
3526


3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563


3564


3565


3566
3567
3568
3569
3570
3571
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
    CompileEnv* envPtr = assemEnvPtr->envPtr;
				/* Compilation environment */
    Tcl_Interp* interp = (Tcl_Interp*) envPtr->iPtr;
				/* Tcl interpreter */
    int depth;			/* Net stack effect */
    int litIndex;		/* Index in the literal pool of the empty
				 * string */


    BasicBlock* curr_bb = assemEnvPtr->curr_bb;
				/* Final basic block in the assembly */

    /*
     * Don't perform these checks if execution doesn't reach the exit (either
     * because of an infinite loop or because the only return is from the
     * middle.
     */

    if (curr_bb->flags & BB_VISITED) {
	/*
	 * Exit with no operands; push an empty one.
	 */

	depth = curr_bb->finalStackDepth + curr_bb->initialStackDepth;
	if (depth == 0) {
	    /*
	     * Emit a 'push' of the empty literal.
	     */

	    litIndex = TclRegisterNewLiteral(envPtr, "", 0);

	    /*
	     * Assumes that 'push' is at slot 0 in TalInstructionTable.
	     */

	    BBEmitInst1or4(assemEnvPtr, 0, litIndex, 0);
	    ++depth;
	}

	/*
	 * Exit with unbalanced stack.
	 */

	if (depth != 1) {
	    if (assemEnvPtr->flags & TCL_EVAL_DIRECT) {
		Tcl_SetObjResult(interp, Tcl_ObjPrintf(


			"stack is unbalanced on exit from the code (depth=%d)",


			depth));


		Tcl_SetErrorCode(interp, "TCL", "ASSEM", "BADSTACK", NULL);
	    }
	    return TCL_ERROR;
	}

	/*
	 * Record stack usage.
	 */

	envPtr->currStackDepth += depth;
    }

    return TCL_OK;
}

/*
 *-----------------------------------------------------------------------------
3721
3722
3723
3724
3725
3726
3727

3728
3729

3730
3731
3732
3733
3734
3735
3736
     */

    fallThruEnclosing = enclosing;
    fallThruState = state;
    jumpEnclosing = enclosing;
    jumpState = state;


    /* TODO: Make sure that the test cases include validating
     *       that a natural loop can't include 'beginCatch' or 'endCatch' */


    if (bbPtr->flags & BB_BEGINCATCH) {
	/*
	 * If the block begins a catch, the state for the successor is 'in
	 * catch'. The jump target is the exception exit, and the state of the
	 * jump target is 'caught.'
	 */







>
|
|
>







3733
3734
3735
3736
3737
3738
3739
3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
     */

    fallThruEnclosing = enclosing;
    fallThruState = state;
    jumpEnclosing = enclosing;
    jumpState = state;

    /*
     * TODO: Make sure that the test cases include validating that a natural
     * loop can't include 'beginCatch' or 'endCatch'
     */

    if (bbPtr->flags & BB_BEGINCATCH) {
	/*
	 * If the block begins a catch, the state for the successor is 'in
	 * catch'. The jump target is the exception exit, and the state of the
	 * jump target is 'caught.'
	 */
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
    CompileEnv* envPtr = assemEnvPtr->envPtr;
				/* Compilation environment */
    BasicBlock* bbPtr;		/* Current basic block */
    BasicBlock* prevPtr = NULL;	/* Previous basic block */
    int catchDepth = 0;		/* Current catch depth */
    int maxCatchDepth = 0;	/* Maximum catch depth in the program */
    BasicBlock** catches;	/* Stack of catches in progress */
    int* catchIndices;		/* Indices of the exception ranges
				 * of catches in progress */
    int i;

    /*
     * Determine the max catch depth for the entire assembly script
     * (excluding embedded eval's and expr's, which will be handled later).
     */








|
|







3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
    CompileEnv* envPtr = assemEnvPtr->envPtr;
				/* Compilation environment */
    BasicBlock* bbPtr;		/* Current basic block */
    BasicBlock* prevPtr = NULL;	/* Previous basic block */
    int catchDepth = 0;		/* Current catch depth */
    int maxCatchDepth = 0;	/* Maximum catch depth in the program */
    BasicBlock** catches;	/* Stack of catches in progress */
    int* catchIndices;		/* Indices of the exception ranges of catches
				 * in progress */
    int i;

    /*
     * Determine the max catch depth for the entire assembly script
     * (excluding embedded eval's and expr's, which will be handled later).
     */

3916
3917
3918
3919
3920
3921
3922


3923
3924
3925
3926





3927
3928
3929
3930
3931
3932
3933
	    TclStoreInt4AtPtr(catchIndices[catchDepth-1],
		    envPtr->codeStart + bbPtr->startOffset - 4);
	}

	prevPtr = bbPtr;
    }



    if (catchDepth != 0) {
	Tcl_Panic("unclosed catch at end of code in "
		"tclAssembly.c:BuildExceptionRanges, can't happen");
    }






    return TCL_OK;
}

/*
 *-----------------------------------------------------------------------------
 *







>
>




>
>
>
>
>







3930
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
3943
3944
3945
3946
3947
3948
3949
3950
3951
3952
3953
3954
	    TclStoreInt4AtPtr(catchIndices[catchDepth-1],
		    envPtr->codeStart + bbPtr->startOffset - 4);
	}

	prevPtr = bbPtr;
    }

    /* Make sure that all catches are closed */

    if (catchDepth != 0) {
	Tcl_Panic("unclosed catch at end of code in "
		"tclAssembly.c:BuildExceptionRanges, can't happen");
    }

    /* Free temp storage */

    ckfree(catchIndices);
    ckfree(catches);

    return TCL_OK;
}

/*
 *-----------------------------------------------------------------------------
 *
4116
4117
4118
4119
4120
4121
4122
4123
4124
4125
4126
4127
4128
4129
4130
    BasicBlock* bbPtr;		/* Current basic block */
    int rangeBase;		/* Base of the foreign exception ranges when
				 * they are reinstalled */
    int rangeIndex;		/* Index of the current foreign exception
				 * range as reinstalled */
    ExceptionRange* range;	/* Current foreign exception range */
    unsigned char opcode;	/* Current instruction's opcode */
    int catchIndex;	/* Index of the exception range to which the
				 * current instruction refers */
    int i;

    /*
     * Walk the basic blocks looking for exceptions in embedded scripts.
     */








|







4137
4138
4139
4140
4141
4142
4143
4144
4145
4146
4147
4148
4149
4150
4151
    BasicBlock* bbPtr;		/* Current basic block */
    int rangeBase;		/* Base of the foreign exception ranges when
				 * they are reinstalled */
    int rangeIndex;		/* Index of the current foreign exception
				 * range as reinstalled */
    ExceptionRange* range;	/* Current foreign exception range */
    unsigned char opcode;	/* Current instruction's opcode */
    int catchIndex;		/* Index of the exception range to which the
				 * current instruction refers */
    int i;

    /*
     * Walk the basic blocks looking for exceptions in embedded scripts.
     */

Changes to generic/tclBasic.c.

211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
    {"case",		Tcl_CaseObjCmd,		NULL,			NULL,	1},
#endif
    {"catch",		Tcl_CatchObjCmd,	TclCompileCatchCmd,	TclNRCatchObjCmd,	1},
    {"concat",		Tcl_ConcatObjCmd,	NULL,			NULL,	1},
    {"continue",	Tcl_ContinueObjCmd,	TclCompileContinueCmd,	NULL,	1},
    {"coroutine",	NULL,			NULL,			TclNRCoroutineObjCmd,	1},
    {"error",		Tcl_ErrorObjCmd,	TclCompileErrorCmd,	NULL,	1},
    {"eval",		Tcl_EvalObjCmd,		NULL,			NULL,	1},
    {"expr",		Tcl_ExprObjCmd,		TclCompileExprCmd,	TclNRExprObjCmd,	1},
    {"for",		Tcl_ForObjCmd,		TclCompileForCmd,	TclNRForObjCmd,	1},
    {"foreach",		Tcl_ForeachObjCmd,	TclCompileForeachCmd,	TclNRForeachCmd,	1},
    {"format",		Tcl_FormatObjCmd,	NULL,			NULL,	1},
    {"global",		Tcl_GlobalObjCmd,	TclCompileGlobalCmd,	NULL,	1},
    {"if",		Tcl_IfObjCmd,		TclCompileIfCmd,	TclNRIfObjCmd,	1},
    {"incr",		Tcl_IncrObjCmd,		TclCompileIncrCmd,	NULL,	1},







|







211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
    {"case",		Tcl_CaseObjCmd,		NULL,			NULL,	1},
#endif
    {"catch",		Tcl_CatchObjCmd,	TclCompileCatchCmd,	TclNRCatchObjCmd,	1},
    {"concat",		Tcl_ConcatObjCmd,	NULL,			NULL,	1},
    {"continue",	Tcl_ContinueObjCmd,	TclCompileContinueCmd,	NULL,	1},
    {"coroutine",	NULL,			NULL,			TclNRCoroutineObjCmd,	1},
    {"error",		Tcl_ErrorObjCmd,	TclCompileErrorCmd,	NULL,	1},
    {"eval",		Tcl_EvalObjCmd,		NULL,			TclNREvalObjCmd,	1},
    {"expr",		Tcl_ExprObjCmd,		TclCompileExprCmd,	TclNRExprObjCmd,	1},
    {"for",		Tcl_ForObjCmd,		TclCompileForCmd,	TclNRForObjCmd,	1},
    {"foreach",		Tcl_ForeachObjCmd,	TclCompileForeachCmd,	TclNRForeachCmd,	1},
    {"format",		Tcl_FormatObjCmd,	NULL,			NULL,	1},
    {"global",		Tcl_GlobalObjCmd,	TclCompileGlobalCmd,	NULL,	1},
    {"if",		Tcl_IfObjCmd,		TclCompileIfCmd,	TclNRIfObjCmd,	1},
    {"incr",		Tcl_IncrObjCmd,		TclCompileIncrCmd,	NULL,	1},
1351
1352
1353
1354
1355
1356
1357
1358

1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
    Tcl_HashEntry *hPtr;
    Tcl_HashSearch search;
    Tcl_HashTable *hTablePtr;
    ResolverScheme *resPtr, *nextResPtr;
    int i;

    /*
     * Punt if there is an error in the Tcl_Release/Tcl_Preserve matchup.

     */

    if (iPtr->numLevels > 0) {
	Tcl_Panic("DeleteInterpProc called with active evals");
    }

    /*
     * The interpreter should already be marked deleted; otherwise how did we
     * get here?
     */







|
>


|







1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
    Tcl_HashEntry *hPtr;
    Tcl_HashSearch search;
    Tcl_HashTable *hTablePtr;
    ResolverScheme *resPtr, *nextResPtr;
    int i;

    /*
     * Punt if there is an error in the Tcl_Release/Tcl_Preserve matchup,
	 * unless we are exiting.
     */

    if ((iPtr->numLevels > 0) && !TclInExit()) {
	Tcl_Panic("DeleteInterpProc called with active evals");
    }

    /*
     * The interpreter should already be marked deleted; otherwise how did we
     * get here?
     */
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
     * background errors occur here, they will be deleted below.
     *
     * Dismantle the namespace after freeing the iPtr->handle so that each
     * bytecode releases its literals without caring to update the literal
     * table, as it will be freed later in this function without further use.
     */

    TclCleanupLiteralTable(interp, &iPtr->literalTable);
    TclHandleFree(iPtr->handle);
    TclTeardownNamespace(iPtr->globalNsPtr);

    /*
     * Delete all the hidden commands.
     */








<







1425
1426
1427
1428
1429
1430
1431

1432
1433
1434
1435
1436
1437
1438
     * background errors occur here, they will be deleted below.
     *
     * Dismantle the namespace after freeing the iPtr->handle so that each
     * bytecode releases its literals without caring to update the literal
     * table, as it will be freed later in this function without further use.
     */


    TclHandleFree(iPtr->handle);
    TclTeardownNamespace(iPtr->globalNsPtr);

    /*
     * Delete all the hidden commands.
     */

1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
    }

    /*
     * Pop the root frame pointer and finish deleting the global
     * namespace. The order is important [Bug 1658572].
     */

    if (iPtr->framePtr != iPtr->rootFramePtr) {
	Tcl_Panic("DeleteInterpProc: popping rootCallFrame with other frames on top");
    }
    Tcl_PopCallFrame(interp);
    ckfree(iPtr->rootFramePtr);
    iPtr->rootFramePtr = NULL;
    Tcl_DeleteNamespace((Tcl_Namespace *) iPtr->globalNsPtr);








|







1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
    }

    /*
     * Pop the root frame pointer and finish deleting the global
     * namespace. The order is important [Bug 1658572].
     */

    if ((iPtr->framePtr != iPtr->rootFramePtr) && !TclInExit()) {
	Tcl_Panic("DeleteInterpProc: popping rootCallFrame with other frames on top");
    }
    Tcl_PopCallFrame(interp);
    ckfree(iPtr->rootFramePtr);
    iPtr->rootFramePtr = NULL;
    Tcl_DeleteNamespace((Tcl_Namespace *) iPtr->globalNsPtr);

1524
1525
1526
1527
1528
1529
1530




1531
1532
1533
1534
1535
1536
1537
    }
    TclFreePackageInfo(iPtr);
    while (iPtr->tracePtr != NULL) {
	Tcl_DeleteTrace((Tcl_Interp *) iPtr, (Tcl_Trace) iPtr->tracePtr);
    }
    if (iPtr->execEnvPtr != NULL) {
	TclDeleteExecEnv(iPtr->execEnvPtr);




    }
    Tcl_DecrRefCount(iPtr->emptyObjPtr);
    iPtr->emptyObjPtr = NULL;

    resPtr = iPtr->resolverPtr;
    while (resPtr) {
	nextResPtr = resPtr->nextPtr;







>
>
>
>







1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
    }
    TclFreePackageInfo(iPtr);
    while (iPtr->tracePtr != NULL) {
	Tcl_DeleteTrace((Tcl_Interp *) iPtr, (Tcl_Trace) iPtr->tracePtr);
    }
    if (iPtr->execEnvPtr != NULL) {
	TclDeleteExecEnv(iPtr->execEnvPtr);
    }
    if (iPtr->scriptFile) {
	Tcl_DecrRefCount(iPtr->scriptFile);
	iPtr->scriptFile = NULL;
    }
    Tcl_DecrRefCount(iPtr->emptyObjPtr);
    iPtr->emptyObjPtr = NULL;

    resPtr = iPtr->resolverPtr;
    while (resPtr) {
	nextResPtr = resPtr->nextPtr;
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

    /*
     * Location stack for uplevel/eval/... scripts which were passed through
     * proc arguments. Actually we track all arguments as we do not and cannot
     * know which arguments will be used as scripts and which will not.
     */

    if (iPtr->lineLAPtr->numEntries) {
	/*
	 * When the interp goes away we have nothing on the stack, so there
	 * are no arguments, so this table has to be empty.
	 */

	Tcl_Panic("Argument location tracking table not empty");
    }

    Tcl_DeleteHashTable(iPtr->lineLAPtr);
    ckfree(iPtr->lineLAPtr);
    iPtr->lineLAPtr = NULL;

    if (iPtr->lineLABCPtr->numEntries) {
	/*
	 * When the interp goes away we have nothing on the stack, so there
	 * are no arguments, so this table has to be empty.
	 */

	Tcl_Panic("Argument location tracking table not empty");
    }







|









|


|







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

    /*
     * Location stack for uplevel/eval/... scripts which were passed through
     * proc arguments. Actually we track all arguments as we do not and cannot
     * know which arguments will be used as scripts and which will not.
     */

    if (iPtr->lineLAPtr->numEntries && !TclInExit()) {
	/*
	 * When the interp goes away we have nothing on the stack, so there
	 * are no arguments, so this table has to be empty.
	 */

	Tcl_Panic("Argument location tracking table not empty");
    }

    Tcl_DeleteHashTable(iPtr->lineLAPtr);
    ckfree((char *) iPtr->lineLAPtr);
    iPtr->lineLAPtr = NULL;

    if (iPtr->lineLABCPtr->numEntries && !TclInExit()) {
	/*
	 * When the interp goes away we have nothing on the stack, so there
	 * are no arguments, so this table has to be empty.
	 */

	Tcl_Panic("Argument location tracking table not empty");
    }
2494
2495
2496
2497
2498
2499
2500
2501

2502
2503
2504
2505
2506
2507
2508
        Tcl_SetErrorCode(interp, "TCL", "VALUE", "COMMAND", NULL);
	result = TCL_ERROR;
	goto done;
    }
    if (Tcl_FindHashEntry(&newNsPtr->cmdTable, newTail) != NULL) {
	Tcl_AppendResult(interp, "can't rename to \"", newName,
		 "\": command already exists", NULL);
        Tcl_SetErrorCode(interp, "TCL", "RENAME", "TARGET_EXISTS", NULL);

	result = TCL_ERROR;
	goto done;
    }

    /*
     * Warning: any changes done in the code here are likely to be needed in
     * Tcl_HideCommand code too (until the common parts are extracted out).







|
>







2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
        Tcl_SetErrorCode(interp, "TCL", "VALUE", "COMMAND", NULL);
	result = TCL_ERROR;
	goto done;
    }
    if (Tcl_FindHashEntry(&newNsPtr->cmdTable, newTail) != NULL) {
	Tcl_AppendResult(interp, "can't rename to \"", newName,
		 "\": command already exists", NULL);
        Tcl_SetErrorCode(interp, "TCL", "OPERATION", "RENAME",
                "TARGET_EXISTS", NULL);
	result = TCL_ERROR;
	goto done;
    }

    /*
     * Warning: any changes done in the code here are likely to be needed in
     * Tcl_HideCommand code too (until the common parts are extracted out).
3641
3642
3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
3653

3654
3655
3656
3657
3658
3659
3660
    Tcl_DecrRefCount(cmdNameObj);

    /*
     * Report unknown functions.
     */

    if (cmdPtr == NULL) {
	Tcl_Obj *message;

	TclNewLiteralStringObj(message, "unknown math function \"");
	Tcl_AppendToObj(message, name, -1);
	Tcl_AppendToObj(message, "\"", 1);
	Tcl_SetObjResult(interp, message);

	Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "MATHFUNC", name, NULL);
	*numArgsPtr = -1;
	*argTypesPtr = NULL;
	*procPtr = NULL;
	*clientDataPtr = NULL;
	return TCL_ERROR;
    }







<
<
<
<
<
|
>







3646
3647
3648
3649
3650
3651
3652





3653
3654
3655
3656
3657
3658
3659
3660
3661
    Tcl_DecrRefCount(cmdNameObj);

    /*
     * Report unknown functions.
     */

    if (cmdPtr == NULL) {





        Tcl_SetObjResult(interp, Tcl_ObjPrintf(
                "unknown math function \"%s\"", name));
	Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "MATHFUNC", name, NULL);
	*numArgsPtr = -1;
	*argTypesPtr = NULL;
	*procPtr = NULL;
	*clientDataPtr = NULL;
	return TCL_ERROR;
    }
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891



3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910


3911
3912
3913
3914
3915
3916
3917
3918
3919
3920
3921
3922
3923
3924
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
3943
3944
3945
3946
3947
3948
3949
3950
3951
3952
3953
3954
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
Tcl_Canceled(
    Tcl_Interp *interp,
    int flags)
{
    register Interp *iPtr = (Interp *) interp;

    /*
	 * Has the current script in progress for this interpreter been
	 * canceled or is the stack being unwound due to the previous script
	 * cancellation?
	 */

    if (TclCanceled(iPtr)) {



	    /*
	     * The CANCELED flag is a one-shot flag that is reset immediately
	     * upon being detected; however, if the TCL_CANCEL_UNWIND flag is
	     * set we will continue to report that the script in progress has
	     * been canceled thereby allowing the evaluation stack for the
	     * interp to be fully unwound.
	     */

	    iPtr->flags &= ~CANCELED;

	    /*
	     * The CANCELED flag was detected and reset; however, if the
	     * caller specified the TCL_CANCEL_UNWIND flag, we only return
	     * TCL_ERROR (indicating that the script in progress has been
	     * canceled) if the evaluation stack for the interp is being fully
	     * unwound.
	     */

	    if (!(flags & TCL_CANCEL_UNWIND)


		    || (iPtr->flags & TCL_CANCEL_UNWIND)) {
		/*
		 * If the TCL_LEAVE_ERR_MSG flags bit is set, place an error
		 * in the interp's result; otherwise, we leave it alone.
		 */

		if (flags & TCL_LEAVE_ERR_MSG) {
		    const char *id, *message = NULL;
		    int length;

		    /*
		     * Setup errorCode variables so that we can differentiate
		     * between being canceled and unwound.
		     */

		    if (iPtr->asyncCancelMsg != NULL) {
			message = Tcl_GetStringFromObj(iPtr->asyncCancelMsg,
				&length);
		    } else {
			length = 0;
		    }

		    if (iPtr->flags & TCL_CANCEL_UNWIND) {
			id = "IUNWIND";
			if (length == 0) {
			    message = "eval unwound";
			}
		    } else {
			id = "ICANCEL";
			if (length == 0) {
			    message = "eval canceled";
			}
		    }

		    Tcl_ResetResult(interp);
		    Tcl_AppendResult(interp, message, NULL);
		    Tcl_SetErrorCode(interp, "TCL", id, message, NULL);
		}

		/*
		 * Return TCL_ERROR to the caller (not necessarily just the
		 * Tcl core itself) that indicates further processing of the
		 * script or command in progress should halt gracefully and as
		 * soon as possible.
		 */

		return TCL_ERROR;
	    }
    }

    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_CancelEval --
 *







|
|
<
|

|
>
>
>
|
|
|
|
|
|
|

|

|
|
|
|
|
<
|

|
>
>
|
|
|
|
|

|
|
|

|
|
|
|

|
|
<
|
|
|

|
|
|
|
|
|
|
|
|
|
|

|
|
|
|

|
|
|
|
<
|

|
<
<
<
<







3880
3881
3882
3883
3884
3885
3886
3887
3888

3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909

3910
3911
3912
3913
3914
3915
3916
3917
3918
3919
3920
3921
3922
3923
3924
3925
3926
3927
3928
3929
3930
3931

3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
3943
3944
3945
3946
3947
3948
3949
3950
3951
3952
3953
3954
3955
3956

3957
3958
3959




3960
3961
3962
3963
3964
3965
3966
Tcl_Canceled(
    Tcl_Interp *interp,
    int flags)
{
    register Interp *iPtr = (Interp *) interp;

    /*
     * Has the current script in progress for this interpreter been canceled
     * or is the stack being unwound due to the previous script cancellation?

     */

    if (!TclCanceled(iPtr)) {
        return TCL_OK;
    }

    /*
     * The CANCELED flag is a one-shot flag that is reset immediately upon
     * being detected; however, if the TCL_CANCEL_UNWIND flag is set we will
     * continue to report that the script in progress has been canceled
     * thereby allowing the evaluation stack for the interp to be fully
     * unwound.
     */

    iPtr->flags &= ~CANCELED;

    /*
     * The CANCELED flag was detected and reset; however, if the caller
     * specified the TCL_CANCEL_UNWIND flag, we only return TCL_ERROR
     * (indicating that the script in progress has been canceled) if the
     * evaluation stack for the interp is being fully unwound.

     */

    if ((flags & TCL_CANCEL_UNWIND) && !(iPtr->flags & TCL_CANCEL_UNWIND)) {
        return TCL_OK;
    }

    /*
     * If the TCL_LEAVE_ERR_MSG flags bit is set, place an error in the
     * interp's result; otherwise, we leave it alone.
     */

    if (flags & TCL_LEAVE_ERR_MSG) {
        const char *id, *message = NULL;
        int length;

        /*
         * Setup errorCode variables so that we can differentiate between
         * being canceled and unwound.
         */

        if (iPtr->asyncCancelMsg != NULL) {
            message = Tcl_GetStringFromObj(iPtr->asyncCancelMsg, &length);

        } else {
            length = 0;
        }

        if (iPtr->flags & TCL_CANCEL_UNWIND) {
            id = "IUNWIND";
            if (length == 0) {
                message = "eval unwound";
            }
        } else {
            id = "ICANCEL";
            if (length == 0) {
                message = "eval canceled";
            }
        }

        Tcl_ResetResult(interp);
        Tcl_AppendResult(interp, message, NULL);
        Tcl_SetErrorCode(interp, "TCL", "CANCEL", id, message, NULL);
    }

    /*
     * Return TCL_ERROR to the caller (not necessarily just the Tcl core
     * itself) that indicates further processing of the script or command in
     * progress should halt gracefully and as soon as possible.

     */

    return TCL_ERROR;




}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_CancelEval --
 *
4138
4139
4140
4141
4142
4143
4144
4145
4146
4147
4148
4149
4150
4151
4152
4153
4154
4155
     *
     * data[1] stores a marker for use by tailcalls; it will be set to 1 by
     * command redirectors (imports, alias, ensembles) so that tailcalls
     * finishes the source command and not just the target.
     */

    if (iPtr->evalFlags & TCL_EVAL_REDIRECT) {
	TclNRAddCallback(interp, NRCommand, NULL, INT2PTR(1), NULL, NULL);
	iPtr->evalFlags &= ~TCL_EVAL_REDIRECT;
    } else {
	TclNRAddCallback(interp, NRCommand, NULL, NULL, NULL, NULL);
    }
    cmdPtrPtr = (Command **) &(TOP_CB(interp)->data[0]);

    TclNRSpliceDeferred(interp);

    iPtr->numLevels++;
    result = TclInterpReady(interp);







|


|







4136
4137
4138
4139
4140
4141
4142
4143
4144
4145
4146
4147
4148
4149
4150
4151
4152
4153
     *
     * data[1] stores a marker for use by tailcalls; it will be set to 1 by
     * command redirectors (imports, alias, ensembles) so that tailcalls
     * finishes the source command and not just the target.
     */

    if (iPtr->evalFlags & TCL_EVAL_REDIRECT) {
	TclNRAddCallback(interp, NRCommand, NULL, INT2PTR(1), INT2PTR(objc), objv);
	iPtr->evalFlags &= ~TCL_EVAL_REDIRECT;
    } else {
	TclNRAddCallback(interp, NRCommand, NULL, NULL, INT2PTR(objc), objv);
    }
    cmdPtrPtr = (Command **) &(TOP_CB(interp)->data[0]);

    TclNRSpliceDeferred(interp);

    iPtr->numLevels++;
    result = TclInterpReady(interp);
4263
4264
4265
4266
4267
4268
4269
4270
4271
4272
4273
4274
4275
4276
4277
4278
4279
4280
4281
4282
4283
4284
4285
4286
4287
4288
4289
4290
4291
4292
4293
4294
4295
4296
4297
    cmdPtr->refCount++;

    /*
     * Find the objProc to call: nreProc if available, objProc otherwise. Push
     * a callback to do the actual running.
     */

#if 0
    {
        Tcl_ObjCmdProc *objProc = cmdPtr->nreProc;
        
        if (!objProc) {
            objProc = cmdPtr->objProc;
        }
        
        TclNRAddCallback(interp, NRRunObjProc, objProc, cmdPtr->objClientData,
                INT2PTR(objc), (ClientData) objv);
    }
    return TCL_OK;
#else
    if (cmdPtr->nreProc) {
        TclNRAddCallback(interp, NRRunObjProc, cmdPtr->nreProc,
                cmdPtr->objClientData, INT2PTR(objc), (ClientData) objv);
        return TCL_OK;
    } else {
	return cmdPtr->objProc(cmdPtr->objClientData, interp, objc, objv);
    }        
#endif
}

void
TclPushTailcallPoint(
    Tcl_Interp *interp)
{
    TclNRAddCallback(interp, NRCommand, NULL, NULL, NULL, NULL);







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

|
|




<







4261
4262
4263
4264
4265
4266
4267













4268
4269
4270
4271
4272
4273
4274

4275
4276
4277
4278
4279
4280
4281
    cmdPtr->refCount++;

    /*
     * Find the objProc to call: nreProc if available, objProc otherwise. Push
     * a callback to do the actual running.
     */














    if (cmdPtr->nreProc) {
        TclNRAddCallback(interp, NRRunObjProc, cmdPtr,
                INT2PTR(objc), (ClientData) objv, NULL);
        return TCL_OK;
    } else {
	return cmdPtr->objProc(cmdPtr->objClientData, interp, objc, objv);
    }        

}

void
TclPushTailcallPoint(
    Tcl_Interp *interp)
{
    TclNRAddCallback(interp, NRCommand, NULL, NULL, NULL, NULL);
4371
4372
4373
4374
4375
4376
4377
4378
4379
4380
4381
4382
4383
4384
4385
4386
4387
4388
4389
4390
4391
4392
4393
NRRunObjProc(
    ClientData data[],
    Tcl_Interp *interp,
    int result)
{
    /* OPT: do not call? */

    Tcl_ObjCmdProc *objProc = (Tcl_ObjCmdProc *)data[0];
    ClientData objClientData = data[1];
    int objc = PTR2INT(data[2]);
    Tcl_Obj **objv = data[3];

    if (result == TCL_OK) {
	return objProc(objClientData, interp, objc, objv);
    }
    return result;
}


/*
 *----------------------------------------------------------------------
 *
 * TEOV_Exception	 -







<
|
|
|

<
|
<
<







4355
4356
4357
4358
4359
4360
4361

4362
4363
4364
4365

4366


4367
4368
4369
4370
4371
4372
4373
NRRunObjProc(
    ClientData data[],
    Tcl_Interp *interp,
    int result)
{
    /* OPT: do not call? */


    Command* cmdPtr = data[0];
    int objc = PTR2INT(data[1]);
    Tcl_Obj **objv = data[2];


    return cmdPtr->nreProc(cmdPtr->objClientData, interp, objc, objv);


}


/*
 *----------------------------------------------------------------------
 *
 * TEOV_Exception	 -
5605
5606
5607
5608
5609
5610
5611




5612
5613
5614
5615
5616
5617
5618
	 * (1) ePtr->nline == objc
	 * (2) (ePtr->line[word] < 0) => !literal, for all words
	 * (3) (word == 0) => !literal
	 *
	 * Item (2) is why we can use objv to get the literals, and do not
	 * have to save them at compile time.
	 */





	for (word = 1; word < objc; word++) {
	    if (ePtr->line[word] >= 0) {
		int isnew;
		Tcl_HashEntry *hPtr = Tcl_CreateHashEntry(iPtr->lineLABCPtr,
			objv[word], &isnew);
		CFWordBC *cfwPtr = ckalloc(sizeof(CFWordBC));







>
>
>
>







5585
5586
5587
5588
5589
5590
5591
5592
5593
5594
5595
5596
5597
5598
5599
5600
5601
5602
	 * (1) ePtr->nline == objc
	 * (2) (ePtr->line[word] < 0) => !literal, for all words
	 * (3) (word == 0) => !literal
	 *
	 * Item (2) is why we can use objv to get the literals, and do not
	 * have to save them at compile time.
	 */

        if (ePtr->nline != objc) {
            Tcl_Panic ("TIP 280 data structure inconsistency");
        }

	for (word = 1; word < objc; word++) {
	    if (ePtr->line[word] >= 0) {
		int isnew;
		Tcl_HashEntry *hPtr = Tcl_CreateHashEntry(iPtr->lineLABCPtr,
			objv[word], &isnew);
		CFWordBC *cfwPtr = ckalloc(sizeof(CFWordBC));
5733
5734
5735
5736
5737
5738
5739
5740
5741
5742
5743
5744
5745
5746
5747
5748
    /*
     * An object which either has no string rep or else is a canonical list is
     * guaranteed to have been generated dynamically: bail out, this cannot
     * have a usable absolute location. _Do not touch_ the information the set
     * up by the caller. It knows better than us.
     */

    if ((!obj->bytes) || ((obj->typePtr == &tclListType) &&
	    ((List *) obj->internalRep.twoPtrValue.ptr1)->canonicalFlag)) {
	return;
    }

    /*
     * First look for location information recorded in the argument
     * stack. That is nearest.
     */







|
<







5717
5718
5719
5720
5721
5722
5723
5724

5725
5726
5727
5728
5729
5730
5731
    /*
     * An object which either has no string rep or else is a canonical list is
     * guaranteed to have been generated dynamically: bail out, this cannot
     * have a usable absolute location. _Do not touch_ the information the set
     * up by the caller. It knows better than us.
     */

    if ((obj->bytes == NULL) || TclListObjIsCanonical(obj)) {

	return;
    }

    /*
     * First look for location information recorded in the argument
     * stack. That is nearest.
     */
5913
5914
5915
5916
5917
5918
5919
5920
5921
5922
5923
5924
5925
5926
5927
5928
5929
5930
5931
5932
5933
5934
5935
5936
5937
				 * evaluation of the script. Supported values
				 * are TCL_EVAL_GLOBAL and TCL_EVAL_DIRECT. */
    const CmdFrame *invoker,	/* Frame of the command doing the eval. */
    int word)			/* Index of the word which is in objPtr. */
{
    Interp *iPtr = (Interp *) interp;
    int result;
    List *listRepPtr = objPtr->internalRep.twoPtrValue.ptr1;

    /*
     * This function consists of three independent blocks for: direct
     * evaluation of canonical lists, compileation and bytecode execution and
     * finally direct evaluation. Precisely one of these blocks will be run.
     */

    if ((objPtr->typePtr == &tclListType) &&		/* is a list */
	    ((objPtr->bytes == NULL ||			/* no string rep */
		    listRepPtr->canonicalFlag))) {	/* or is canonical */
	Tcl_Obj *listPtr = objPtr;
	CmdFrame *eoFramePtr = NULL;
	int objc;
	Tcl_Obj **objv;

	/*
	 * Pure List Optimization (no string representation). In this case, we







<







<
<
|







5896
5897
5898
5899
5900
5901
5902

5903
5904
5905
5906
5907
5908
5909


5910
5911
5912
5913
5914
5915
5916
5917
				 * evaluation of the script. Supported values
				 * are TCL_EVAL_GLOBAL and TCL_EVAL_DIRECT. */
    const CmdFrame *invoker,	/* Frame of the command doing the eval. */
    int word)			/* Index of the word which is in objPtr. */
{
    Interp *iPtr = (Interp *) interp;
    int result;


    /*
     * This function consists of three independent blocks for: direct
     * evaluation of canonical lists, compileation and bytecode execution and
     * finally direct evaluation. Precisely one of these blocks will be run.
     */



    if (TclListObjIsCanonical(objPtr)) {
	Tcl_Obj *listPtr = objPtr;
	CmdFrame *eoFramePtr = NULL;
	int objc;
	Tcl_Obj **objv;

	/*
	 * Pure List Optimization (no string representation). In this case, we
8864
8865
8866
8867
8868
8869
8870

8871
8872
8873
8874
8875
8876
8877
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    Command *cmdPtr;
    CoroutineData *corPtr;
    const char *fullName, *procName;
    Namespace *nsPtr, *altNsPtr, *cxtNsPtr;
    Tcl_DString ds;

    
    if (objc < 3) {
	Tcl_WrongNumArgs(interp, 1, objv, "name cmd ?arg ...?");
	return TCL_ERROR;
    }

    /*







>







8844
8845
8846
8847
8848
8849
8850
8851
8852
8853
8854
8855
8856
8857
8858
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    Command *cmdPtr;
    CoroutineData *corPtr;
    const char *fullName, *procName;
    Namespace *nsPtr, *altNsPtr, *cxtNsPtr;
    Tcl_DString ds;
    Namespace *lookupNsPtr = iPtr->varFramePtr->nsPtr;
    
    if (objc < 3) {
	Tcl_WrongNumArgs(interp, 1, objv, "name cmd ?arg ...?");
	return TCL_ERROR;
    }

    /*
8950
8951
8952
8953
8954
8955
8956
8957
8958
8959
8960
8961
8962
8963
8964
8965
8966
8967
8968
8969
8970
8971
8972
8973
8974
8975
8976



8977
8978
8979
8980
8981
8982
8983



8984
8985
8986
8987
8988
8989
8990
		    &isNew);

	    Tcl_SetHashValue(newPtr, Tcl_GetHashValue(hePtr));
	}
    }

    /*
     * Save the base context.
     */

    corPtr->running.framePtr = iPtr->rootFramePtr;
    corPtr->running.varFramePtr = iPtr->rootFramePtr;
    corPtr->running.cmdFramePtr = NULL;
    corPtr->running.lineLABCPtr = corPtr->lineLABCPtr;
    corPtr->stackLevel = NULL;
    corPtr->auxNumLevels = 0;
    iPtr->numLevels--;
    
    /*
     * Create the coro's execEnv, switch to it to push the exit and coro
     * command callbacks, then switch back. 
     */

    corPtr->eePtr = TclCreateExecEnv(interp, CORO_STACK_INITIAL_SIZE);
    corPtr->callerEEPtr = iPtr->execEnvPtr;
    corPtr->eePtr->corPtr = corPtr;
    



    iPtr->execEnvPtr = corPtr->eePtr;

    TclNRAddCallback(interp, NRCoroutineExitCallback, corPtr,
	    NULL, NULL, NULL);

    iPtr->lookupNsPtr = iPtr->varFramePtr->nsPtr;
    Tcl_NREvalObj(interp, Tcl_NewListObj(objc-2, objv+2), 0);



    iPtr->execEnvPtr = corPtr->callerEEPtr;
    
    /*
     * Now just resume the coroutine. Take care to insure that the command is
     * looked up in the correct namespace.
     */








|



















>
>
>





|

>
>
>







8931
8932
8933
8934
8935
8936
8937
8938
8939
8940
8941
8942
8943
8944
8945
8946
8947
8948
8949
8950
8951
8952
8953
8954
8955
8956
8957
8958
8959
8960
8961
8962
8963
8964
8965
8966
8967
8968
8969
8970
8971
8972
8973
8974
8975
8976
8977
		    &isNew);

	    Tcl_SetHashValue(newPtr, Tcl_GetHashValue(hePtr));
	}
    }

    /*
     * Create the base context.
     */

    corPtr->running.framePtr = iPtr->rootFramePtr;
    corPtr->running.varFramePtr = iPtr->rootFramePtr;
    corPtr->running.cmdFramePtr = NULL;
    corPtr->running.lineLABCPtr = corPtr->lineLABCPtr;
    corPtr->stackLevel = NULL;
    corPtr->auxNumLevels = 0;
    iPtr->numLevels--;
    
    /*
     * Create the coro's execEnv, switch to it to push the exit and coro
     * command callbacks, then switch back. 
     */

    corPtr->eePtr = TclCreateExecEnv(interp, CORO_STACK_INITIAL_SIZE);
    corPtr->callerEEPtr = iPtr->execEnvPtr;
    corPtr->eePtr->corPtr = corPtr;
    
    SAVE_CONTEXT(corPtr->caller);
    corPtr->callerEEPtr = iPtr->execEnvPtr;
    RESTORE_CONTEXT(corPtr->running);
    iPtr->execEnvPtr = corPtr->eePtr;

    TclNRAddCallback(interp, NRCoroutineExitCallback, corPtr,
	    NULL, NULL, NULL);

    iPtr->lookupNsPtr = lookupNsPtr;
    Tcl_NREvalObj(interp, Tcl_NewListObj(objc-2, objv+2), 0);

    SAVE_CONTEXT(corPtr->running);
    RESTORE_CONTEXT(corPtr->caller);
    iPtr->execEnvPtr = corPtr->callerEEPtr;
    
    /*
     * Now just resume the coroutine. Take care to insure that the command is
     * looked up in the correct namespace.
     */

Changes to generic/tclCkalloc.c.

181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
	    "current packets allocated %10d\n"
	    "current bytes allocated   %10lu\n"
	    "maximum packets allocated %10d\n"
	    "maximum bytes allocated   %10lu\n",
	    total_mallocs,
	    total_frees,
	    current_malloc_packets,
	    current_bytes_malloced,
	    maximum_malloc_packets,
	    maximum_bytes_malloced);
    if (flags == 0) {
	fprintf((FILE *)clientData, "%s", buf);
    } else {
	/* Assume objPtr to append to */
	Tcl_AppendToObj((Tcl_Obj *) clientData, buf, -1);
    }
    return 1;







|

|







181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
	    "current packets allocated %10d\n"
	    "current bytes allocated   %10lu\n"
	    "maximum packets allocated %10d\n"
	    "maximum bytes allocated   %10lu\n",
	    total_mallocs,
	    total_frees,
	    current_malloc_packets,
	    (unsigned long)current_bytes_malloced,
	    maximum_malloc_packets,
	    (unsigned long)maximum_bytes_malloced);
    if (flags == 0) {
	fprintf((FILE *)clientData, "%s", buf);
    } else {
	/* Assume objPtr to append to */
	Tcl_AppendToObj((Tcl_Obj *) clientData, buf, -1);
    }
    return 1;
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
	return TCL_OK;
    }
    if (strcmp(argv[1],"info") == 0) {
	Tcl_SetObjResult(interp, Tcl_ObjPrintf(
		"%-25s %10d\n%-25s %10d\n%-25s %10d\n%-25s %10lu\n%-25s %10d\n%-25s %10lu\n",
		"total mallocs", total_mallocs, "total frees", total_frees,
		"current packets allocated", current_malloc_packets,
		"current bytes allocated", current_bytes_malloced,
		"maximum packets allocated", maximum_malloc_packets,
		"maximum bytes allocated", maximum_bytes_malloced));
	return TCL_OK;
    }
    if (strcmp(argv[1],"init") == 0) {
	if (argc != 3) {
	    goto bad_suboption;
	}
	init_malloced_bodies = (strcmp(argv[2],"on") == 0);







|

|







848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
	return TCL_OK;
    }
    if (strcmp(argv[1],"info") == 0) {
	Tcl_SetObjResult(interp, Tcl_ObjPrintf(
		"%-25s %10d\n%-25s %10d\n%-25s %10d\n%-25s %10lu\n%-25s %10d\n%-25s %10lu\n",
		"total mallocs", total_mallocs, "total frees", total_frees,
		"current packets allocated", current_malloc_packets,
		"current bytes allocated", (unsigned long)current_bytes_malloced,
		"maximum packets allocated", maximum_malloc_packets,
		"maximum bytes allocated", (unsigned long)maximum_bytes_malloced));
	return TCL_OK;
    }
    if (strcmp(argv[1],"init") == 0) {
	if (argc != 3) {
	    goto bad_suboption;
	}
	init_malloced_bodies = (strcmp(argv[2],"on") == 0);

Changes to generic/tclCmdAH.c.

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
	Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf(
		"\n    (\"catch\" body line %d)", Tcl_GetErrorLine(interp)));
	return TCL_ERROR;
    }

    if (objc >= 3) {
	if (NULL == Tcl_ObjSetVar2(interp, varNamePtr, NULL,
		Tcl_GetObjResult(interp), 0)) {
	    Tcl_ResetResult(interp);
	    Tcl_AppendResult(interp,
		    "couldn't save command result in variable", NULL);
	    return TCL_ERROR;
	}
    }
    if (objc == 4) {
	Tcl_Obj *options = Tcl_GetReturnOptions(interp, result);

	if (NULL == Tcl_ObjSetVar2(interp, optionVarNamePtr, NULL,
		options, 0)) {
	    Tcl_DecrRefCount(options);
	    Tcl_ResetResult(interp);
	    Tcl_AppendResult(interp,
		    "couldn't save return options in variable", NULL);
	    return TCL_ERROR;
	}
    }

    Tcl_ResetResult(interp);
    Tcl_SetObjResult(interp, Tcl_NewIntObj(result));
    return TCL_OK;







|
<
<
<







|

<
<
<







341
342
343
344
345
346
347
348



349
350
351
352
353
354
355
356
357



358
359
360
361
362
363
364
	Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf(
		"\n    (\"catch\" body line %d)", Tcl_GetErrorLine(interp)));
	return TCL_ERROR;
    }

    if (objc >= 3) {
	if (NULL == Tcl_ObjSetVar2(interp, varNamePtr, NULL,
		Tcl_GetObjResult(interp), TCL_LEAVE_ERR_MSG)) {



	    return TCL_ERROR;
	}
    }
    if (objc == 4) {
	Tcl_Obj *options = Tcl_GetReturnOptions(interp, result);

	if (NULL == Tcl_ObjSetVar2(interp, optionVarNamePtr, NULL,
		options, TCL_LEAVE_ERR_MSG)) {
	    Tcl_DecrRefCount(options);



	    return TCL_ERROR;
	}
    }

    Tcl_ResetResult(interp);
    Tcl_SetObjResult(interp, Tcl_NewIntObj(result));
    return TCL_OK;
643
644
645
646
647
648
649


650
651
652
653
654
655
656
    if (objc == 1) {
	Tcl_SetObjResult(interp, Tcl_GetEncodingSearchPath());
	return TCL_OK;
    }
    if (Tcl_SetEncodingSearchPath(objv[1]) == TCL_ERROR) {
	Tcl_AppendResult(interp, "expected directory list but got \"",
		TclGetString(objv[1]), "\"", NULL);


	return TCL_ERROR;
    }
    Tcl_SetObjResult(interp, objv[1]);
    return TCL_OK;
}

/*







>
>







637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
    if (objc == 1) {
	Tcl_SetObjResult(interp, Tcl_GetEncodingSearchPath());
	return TCL_OK;
    }
    if (Tcl_SetEncodingSearchPath(objv[1]) == TCL_ERROR) {
	Tcl_AppendResult(interp, "expected directory list but got \"",
		TclGetString(objv[1]), "\"", NULL);
	Tcl_SetErrorCode(interp, "TCL", "OPERATION", "ENCODING", "BADPATH",
		NULL);
	return TCL_ERROR;
    }
    Tcl_SetObjResult(interp, objv[1]);
    return TCL_OK;
}

/*
732
733
734
735
736
737
738










739
740
741
742
743
744
745
		"\n    (\"eval\" body line %d)", Tcl_GetErrorLine(interp)));
    }
    return result;
}

int
Tcl_EvalObjCmd(










    ClientData dummy,		/* Not used. */
    Tcl_Interp *interp,		/* Current interpreter. */
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    register Tcl_Obj *objPtr;
    Interp *iPtr = (Interp *) interp;







>
>
>
>
>
>
>
>
>
>







728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
		"\n    (\"eval\" body line %d)", Tcl_GetErrorLine(interp)));
    }
    return result;
}

int
Tcl_EvalObjCmd(
    ClientData dummy,		/* Not used. */
    Tcl_Interp *interp,		/* Current interpreter. */
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    return Tcl_NRCallObjProc(interp, TclNREvalObjCmd, dummy, objc, objv);    
}

int
TclNREvalObjCmd(
    ClientData dummy,		/* Not used. */
    Tcl_Interp *interp,		/* Current interpreter. */
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    register Tcl_Obj *objPtr;
    Interp *iPtr = (Interp *) interp;
1053
1054
1055
1056
1057
1058
1059











1060
1061
1062
1063
1064
1065
1066
			unsafeInfo[i].cmdName,
			Tcl_GetString(Tcl_GetObjResult(interp)));
	    }
	}
    }
    Tcl_DStringFree(&oldBuf);
    Tcl_DStringFree(&newBuf);











    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * FileAttrAccessTimeCmd --







>
>
>
>
>
>
>
>
>
>
>







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
			unsafeInfo[i].cmdName,
			Tcl_GetString(Tcl_GetObjResult(interp)));
	    }
	}
    }
    Tcl_DStringFree(&oldBuf);
    Tcl_DStringFree(&newBuf);

    /*
     * Ugh. The [file] command is now actually safe, but it is assumed by
     * scripts that it is not, which messes up security policies. [Bug
     * 3211758]
     */

    if (Tcl_HideCommand(interp, "file", "file") != TCL_OK) {
	Tcl_Panic("problem making 'file' safe: %s",
		Tcl_GetString(Tcl_GetObjResult(interp)));
    }
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * FileAttrAccessTimeCmd --
1784
1785
1786
1787
1788
1789
1790


1791
1792
1793
1794
1795
1796
1797
    if (objc != 2) {
	Tcl_WrongNumArgs(interp, 1, objv, "name");
	return TCL_ERROR;
    }
    fsInfo = Tcl_FSFileSystemInfo(objv[1]);
    if (fsInfo == NULL) {
	Tcl_SetResult(interp, "unrecognised path", TCL_STATIC);


	return TCL_ERROR;
    }
    Tcl_SetObjResult(interp, fsInfo);
    return TCL_OK;
}

/*







>
>







1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
    if (objc != 2) {
	Tcl_WrongNumArgs(interp, 1, objv, "name");
	return TCL_ERROR;
    }
    fsInfo = Tcl_FSFileSystemInfo(objv[1]);
    if (fsInfo == NULL) {
	Tcl_SetResult(interp, "unrecognised path", TCL_STATIC);
	Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "FILESYSTEM",
		Tcl_GetString(objv[1]), NULL);
	return TCL_ERROR;
    }
    Tcl_SetObjResult(interp, fsInfo);
    return TCL_OK;
}

/*
1935
1936
1937
1938
1939
1940
1941


1942
1943
1944
1945
1946
1947
1948
	Tcl_WrongNumArgs(interp, 1, objv, "name");
	return TCL_ERROR;
    }
    res = Tcl_FSSplitPath(objv[1], NULL);
    if (res == NULL) {
	Tcl_AppendResult(interp, "could not read \"", TclGetString(objv[1]),
		"\": no such file or directory", NULL);


	return TCL_ERROR;
    }
    Tcl_SetObjResult(interp, res);
    return TCL_OK;
}

/*







>
>







1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
	Tcl_WrongNumArgs(interp, 1, objv, "name");
	return TCL_ERROR;
    }
    res = Tcl_FSSplitPath(objv[1], NULL);
    if (res == NULL) {
	Tcl_AppendResult(interp, "could not read \"", TclGetString(objv[1]),
		"\": no such file or directory", NULL);
	Tcl_SetErrorCode(interp, "TCL", "OPERATION", "PATHSPLIT", "NONESUCH",
		NULL);
	return TCL_ERROR;
    }
    Tcl_SetObjResult(interp, res);
    return TCL_OK;
}

/*
2034
2035
2036
2037
2038
2039
2040


2041
2042
2043
2044
2045
2046
2047
	}
	Tcl_SetObjResult(interp, Tcl_NewStringObj(separator, 1));
    } else {
	Tcl_Obj *separatorObj = Tcl_FSPathSeparator(objv[1]);

	if (separatorObj == NULL) {
	    Tcl_SetResult(interp, "unrecognised path", TCL_STATIC);


	    return TCL_ERROR;
	}
	Tcl_SetObjResult(interp, separatorObj);
    }
    return TCL_OK;
}








>
>







2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
	}
	Tcl_SetObjResult(interp, Tcl_NewStringObj(separator, 1));
    } else {
	Tcl_Obj *separatorObj = Tcl_FSPathSeparator(objv[1]);

	if (separatorObj == NULL) {
	    Tcl_SetResult(interp, "unrecognised path", TCL_STATIC);
	    Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "FILESYSTEM",
		    Tcl_GetString(objv[1]), NULL);
	    return TCL_ERROR;
	}
	Tcl_SetObjResult(interp, separatorObj);
    }
    return TCL_OK;
}

2588
2589
2590
2591
2592
2593
2594


2595
2596
2597
2598
2599
2600
2601
	    result = TCL_ERROR;
	    goto done;
	}
	TclListObjGetElements(NULL, statePtr->vCopyList[i],
		&statePtr->varcList[i], &statePtr->varvList[i]);
	if (statePtr->varcList[i] < 1) {
	    Tcl_AppendResult(interp, "foreach varlist is empty", NULL);


	    result = TCL_ERROR;
	    goto done;
	}

	statePtr->aCopyList[i] = TclListObjCopy(interp, objv[2+i*2]);
	if (statePtr->aCopyList[i] == NULL) {
	    result = TCL_ERROR;







>
>







2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
	    result = TCL_ERROR;
	    goto done;
	}
	TclListObjGetElements(NULL, statePtr->vCopyList[i],
		&statePtr->varcList[i], &statePtr->varvList[i]);
	if (statePtr->varcList[i] < 1) {
	    Tcl_AppendResult(interp, "foreach varlist is empty", NULL);
	    Tcl_SetErrorCode(interp, "TCL", "OPERATION", "FOREACH",
		    "NEEDVARS", NULL);
	    result = TCL_ERROR;
	    goto done;
	}

	statePtr->aCopyList[i] = TclListObjCopy(interp, objv[2+i*2]);
	if (statePtr->aCopyList[i] == NULL) {
	    result = TCL_ERROR;

Changes to generic/tclCmdIL.c.

962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
InfoDefaultCmd(
    ClientData dummy,		/* Not used. */
    Tcl_Interp *interp,		/* Current interpreter. */
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    Interp *iPtr = (Interp *) interp;
    const char *procName, *argName, *varName;
    Proc *procPtr;
    CompiledLocal *localPtr;
    Tcl_Obj *valueObjPtr;

    if (objc != 4) {
	Tcl_WrongNumArgs(interp, 1, objv, "procname arg varname");
	return TCL_ERROR;







|







962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
InfoDefaultCmd(
    ClientData dummy,		/* Not used. */
    Tcl_Interp *interp,		/* Current interpreter. */
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    Interp *iPtr = (Interp *) interp;
    const char *procName, *argName;
    Proc *procPtr;
    CompiledLocal *localPtr;
    Tcl_Obj *valueObjPtr;

    if (objc != 4) {
	Tcl_WrongNumArgs(interp, 1, objv, "procname arg varname");
	return TCL_ERROR;
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

    for (localPtr = procPtr->firstLocalPtr;  localPtr != NULL;
	    localPtr = localPtr->nextPtr) {
	if (TclIsVarArgument(localPtr)
		&& (strcmp(argName, localPtr->name) == 0)) {
	    if (localPtr->defValuePtr != NULL) {
		valueObjPtr = Tcl_ObjSetVar2(interp, objv[3], NULL,
			localPtr->defValuePtr, 0);
		if (valueObjPtr == NULL) {
		    goto defStoreError;
		}
		Tcl_SetObjResult(interp, Tcl_NewIntObj(1));
	    } else {
		Tcl_Obj *nullObjPtr = Tcl_NewObj();

		valueObjPtr = Tcl_ObjSetVar2(interp, objv[3], NULL,
			nullObjPtr, 0);
		if (valueObjPtr == NULL) {
		    goto defStoreError;
		}
		Tcl_SetObjResult(interp, Tcl_NewIntObj(0));
	    }
	    return TCL_OK;
	}
    }

    Tcl_AppendResult(interp, "procedure \"", procName,
	    "\" doesn't have an argument \"", argName, "\"", NULL);
    Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "ARGUMENT", argName, NULL);
    return TCL_ERROR;

  defStoreError:
    varName = TclGetString(objv[3]);
    Tcl_AppendResult(interp, "couldn't store default value in variable \"",
	    varName, "\"", NULL);
    return TCL_ERROR;
}

/*
 *----------------------------------------------------------------------
 *
 * InfoErrorStackCmd --
 *







|

|






|

|











<
<
<
<
<
<







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

    for (localPtr = procPtr->firstLocalPtr;  localPtr != NULL;
	    localPtr = localPtr->nextPtr) {
	if (TclIsVarArgument(localPtr)
		&& (strcmp(argName, localPtr->name) == 0)) {
	    if (localPtr->defValuePtr != NULL) {
		valueObjPtr = Tcl_ObjSetVar2(interp, objv[3], NULL,
			localPtr->defValuePtr, TCL_LEAVE_ERR_MSG);
		if (valueObjPtr == NULL) {
		    return TCL_ERROR;
		}
		Tcl_SetObjResult(interp, Tcl_NewIntObj(1));
	    } else {
		Tcl_Obj *nullObjPtr = Tcl_NewObj();

		valueObjPtr = Tcl_ObjSetVar2(interp, objv[3], NULL,
			nullObjPtr, TCL_LEAVE_ERR_MSG);
		if (valueObjPtr == NULL) {
		    return TCL_ERROR;
		}
		Tcl_SetObjResult(interp, Tcl_NewIntObj(0));
	    }
	    return TCL_OK;
	}
    }

    Tcl_AppendResult(interp, "procedure \"", procName,
	    "\" doesn't have an argument \"", argName, "\"", NULL);
    Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "ARGUMENT", argName, NULL);
    return TCL_ERROR;






}

/*
 *----------------------------------------------------------------------
 *
 * InfoErrorStackCmd --
 *
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
    Tcl_Interp *target;
    Interp *iPtr;

    if ((objc != 1) && (objc != 2)) {
	Tcl_WrongNumArgs(interp, 1, objv, "?interp?");
	return TCL_ERROR;
    }
    
    target = interp;
    if (objc == 2) {
        target = Tcl_GetSlave(interp, Tcl_GetString(objv[1]));
        if (target == NULL) {
            return TCL_ERROR;
        }
    }

    iPtr = (Interp *) target;
    Tcl_SetObjResult(interp, iPtr->errorStack);
    
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * TclInfoExistsCmd --







|










|







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
    Tcl_Interp *target;
    Interp *iPtr;

    if ((objc != 1) && (objc != 2)) {
	Tcl_WrongNumArgs(interp, 1, objv, "?interp?");
	return TCL_ERROR;
    }

    target = interp;
    if (objc == 2) {
        target = Tcl_GetSlave(interp, Tcl_GetString(objv[1]));
        if (target == NULL) {
            return TCL_ERROR;
        }
    }

    iPtr = (Interp *) target;
    Tcl_SetObjResult(interp, iPtr->errorStack);

    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * TclInfoExistsCmd --
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
InfoFrameCmd(
    ClientData dummy,		/* Not used. */
    Tcl_Interp *interp,		/* Current interpreter. */
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    Interp *iPtr = (Interp *) interp;
    int level, topLevel;
    CmdFrame *framePtr;







    topLevel = ((iPtr->cmdFramePtr == NULL)
	    ? 0
	    : iPtr->cmdFramePtr->level);


    if (iPtr->execEnvPtr->corPtr) {
	/*
	 * A coroutine: must fix the level computations AND the cmdFrame chain,
	 * which is interrupted at the base.
	 */


        CoroutineData *corPtr = iPtr->execEnvPtr->corPtr;
        CmdFrame *runPtr = iPtr->cmdFramePtr;
        CmdFrame *lastPtr = NULL;
        

        topLevel += corPtr->caller.cmdFramePtr->level;

        while (runPtr && (runPtr != corPtr->caller.cmdFramePtr)) {
            lastPtr = runPtr;
            runPtr = runPtr->nextPtr;
        }
        if (lastPtr && !runPtr) {
            lastPtr->nextPtr = corPtr->caller.cmdFramePtr;


        }
    }

    if (objc == 1) {
	/*
	 * Just "info frame".
	 */

	Tcl_SetObjResult(interp, Tcl_NewIntObj(topLevel));
	return TCL_OK;
    } else if (objc != 2) {
	Tcl_WrongNumArgs(interp, 1, objv, "?number?");
	return TCL_ERROR;
    }

    /*
     * We've got "info frame level" and must parse the level first.
     */

    if (TclGetIntFromObj(interp, objv[1], &level) != TCL_OK) {
	return TCL_ERROR;

    }

    if ((level > topLevel) || (level <= - topLevel)) {
    levelError:
	Tcl_AppendResult(interp, "bad level \"", TclGetString(objv[1]), "\"",
		NULL);
	Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "STACK_FRAME",
		TclGetString(objv[1]), NULL);
	return TCL_ERROR;

    }

    /*
     * Let us convert to relative so that we know how many levels to go back
     */

    if (level > 0) {
	level -= topLevel;
    }

    framePtr = iPtr->cmdFramePtr;
    while (++level <= 0) {
	framePtr = framePtr->nextPtr;
	if (!framePtr) {
	    goto levelError;
	}
    }

    Tcl_SetObjResult(interp, TclInfoFrame(interp, framePtr));

















    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * TclInfoFrame --
 *







|
|
>
>
>
>
>
>





<
|




>

<
|
<
|
>

>
|
|
|
|
|
|
>
>
|








|
<
<
<







|
>








|
>



















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







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
InfoFrameCmd(
    ClientData dummy,		/* Not used. */
    Tcl_Interp *interp,		/* Current interpreter. */
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    Interp *iPtr = (Interp *) interp;
    int level, topLevel, code = TCL_OK;
    CmdFrame *runPtr, *framePtr;
    CoroutineData *corPtr = iPtr->execEnvPtr->corPtr;

    if (objc > 2) {
	Tcl_WrongNumArgs(interp, 1, objv, "?number?");
	return TCL_ERROR;
    }

    topLevel = ((iPtr->cmdFramePtr == NULL)
	    ? 0
	    : iPtr->cmdFramePtr->level);


    if (corPtr) {
	/*
	 * A coroutine: must fix the level computations AND the cmdFrame chain,
	 * which is interrupted at the base.
	 */
	CmdFrame *lastPtr = NULL;


        runPtr = iPtr->cmdFramePtr;


	/* TODO - deal with overflow */
        topLevel += corPtr->caller.cmdFramePtr->level;
	while (runPtr) {
	    runPtr->level += corPtr->caller.cmdFramePtr->level;
	    lastPtr = runPtr;
	    runPtr = runPtr->nextPtr;
	}
	if (lastPtr) {
	    lastPtr->nextPtr = corPtr->caller.cmdFramePtr;
	} else {
	    iPtr->cmdFramePtr = corPtr->caller.cmdFramePtr;
	}
    }

    if (objc == 1) {
	/*
	 * Just "info frame".
	 */

	Tcl_SetObjResult(interp, Tcl_NewIntObj(topLevel));
	goto done;



    }

    /*
     * We've got "info frame level" and must parse the level first.
     */

    if (TclGetIntFromObj(interp, objv[1], &level) != TCL_OK) {
	code = TCL_ERROR;
	goto done;
    }

    if ((level > topLevel) || (level <= - topLevel)) {
    levelError:
	Tcl_AppendResult(interp, "bad level \"", TclGetString(objv[1]), "\"",
		NULL);
	Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "STACK_FRAME",
		TclGetString(objv[1]), NULL);
	code = TCL_ERROR;
	goto done;
    }

    /*
     * Let us convert to relative so that we know how many levels to go back
     */

    if (level > 0) {
	level -= topLevel;
    }

    framePtr = iPtr->cmdFramePtr;
    while (++level <= 0) {
	framePtr = framePtr->nextPtr;
	if (!framePtr) {
	    goto levelError;
	}
    }

    Tcl_SetObjResult(interp, TclInfoFrame(interp, framePtr));

  done:
    if (corPtr) {

	if (iPtr->cmdFramePtr == corPtr->caller.cmdFramePtr) {
	    iPtr->cmdFramePtr = NULL;
	} else {
	    runPtr = iPtr->cmdFramePtr;
	    while (runPtr->nextPtr != corPtr->caller.cmdFramePtr) {
	    	runPtr->level -= corPtr->caller.cmdFramePtr->level;
		runPtr = runPtr->nextPtr;
	    }
	    runPtr->level = 1;
	    runPtr->nextPtr = NULL;
	}

    }
    return code;
}

/*
 *----------------------------------------------------------------------
 *
 * TclInfoFrame --
 *
1517
1518
1519
1520
1521
1522
1523

1524
1525
1526
1527
1528
1529
1530

    name = Tcl_GetHostName();
    if (name) {
	Tcl_SetObjResult(interp, Tcl_NewStringObj(name, -1));
	return TCL_OK;
    }
    Tcl_SetResult(interp, "unable to determine name of host", TCL_STATIC);

    return TCL_ERROR;
}

/*
 *----------------------------------------------------------------------
 *
 * InfoLevelCmd --







>







1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549

    name = Tcl_GetHostName();
    if (name) {
	Tcl_SetObjResult(interp, Tcl_NewStringObj(name, -1));
	return TCL_OK;
    }
    Tcl_SetResult(interp, "unable to determine name of host", TCL_STATIC);
    Tcl_SetErrorCode(interp, "TCL", "OPERATION", "HOSTNAME", "UNKNOWN", NULL);
    return TCL_ERROR;
}

/*
 *----------------------------------------------------------------------
 *
 * InfoLevelCmd --
1634
1635
1636
1637
1638
1639
1640

1641
1642
1643
1644
1645
1646
1647

    libDirName = Tcl_GetVar(interp, "tcl_library", TCL_GLOBAL_ONLY);
    if (libDirName != NULL) {
	Tcl_SetObjResult(interp, Tcl_NewStringObj(libDirName, -1));
	return TCL_OK;
    }
    Tcl_SetResult(interp, "no library has been specified for Tcl",TCL_STATIC);

    return TCL_ERROR;
}

/*
 *----------------------------------------------------------------------
 *
 * InfoLoadedCmd --







>







1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667

    libDirName = Tcl_GetVar(interp, "tcl_library", TCL_GLOBAL_ONLY);
    if (libDirName != NULL) {
	Tcl_SetObjResult(interp, Tcl_NewStringObj(libDirName, -1));
	return TCL_OK;
    }
    Tcl_SetResult(interp, "no library has been specified for Tcl",TCL_STATIC);
    Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "VARIABLE", "tcl_library",NULL);
    return TCL_ERROR;
}

/*
 *----------------------------------------------------------------------
 *
 * InfoLoadedCmd --
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
InfoLoadedCmd(
    ClientData dummy,		/* Not used. */
    Tcl_Interp *interp,		/* Current interpreter. */
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    const char *interpName;
    int result;

    if ((objc != 1) && (objc != 2)) {
	Tcl_WrongNumArgs(interp, 1, objv, "?interp?");
	return TCL_ERROR;
    }

    if (objc == 1) {		/* Get loaded pkgs in all interpreters. */
	interpName = NULL;
    } else {			/* Get pkgs just in specified interp. */
	interpName = TclGetString(objv[1]);
    }
    result = TclGetLoadedPackages(interp, interpName);
    return result;
}

/*
 *----------------------------------------------------------------------
 *
 * InfoNameOfExecutableCmd --
 *







<











|
<







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
InfoLoadedCmd(
    ClientData dummy,		/* Not used. */
    Tcl_Interp *interp,		/* Current interpreter. */
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    const char *interpName;


    if ((objc != 1) && (objc != 2)) {
	Tcl_WrongNumArgs(interp, 1, objv, "?interp?");
	return TCL_ERROR;
    }

    if (objc == 1) {		/* Get loaded pkgs in all interpreters. */
	interpName = NULL;
    } else {			/* Get pkgs just in specified interp. */
	interpName = TclGetString(objv[1]);
    }
    return TclGetLoadedPackages(interp, interpName);

}

/*
 *----------------------------------------------------------------------
 *
 * InfoNameOfExecutableCmd --
 *
2263
2264
2265
2266
2267
2268
2269

2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281

    /*
     * Set the interpreter's object result to the last element extracted.
     */

    if (elemPtr == NULL) {
	return TCL_ERROR;

    } else {
	Tcl_SetObjResult(interp, elemPtr);
	Tcl_DecrRefCount(elemPtr);
	return TCL_OK;
    }
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_LinsertObjCmd --
 *







>
|
|
|
|
<







2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292

2293
2294
2295
2296
2297
2298
2299

    /*
     * Set the interpreter's object result to the last element extracted.
     */

    if (elemPtr == NULL) {
	return TCL_ERROR;
    }

    Tcl_SetObjResult(interp, elemPtr);
    Tcl_DecrRefCount(elemPtr);
    return TCL_OK;

}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_LinsertObjCmd --
 *
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
{
    /*
     * If there are no list elements, the result is an empty object.
     * Otherwise set the interpreter's result object to be a list object.
     */

    if (objc > 1) {
	Tcl_SetObjResult(interp, Tcl_NewListObj((objc-1), &(objv[1])));
    }
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *







|







2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
{
    /*
     * If there are no list elements, the result is an empty object.
     * Otherwise set the interpreter's result object to be a list object.
     */

    if (objc > 1) {
	Tcl_SetObjResult(interp, Tcl_NewListObj(objc-1, &objv[1]));
    }
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518

    result = TclListObjGetElements(interp, objv[1], &listLen, &elemPtrs);
    if (result != TCL_OK) {
	return result;
    }

    if (Tcl_IsShared(objv[1]) ||
	    (((List *) objv[1]->internalRep.twoPtrValue.ptr1)->refCount > 1)) {
	Tcl_SetObjResult(interp, Tcl_NewListObj(last - first + 1,
		&(elemPtrs[first])));
    } else {
	/*
	 * In-place is possible.
	 */

	if (last < (listLen - 1)) {
	    Tcl_ListObjReplace(interp, objv[1], last + 1, listLen - 1 - last,







|

|







2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536

    result = TclListObjGetElements(interp, objv[1], &listLen, &elemPtrs);
    if (result != TCL_OK) {
	return result;
    }

    if (Tcl_IsShared(objv[1]) ||
	    ((ListRepPtr(objv[1])->refCount > 1))) {
	Tcl_SetObjResult(interp, Tcl_NewListObj(last - first + 1,
		&elemPtrs[first]));
    } else {
	/*
	 * In-place is possible.
	 */

	if (last < (listLen - 1)) {
	    Tcl_ListObjReplace(interp, objv[1], last + 1, listLen - 1 - last,
2570
2571
2572
2573
2574
2575
2576

2577
2578
2579
2580
2581
2582
2583
2584
2585
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
2617
2618
    }
    if (TCL_OK != TclGetIntFromObj(interp, objv[1], &elementCount)) {
	return TCL_ERROR;
    }
    if (elementCount < 0) {
	Tcl_SetObjResult(interp, Tcl_Format(NULL,
		"bad count \"%d\": must be integer >= 0", 1, objv+1));

	return TCL_ERROR;
    }

    /*
     * Skip forward to the interesting arguments now we've finished parsing.
     */

    objc -= 2;
    objv += 2;

    /*
     * Final sanity check. Total number of elements must fit in a signed
     * integer. We also limit the number of elements to 512M-1 so allocations
     * on 32-bit machines are guaranteed to be less than 2GB! [Bug 2130992]
     */

    totalElems = objc * elementCount;
    if (totalElems != 0 && (totalElems/objc != elementCount
	    || totalElems/elementCount != objc)) {
	Tcl_AppendResult(interp, "too many elements in result list", NULL);


	return TCL_ERROR;
    }
    if (totalElems >= 0x20000000) {
	Tcl_AppendResult(interp, "too many elements in result list", NULL);
	return TCL_ERROR;
    }

    /*
     * Get an empty list object that is allocated large enough to hold each
     * init value elementCount times.
     */

    listPtr = Tcl_NewListObj(totalElems, NULL);
    if (totalElems) {
	List *listRepPtr = listPtr->internalRep.twoPtrValue.ptr1;

	listRepPtr->elemCount = elementCount*objc;
	dataArray = &listRepPtr->elements;
    }

    /*
     * Set the elements. Note that we handle the common degenerate case of a







>










<
|
<
<
<

<
<
|
|
>
>


|
<
<
<








|







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
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
    }
    if (TCL_OK != TclGetIntFromObj(interp, objv[1], &elementCount)) {
	return TCL_ERROR;
    }
    if (elementCount < 0) {
	Tcl_SetObjResult(interp, Tcl_Format(NULL,
		"bad count \"%d\": must be integer >= 0", 1, objv+1));
        Tcl_SetErrorCode(interp, "TCL","OPERATION","LREPEAT","NEGARG", NULL);
	return TCL_ERROR;
    }

    /*
     * Skip forward to the interesting arguments now we've finished parsing.
     */

    objc -= 2;
    objv += 2;


    /* Final sanity check. Do not exceed limits on max list length. */






    if (elementCount && objc > LIST_MAX/elementCount) {
	Tcl_SetObjResult(interp, Tcl_ObjPrintf(
		"max length of a Tcl list (%d elements) exceeded", LIST_MAX));
        Tcl_SetErrorCode(interp, "TCL", "MEMORY", NULL);
	return TCL_ERROR;
    }
    totalElems = objc * elementCount;




    /*
     * Get an empty list object that is allocated large enough to hold each
     * init value elementCount times.
     */

    listPtr = Tcl_NewListObj(totalElems, NULL);
    if (totalElems) {
	List *listRepPtr = ListRepPtr(listPtr);

	listRepPtr->elemCount = elementCount*objc;
	dataArray = &listRepPtr->elements;
    }

    /*
     * Set the elements. Note that we handle the common degenerate case of a
2709
2710
2711
2712
2713
2714
2715

2716
2717
2718
2719
2720
2721
2722
     * be properly constrained by TclGetIntForIndex because we use listLen-1
     * (to allow for replacing the last elem).
     */

    if ((first >= listLen) && (listLen > 0)) {
	Tcl_AppendResult(interp, "list doesn't contain element ",
		TclGetString(objv[2]), NULL);

	return TCL_ERROR;
    }
    if (last >= listLen) {
	last = listLen - 1;
    }
    if (first <= last) {
	numToDelete = last - first + 1;







>







2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
     * be properly constrained by TclGetIntForIndex because we use listLen-1
     * (to allow for replacing the last elem).
     */

    if ((first >= listLen) && (listLen > 0)) {
	Tcl_AppendResult(interp, "list doesn't contain element ",
		TclGetString(objv[2]), NULL);
        Tcl_SetErrorCode(interp, "TCL","OPERATION","LREPLACE","BADIDX", NULL);
	return TCL_ERROR;
    }
    if (last >= listLen) {
	last = listLen - 1;
    }
    if (first <= last) {
	numToDelete = last - first + 1;
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
     */

    if (!elemc) {
	Tcl_SetObjResult(interp, objv[1]);
	return TCL_OK;
    }

    if (Tcl_IsShared(objv[1])) {

	Tcl_Obj *resultObj, **dataArray;
	List *listPtr;

    makeNewReversedList:
	resultObj = Tcl_NewListObj(elemc, NULL);
	listPtr = resultObj->internalRep.twoPtrValue.ptr1;
	listPtr->elemCount = elemc;
	dataArray = &listPtr->elements;

	for (i=0,j=elemc-1 ; i<elemc ; i++,j--) {
	    dataArray[j] = elemv[i];
	    Tcl_IncrRefCount(elemv[i]);
	}

	Tcl_SetObjResult(interp, resultObj);
    } else {
	/*
	 * It is theoretically possible for a list object to have a shared
	 * internal representation, but be an unshared object. Check for this
	 * and use the "shared" code if we have that problem. [Bug 1675044]
	 */

	if (((List *) objv[1]->internalRep.twoPtrValue.ptr1)->refCount > 1) {
	    goto makeNewReversedList;
	}

	/*
	 * Not shared, so swap "in place". This relies on Tcl_LOGE above
	 * returning a pointer to the live array of Tcl_Obj values.
	 */

	for (i=0,j=elemc-1 ; i<j ; i++,j--) {







|
>

|

<

|
|
|








<
<
<
<
<
<
<
<
<







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
     */

    if (!elemc) {
	Tcl_SetObjResult(interp, objv[1]);
	return TCL_OK;
    }

    if (Tcl_IsShared(objv[1])
	    || (ListRepPtr(objv[1])->refCount > 1)) {	/* Bug 1675044 */
	Tcl_Obj *resultObj, **dataArray;
	List *listRepPtr;


	resultObj = Tcl_NewListObj(elemc, NULL);
	listRepPtr = ListRepPtr(resultObj);
	listRepPtr->elemCount = elemc;
	dataArray = &listRepPtr->elements;

	for (i=0,j=elemc-1 ; i<elemc ; i++,j--) {
	    dataArray[j] = elemv[i];
	    Tcl_IncrRefCount(elemv[i]);
	}

	Tcl_SetObjResult(interp, resultObj);
    } else {










	/*
	 * Not shared, so swap "in place". This relies on Tcl_LOGE above
	 * returning a pointer to the live array of Tcl_Obj values.
	 */

	for (i=0,j=elemc-1 ; i<j ; i++,j--) {
2989
2990
2991
2992
2993
2994
2995

2996
2997
2998
2999
3000
3001
3002
	     */

	    if (startPtr != NULL) {
		Tcl_DecrRefCount(startPtr);
	    }
	    if (i > objc-4) {
		Tcl_AppendResult(interp, "missing starting index", NULL);

		result = TCL_ERROR;
		goto done;
	    }
	    i++;
	    if (objv[i] == objv[objc - 2]) {
		/*
		 * Take copy to prevent shimmering problems. Note that it does







>







2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
	     */

	    if (startPtr != NULL) {
		Tcl_DecrRefCount(startPtr);
	    }
	    if (i > objc-4) {
		Tcl_AppendResult(interp, "missing starting index", NULL);
                Tcl_SetErrorCode(interp, "TCL", "ARGUMENT", "MISSING", NULL);
		result = TCL_ERROR;
		goto done;
	    }
	    i++;
	    if (objv[i] == objv[objc - 2]) {
		/*
		 * Take copy to prevent shimmering problems. Note that it does
3021
3022
3023
3024
3025
3026
3027

3028
3029
3030
3031
3032
3033
3034
	    if (i > objc-4) {
		if (startPtr != NULL) {
		    Tcl_DecrRefCount(startPtr);
		}
		Tcl_AppendResult(interp,
			"\"-index\" option must be followed by list index",
			NULL);

		return TCL_ERROR;
	    }

	    /*
	     * Store the extracted indices for processing by sublist
	     * extraction. Note that we don't do this using objects because
	     * that has shimmering problems.







>







3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
	    if (i > objc-4) {
		if (startPtr != NULL) {
		    Tcl_DecrRefCount(startPtr);
		}
		Tcl_AppendResult(interp,
			"\"-index\" option must be followed by list index",
			NULL);
                Tcl_SetErrorCode(interp, "TCL", "ARGUMENT", "MISSING", NULL);
		return TCL_ERROR;
	    }

	    /*
	     * Store the extracted indices for processing by sublist
	     * extraction. Note that we don't do this using objects because
	     * that has shimmering problems.
3080
3081
3082
3083
3084
3085
3086


3087
3088
3089
3090
3091
3092


3093
3094
3095
3096
3097
3098
3099

    if (returnSubindices && sortInfo.indexc==0) {
	if (startPtr != NULL) {
	    Tcl_DecrRefCount(startPtr);
	}
	Tcl_AppendResult(interp,
		"-subindices cannot be used without -index option", NULL);


	return TCL_ERROR;
    }

    if (bisect && (allMatches || negatedMatch)) {
	Tcl_AppendResult(interp,
		"-bisect is not compatible with -all or -not", NULL);


	return TCL_ERROR;
    }

    if (mode == REGEXP) {
	/*
	 * We can shimmer regexp/list if listv[i] == pattern, so get the
	 * regexp rep before the list rep. First time round, omit the interp







>
>






>
>







3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109

    if (returnSubindices && sortInfo.indexc==0) {
	if (startPtr != NULL) {
	    Tcl_DecrRefCount(startPtr);
	}
	Tcl_AppendResult(interp,
		"-subindices cannot be used without -index option", NULL);
        Tcl_SetErrorCode(interp, "TCL", "OPERATION", "LSEARCH",
                "BAD_OPTION_MIX", NULL);
	return TCL_ERROR;
    }

    if (bisect && (allMatches || negatedMatch)) {
	Tcl_AppendResult(interp,
		"-bisect is not compatible with -all or -not", NULL);
        Tcl_SetErrorCode(interp, "TCL", "OPERATION", "LSEARCH",
                "BAD_OPTION_MIX", NULL);
	return TCL_ERROR;
    }

    if (mode == REGEXP) {
	/*
	 * We can shimmer regexp/list if listv[i] == pattern, so get the
	 * regexp rep before the list rep. First time round, omit the interp
3653
3654
3655
3656
3657
3658
3659

3660
3661
3662
3663
3664
3665
3666
	    sortInfo.sortMode = SORTMODE_ASCII;
	    break;
	case LSORT_COMMAND:
	    if (i == objc-2) {
		Tcl_AppendResult(interp,
			"\"-command\" option must be followed "
			"by comparison command", NULL);

		sortInfo.resultCode = TCL_ERROR;
		goto done2;
	    }
	    sortInfo.sortMode = SORTMODE_COMMAND;
	    cmdPtr = objv[i+1];
	    i++;
	    break;







>







3663
3664
3665
3666
3667
3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
	    sortInfo.sortMode = SORTMODE_ASCII;
	    break;
	case LSORT_COMMAND:
	    if (i == objc-2) {
		Tcl_AppendResult(interp,
			"\"-command\" option must be followed "
			"by comparison command", NULL);
                Tcl_SetErrorCode(interp, "TCL", "ARGUMENT", "MISSING", NULL);
		sortInfo.resultCode = TCL_ERROR;
		goto done2;
	    }
	    sortInfo.sortMode = SORTMODE_COMMAND;
	    cmdPtr = objv[i+1];
	    i++;
	    break;
3676
3677
3678
3679
3680
3681
3682

3683
3684
3685
3686
3687
3688
3689
	case LSORT_INDEX: {
            int indexc, dummy;
	    Tcl_Obj **indexv;

	    if (i == objc-2) {
		Tcl_AppendResult(interp, "\"-index\" option must be "
			"followed by list index", NULL);

                sortInfo.resultCode = TCL_ERROR;
                goto done2;
	    }
	    if (TclListObjGetElements(interp, objv[i+1], &indexc,
		    &indexv) != TCL_OK) {
                sortInfo.resultCode = TCL_ERROR;
                goto done2;







>







3687
3688
3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
	case LSORT_INDEX: {
            int indexc, dummy;
	    Tcl_Obj **indexv;

	    if (i == objc-2) {
		Tcl_AppendResult(interp, "\"-index\" option must be "
			"followed by list index", NULL);
                Tcl_SetErrorCode(interp, "TCL", "ARGUMENT", "MISSING", NULL);
                sortInfo.resultCode = TCL_ERROR;
                goto done2;
	    }
	    if (TclListObjGetElements(interp, objv[i+1], &indexc,
		    &indexv) != TCL_OK) {
                sortInfo.resultCode = TCL_ERROR;
                goto done2;
3725
3726
3727
3728
3729
3730
3731

3732
3733
3734
3735
3736
3737
3738
3739
3740
3741


3742
3743
3744
3745
3746
3747
3748
	case LSORT_INDICES:
	    indices = 1;
	    break;
	case LSORT_STRIDE:
	    if (i == objc-2) {
		Tcl_AppendResult(interp, "\"-stride\" option must be ",
			"followed by stride length", NULL);

		sortInfo.resultCode = TCL_ERROR;
		goto done2;
	    }
	    if (Tcl_GetIntFromObj(interp, objv[i+1], &groupSize) != TCL_OK) {
		sortInfo.resultCode = TCL_ERROR;
		goto done2;
	    }
	    if (groupSize < 2) {
		Tcl_AppendResult(interp, "stride length must be at least 2",
			NULL);


		sortInfo.resultCode = TCL_ERROR;
		goto done2;
	    }
	    group = 1;
	    i++;
	    break;
	}







>










>
>







3737
3738
3739
3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
3753
3754
3755
3756
3757
3758
3759
3760
3761
3762
3763
	case LSORT_INDICES:
	    indices = 1;
	    break;
	case LSORT_STRIDE:
	    if (i == objc-2) {
		Tcl_AppendResult(interp, "\"-stride\" option must be ",
			"followed by stride length", NULL);
                Tcl_SetErrorCode(interp, "TCL", "ARGUMENT", "MISSING", NULL);
		sortInfo.resultCode = TCL_ERROR;
		goto done2;
	    }
	    if (Tcl_GetIntFromObj(interp, objv[i+1], &groupSize) != TCL_OK) {
		sortInfo.resultCode = TCL_ERROR;
		goto done2;
	    }
	    if (groupSize < 2) {
		Tcl_AppendResult(interp, "stride length must be at least 2",
			NULL);
                Tcl_SetErrorCode(interp, "TCL", "OPERATION", "LSORT",
                        "BADSTRIDE", NULL);
		sortInfo.resultCode = TCL_ERROR;
		goto done2;
	    }
	    group = 1;
	    i++;
	    break;
	}
3831
3832
3833
3834
3835
3836
3837


3838
3839
3840
3841
3842
3843
3844
3845
3846
3847
3848
3849
3850
3851
3852
3853
3854
3855


3856
3857
3858
3859
3860
3861
3862
     */

    if (group) {
	if (length % groupSize) {
	    Tcl_AppendResult(interp,
		    "list size must be a multiple of the stride length",
		    NULL);


	    sortInfo.resultCode = TCL_ERROR;
	    goto done;
	}
	length = length / groupSize;
	if (sortInfo.indexc > 0) {
	    /*
	     * Use the first value in the list supplied to -index as the
	     * offset of the element within each group by which to sort.
	     */

	    groupOffset = sortInfo.indexv[0];
	    if (groupOffset <= SORTIDX_END) {
		groupOffset = (groupOffset - SORTIDX_END) + groupSize - 1;
	    }
	    if (groupOffset < 0 || groupOffset >= groupSize) {
		Tcl_AppendResult(interp, "when used with \"-stride\", the "
			"leading \"-index\" value must be within the group",
			NULL);


		sortInfo.resultCode = TCL_ERROR;
		goto done;
	    }
	    if (sortInfo.indexc == 1) {
		sortInfo.indexc = 0;
		sortInfo.indexv = NULL;
	    } else {







>
>


















>
>







3846
3847
3848
3849
3850
3851
3852
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
     */

    if (group) {
	if (length % groupSize) {
	    Tcl_AppendResult(interp,
		    "list size must be a multiple of the stride length",
		    NULL);
            Tcl_SetErrorCode(interp, "TCL", "OPERATION", "LSORT", "BADSTRIDE",
                    NULL);
	    sortInfo.resultCode = TCL_ERROR;
	    goto done;
	}
	length = length / groupSize;
	if (sortInfo.indexc > 0) {
	    /*
	     * Use the first value in the list supplied to -index as the
	     * offset of the element within each group by which to sort.
	     */

	    groupOffset = sortInfo.indexv[0];
	    if (groupOffset <= SORTIDX_END) {
		groupOffset = (groupOffset - SORTIDX_END) + groupSize - 1;
	    }
	    if (groupOffset < 0 || groupOffset >= groupSize) {
		Tcl_AppendResult(interp, "when used with \"-stride\", the "
			"leading \"-index\" value must be within the group",
			NULL);
                Tcl_SetErrorCode(interp, "TCL", "OPERATION", "LSORT",
                        "BADINDEX", NULL);
		sortInfo.resultCode = TCL_ERROR;
		goto done;
	    }
	    if (sortInfo.indexc == 1) {
		sortInfo.indexc = 0;
		sortInfo.indexv = NULL;
	    } else {
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
4000
4001
     */

    if (sortInfo.resultCode == TCL_OK) {
	List *listRepPtr;
	Tcl_Obj **newArray, *objPtr;

	resultPtr = Tcl_NewListObj(sortInfo.numElements * groupSize, NULL);
	listRepPtr = resultPtr->internalRep.twoPtrValue.ptr1;
	newArray = &listRepPtr->elements;
	if (group) {
	    for (i=0; elementPtr!=NULL ; elementPtr=elementPtr->nextPtr) {
		idx = elementPtr->payload.index;
		for (j = 0; j < groupSize; j++) {
		    if (indices) {
			objPtr = Tcl_NewIntObj(idx + j - groupOffset);







|







4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016
4017
4018
4019
4020
     */

    if (sortInfo.resultCode == TCL_OK) {
	List *listRepPtr;
	Tcl_Obj **newArray, *objPtr;

	resultPtr = Tcl_NewListObj(sortInfo.numElements * groupSize, NULL);
	listRepPtr = ListRepPtr(resultPtr);
	newArray = &listRepPtr->elements;
	if (group) {
	    for (i=0; elementPtr!=NULL ; elementPtr=elementPtr->nextPtr) {
		idx = elementPtr->payload.index;
		for (j = 0; j < groupSize; j++) {
		    if (indices) {
			objPtr = Tcl_NewIntObj(idx + j - groupOffset);
4235
4236
4237
4238
4239
4240
4241


4242
4243
4244
4245
4246
4247
4248
	 */

	if (TclGetIntFromObj(infoPtr->interp,
		Tcl_GetObjResult(infoPtr->interp), &order) != TCL_OK) {
	    Tcl_ResetResult(infoPtr->interp);
	    Tcl_AppendResult(infoPtr->interp,
		    "-compare command returned non-integer result", NULL);


	    infoPtr->resultCode = TCL_ERROR;
	    return 0;
	}
    }
    if (!infoPtr->isIncreasing) {
	order = -order;
    }







>
>







4254
4255
4256
4257
4258
4259
4260
4261
4262
4263
4264
4265
4266
4267
4268
4269
	 */

	if (TclGetIntFromObj(infoPtr->interp,
		Tcl_GetObjResult(infoPtr->interp), &order) != TCL_OK) {
	    Tcl_ResetResult(infoPtr->interp);
	    Tcl_AppendResult(infoPtr->interp,
		    "-compare command returned non-integer result", NULL);
            Tcl_SetErrorCode(infoPtr->interp, "TCL", "OPERATION", "LSORT",
                    "COMPARISONFAILED", NULL);
	    infoPtr->resultCode = TCL_ERROR;
	    return 0;
	}
    }
    if (!infoPtr->isIncreasing) {
	order = -order;
    }
4445
4446
4447
4448
4449
4450
4451
4452
4453
4454
4455
4456

4457
4458
4459
4460
4461
4462
4463
4464

	if (Tcl_ListObjIndex(infoPtr->interp, objPtr, index,
		&currentObj) != TCL_OK) {
	    infoPtr->resultCode = TCL_ERROR;
	    return NULL;
	}
	if (currentObj == NULL) {
	    char buffer[TCL_INTEGER_SPACE];

	    TclFormatInt(buffer, index);
	    Tcl_AppendResult(infoPtr->interp, "element ", buffer,
		    " missing from sublist \"", TclGetString(objPtr), "\"",

		    NULL);
	    infoPtr->resultCode = TCL_ERROR;
	    return NULL;
	}
	objPtr = currentObj;
    }
    return objPtr;
}







<
|
<
|
|
>
|







4466
4467
4468
4469
4470
4471
4472

4473

4474
4475
4476
4477
4478
4479
4480
4481
4482
4483
4484

	if (Tcl_ListObjIndex(infoPtr->interp, objPtr, index,
		&currentObj) != TCL_OK) {
	    infoPtr->resultCode = TCL_ERROR;
	    return NULL;
	}
	if (currentObj == NULL) {

            Tcl_SetObjResult(infoPtr->interp, Tcl_ObjPrintf(

                    "element %d missing from sublist \"%s\"",
                    index, TclGetString(objPtr)));
            Tcl_SetErrorCode(infoPtr->interp, "TCL", "OPERATION", "LSORT",
                    "INDEXFAILED", NULL);
	    infoPtr->resultCode = TCL_ERROR;
	    return NULL;
	}
	objPtr = currentObj;
    }
    return objPtr;
}

Changes to generic/tclCmdMZ.c.

1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
	    result = 0;
	    failat = 0;
	} else {
	    failat = stop - string1;
	    if (stop < end) {
		result = 0;
		TclFreeIntRep(objPtr);
		objPtr->typePtr = NULL;
	    }
	}
	break;
    }
    case STR_IS_GRAPH:
	chcomp = Tcl_UniCharIsGraph;
	break;







<







1556
1557
1558
1559
1560
1561
1562

1563
1564
1565
1566
1567
1568
1569
	    result = 0;
	    failat = 0;
	} else {
	    failat = stop - string1;
	    if (stop < end) {
		result = 0;
		TclFreeIntRep(objPtr);

	    }
	}
	break;
    }
    case STR_IS_GRAPH:
	chcomp = Tcl_UniCharIsGraph;
	break;
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
		 * so return failure index as the point where parsing stopped.
		 * Clear out the internal rep, since keeping it would leave
		 * *objPtr in an inconsistent state.
		 */

		failat = stop - string1;
		TclFreeIntRep(objPtr);
		objPtr->typePtr = NULL;
	    }
	} else {
	    /*
	     * No prefix is a valid integer. Fail at beginning.
	     */

	    failat = 0;







<







1612
1613
1614
1615
1616
1617
1618

1619
1620
1621
1622
1623
1624
1625
		 * so return failure index as the point where parsing stopped.
		 * Clear out the internal rep, since keeping it would leave
		 * *objPtr in an inconsistent state.
		 */

		failat = stop - string1;
		TclFreeIntRep(objPtr);

	    }
	} else {
	    /*
	     * No prefix is a valid integer. Fail at beginning.
	     */

	    failat = 0;
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
	    /*
	     * Need to figure out where the list parsing failed, which is
	     * fairly expensive. This is adapted from the core of
	     * SetListFromAny().
	     */

	    const char *elemStart, *nextElem;
	    int lenRemain, elemSize, hasBrace;
	    register const char *p;

	    string1 = TclGetStringFromObj(objPtr, &length1);
	    end = string1 + length1;
	    failat = -1;
	    for (p=string1, lenRemain=length1; lenRemain > 0;
		    p=nextElem, lenRemain=end-nextElem) {
		if (TCL_ERROR == TclFindElement(NULL, p, lenRemain,
			&elemStart, &nextElem, &elemSize, &hasBrace)) {
		    Tcl_Obj *tmpStr;

		    /*
		     * This is the simplest way of getting the number of
		     * characters parsed. Note that this is not the same as
		     * the number of bytes when parsing strings with non-ASCII
		     * characters in them.
		     *
		     * Skip leading spaces first. This is only really an issue
		     * if it is the first "element" that has the failure.
		     */

		    while (isspace(UCHAR(*p))) {		/* INTL: ? */
			p++;
		    }
		    TclNewStringObj(tmpStr, string1, p-string1);
		    failat = Tcl_GetCharLength(tmpStr);
		    TclDecrRefCount(tmpStr);
		    break;
		}







|








|












|







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
	    /*
	     * Need to figure out where the list parsing failed, which is
	     * fairly expensive. This is adapted from the core of
	     * SetListFromAny().
	     */

	    const char *elemStart, *nextElem;
	    int lenRemain, elemSize;
	    register const char *p;

	    string1 = TclGetStringFromObj(objPtr, &length1);
	    end = string1 + length1;
	    failat = -1;
	    for (p=string1, lenRemain=length1; lenRemain > 0;
		    p=nextElem, lenRemain=end-nextElem) {
		if (TCL_ERROR == TclFindElement(NULL, p, lenRemain,
			&elemStart, &nextElem, &elemSize, NULL)) {
		    Tcl_Obj *tmpStr;

		    /*
		     * This is the simplest way of getting the number of
		     * characters parsed. Note that this is not the same as
		     * the number of bytes when parsing strings with non-ASCII
		     * characters in them.
		     *
		     * Skip leading spaces first. This is only really an issue
		     * if it is the first "element" that has the failure.
		     */

		    while (TclIsSpaceProc(*p)) {
			p++;
		    }
		    TclNewStringObj(tmpStr, string1, p-string1);
		    failat = Tcl_GetCharLength(tmpStr);
		    TclDecrRefCount(tmpStr);
		    break;
		}
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
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
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179

3180
3181
3182
3183
3184
3185
3186
static int
StringTrimCmd(
    ClientData dummy,		/* Not used. */
    Tcl_Interp *interp,		/* Current interpreter. */
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    Tcl_UniChar ch, trim;
    register const char *p, *end;
    const char *check, *checkEnd, *string1, *string2;
    int offset, length1, length2;

    if (objc == 3) {
	string2 = TclGetStringFromObj(objv[2], &length2);
    } else if (objc == 2) {
	string2 = DEFAULT_TRIM_SET;
	length2 = strlen(DEFAULT_TRIM_SET);
    } else {
	Tcl_WrongNumArgs(interp, 1, objv, "string ?chars?");
	return TCL_ERROR;
    }
    string1 = TclGetStringFromObj(objv[1], &length1);
    checkEnd = string2 + length2;

    /*
     * The outer loop iterates over the string. The inner loop iterates over
     * the trim characters. The loops terminate as soon as a non-trim
     * character is discovered and string1 is left pointing at the first
     * non-trim character.
     */

    end = string1 + length1;
    for (p = string1; p < end; p += offset) {
	offset = TclUtfToUniChar(p, &ch);

	for (check = string2; ; ) {
	    if (check >= checkEnd) {
		p = end;
		break;
	    }
	    check += TclUtfToUniChar(check, &trim);
	    if (ch == trim) {
		length1 -= offset;
		string1 += offset;
		break;
	    }
	}
    }

    /*
     * The outer loop iterates over the string. The inner loop iterates over
     * the trim characters. The loops terminate as soon as a non-trim
     * character is discovered and length1 marks the last non-trim character.
     */

    end = string1;
    for (p = string1 + length1; p > end; ) {
	p = Tcl_UtfPrev(p, string1);
	offset = TclUtfToUniChar(p, &ch);
	check = string2;
	while (1) {
	    if (check >= checkEnd) {
		p = end;
		break;
	    }
	    check += TclUtfToUniChar(check, &trim);
	    if (ch == trim) {
		length1 -= offset;
		break;
	    }
	}
    }

    Tcl_SetObjResult(interp, Tcl_NewStringObj(string1, length1));

    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * StringTrimLCmd --







<
<
|
|











<

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







3104
3105
3106
3107
3108
3109
3110


3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123

3124






3125



3126




3127

































3128
3129
3130
3131
3132
3133
3134
3135
3136
static int
StringTrimCmd(
    ClientData dummy,		/* Not used. */
    Tcl_Interp *interp,		/* Current interpreter. */
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{


    const char *string1, *string2;
    int triml, trimr, length1, length2;

    if (objc == 3) {
	string2 = TclGetStringFromObj(objv[2], &length2);
    } else if (objc == 2) {
	string2 = DEFAULT_TRIM_SET;
	length2 = strlen(DEFAULT_TRIM_SET);
    } else {
	Tcl_WrongNumArgs(interp, 1, objv, "string ?chars?");
	return TCL_ERROR;
    }
    string1 = TclGetStringFromObj(objv[1], &length1);








    triml = TclTrimLeft(string1, length1, string2, length2);



    trimr = TclTrimRight(string1 + triml, length1 - triml, string2, length2);






































    Tcl_SetObjResult(interp,
	    Tcl_NewStringObj(string1 + triml, length1 - triml - trimr));
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * StringTrimLCmd --
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
static int
StringTrimLCmd(
    ClientData dummy,		/* Not used. */
    Tcl_Interp *interp,		/* Current interpreter. */
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    Tcl_UniChar ch, trim;
    register const char *p, *end;
    const char *check, *checkEnd, *string1, *string2;
    int offset, length1, length2;

    if (objc == 3) {
	string2 = TclGetStringFromObj(objv[2], &length2);
    } else if (objc == 2) {
	string2 = DEFAULT_TRIM_SET;
	length2 = strlen(DEFAULT_TRIM_SET);
    } else {
	Tcl_WrongNumArgs(interp, 1, objv, "string ?chars?");
	return TCL_ERROR;
    }
    string1 = TclGetStringFromObj(objv[1], &length1);
    checkEnd = string2 + length2;

    /*
     * The outer loop iterates over the string. The inner loop iterates over
     * the trim characters. The loops terminate as soon as a non-trim
     * character is discovered and string1 is left pointing at the first
     * non-trim character.
     */

    end = string1 + length1;
    for (p = string1; p < end; p += offset) {
	offset = TclUtfToUniChar(p, &ch);

	for (check = string2; ; ) {
	    if (check >= checkEnd) {
		p = end;
		break;
	    }
	    check += TclUtfToUniChar(check, &trim);
	    if (ch == trim) {
		length1 -= offset;
		string1 += offset;
		break;
	    }
	}
    }

    Tcl_SetObjResult(interp, Tcl_NewStringObj(string1, length1));
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * StringTrimRCmd --







<
<
|
|











<

<
<
<
<
<
<
|
<
<
<

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







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
3180
3181
3182
static int
StringTrimLCmd(
    ClientData dummy,		/* Not used. */
    Tcl_Interp *interp,		/* Current interpreter. */
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{


    const char *string1, *string2;
    int trim, length1, length2;

    if (objc == 3) {
	string2 = TclGetStringFromObj(objv[2], &length2);
    } else if (objc == 2) {
	string2 = DEFAULT_TRIM_SET;
	length2 = strlen(DEFAULT_TRIM_SET);
    } else {
	Tcl_WrongNumArgs(interp, 1, objv, "string ?chars?");
	return TCL_ERROR;
    }
    string1 = TclGetStringFromObj(objv[1], &length1);








    trim = TclTrimLeft(string1, length1, string2, length2);


















    Tcl_SetObjResult(interp, Tcl_NewStringObj(string1+trim, length1-trim));
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * StringTrimRCmd --
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
static int
StringTrimRCmd(
    ClientData dummy,		/* Not used. */
    Tcl_Interp *interp,		/* Current interpreter. */
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    Tcl_UniChar ch, trim;
    register const char *p, *end;
    const char *check, *checkEnd, *string1, *string2;
    int offset, length1, length2;

    if (objc == 3) {
	string2 = TclGetStringFromObj(objv[2], &length2);
    } else if (objc == 2) {
	string2 = DEFAULT_TRIM_SET;
	length2 = strlen(DEFAULT_TRIM_SET);
    } else {
	Tcl_WrongNumArgs(interp, 1, objv, "string ?chars?");
	return TCL_ERROR;
    }
    string1 = TclGetStringFromObj(objv[1], &length1);
    checkEnd = string2 + length2;

    /*
     * The outer loop iterates over the string. The inner loop iterates over
     * the trim characters. The loops terminate as soon as a non-trim
     * character is discovered and length1 marks the last non-trim character.
     */

    end = string1;
    for (p = string1 + length1; p > end; ) {
	p = Tcl_UtfPrev(p, string1);
	offset = TclUtfToUniChar(p, &ch);
	check = string2;
	while (1) {
	    if (check >= checkEnd) {
		p = end;
		break;
	    }
	    check += TclUtfToUniChar(check, &trim);
	    if (ch == trim) {
		length1 -= offset;
		break;
	    }
	}
    }

    Tcl_SetObjResult(interp, Tcl_NewStringObj(string1, length1));
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * TclInitStringCmd --







<
<
|
|











<

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







3198
3199
3200
3201
3202
3203
3204


3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217

3218





3219









3220








3221
3222
3223
3224
3225
3226
3227
3228
static int
StringTrimRCmd(
    ClientData dummy,		/* Not used. */
    Tcl_Interp *interp,		/* Current interpreter. */
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{


    const char *string1, *string2;
    int trim, length1, length2;

    if (objc == 3) {
	string2 = TclGetStringFromObj(objv[2], &length2);
    } else if (objc == 2) {
	string2 = DEFAULT_TRIM_SET;
	length2 = strlen(DEFAULT_TRIM_SET);
    } else {
	Tcl_WrongNumArgs(interp, 1, objv, "string ?chars?");
	return TCL_ERROR;
    }
    string1 = TclGetStringFromObj(objv[1], &length1);







    trim = TclTrimRight(string1, length1, string2, length2);


















    Tcl_SetObjResult(interp, Tcl_NewStringObj(string1, length1-trim));
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * TclInitStringCmd --

Changes to generic/tclCompCmds.c.

1230
1231
1232
1233
1234
1235
1236




























































































































































































































1237
1238
1239
1240
1241
1242
1243
	return TCL_ERROR;
    }
    CompileWord(envPtr, keyTokenPtr, interp, 3);
    CompileWord(envPtr, valueTokenPtr, interp, 4);
    TclEmitInstInt4( INST_DICT_LAPPEND, dictVarIndex, envPtr);
    return TCL_OK;
}





























































































































































































































/*
 *----------------------------------------------------------------------
 *
 * DupDictUpdateInfo, FreeDictUpdateInfo --
 *
 *	Functions to duplicate, release and print the aux data created for use







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







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
	return TCL_ERROR;
    }
    CompileWord(envPtr, keyTokenPtr, interp, 3);
    CompileWord(envPtr, valueTokenPtr, interp, 4);
    TclEmitInstInt4( INST_DICT_LAPPEND, dictVarIndex, envPtr);
    return TCL_OK;
}

int
TclCompileDictWithCmd(
    Tcl_Interp *interp,		/* Used for looking up stuff. */
    Tcl_Parse *parsePtr,	/* Points to a parse structure for the command
				 * created by Tcl_ParseCommand. */
    Command *cmdPtr,		/* Points to defintion of command being
				 * compiled. */
    CompileEnv *envPtr)		/* Holds resulting instructions. */
{
    DefineLineInformation;	/* TIP #280 */
    int i, range, varNameTmp, pathTmp, keysTmp, gotPath, dictVar = -1;
    Tcl_Token *dictVarTokenPtr, *tokenPtr;
    int savedStackDepth = envPtr->currStackDepth;
    JumpFixup jumpFixup;

    /*
     * There must be at least one argument after the command and we must be in
     * a procedure so we can have local temporaries.
     */

    if (envPtr->procPtr == NULL) {
	return TCL_ERROR;
    }
    if (parsePtr->numWords < 3) {
	return TCL_ERROR;
    }

    /*
     * Parse the command (trivially). Expect the following:
     *   dict with <any (varName)> ?<any> ...? <literal>
     */

    dictVarTokenPtr = TokenAfter(parsePtr->tokenPtr);
    tokenPtr = TokenAfter(dictVarTokenPtr);
    for (i=3 ; i<parsePtr->numWords ; i++) {
	tokenPtr = TokenAfter(tokenPtr);
    }
    if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
	return TCL_ERROR;
    }

    /*
     * Allocate local (unnamed, untraced) working variables.
     */

    gotPath = (parsePtr->numWords > 3);
    if (dictVarTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
	const char *ptr = dictVarTokenPtr[1].start;
	const char *end = ptr + dictVarTokenPtr[1].size;
	int notArray = 1;

	/*
	 * A conservative check for if we're working with an array since we
	 * have a reasonable fallback if things are tricky.
	 */

	for (; ptr<end ; ptr++) {
	    if (*ptr == '(' || *ptr == ')') {
		notArray = 0;
		break;
	    }
	}
	if (notArray) {
	    dictVar = TclFindCompiledLocal(dictVarTokenPtr[1].start,
		    dictVarTokenPtr[1].size, 1, envPtr);
	}
    }
    if (dictVar == -1) {
	varNameTmp = TclFindCompiledLocal(NULL, 0, 1, envPtr);
    } else {
	varNameTmp = -1;
    }
    if (gotPath) {
	pathTmp = TclFindCompiledLocal(NULL, 0, 1, envPtr);
    } else {
	pathTmp = -1;
    }
    keysTmp = TclFindCompiledLocal(NULL, 0, 1, envPtr);

    /*
     * Issue instructions. First, the part to expand the dictionary.
     */

    tokenPtr = dictVarTokenPtr;
    if (varNameTmp > -1) {
	CompileWord(envPtr, tokenPtr, interp, 0);
	if (varNameTmp <= 255) {
	    TclEmitInstInt1(	INST_STORE_SCALAR1, varNameTmp,	envPtr);
	} else {
	    TclEmitInstInt4(	INST_STORE_SCALAR4, varNameTmp,	envPtr);
	}
    }
    tokenPtr = TokenAfter(tokenPtr);
    if (gotPath) {
	for (i=2 ; i<parsePtr->numWords-1 ; i++) {
	    CompileWord(envPtr, tokenPtr, interp, i-1);
	    tokenPtr = TokenAfter(tokenPtr);
	}
	TclEmitInstInt4(	INST_LIST, parsePtr->numWords-3,envPtr);
	if (pathTmp <= 255) {
	    TclEmitInstInt1(	INST_STORE_SCALAR1, pathTmp,	envPtr);
	} else {
	    TclEmitInstInt4(	INST_STORE_SCALAR4, pathTmp,	envPtr);
	}
	TclEmitOpcode(		INST_POP,			envPtr);
    }
    if (dictVar == -1) {
	TclEmitOpcode(		INST_LOAD_STK,			envPtr);
    } else if (dictVar <= 255) {
	TclEmitInstInt1(	INST_LOAD_SCALAR1, dictVar,	envPtr);
    } else {
	TclEmitInstInt4(	INST_LOAD_SCALAR4, dictVar,	envPtr);
    }
    if (gotPath) {
	if (pathTmp <= 255) {
	    TclEmitInstInt1(	INST_LOAD_SCALAR1, pathTmp,	envPtr);
	} else {
	    TclEmitInstInt4(	INST_LOAD_SCALAR4, pathTmp,	envPtr);
	}
    } else {
	PushLiteral(envPtr, "", 0);
    }
    TclEmitOpcode(		INST_DICT_EXPAND,		envPtr);
    if (keysTmp <= 255) {
	TclEmitInstInt1(	INST_STORE_SCALAR1, keysTmp,	envPtr);
    } else {
	TclEmitInstInt4(	INST_STORE_SCALAR4, keysTmp,	envPtr);
    }
    TclEmitOpcode(		INST_POP,			envPtr);

    /*
     * Now the body of the [dict with].
     */

    range = DeclareExceptionRange(envPtr, CATCH_EXCEPTION_RANGE);
    TclEmitInstInt4(		INST_BEGIN_CATCH4, range,	envPtr);

    ExceptionRangeStarts(envPtr, range);
    envPtr->currStackDepth++;
    SetLineInformation(parsePtr->numWords-1);
    CompileBody(envPtr, tokenPtr, interp);
    envPtr->currStackDepth = savedStackDepth;
    ExceptionRangeEnds(envPtr, range);

    /*
     * Now fold the results back into the dictionary in the OK case.
     */

    TclEmitOpcode(		INST_END_CATCH,			envPtr);
    if (varNameTmp > -1 && varNameTmp <= 255) {
	TclEmitInstInt1(	INST_LOAD_SCALAR1, varNameTmp,	envPtr);
    } else if (varNameTmp > -1) {
	TclEmitInstInt4(	INST_LOAD_SCALAR4, varNameTmp,	envPtr);
    }
    if (gotPath) {
	if (pathTmp <= 255) {
	    TclEmitInstInt1(	INST_LOAD_SCALAR1, pathTmp,	envPtr);
	} else {
	    TclEmitInstInt4(	INST_LOAD_SCALAR4, pathTmp,	envPtr);
	}
    } else {
	PushLiteral(envPtr, "", 0);
    }
    if (keysTmp <= 255) {
	TclEmitInstInt1(	INST_LOAD_SCALAR1, keysTmp,	envPtr);
    } else {
	TclEmitInstInt4(	INST_LOAD_SCALAR4, keysTmp,	envPtr);
    }
    if (dictVar == -1) {
	TclEmitOpcode(		INST_DICT_RECOMBINE_STK,	envPtr);
    } else {
	TclEmitInstInt4(	INST_DICT_RECOMBINE_IMM, dictVar, envPtr);
    }
    TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &jumpFixup);

    /*
     * Now fold the results back into the dictionary in the exception case.
     */

    ExceptionRangeTarget(envPtr, range, catchOffset);
    TclEmitOpcode(		INST_PUSH_RETURN_OPTIONS,	envPtr);
    TclEmitOpcode(		INST_PUSH_RESULT,		envPtr);
    TclEmitOpcode(		INST_END_CATCH,			envPtr);
    if (varNameTmp > -1 && varNameTmp <= 255) {
	TclEmitInstInt1(	INST_LOAD_SCALAR1, varNameTmp,	envPtr);
    } else if (varNameTmp > -1) {
	TclEmitInstInt4(	INST_LOAD_SCALAR4, varNameTmp,	envPtr);
    }
    if (parsePtr->numWords > 3) {
	if (pathTmp <= 255) {
	    TclEmitInstInt1(	INST_LOAD_SCALAR1, pathTmp,	envPtr);
	} else {
	    TclEmitInstInt4(	INST_LOAD_SCALAR4, pathTmp,	envPtr);
	}
    } else {
	PushLiteral(envPtr, "", 0);
    }
    if (keysTmp <= 255) {
	TclEmitInstInt1(	INST_LOAD_SCALAR1, keysTmp,	envPtr);
    } else {
	TclEmitInstInt4(	INST_LOAD_SCALAR4, keysTmp,	envPtr);
    }
    if (dictVar == -1) {
	TclEmitOpcode(		INST_DICT_RECOMBINE_STK,	envPtr);
    } else {
	TclEmitInstInt4(	INST_DICT_RECOMBINE_IMM, dictVar, envPtr);
    }
    TclEmitOpcode(		INST_RETURN_STK,		envPtr);

    /*
     * Prepare for the start of the next command.
     */

    if (TclFixupForwardJumpToHere(envPtr, &jumpFixup, 127)) {
	Tcl_Panic("TclCompileDictCmd(update): bad jump distance %d",
		(int) (CurrentOffset(envPtr) - jumpFixup.codeOffset));
    }
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * DupDictUpdateInfo, FreeDictUpdateInfo --
 *
 *	Functions to duplicate, release and print the aux data created for use
3640
3641
3642
3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654
    Tcl_Obj *msg = Tcl_GetObjResult(interp);
    int numBytes;
    const char *bytes = TclGetStringFromObj(msg, &numBytes);

    TclErrorStackResetIf(interp, bytes, numBytes);
    TclEmitPush(TclRegisterNewLiteral(envPtr, bytes, numBytes), envPtr);
    CompileReturnInternal(envPtr, INST_SYNTAX, TCL_ERROR, 0,
	    Tcl_GetReturnOptions(interp, TCL_ERROR));
}

/*
 *----------------------------------------------------------------------
 *
 * TclCompileUpvarCmd --
 *







|







3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
    Tcl_Obj *msg = Tcl_GetObjResult(interp);
    int numBytes;
    const char *bytes = TclGetStringFromObj(msg, &numBytes);

    TclErrorStackResetIf(interp, bytes, numBytes);
    TclEmitPush(TclRegisterNewLiteral(envPtr, bytes, numBytes), envPtr);
    CompileReturnInternal(envPtr, INST_SYNTAX, TCL_ERROR, 0,
			  TclNoErrorStack(interp, Tcl_GetReturnOptions(interp, TCL_ERROR)));
}

/*
 *----------------------------------------------------------------------
 *
 * TclCompileUpvarCmd --
 *

Changes to generic/tclCompCmdsSZ.c.

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
				 * created by Tcl_ParseCommand. */
    Command *cmdPtr,		/* Points to defintion of command being
				 * compiled. */
    CompileEnv *envPtr)		/* Holds resulting instructions. */
{
    Tcl_Token *tokenPtr;	/* Pointer to tokens in command. */
    int numWords;		/* Number of words in command. */

    Tcl_Token *valueTokenPtr;	/* Token for the value to switch on. */
    enum {Switch_Exact, Switch_Glob, Switch_Regexp} mode;
				/* What kind of switch are we doing? */

    Tcl_Token *bodyTokenArray;	/* Array of real pattern list items. */
    Tcl_Token **bodyToken;	/* Array of pointers to pattern list items. */
    int *bodyLines;		/* Array of line numbers for body list
				 * items. */
    int **bodyContLines;	/* Array of continuation line info. */
    int noCase;			/* Has the -nocase flag been given? */
    int foundMode = 0;		/* Have we seen a mode flag yet? */
    int isListedArms = 0;
    int i, valueIndex;
    int result = TCL_ERROR;
    DefineLineInformation;	/* TIP #280 */
    int *clNext = envPtr->clNext;

    /*
     * Only handle the following versions:







>



>







<







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
				 * created by Tcl_ParseCommand. */
    Command *cmdPtr,		/* Points to defintion of command being
				 * compiled. */
    CompileEnv *envPtr)		/* Holds resulting instructions. */
{
    Tcl_Token *tokenPtr;	/* Pointer to tokens in command. */
    int numWords;		/* Number of words in command. */

    Tcl_Token *valueTokenPtr;	/* Token for the value to switch on. */
    enum {Switch_Exact, Switch_Glob, Switch_Regexp} mode;
				/* What kind of switch are we doing? */

    Tcl_Token *bodyTokenArray;	/* Array of real pattern list items. */
    Tcl_Token **bodyToken;	/* Array of pointers to pattern list items. */
    int *bodyLines;		/* Array of line numbers for body list
				 * items. */
    int **bodyContLines;	/* Array of continuation line info. */
    int noCase;			/* Has the -nocase flag been given? */
    int foundMode = 0;		/* Have we seen a mode flag yet? */

    int i, valueIndex;
    int result = TCL_ERROR;
    DefineLineInformation;	/* TIP #280 */
    int *clNext = envPtr->clNext;

    /*
     * Only handle the following versions:
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
     * that in the case of the quoted bodies, this is tricky as we cannot use
     * copies of the string from the input token for the generated tokens (it
     * causes a crash during exception handling). When multiple tokens are
     * available at this point, this is pretty easy.
     */

    if (numWords == 1) {
	Tcl_DString bodyList;
	const char **argv = NULL, *tokenStartPtr, *p;

	int bline;		/* TIP #280: line of the pattern/action list,
				 * and start of list for when tracking the
				 * location. This list comes immediately after
				 * the value we switch on. */
	int isTokenBraced;

	/*
	 * Test that we've got a suitable body list as a simple (i.e. braced)
	 * word, and that the elements of the body are simple words too. This
	 * is really rather nasty indeed.
	 */

	if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
	    return TCL_ERROR;
	}

	Tcl_DStringInit(&bodyList);
	Tcl_DStringAppend(&bodyList, tokenPtr[1].start, tokenPtr[1].size);
	if (Tcl_SplitList(NULL, Tcl_DStringValue(&bodyList), &numWords,
		&argv) != TCL_OK) {
	    Tcl_DStringFree(&bodyList);
	    return TCL_ERROR;
	}
	Tcl_DStringFree(&bodyList);

	/*
	 * Now we know what the switch arms are, we've got to see whether we
	 * can synthesize tokens for the arms. First check whether we've got a
	 * valid number of arms since we can do that now.
	 */

	if (numWords == 0 || numWords % 2) {
	    ckfree(argv);
	    return TCL_ERROR;
	}

	isListedArms = 1;
	bodyTokenArray = ckalloc(sizeof(Tcl_Token) * numWords);
	bodyToken = ckalloc(sizeof(Tcl_Token *) * numWords);
	bodyLines = ckalloc(sizeof(int) * numWords);
	bodyContLines = ckalloc(sizeof(int*) * numWords);

	/*
	 * Locate the start of the arms within the overall word.
	 */

	bline = mapPtr->loc[eclIndex].line[valueIndex+1];
	p = tokenStartPtr = tokenPtr[1].start;
	while (isspace(UCHAR(*tokenStartPtr))) {
	    tokenStartPtr++;
	}
	if (*tokenStartPtr == '{') {
	    tokenStartPtr++;
	    isTokenBraced = 1;
	} else {
	    isTokenBraced = 0;
	}

	/*

	 * TIP #280: Count lines within the literal list.
	 */

	for (i=0 ; i<numWords ; i++) {

	    bodyTokenArray[i].type = TCL_TOKEN_TEXT;
	    bodyTokenArray[i].start = tokenStartPtr;

	    bodyTokenArray[i].size = strlen(argv[i]);
	    bodyTokenArray[i].numComponents = 0;
	    bodyToken[i] = bodyTokenArray+i;
	    tokenStartPtr += bodyTokenArray[i].size;

	    /*
	     * Test to see if we have guessed the end of the word correctly;
	     * if not, we can't feed the real string to the sub-compilation
	     * engine, and we're then stuck and so have to punt out to doing
	     * everything at runtime.
	     */

	    if ((isTokenBraced && *(tokenStartPtr++) != '}') ||
		    (tokenStartPtr < tokenPtr[1].start+tokenPtr[1].size
		    && !isspace(UCHAR(*tokenStartPtr)))) {
		ckfree(argv);
		goto freeTemporaries;
	    }




	    /*
	     * TIP #280: Now determine the line the list element starts on
	     * (there is no need to do it earlier, due to the possibility of
	     * aborting, see above).
	     */

	    TclAdvanceLines(&bline, p, bodyTokenArray[i].start);
	    TclAdvanceContinuations(&bline, &clNext,
		    bodyTokenArray[i].start - envPtr->source);
	    bodyLines[i] = bline;
	    bodyContLines[i] = clNext;
	    p = bodyTokenArray[i].start;

	    while (isspace(UCHAR(*tokenStartPtr))) {
		tokenStartPtr++;
		if (tokenStartPtr >= tokenPtr[1].start+tokenPtr[1].size) {
		    break;
		}
	    }
	    if (*tokenStartPtr == '{') {

		tokenStartPtr++;
		isTokenBraced = 1;
	    } else {
		isTokenBraced = 0;
	    }
	}
	ckfree(argv);

	/*
	 * Check that we've parsed everything we thought we were going to
	 * parse. If not, something odd is going on (I believe it is possible
	 * to defeat the code above) and we should bail out.
	 */

	if (tokenStartPtr != tokenPtr[1].start+tokenPtr[1].size) {
	    goto freeTemporaries;
	}

    } else if (numWords % 2 || numWords == 0) {
	/*
	 * Odd number of words (>1) available, or no words at all available.
	 * Both are error cases, so punt and let the interpreted-version
	 * generate the error message. Note that the second case probably
	 * should get caught earlier, but it's easy to check here again anyway
	 * because it'd cause a nasty crash otherwise.







<
|
>




<

<
<
<
<
<
<



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


<
<
|
|
|
|
<
<
<
<


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

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







|

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

<







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
     * that in the case of the quoted bodies, this is tricky as we cannot use
     * copies of the string from the input token for the generated tokens (it
     * causes a crash during exception handling). When multiple tokens are
     * available at this point, this is pretty easy.
     */

    if (numWords == 1) {

	const char *bytes;
	int maxLen, numBytes;
	int bline;		/* TIP #280: line of the pattern/action list,
				 * and start of list for when tracking the
				 * location. This list comes immediately after
				 * the value we switch on. */








	if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
	    return TCL_ERROR;
	}
	bytes = tokenPtr[1].start;

	numBytes = tokenPtr[1].size;






	/* Allocate enough space to work in. */





	maxLen = TclMaxListLength(bytes, numBytes, NULL);
	if (maxLen < 2)  {

	    return TCL_ERROR;
	}


	bodyTokenArray = ckalloc(sizeof(Tcl_Token) * maxLen);
	bodyToken = ckalloc(sizeof(Tcl_Token *) * maxLen);
	bodyLines = ckalloc(sizeof(int) * maxLen);
	bodyContLines = ckalloc(sizeof(int*) * maxLen);





	bline = mapPtr->loc[eclIndex].line[valueIndex+1];








	numWords = 0;

	while (numBytes > 0) {

	    const char *prevBytes = bytes;
	    int literal;



	    if (TCL_OK != TclFindElement(NULL, bytes, numBytes,
		    &(bodyTokenArray[numWords].start), &bytes,
		    &(bodyTokenArray[numWords].size), &literal) || !literal) {
	    abort:
		ckfree((char *) bodyToken);
		ckfree((char *) bodyTokenArray);
		ckfree((char *) bodyLines);
		ckfree((char *) bodyContLines);
		return TCL_ERROR;






	    }






	    bodyTokenArray[numWords].type = TCL_TOKEN_TEXT;
	    bodyTokenArray[numWords].numComponents = 0;
	    bodyToken[numWords] = bodyTokenArray + numWords;

	    /*
	     * TIP #280: Now determine the line the list element starts on
	     * (there is no need to do it earlier, due to the possibility of
	     * aborting, see above).
	     */

	    TclAdvanceLines(&bline, prevBytes, bodyTokenArray[numWords].start);
	    TclAdvanceContinuations(&bline, &clNext,
		    bodyTokenArray[numWords].start - envPtr->source);
	    bodyLines[numWords] = bline;
	    bodyContLines[numWords] = clNext;
	    TclAdvanceLines(&bline, bodyTokenArray[numWords].start, bytes);
	    TclAdvanceContinuations(&bline, &clNext, bytes - envPtr->source);







	    numBytes -= (bytes - prevBytes);
	    numWords++;



	}


	if (numWords % 2) {





	    goto abort;


	}

    } else if (numWords % 2 || numWords == 0) {
	/*
	 * Odd number of words (>1) available, or no words at all available.
	 * Both are error cases, so punt and let the interpreted-version
	 * generate the error message. Note that the second case probably
	 * should get caught earlier, but it's easy to check here again anyway
	 * because it'd cause a nasty crash otherwise.
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
	for (i=0 ; i<numWords ; i++) {
	    /*
	     * We only handle the very simplest case. Anything more complex is
	     * a good reason to go to the interpreted case anyway due to
	     * traces, etc.
	     */

	    if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD ||
		    tokenPtr->numComponents != 1) {
		goto freeTemporaries;
	    }
	    bodyToken[i] = tokenPtr+1;

	    /*
	     * TIP #280: Copy line information from regular cmd info.
	     */







|
<







1136
1137
1138
1139
1140
1141
1142
1143

1144
1145
1146
1147
1148
1149
1150
	for (i=0 ; i<numWords ; i++) {
	    /*
	     * We only handle the very simplest case. Anything more complex is
	     * a good reason to go to the interpreted case anyway due to
	     * traces, etc.
	     */

	    if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {

		goto freeTemporaries;
	    }
	    bodyToken[i] = tokenPtr+1;

	    /*
	     * TIP #280: Copy line information from regular cmd info.
	     */
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
     * Now we commit to generating code; the parsing stage per se is done.
     * Check if we can generate a jump table, since if so that's faster than
     * doing an explicit compare with each body. Note that we're definitely
     * over-conservative with determining whether we can do the jump table,
     * but it handles the most common case well enough.
     */

    if ((isListedArms) && (mode == Switch_Exact) && (!noCase)) {
	IssueSwitchJumpTable(interp, envPtr, mapPtr, eclIndex, valueIndex,
		valueTokenPtr, numWords, bodyToken, bodyLines, bodyContLines);
    } else {
	IssueSwitchChainedTests(interp, envPtr, mapPtr, eclIndex, mode,noCase,
		valueIndex, valueTokenPtr, numWords, bodyToken, bodyLines,
		bodyContLines);
    }







|







1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
     * Now we commit to generating code; the parsing stage per se is done.
     * Check if we can generate a jump table, since if so that's faster than
     * doing an explicit compare with each body. Note that we're definitely
     * over-conservative with determining whether we can do the jump table,
     * but it handles the most common case well enough.
     */

    if (mode == Switch_Exact) {
	IssueSwitchJumpTable(interp, envPtr, mapPtr, eclIndex, valueIndex,
		valueTokenPtr, numWords, bodyToken, bodyLines, bodyContLines);
    } else {
	IssueSwitchChainedTests(interp, envPtr, mapPtr, eclIndex, mode,noCase,
		valueIndex, valueTokenPtr, numWords, bodyToken, bodyLines,
		bodyContLines);
    }

Changes to generic/tclCompExpr.c.

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
#define INCOMPLETE	4	/* A parse error. Used only when the single
				 * "=" is encountered.  */
#define INVALID		5	/* A parse error. Used when any punctuation
				 * appears that's not a supported operator. */

/* Leaf lexemes */

#define NUMBER		( LEAF | 1)	/* For literal numbers */


#define SCRIPT		( LEAF | 2)	/* Script substitution; [foo] */

#define BOOLEAN		( LEAF | BAREWORD)	/* For literal booleans */

#define BRACED		( LEAF | 4)	/* Braced string; {foo bar} */

#define VARIABLE	( LEAF | 5)	/* Variable substitution; $x */

#define QUOTED		( LEAF | 6)	/* Quoted string; "foo $bar [soom]" */

#define EMPTY		( LEAF | 7)	/* Used only for an empty argument
					 * list to a function. Represents the
					 * empty string within parens in the
					 * expression: rand() */

/* Unary operator lexemes */

#define UNARY_PLUS	( UNARY | PLUS)
#define UNARY_MINUS	( UNARY | MINUS)
#define FUNCTION	( UNARY | BAREWORD)	/* This is a bit of "creative
					 * interpretation" on the part of the
					 * parser. A function call is parsed
					 * into the parse tree according to
					 * the perspective that the function
					 * name is a unary operator and its
					 * argument list, enclosed in parens,
					 * is its operand. The additional
					 * requirements not implied generally
					 * by treatment as a unary operator --
					 * for example, the requirement that
					 * the operand be enclosed in parens
					 * -- are hard coded in the relevant
					 * portions of ParseExpr(). We trade
					 * off the need to include such
					 * exceptional handling in the code
					 * against the need we would otherwise
					 * have for more lexeme categories. */

#define START		( UNARY | 4)	/* This lexeme isn't parsed from the
					 * expression text at all. It
					 * represents the start of the
					 * expression and sits at the root of
					 * the parse tree where it serves as
					 * the start/end point of
					 * traversals. */
#define OPEN_PAREN	( UNARY | 5)	/* Another bit of creative
					 * interpretation, where we treat "("
					 * as a unary operator with the
					 * sub-expression between it and its
					 * matching ")" as its operand. See
					 * CLOSE_PAREN below. */
#define NOT		( UNARY | 6)
#define BIT_NOT		( UNARY | 7)

/* Binary operator lexemes */

#define BINARY_PLUS	( BINARY |  PLUS)
#define BINARY_MINUS	( BINARY |  MINUS)
#define COMMA		( BINARY |  3)	/* The "," operator is a low
					 * precedence binary operator that
					 * separates the arguments in a
					 * function call. The additional
					 * constraint that this operator can
					 * only legally appear at the right
					 * places within a function call
					 * argument list are hard coded within
					 * ParseExpr().  */
#define MULT		( BINARY |  4)
#define DIVIDE		( BINARY |  5)
#define MOD		( BINARY |  6)
#define LESS		( BINARY |  7)
#define GREATER		( BINARY |  8)
#define BIT_AND		( BINARY |  9)
#define BIT_XOR		( BINARY | 10)
#define BIT_OR		( BINARY | 11)

#define QUESTION	( BINARY | 12)	/* These two lexemes make up the */
#define COLON		( BINARY | 13)	/* ternary conditional operator,
					 * $x ? $y : $z . We treat them as two
					 * binary operators to avoid another
					 * lexeme category, and code the
					 * additional constraints directly in
					 * ParseExpr(). For instance, the
					 * right operand of a "?" operator
					 * must be a ":" operator. */
#define LEFT_SHIFT	( BINARY | 14)
#define RIGHT_SHIFT	( BINARY | 15)
#define LEQ		( BINARY | 16)
#define GEQ		( BINARY | 17)
#define EQUAL		( BINARY | 18)
#define NEQ		( BINARY | 19)
#define AND		( BINARY | 20)
#define OR		( BINARY | 21)
#define STREQ		( BINARY | 22)
#define STRNEQ		( BINARY | 23)

#define EXPON		( BINARY | 24)	/* Unlike the other binary operators,
					 * EXPON is right associative and this
					 * distinction is coded directly in
					 * ParseExpr(). */
#define IN_LIST		( BINARY | 25)
#define NOT_IN_LIST	( BINARY | 26)
#define CLOSE_PAREN	( BINARY | 27)	/* By categorizing the CLOSE_PAREN
					 * lexeme as a BINARY operator, the
					 * normal parsing rules for binary
					 * operators assure that a close paren
					 * will not directly follow another
					 * operator, and the machinery already
					 * in place to connect operands to
					 * operators according to precedence
					 * performs most of the work of
					 * matching open and close parens for
					 * us. In the end though, a close
					 * paren is not really a binary
					 * operator, and some special coding
					 * in ParseExpr() make sure we never
					 * put an actual CLOSE_PAREN node in
					 * the parse tree. The sub-expression
					 * between parens becomes the single
					 * argument of the matching OPEN_PAREN
					 * unary operator. */

#define END		( BINARY | 28)	/* This lexeme represents the end of
					 * the string being parsed. Treating
					 * it as a binary operator follows the
					 * same logic as the CLOSE_PAREN
					 * lexeme and END pairs with START, in
					 * the same way that CLOSE_PAREN pairs
					 * with OPEN_PAREN. */

/*
 * When ParseExpr() builds the parse tree it must choose which operands to
 * connect to which operators.  This is done according to operator precedence.
 * The greater an operator's precedence the greater claim it has to link to
 * an available operand.  The Precedence enumeration lists the precedence
 * values used by Tcl expression operators, from lowest to highest claim.
 * Each precedence level is commented with the operators that hold that
 * precedence.
 */

enum Precedence {
    PREC_END = 1,	/* END */
    PREC_START,		/* START */
    PREC_CLOSE_PAREN,	/* ")" */
    PREC_OPEN_PAREN,	/* "(" */







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



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



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



|
|
|
|
<







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
#define INCOMPLETE	4	/* A parse error. Used only when the single
				 * "=" is encountered.  */
#define INVALID		5	/* A parse error. Used when any punctuation
				 * appears that's not a supported operator. */

/* Leaf lexemes */

#define NUMBER		(LEAF | 1)
				/* For literal numbers */
#define SCRIPT		(LEAF | 2)
				/* Script substitution; [foo] */
#define BOOLEAN		(LEAF | BAREWORD)
				/* For literal booleans */
#define BRACED		(LEAF | 4)
				/* Braced string; {foo bar} */
#define VARIABLE	(LEAF | 5)
				/* Variable substitution; $x */
#define QUOTED		(LEAF | 6)
				/* Quoted string; "foo $bar [soom]" */
#define EMPTY		(LEAF | 7)
				/* Used only for an empty argument list to a
				 * function. Represents the empty string

				 * within parens in the expression: rand() */

/* Unary operator lexemes */

#define UNARY_PLUS	(UNARY | PLUS)
#define UNARY_MINUS	(UNARY | MINUS)
#define FUNCTION	(UNARY | BAREWORD)
				/* This is a bit of "creative interpretation"
				 * on the part of the parser. A function call
				 * is parsed into the parse tree according to
				 * the perspective that the function name is a
				 * unary operator and its argument list,
				 * enclosed in parens, is its operand. The

				 * additional requirements not implied
				 * generally by treatment as a unary operator
				 * -- for example, the requirement that the
				 * operand be enclosed in parens -- are hard
				 * coded in the relevant portions of
				 * ParseExpr(). We trade off the need to

				 * include such exceptional handling in the
				 * code against the need we would otherwise
				 * have for more lexeme categories. */
#define START		(UNARY | 4)
				/* This lexeme isn't parsed from the
				 * expression text at all. It represents the

				 * start of the expression and sits at the
				 * root of the parse tree where it serves as
				 * the start/end point of traversals. */

#define OPEN_PAREN	(UNARY | 5)
				/* Another bit of creative interpretation,
				 * where we treat "(" as a unary operator with
				 * the sub-expression between it and its
				 * matching ")" as its operand. See
				 * CLOSE_PAREN below. */
#define NOT		(UNARY | 6)
#define BIT_NOT		(UNARY | 7)

/* Binary operator lexemes */

#define BINARY_PLUS	(BINARY |  PLUS)
#define BINARY_MINUS	(BINARY |  MINUS)
#define COMMA		(BINARY |  3)
				/* The "," operator is a low precedence binary
				 * operator that separates the arguments in a
				 * function call. The additional constraint
				 * that this operator can only legally appear

				 * at the right places within a function call
				 * argument list are hard coded within
				 * ParseExpr().  */
#define MULT		(BINARY |  4)
#define DIVIDE		(BINARY |  5)
#define MOD		(BINARY |  6)
#define LESS		(BINARY |  7)
#define GREATER		(BINARY |  8)
#define BIT_AND		(BINARY |  9)
#define BIT_XOR		(BINARY | 10)
#define BIT_OR		(BINARY | 11)
#define QUESTION	(BINARY | 12)
				/* These two lexemes make up the */
#define COLON		(BINARY | 13)
				/* ternary conditional operator, $x ? $y : $z.
				 * We treat them as two binary operators to
				 * avoid another lexeme category, and code the
				 * additional constraints directly in
				 * ParseExpr(). For instance, the right
				 * operand of a "?" operator must be a ":"
				 * operator. */
#define LEFT_SHIFT	(BINARY | 14)
#define RIGHT_SHIFT	(BINARY | 15)
#define LEQ		(BINARY | 16)
#define GEQ		(BINARY | 17)
#define EQUAL		(BINARY | 18)
#define NEQ		(BINARY | 19)
#define AND		(BINARY | 20)
#define OR		(BINARY | 21)
#define STREQ		(BINARY | 22)
#define STRNEQ		(BINARY | 23)
#define EXPON		(BINARY | 24)
				/* Unlike the other binary operators, EXPON is
				 * right associative and this distinction is

				 * coded directly in ParseExpr(). */
#define IN_LIST		(BINARY | 25)
#define NOT_IN_LIST	(BINARY | 26)
#define CLOSE_PAREN	(BINARY | 27)
				/* By categorizing the CLOSE_PAREN lexeme as a
				 * BINARY operator, the normal parsing rules
				 * for binary operators assure that a close
				 * paren will not directly follow another
				 * operator, and the machinery already in
				 * place to connect operands to operators
				 * according to precedence performs most of

				 * the work of matching open and close parens
				 * for us. In the end though, a close paren is
				 * not really a binary operator, and some

				 * special coding in ParseExpr() make sure we
				 * never put an actual CLOSE_PAREN node in the
				 * parse tree. The sub-expression between
				 * parens becomes the single argument of the

				 * matching OPEN_PAREN unary operator. */
#define END		(BINARY | 28)
				/* This lexeme represents the end of the
				 * string being parsed. Treating it as a
				 * binary operator follows the same logic as

				 * the CLOSE_PAREN lexeme and END pairs with
				 * START, in the same way that CLOSE_PAREN
				 * pairs with OPEN_PAREN. */

/*
 * When ParseExpr() builds the parse tree it must choose which operands to
 * connect to which operators.  This is done according to operator precedence.
 * The greater an operator's precedence the greater claim it has to link to an
 * available operand.  The Precedence enumeration lists the precedence values
 * used by Tcl expression operators, from lowest to highest claim.  Each
 * precedence level is commented with the operators that hold that precedence.

 */

enum Precedence {
    PREC_END = 1,	/* END */
    PREC_START,		/* START */
    PREC_CLOSE_PAREN,	/* ")" */
    PREC_OPEN_PAREN,	/* "(" */
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
    PREC_ADD,		/* "+", "-" */
    PREC_MULT,		/* "*", "/", "%" */
    PREC_EXPON,		/* "**" */
    PREC_UNARY		/* "+", "-", FUNCTION, "!", "~" */
};

/*
 * Here the same information contained in the comments above is stored
 * in inverted form, so that given a lexeme, one can quickly look up 
 * its precedence value.
 */

static const unsigned char prec[] = {
    /* Non-operator lexemes */
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,







|
|
|







316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
    PREC_ADD,		/* "+", "-" */
    PREC_MULT,		/* "*", "/", "%" */
    PREC_EXPON,		/* "**" */
    PREC_UNARY		/* "+", "-", FUNCTION, "!", "~" */
};

/*
 * Here the same information contained in the comments above is stored in
 * inverted form, so that given a lexeme, one can quickly look up its
 * precedence value.
 */

static const unsigned char prec[] = {
    /* Non-operator lexemes */
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
595
596
597
598
599
600
601

602


603
604
605
606
607
608
609
				 * moment. OT_EMPTY is a nonsense value used
				 * only to silence compiler warnings. During a
				 * parse, complete will always hold an index
				 * or an OperandTypes value pointing to an
				 * actual leaf at the time the complete tree
				 * is needed. */


    /* These variables control generation of the error message. */


    Tcl_Obj *msg = NULL;	/* The error message. */
    Tcl_Obj *post = NULL;	/* In a few cases, an additional postscript
				 * for the error message, supplying more
				 * information after the error msg and
				 * location have been reported. */
    const char *errCode = NULL;	/* The detail word of the errorCode list, or
				 * NULL to indicate that no changes to the







>
|
>
>







595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
				 * moment. OT_EMPTY is a nonsense value used
				 * only to silence compiler warnings. During a
				 * parse, complete will always hold an index
				 * or an OperandTypes value pointing to an
				 * actual leaf at the time the complete tree
				 * is needed. */

    /*
     * These variables control generation of the error message.
     */

    Tcl_Obj *msg = NULL;	/* The error message. */
    Tcl_Obj *post = NULL;	/* In a few cases, an additional postscript
				 * for the error message, supplying more
				 * information after the error msg and
				 * location have been reported. */
    const char *errCode = NULL;	/* The detail word of the errorCode list, or
				 * NULL to indicate that no changes to the
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
    while (1) {
	OpNode *nodePtr;	/* Points to the OpNode we may fill this pass
				 * through the loop. */
	unsigned char lexeme;	/* The lexeme we parse this iteration. */
	Tcl_Obj *literal;	/* Filled by the ParseLexeme() call when a
				 * literal is parsed that has a Tcl_Obj rep
				 * worth preserving. */
	const char *lastStart = start - scanned;
				/* Compute where the lexeme parsed the
				 * previous pass through the loop began. This
				 * is helpful for detecting invalid octals and
				 * providing more complete error messages. */

	/*
	 * Each pass through this loop adds up to one more OpNode. Allocate
	 * space for one if required.
	 */

	if (nodesUsed >= nodesAvailable) {







<
<
<
<
<







658
659
660
661
662
663
664





665
666
667
668
669
670
671
    while (1) {
	OpNode *nodePtr;	/* Points to the OpNode we may fill this pass
				 * through the loop. */
	unsigned char lexeme;	/* The lexeme we parse this iteration. */
	Tcl_Obj *literal;	/* Filled by the ParseLexeme() call when a
				 * literal is parsed that has a Tcl_Obj rep
				 * worth preserving. */






	/*
	 * Each pass through this loop adds up to one more OpNode. Allocate
	 * space for one if required.
	 */

	if (nodesUsed >= nodesAvailable) {
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
			    (scanned < limit) ? scanned : limit - 3,
			    start, (scanned < limit) ? "" : "...",
			    (scanned < limit) ? scanned : limit - 3,
			    start, (scanned < limit) ? "" : "...");
		    Tcl_AppendPrintfToObj(post, " or \"%.*s%s(...)\" or ...",
			    (scanned < limit) ? scanned : limit - 3,
			    start, (scanned < limit) ? "" : "...");
		    if (NotOperator(lastParsed)) {
			errCode = "BADNUMBER";
			if ((lastStart[0] == '0')
				&& ((lastStart[1] == 'o')
				|| (lastStart[1] == 'O'))
				&& (lastStart[2] >= '0')
				&& (lastStart[2] <= '9')) {
			    const char *end = lastStart + 2;
			    Tcl_Obj *copy;


			    while (isdigit(UCHAR(*end))) {


				end++;
			    }






			    copy = Tcl_NewStringObj(lastStart, end-lastStart);
			    if (TclCheckBadOctal(NULL, Tcl_GetString(copy))) {






				Tcl_AppendToObj(post,
					" (invalid octal number?)", -1);

				errCode = "BADNUMBER";
				subErrCode = "OCTAL";
			    }
			    Tcl_DecrRefCount(copy);

			}
			scanned = 0;
			insertMark = 1;
			parsePtr->errorType = TCL_PARSE_BAD_NUMBER;
		    } else {
			errCode = "BAREWORD";

		    }
		    goto error;
		}
		break;
	    case PLUS:
	    case MINUS:
		if (IsOperator(lastParsed)) {
		    /*
		     * A "+" or "-" coming just after another operator must be
		     * interpreted as a unary operator.
		     */

		    lexeme |= UNARY;
		} else {
		    lexeme |= BINARY;
		}
	    }
	}	/* Uncategorized lexemes */


	/* Handle lexeme based on its category. */


	switch (NODE_TYPE & lexeme) {

	/*
	 * Each LEAF results in either a literal getting appended to the
	 * litList, or a sequence of Tcl_Tokens representing a Tcl word
	 * getting appended to the parsePtr->tokens. No OpNode is filled for
	 * this lexeme.
	 */

	case LEAF: {
	    Tcl_Token *tokenPtr;
	    const char *end = start;
	    int wordIndex;
	    int code = TCL_OK;

	    /*
	     * A leaf operand appearing just after something that's not an
	     * operator is a syntax error.
	     */

	    if (NotOperator(lastParsed)) {
		msg = Tcl_ObjPrintf("missing operator at %s", mark);
		errCode = "MISSING";
		if (lastStart[0] == '0') {
		    Tcl_Obj *copy = Tcl_NewStringObj(lastStart,
			    start + scanned - lastStart);

		    if (TclCheckBadOctal(NULL, Tcl_GetString(copy))) {
			TclNewLiteralStringObj(post,
				"looks like invalid octal number");
			errCode = "BADNUMBER_OCTAL";
		    }
		    Tcl_DecrRefCount(copy);
		}
		scanned = 0;
		insertMark = 1;
		parsePtr->errorType = TCL_PARSE_BAD_NUMBER;


		/* Free any literal to avoid a memleak. */


		if ((lexeme == NUMBER) || (lexeme == BOOLEAN)) {
		    Tcl_DecrRefCount(literal);
		}
		goto error;
	    }

	    switch (lexeme) {







<
|
|
<
<
<
<
|
|
>

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



















>
|
>
>

|
|
|
|
|
|
|

<













<
<
<
<
<
<
<
<
<
<
<


<

>
|
>
>







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
			    (scanned < limit) ? scanned : limit - 3,
			    start, (scanned < limit) ? "" : "...",
			    (scanned < limit) ? scanned : limit - 3,
			    start, (scanned < limit) ? "" : "...");
		    Tcl_AppendPrintfToObj(post, " or \"%.*s%s(...)\" or ...",
			    (scanned < limit) ? scanned : limit - 3,
			    start, (scanned < limit) ? "" : "...");

		    errCode = "BAREWORD";
		    if (start[0] == '0') {




			const char *stop;
			TclParseNumber(NULL, NULL, NULL, start, scanned,
				&stop, TCL_PARSE_NO_WHITESPACE);

			if (isdigit(UCHAR(*stop)) || (stop == start + 1)) {
			    switch (start[1]) {
			    case 'b':
				Tcl_AppendToObj(post,

					" (invalid binary number?)", -1);
				parsePtr->errorType = TCL_PARSE_BAD_NUMBER;
				errCode = "BADNUMBER";
				subErrCode = "BINARY";
				break;
			    case 'o':
				Tcl_AppendToObj(post,
					" (invalid octal number?)", -1);
				parsePtr->errorType = TCL_PARSE_BAD_NUMBER;
				errCode = "BADNUMBER";
				subErrCode = "OCTAL";
				break;
			    default:
				if (isdigit(UCHAR(start[1]))) {
				    Tcl_AppendToObj(post,
					    " (invalid octal number?)", -1);
				    parsePtr->errorType = TCL_PARSE_BAD_NUMBER;
				    errCode = "BADNUMBER";
				    subErrCode = "OCTAL";
				}

				break;
			    }





			}
		    }
		    goto error;
		}
		break;
	    case PLUS:
	    case MINUS:
		if (IsOperator(lastParsed)) {
		    /*
		     * A "+" or "-" coming just after another operator must be
		     * interpreted as a unary operator.
		     */

		    lexeme |= UNARY;
		} else {
		    lexeme |= BINARY;
		}
	    }
	}	/* Uncategorized lexemes */

	/*
	 * Handle lexeme based on its category.
	 */

	switch (NODE_TYPE & lexeme) {
	case LEAF: {
	    /*
	     * Each LEAF results in either a literal getting appended to the
	     * litList, or a sequence of Tcl_Tokens representing a Tcl word
	     * getting appended to the parsePtr->tokens. No OpNode is filled
	     * for this lexeme.
	     */


	    Tcl_Token *tokenPtr;
	    const char *end = start;
	    int wordIndex;
	    int code = TCL_OK;

	    /*
	     * A leaf operand appearing just after something that's not an
	     * operator is a syntax error.
	     */

	    if (NotOperator(lastParsed)) {
		msg = Tcl_ObjPrintf("missing operator at %s", mark);
		errCode = "MISSING";











		scanned = 0;
		insertMark = 1;


		/*
		 * Free any literal to avoid a memleak.
		 */

		if ((lexeme == NUMBER) || (lexeme == BOOLEAN)) {
		    Tcl_DecrRefCount(literal);
		}
		goto error;
	    }

	    switch (lexeme) {
1034
1035
1036
1037
1038
1039
1040

1041


1042
1043
1044
1045
1046
1047
1048
		msg = Tcl_ObjPrintf("missing operator at %s", mark);
		scanned = 0;
		insertMark = 1;
		errCode = "MISSING";
		goto error;
	    }


	    /* Create an OpNode for the unary operator */


	    nodePtr->lexeme = lexeme;
	    nodePtr->precedence = prec[lexeme];
	    nodePtr->mark = MARK_RIGHT;

	    /*
	     * A FUNCTION cannot be a constant expression, because Tcl allows
	     * functions to return variable results with the same arguments;







>
|
>
>







1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
		msg = Tcl_ObjPrintf("missing operator at %s", mark);
		scanned = 0;
		insertMark = 1;
		errCode = "MISSING";
		goto error;
	    }

	    /*
	     * Create an OpNode for the unary operator.
	     */

	    nodePtr->lexeme = lexeme;
	    nodePtr->precedence = prec[lexeme];
	    nodePtr->mark = MARK_RIGHT;

	    /*
	     * A FUNCTION cannot be a constant expression, because Tcl allows
	     * functions to return variable results with the same arguments;
1505
1506
1507
1508
1509
1510
1511

1512


1513
1514
1515
1516
1517
1518
1519
	case OT_EMPTY:

	    /* No tokens and no characters for the OT_EMPTY leaf. */
	    break;

	case OT_LITERAL:


	    /* Skip any white space that comes before the literal */


	    scanned = TclParseAllWhiteSpace(start, numBytes);
	    start += scanned;
	    numBytes -= scanned;

	    /*
	     * Reparse the literal to get pointers into source string.
	     */







>
|
>
>







1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
	case OT_EMPTY:

	    /* No tokens and no characters for the OT_EMPTY leaf. */
	    break;

	case OT_LITERAL:

	    /*
	     * Skip any white space that comes before the literal.
	     */

	    scanned = TclParseAllWhiteSpace(start, numBytes);
	    start += scanned;
	    numBytes -= scanned;

	    /*
	     * Reparse the literal to get pointers into source string.
	     */
1588
1589
1590
1591
1592
1593
1594

1595


1596
1597
1598
1599
1600
1601
1602
	    numBytes -= scanned;
	    tokenPtr += toCopy;
	    break;
	}

	default:


	    /* Advance to the child node, which is an operator. */


	    nodePtr = nodes + next;

	    /*
	     * Skip any white space that comes before the subexpression.
	     */

	    scanned = TclParseAllWhiteSpace(start, numBytes);







>
|
>
>







1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
	    numBytes -= scanned;
	    tokenPtr += toCopy;
	    break;
	}

	default:

	    /*
	     * Advance to the child node, which is an operator.
	     */

	    nodePtr = nodes + next;

	    /*
	     * Skip any white space that comes before the subexpression.
	     */

	    scanned = TclParseAllWhiteSpace(start, numBytes);
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
	case MARK_LEFT:
	    next = nodePtr->left;
	    break;

	case MARK_RIGHT:
	    next = nodePtr->right;


	    /* Skip any white space that comes before the operator */


	    scanned = TclParseAllWhiteSpace(start, numBytes);
	    start += scanned;
	    numBytes -= scanned;

	    /*
	     * Here we scan from the string the operator corresponding to
	     * nodePtr->lexeme.
	     */

	    scanned = ParseLexeme(start, numBytes, &lexeme, NULL);

	    switch(nodePtr->lexeme) {
	    case OPEN_PAREN:
	    case COMMA:
	    case COLON:


		/* No tokens for these lexemes -> nothing to do. */


		break;

	    default:

		/*
		 * Record in the TCL_TOKEN_OPERATOR token the pointers into
		 * the string marking where the operator is.







>
|
>
>
















>
|
>
>







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
	case MARK_LEFT:
	    next = nodePtr->left;
	    break;

	case MARK_RIGHT:
	    next = nodePtr->right;

	    /*
	     * Skip any white space that comes before the operator.
	     */

	    scanned = TclParseAllWhiteSpace(start, numBytes);
	    start += scanned;
	    numBytes -= scanned;

	    /*
	     * Here we scan from the string the operator corresponding to
	     * nodePtr->lexeme.
	     */

	    scanned = ParseLexeme(start, numBytes, &lexeme, NULL);

	    switch(nodePtr->lexeme) {
	    case OPEN_PAREN:
	    case COMMA:
	    case COLON:

		/*
		 * No tokens for these lexemes -> nothing to do.
		 */

		break;

	    default:

		/*
		 * Record in the TCL_TOKEN_OPERATOR token the pointers into
		 * the string marking where the operator is.
1721
1722
1723
1724
1725
1726
1727

1728


1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
	    case COLON:

		/* No tokens for these lexemes -> nothing to do. */
		break;

	    case OPEN_PAREN:


		/* Skip past matching close paren. */


		scanned = TclParseAllWhiteSpace(start, numBytes);
		start += scanned;
		numBytes -= scanned;
		scanned = ParseLexeme(start, numBytes, &lexeme, NULL);
		start += scanned;
		numBytes -= scanned;
		break;

	    default: {

		/*
		 * Before we leave this node/operator/subexpression for the
		 * last time, finish up its tokens....
		 * 
		 * Our current position scanning the string is where the
		 * substring for the subexpression ends.







>
|
>
>








|







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
	    case COLON:

		/* No tokens for these lexemes -> nothing to do. */
		break;

	    case OPEN_PAREN:

		/*
		 * Skip past matching close paren.
		 */

		scanned = TclParseAllWhiteSpace(start, numBytes);
		start += scanned;
		numBytes -= scanned;
		scanned = ParseLexeme(start, numBytes, &lexeme, NULL);
		start += scanned;
		numBytes -= scanned;
		break;

	    default:

		/*
		 * Before we leave this node/operator/subexpression for the
		 * last time, finish up its tokens....
		 * 
		 * Our current position scanning the string is where the
		 * substring for the subexpression ends.
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
		 * fill in the zero numComponents for the operator Tcl_Token.
		 */

		parentIdx = subExprTokenPtr[1].numComponents;
		subExprTokenPtr[1].numComponents = 0;
		subExprTokenIdx = parentIdx;
		break;
	    }
	    }

	    /*
	     * Since we're returning to parent, skip child handling code.
	     */

	    nodePtr = nodes + nodePtr->p.parent;







<







1778
1779
1780
1781
1782
1783
1784

1785
1786
1787
1788
1789
1790
1791
		 * fill in the zero numComponents for the operator Tcl_Token.
		 */

		parentIdx = subExprTokenPtr[1].numComponents;
		subExprTokenPtr[1].numComponents = 0;
		subExprTokenIdx = parentIdx;
		break;

	    }

	    /*
	     * Since we're returning to parent, skip child handling code.
	     */

	    nodePtr = nodes + nodePtr->p.parent;
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
	    }
	}
    }

    literal = Tcl_NewObj();
    if (TclParseNumber(NULL, literal, NULL, start, numBytes, &end,
	    TCL_PARSE_NO_WHITESPACE) == TCL_OK) {




	TclInitStringRep(literal, start, end-start);
	*lexemePtr = NUMBER;
	if (literalPtr) {
	    *literalPtr = literal;
	} else {
	    Tcl_DecrRefCount(literal);
	}
	return (end-start);





































    }

    if (Tcl_UtfCharComplete(start, numBytes)) {
	scanned = Tcl_UtfToUniChar(start, &ch);
    } else {
	char utfBytes[TCL_UTF_MAX];

	memcpy(utfBytes, start, (size_t) numBytes);
	utfBytes[numBytes] = '\0';
	scanned = Tcl_UtfToUniChar(utfBytes, &ch);
    }
    if (!isalpha(UCHAR(ch))) {
	*lexemePtr = INVALID;
	Tcl_DecrRefCount(literal);
	return scanned;
    }
    end = start;
    while (isalnum(UCHAR(ch)) || (UCHAR(ch) == '_')) {
	end += scanned;







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











|







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
	    }
	}
    }

    literal = Tcl_NewObj();
    if (TclParseNumber(NULL, literal, NULL, start, numBytes, &end,
	    TCL_PARSE_NO_WHITESPACE) == TCL_OK) {
	if (end < start + numBytes && !isalnum(UCHAR(*end))
		&& UCHAR(*end) != '_') {
	
	number:
	    TclInitStringRep(literal, start, end-start);
	    *lexemePtr = NUMBER;
	    if (literalPtr) {
		*literalPtr = literal;
	    } else {
		Tcl_DecrRefCount(literal);
	    }
	    return (end-start);
	} else {
	    unsigned char lexeme;

	    /*
	     * We have a number followed directly by bareword characters
	     * (alpha, digit, underscore).  Is this a number followed by
	     * bareword syntax error?  Or should we join into one bareword?
	     * Example: Inf + luence + () becomes a valid function call.
	     * [Bug 3401704]
	     */
	    if (literal->typePtr == &tclDoubleType) {
		const char *p = start;

		while (p < end) {
		    if (!isalnum(UCHAR(*p++))) {
			/*
			 * The number has non-bareword characters, so we 
			 * must treat it as a number.
			 */
			goto number;
		    }
		}
	    }
	    ParseLexeme(end, numBytes-(end-start), &lexeme, NULL);
	    if ((NODE_TYPE & lexeme) == BINARY) {
		/*
		 * The bareword characters following the number take the
		 * form of an operator (eq, ne, in, ni, ...) so we treat
		 * as number + operator.
		 */
		goto number;
	    }

	    /*
	     * Otherwise, fall through and parse the whole as a bareword.
	     */
	}
    }

    if (Tcl_UtfCharComplete(start, numBytes)) {
	scanned = Tcl_UtfToUniChar(start, &ch);
    } else {
	char utfBytes[TCL_UTF_MAX];

	memcpy(utfBytes, start, (size_t) numBytes);
	utfBytes[numBytes] = '\0';
	scanned = Tcl_UtfToUniChar(utfBytes, &ch);
    }
    if (!isalnum(UCHAR(ch))) {
	*lexemePtr = INVALID;
	Tcl_DecrRefCount(literal);
	return scanned;
    }
    end = start;
    while (isalnum(UCHAR(ch)) || (UCHAR(ch) == '_')) {
	end += scanned;
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
		 */

		nodePtr->left = numWords;
		numWords = 2;	/* Command plus one argument */
		break;
	    }
	    case QUESTION:
		TclEmitForwardJump(envPtr, TCL_FALSE_JUMP, &(jumpPtr->jump));
		break;
	    case COLON:
		CLANG_ASSERT(jumpPtr);
		TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP,
			&(jumpPtr->next->jump));
		envPtr->currStackDepth = jumpPtr->depth;
		jumpPtr->offset = (envPtr->codeNext - envPtr->codeStart);
		jumpPtr->convert = convert;
		convert = 1;
		break;
	    case AND:
		TclEmitForwardJump(envPtr, TCL_FALSE_JUMP, &(jumpPtr->jump));
		break;
	    case OR:
		TclEmitForwardJump(envPtr, TCL_TRUE_JUMP, &(jumpPtr->jump));
		break;
	    }
	} else {
	    switch (nodePtr->lexeme) {
	    case START:
	    case QUESTION:
		if (convert && (nodePtr == rootPtr)) {







|




|






|


|







2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
		 */

		nodePtr->left = numWords;
		numWords = 2;	/* Command plus one argument */
		break;
	    }
	    case QUESTION:
		TclEmitForwardJump(envPtr, TCL_FALSE_JUMP, &jumpPtr->jump);
		break;
	    case COLON:
		CLANG_ASSERT(jumpPtr);
		TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP,
			&jumpPtr->next->jump);
		envPtr->currStackDepth = jumpPtr->depth;
		jumpPtr->offset = (envPtr->codeNext - envPtr->codeStart);
		jumpPtr->convert = convert;
		convert = 1;
		break;
	    case AND:
		TclEmitForwardJump(envPtr, TCL_FALSE_JUMP, &jumpPtr->jump);
		break;
	    case OR:
		TclEmitForwardJump(envPtr, TCL_TRUE_JUMP, &jumpPtr->jump);
		break;
	    }
	} else {
	    switch (nodePtr->lexeme) {
	    case START:
	    case QUESTION:
		if (convert && (nodePtr == rootPtr)) {
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376

2377
2378
2379
2380
2381
2382
2383
		 * Each comma implies another function argument.
		 */

		numWords++;
		break;
	    case COLON:
		CLANG_ASSERT(jumpPtr);
		if (TclFixupForwardJump(envPtr, &(jumpPtr->next->jump),
			(envPtr->codeNext - envPtr->codeStart)
			- jumpPtr->next->jump.codeOffset, 127)) {
		    jumpPtr->offset += 3;
		}
		TclFixupForwardJump(envPtr, &(jumpPtr->jump),
			jumpPtr->offset - jumpPtr->jump.codeOffset, 127);
		convert |= jumpPtr->convert;
		envPtr->currStackDepth = jumpPtr->depth + 1;
		freePtr = jumpPtr;
		jumpPtr = jumpPtr->next;
		TclStackFree(interp, freePtr);
		freePtr = jumpPtr;
		jumpPtr = jumpPtr->next;
		TclStackFree(interp, freePtr);
		break;
	    case AND:
	    case OR:
		CLANG_ASSERT(jumpPtr);
		TclEmitForwardJump(envPtr, (nodePtr->lexeme == AND)
			?  TCL_FALSE_JUMP : TCL_TRUE_JUMP,
			&(jumpPtr->next->jump));
		TclEmitPush(TclRegisterNewLiteral(envPtr,
			(nodePtr->lexeme == AND) ? "1" : "0", 1), envPtr);
		TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP,
			&(jumpPtr->next->next->jump));
		TclFixupForwardJumpToHere(envPtr, &(jumpPtr->next->jump), 127);
		if (TclFixupForwardJumpToHere(envPtr, &(jumpPtr->jump), 127)) {
		    jumpPtr->next->next->jump.codeOffset += 3;
		}
		TclEmitPush(TclRegisterNewLiteral(envPtr,
			(nodePtr->lexeme == AND) ? "0" : "1", 1), envPtr);
		TclFixupForwardJumpToHere(envPtr, &(jumpPtr->next->next->jump),
			127);
		convert = 0;
		envPtr->currStackDepth = jumpPtr->depth + 1;
		freePtr = jumpPtr;
		jumpPtr = jumpPtr->next;
		TclStackFree(interp, freePtr);
		freePtr = jumpPtr;
		jumpPtr = jumpPtr->next;
		TclStackFree(interp, freePtr);
		freePtr = jumpPtr;
		jumpPtr = jumpPtr->next;
		TclStackFree(interp, freePtr);
		break;
	    default:
		TclEmitOpcode(instruction[nodePtr->lexeme], envPtr);
		convert = 0;
		break;
	    }
	    if (nodePtr == rootPtr) {

		/* We're done */

		return;
	    }
	    nodePtr = nodes + nodePtr->p.parent;
	    continue;
	}

	nodePtr->mark++;







|




|















|



|
|
|




|



















<

>







2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429

2430
2431
2432
2433
2434
2435
2436
2437
2438
		 * Each comma implies another function argument.
		 */

		numWords++;
		break;
	    case COLON:
		CLANG_ASSERT(jumpPtr);
		if (TclFixupForwardJump(envPtr, &jumpPtr->next->jump,
			(envPtr->codeNext - envPtr->codeStart)
			- jumpPtr->next->jump.codeOffset, 127)) {
		    jumpPtr->offset += 3;
		}
		TclFixupForwardJump(envPtr, &jumpPtr->jump,
			jumpPtr->offset - jumpPtr->jump.codeOffset, 127);
		convert |= jumpPtr->convert;
		envPtr->currStackDepth = jumpPtr->depth + 1;
		freePtr = jumpPtr;
		jumpPtr = jumpPtr->next;
		TclStackFree(interp, freePtr);
		freePtr = jumpPtr;
		jumpPtr = jumpPtr->next;
		TclStackFree(interp, freePtr);
		break;
	    case AND:
	    case OR:
		CLANG_ASSERT(jumpPtr);
		TclEmitForwardJump(envPtr, (nodePtr->lexeme == AND)
			?  TCL_FALSE_JUMP : TCL_TRUE_JUMP,
			&jumpPtr->next->jump);
		TclEmitPush(TclRegisterNewLiteral(envPtr,
			(nodePtr->lexeme == AND) ? "1" : "0", 1), envPtr);
		TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP,
			&jumpPtr->next->next->jump);
		TclFixupForwardJumpToHere(envPtr, &jumpPtr->next->jump, 127);
		if (TclFixupForwardJumpToHere(envPtr, &jumpPtr->jump, 127)) {
		    jumpPtr->next->next->jump.codeOffset += 3;
		}
		TclEmitPush(TclRegisterNewLiteral(envPtr,
			(nodePtr->lexeme == AND) ? "0" : "1", 1), envPtr);
		TclFixupForwardJumpToHere(envPtr, &jumpPtr->next->next->jump,
			127);
		convert = 0;
		envPtr->currStackDepth = jumpPtr->depth + 1;
		freePtr = jumpPtr;
		jumpPtr = jumpPtr->next;
		TclStackFree(interp, freePtr);
		freePtr = jumpPtr;
		jumpPtr = jumpPtr->next;
		TclStackFree(interp, freePtr);
		freePtr = jumpPtr;
		jumpPtr = jumpPtr->next;
		TclStackFree(interp, freePtr);
		break;
	    default:
		TclEmitOpcode(instruction[nodePtr->lexeme], envPtr);
		convert = 0;
		break;
	    }
	    if (nodePtr == rootPtr) {

		/* We're done */

		return;
	    }
	    nodePtr = nodes + nodePtr->p.parent;
	    continue;
	}

	nodePtr->mark++;
2439
2440
2441
2442
2443
2444
2445

























2446

2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463

2464
2465
2466
2467
2468
2469
2470
	    break;
	default:
	    if (optimize && nodes[next].constant) {
		Tcl_InterpState save = Tcl_SaveInterpState(interp, TCL_OK);

		if (ExecConstantExprTree(interp, nodes, next, litObjvPtr)
			== TCL_OK) {

























		    TclEmitPush(TclAddLiteralObj(envPtr,

			    Tcl_GetObjResult(interp), NULL), envPtr);
		} else {
		    TclCompileSyntaxError(interp, envPtr);
		}
		Tcl_RestoreInterpState(interp, save);
		convert = 0;
	    } else {
		nodePtr = nodes + next;
	    }
	}
    }
}

/*
 *----------------------------------------------------------------------
 *
 * TclSingleOpCmd --

 *	Implements the commands: ~, !, <<, >>, %, !=, ne, in, ni
 *	in the ::tcl::mathop namespace.  These commands have no
 *	extension to arbitrary arguments; they accept only exactly one
 *	or exactly two arguments as suitable for the operator.
 *
 * Results:
 *	A standard Tcl return code and result left in interp.







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
















>







2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
	    break;
	default:
	    if (optimize && nodes[next].constant) {
		Tcl_InterpState save = Tcl_SaveInterpState(interp, TCL_OK);

		if (ExecConstantExprTree(interp, nodes, next, litObjvPtr)
			== TCL_OK) {
		    int index;
		    Tcl_Obj *objPtr = Tcl_GetObjResult(interp);

		    /*
		     * Don't generate a string rep, but if we have one
		     * already, then use it to share via the literal table.
		     */

		    if (objPtr->bytes) {
			Tcl_Obj *tableValue;

			index = TclRegisterNewLiteral(envPtr, objPtr->bytes,
				objPtr->length);
			tableValue = envPtr->literalArrayPtr[index].objPtr;
			if ((tableValue->typePtr == NULL) &&
				(objPtr->typePtr != NULL)) {
			    /*
			     * Same intrep surgery as for OT_LITERAL.
			     */

			    tableValue->typePtr = objPtr->typePtr;
			    tableValue->internalRep = objPtr->internalRep;
			    objPtr->typePtr = NULL;
			}
		    } else {
			index = TclAddLiteralObj(envPtr, objPtr, NULL);
		    }
		    TclEmitPush(index, envPtr);
		} else {
		    TclCompileSyntaxError(interp, envPtr);
		}
		Tcl_RestoreInterpState(interp, save);
		convert = 0;
	    } else {
		nodePtr = nodes + next;
	    }
	}
    }
}

/*
 *----------------------------------------------------------------------
 *
 * TclSingleOpCmd --
 *
 *	Implements the commands: ~, !, <<, >>, %, !=, ne, in, ni
 *	in the ::tcl::mathop namespace.  These commands have no
 *	extension to arbitrary arguments; they accept only exactly one
 *	or exactly two arguments as suitable for the operator.
 *
 * Results:
 *	A standard Tcl return code and result left in interp.
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
    Tcl_Obj *const objv[])
{
    TclOpCmdClientData *occdPtr = clientData;
    unsigned char lexeme;
    OpNode nodes[2];
    Tcl_Obj *const *litObjv = objv + 1;

    if (objc != 1+occdPtr->i.numArgs) {
	Tcl_WrongNumArgs(interp, 1, objv, occdPtr->expected);
	return TCL_ERROR;
    }

    ParseLexeme(occdPtr->op, strlen(occdPtr->op), &lexeme, NULL);
    nodes[0].lexeme = START;
    nodes[0].mark = MARK_RIGHT;







|







2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
    Tcl_Obj *const objv[])
{
    TclOpCmdClientData *occdPtr = clientData;
    unsigned char lexeme;
    OpNode nodes[2];
    Tcl_Obj *const *litObjv = objv + 1;

    if (objc != 1 + occdPtr->i.numArgs) {
	Tcl_WrongNumArgs(interp, 1, objv, occdPtr->expected);
	return TCL_ERROR;
    }

    ParseLexeme(occdPtr->op, strlen(occdPtr->op), &lexeme, NULL);
    nodes[0].lexeme = START;
    nodes[0].mark = MARK_RIGHT;

Changes to generic/tclCompile.c.

417
418
419
420
421
422
423














424
425
426
427
428
429
430
    {"unsetArrayStk",	 2,    -2,        1,	{OPERAND_UINT1}},
	/* Make array element cease to exist; element is stktop, array name is
	 * stknext; op1 is 1 for errors on problems, 0 otherwise */
    {"unsetStk",	 2,    -1,        1,	{OPERAND_UINT1}},
	/* Make general variable cease to exist; unparsed variable name is
	 * stktop; op1 is 1 for errors on problems, 0 otherwise */















    {NULL, 0, 0, 0, {OPERAND_NONE}}
};

/*
 * Prototypes for procedures defined later in this file:
 */








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







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
    {"unsetArrayStk",	 2,    -2,        1,	{OPERAND_UINT1}},
	/* Make array element cease to exist; element is stktop, array name is
	 * stknext; op1 is 1 for errors on problems, 0 otherwise */
    {"unsetStk",	 2,    -1,        1,	{OPERAND_UINT1}},
	/* Make general variable cease to exist; unparsed variable name is
	 * stktop; op1 is 1 for errors on problems, 0 otherwise */

    {"dictExpand",       1,    -1,        0,    {OPERAND_NONE}},
        /* Probe into a dict and extract it (or a subdict of it) into
         * variables with matched names. Produces list of keys bound as
         * result. Part of [dict with].
	 * Stack:  ... dict path => ... keyList */
    {"dictRecombineStk", 1,    -3,        0,    {OPERAND_NONE}},
        /* Map variable contents back into a dictionary in a variable. Part of
         * [dict with].
	 * Stack:  ... dictVarName path keyList => ... */
    {"dictRecombineImm", 1,    -2,        1,    {OPERAND_LVT4}},
        /* Map variable contents back into a dictionary in the local variable
         * indicated by the LVT index. Part of [dict with].
	 * Stack:  ... path keyList => ... */

    {NULL, 0, 0, 0, {OPERAND_NONE}}
};

/*
 * Prototypes for procedures defined later in this file:
 */

505
506
507
508
509
510
511
512

513
514
515
516
517
518
519
520
521
522
523
524
 *
 * TclSetByteCodeFromAny --
 *
 *	Part of the bytecode Tcl object type implementation. Attempts to
 *	generate an byte code internal form for the Tcl object "objPtr" by
 *	compiling its string representation. This function also takes a hook
 *	procedure that will be invoked to perform any needed post processing
 *	on the compilation results before generating byte codes.

 *
 * Results:
 *	The return value is a standard Tcl object result. If an error occurs
 *	during compilation, an error message is left in the interpreter's
 *	result unless "interp" is NULL.
 *
 * Side effects:
 *	Frees the old internal representation. If no error occurs, then the
 *	compiled code is stored as "objPtr"s bytecode representation. Also, if
 *	debugging, initializes the "tcl_traceCompile" Tcl variable used to
 *	trace compilations.
 *







|
>




|







519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
 *
 * TclSetByteCodeFromAny --
 *
 *	Part of the bytecode Tcl object type implementation. Attempts to
 *	generate an byte code internal form for the Tcl object "objPtr" by
 *	compiling its string representation. This function also takes a hook
 *	procedure that will be invoked to perform any needed post processing
 *	on the compilation results before generating byte codes. interp is
 *	compilation context and may not be NULL.
 *
 * Results:
 *	The return value is a standard Tcl object result. If an error occurs
 *	during compilation, an error message is left in the interpreter's
 *	result.
 *
 * Side effects:
 *	Frees the old internal representation. If no error occurs, then the
 *	compiled code is stored as "objPtr"s bytecode representation. Also, if
 *	debugging, initializes the "tcl_traceCompile" Tcl variable used to
 *	trace compilations.
 *
668
669
670
671
672
673
674



675
676
677
678
679
680
681

static int
SetByteCodeFromAny(
    Tcl_Interp *interp,		/* The interpreter for which the code is being
				 * compiled. Must not be NULL. */
    Tcl_Obj *objPtr)		/* The object to make a ByteCode object. */
{



    TclSetByteCodeFromAny(interp, objPtr, NULL, NULL);
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *







>
>
>







683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699

static int
SetByteCodeFromAny(
    Tcl_Interp *interp,		/* The interpreter for which the code is being
				 * compiled. Must not be NULL. */
    Tcl_Obj *objPtr)		/* The object to make a ByteCode object. */
{
    if (interp == NULL) {
	return TCL_ERROR;
    }
    TclSetByteCodeFromAny(interp, objPtr, NULL, NULL);
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
2435
2436
2437
2438
2439
2440
2441



















2442

2443
2444
2445
2446
2447
2448
2449
    p += sizeof(ByteCode);
    codePtr->codeStart = p;
    memcpy(p, envPtr->codeStart, (size_t) codeBytes);

    p += TCL_ALIGN(codeBytes);		/* align object array */
    codePtr->objArrayPtr = (Tcl_Obj **) p;
    for (i = 0;  i < numLitObjects;  i++) {



















	codePtr->objArrayPtr[i] = envPtr->literalArrayPtr[i].objPtr;

    }

    p += TCL_ALIGN(objArrayBytes);	/* align exception range array */
    if (exceptArrayBytes > 0) {
	codePtr->exceptArrayPtr = (ExceptionRange *) p;
	memcpy(p, envPtr->exceptArrayPtr, (size_t) exceptArrayBytes);
    } else {







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







2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
    p += sizeof(ByteCode);
    codePtr->codeStart = p;
    memcpy(p, envPtr->codeStart, (size_t) codeBytes);

    p += TCL_ALIGN(codeBytes);		/* align object array */
    codePtr->objArrayPtr = (Tcl_Obj **) p;
    for (i = 0;  i < numLitObjects;  i++) {
	if (objPtr == envPtr->literalArrayPtr[i].objPtr) {
	    /*
	     * Prevent circular reference where the bytecode intrep of
	     * a value contains a literal which is that same value.
	     * If this is allowed to happen, refcount decrements may not
	     * reach zero, and memory may leak.  Bugs 467523, 3357771
	     *
	     * NOTE:  [Bugs 3392070, 3389764] We make a copy based completely
	     * on the string value, and do not call Tcl_DuplicateObj() so we
             * can be sure we do not have any lingering cycles hiding in
	     * the intrep.
	     */
	    int numBytes;
	    const char *bytes = Tcl_GetStringFromObj(objPtr, &numBytes);

	    codePtr->objArrayPtr[i] = Tcl_NewStringObj(bytes, numBytes);
	    Tcl_IncrRefCount(codePtr->objArrayPtr[i]);
	    Tcl_DecrRefCount(objPtr);
	} else {
	    codePtr->objArrayPtr[i] = envPtr->literalArrayPtr[i].objPtr;
	}
    }

    p += TCL_ALIGN(objArrayBytes);	/* align exception range array */
    if (exceptArrayBytes > 0) {
	codePtr->exceptArrayPtr = (ExceptionRange *) p;
	memcpy(p, envPtr->exceptArrayPtr, (size_t) exceptArrayBytes);
    } else {
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474

    p += auxDataArrayBytes;
#ifndef TCL_COMPILE_DEBUG
    EncodeCmdLocMap(envPtr, codePtr, (unsigned char *) p);
#else
    nextPtr = EncodeCmdLocMap(envPtr, codePtr, (unsigned char *) p);
    if (((size_t)(nextPtr - p)) != cmdLocBytes) {
	Tcl_Panic("TclInitByteCodeObj: encoded cmd location bytes %d != expected size %d", (nextPtr - p), cmdLocBytes);
    }
#endif

    /*
     * Record various compilation-related statistics about the new ByteCode
     * structure. Don't include overhead for statistics-related fields.
     */







|







2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512

    p += auxDataArrayBytes;
#ifndef TCL_COMPILE_DEBUG
    EncodeCmdLocMap(envPtr, codePtr, (unsigned char *) p);
#else
    nextPtr = EncodeCmdLocMap(envPtr, codePtr, (unsigned char *) p);
    if (((size_t)(nextPtr - p)) != cmdLocBytes) {
	Tcl_Panic("TclInitByteCodeObj: encoded cmd location bytes %lu != expected size %lu", (unsigned long)(nextPtr - p), (unsigned long)cmdLocBytes);
    }
#endif

    /*
     * Record various compilation-related statistics about the new ByteCode
     * structure. Don't include overhead for statistics-related fields.
     */
3312
3313
3314
3315
3316
3317
3318
































































3319
3320
3321
3322
3323
3324
3325
	    rangePtr->catchOffset += 3;
	    break;
	default:
	    Tcl_Panic("TclFixupForwardJump: bad ExceptionRange type %d",
		    rangePtr->type);
	}
    }
































































    return 1;			/* the jump was grown */
}

/*
 *----------------------------------------------------------------------
 *
 * TclGetInstructionTable --







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







3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
	    rangePtr->catchOffset += 3;
	    break;
	default:
	    Tcl_Panic("TclFixupForwardJump: bad ExceptionRange type %d",
		    rangePtr->type);
	}
    }

    /*
     * TIP #280: Adjust the mapping from PC values to the per-command
     * information about arguments and their line numbers.
     *
     * Note: We cannot simply remove an out-of-date entry and then reinsert
     * with the proper PC, because then we might overwrite another entry which
     * was at that location. Therefore we pull (copy + delete) all effected
     * entries (beyond the fixed PC) into an array, update them there, and at
     * last reinsert them all.
     */

    {
	ExtCmdLoc* eclPtr = envPtr->extCmdMapPtr;

	/* A helper structure */

	typedef struct {
	    int pc;
	    int cmd;
	} MAP;

	/*
	 * And the helper array. At most the whole hashtable is placed into
	 * this.
	 */

	MAP *map = (MAP*) ckalloc (sizeof(MAP) * eclPtr->litInfo.numEntries);

	Tcl_HashSearch hSearch;
	Tcl_HashEntry* hPtr;
	int n, k, isnew;

	/*
	 * Phase I: Locate the affected entries, and save them in adjusted
	 * form to the array. This removes them from the hash.
	 */

	for (n = 0, hPtr = Tcl_FirstHashEntry(&eclPtr->litInfo, &hSearch);
	     hPtr != NULL;
	     hPtr = Tcl_NextHashEntry(&hSearch)) {

	    map [n].cmd = PTR2INT(Tcl_GetHashValue(hPtr));
	    map [n].pc  = PTR2INT(Tcl_GetHashKey (&eclPtr->litInfo,hPtr));

	    if (map[n].pc >= (jumpFixupPtr->codeOffset + 2)) {
		Tcl_DeleteHashEntry(hPtr);
		map [n].pc += 3;
		n++;
	    }
	}

	/*
	 * Phase II: Re-insert the modified entries into the hash.
	 */

	for (k=0;k<n;k++) {
	    hPtr = Tcl_CreateHashEntry(&eclPtr->litInfo, INT2PTR(map[k].pc), &isnew);
	    Tcl_SetHashValue(hPtr, INT2PTR(map[k].cmd));
	}

	ckfree (map);
    }

    return 1;			/* the jump was grown */
}

/*
 *----------------------------------------------------------------------
 *
 * TclGetInstructionTable --
4362
4363
4364
4365
4366
4367
4368
4369
4370
4371
4372
4373
4374
4375
4376
 * TclNewInstNameObj --
 *
 *	Creates a new InstName Tcl_Obj based on the given instruction
 *
 *----------------------------------------------------------------------
 */

MODULE_SCOPE Tcl_Obj *
TclNewInstNameObj(
    unsigned char inst)
{
    Tcl_Obj *objPtr = Tcl_NewObj();

    objPtr->typePtr = &tclInstNameType;
    objPtr->internalRep.longValue = (long) inst;







|







4464
4465
4466
4467
4468
4469
4470
4471
4472
4473
4474
4475
4476
4477
4478
 * TclNewInstNameObj --
 *
 *	Creates a new InstName Tcl_Obj based on the given instruction
 *
 *----------------------------------------------------------------------
 */

Tcl_Obj *
TclNewInstNameObj(
    unsigned char inst)
{
    Tcl_Obj *objPtr = Tcl_NewObj();

    objPtr->typePtr = &tclInstNameType;
    objPtr->internalRep.longValue = (long) inst;
4487
4488
4489
4490
4491
4492
4493





4494
4495
4496
4497
4498
4499
4500
void
RecordByteCodeStats(
    ByteCode *codePtr)		/* Points to ByteCode structure with info
				 * to add to accumulated statistics. */
{
    Interp *iPtr = (Interp *) *codePtr->interpHandle;
    register ByteCodeStats *statsPtr = &iPtr->stats;






    statsPtr->numCompilations++;
    statsPtr->totalSrcBytes += (double) codePtr->numSrcBytes;
    statsPtr->totalByteCodeBytes += (double) codePtr->structureSize;
    statsPtr->currentSrcBytes += (double) codePtr->numSrcBytes;
    statsPtr->currentByteCodeBytes += (double) codePtr->structureSize;








>
>
>
>
>







4589
4590
4591
4592
4593
4594
4595
4596
4597
4598
4599
4600
4601
4602
4603
4604
4605
4606
4607
void
RecordByteCodeStats(
    ByteCode *codePtr)		/* Points to ByteCode structure with info
				 * to add to accumulated statistics. */
{
    Interp *iPtr = (Interp *) *codePtr->interpHandle;
    register ByteCodeStats *statsPtr = &iPtr->stats;

    if (iPtr == NULL) {
	/* Avoid segfaulting in case we're called in a deleted interp */
	return;
    }

    statsPtr->numCompilations++;
    statsPtr->totalSrcBytes += (double) codePtr->numSrcBytes;
    statsPtr->totalByteCodeBytes += (double) codePtr->structureSize;
    statsPtr->currentSrcBytes += (double) codePtr->numSrcBytes;
    statsPtr->currentByteCodeBytes += (double) codePtr->structureSize;

Changes to generic/tclCompile.h.

672
673
674
675
676
677
678




679
680
681
682
683
684
685
686
687

/* For [unset] compilation */
#define INST_UNSET_SCALAR		134
#define INST_UNSET_ARRAY		135
#define INST_UNSET_ARRAY_STK		136
#define INST_UNSET_STK			137





/* The last opcode */
#define LAST_INST_OPCODE		137

/*
 * Table describing the Tcl bytecode instructions: their name (for displaying
 * code), total number of code bytes required (including operand bytes), and a
 * description of the type of each operand. These operand types include signed
 * and unsigned integers of length one and four bytes. The unsigned integers
 * are used for indexes or for, e.g., the count of objects to push in a "push"







>
>
>
>

|







672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691

/* For [unset] compilation */
#define INST_UNSET_SCALAR		134
#define INST_UNSET_ARRAY		135
#define INST_UNSET_ARRAY_STK		136
#define INST_UNSET_STK			137

#define INST_DICT_EXPAND		138
#define INST_DICT_RECOMBINE_STK		139
#define INST_DICT_RECOMBINE_IMM		140

/* The last opcode */
#define LAST_INST_OPCODE		140

/*
 * Table describing the Tcl bytecode instructions: their name (for displaying
 * code), total number of code bytes required (including operand bytes), and a
 * description of the type of each operand. These operand types include signed
 * and unsigned integers of length one and four bytes. The unsigned integers
 * are used for indexes or for, e.g., the count of objects to push in a "push"

Changes to generic/tclConfig.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
	    Tcl_SetResult(interp, "insufficient memory to create list",
		    TCL_STATIC);
	    Tcl_SetErrorCode(interp, "TCL", "MEMORY", NULL);
	    return TCL_ERROR;
	}

	if (n) {
	    List *listRepPtr = (List *)
		    listPtr->internalRep.twoPtrValue.ptr1;
	    Tcl_DictSearch s;
	    Tcl_Obj *key, **vals;
	    int done, i = 0;

	    listRepPtr->elemCount = n;
	    vals = &listRepPtr->elements;

	    for (Tcl_DictObjFirst(interp, pkgDict, &s, &key, NULL, &done);
		    !done; Tcl_DictObjNext(&s, &key, NULL, &done)) {
		vals[i++] = key;
		Tcl_IncrRefCount(key);
	    }
	}

	Tcl_SetObjResult(interp, listPtr);
	return TCL_OK;

    default:







<
<

|
|
<
<
<



|
<







273
274
275
276
277
278
279


280
281
282



283
284
285
286

287
288
289
290
291
292
293
	    Tcl_SetResult(interp, "insufficient memory to create list",
		    TCL_STATIC);
	    Tcl_SetErrorCode(interp, "TCL", "MEMORY", NULL);
	    return TCL_ERROR;
	}

	if (n) {


	    Tcl_DictSearch s;
	    Tcl_Obj *key;
	    int done;




	    for (Tcl_DictObjFirst(interp, pkgDict, &s, &key, NULL, &done);
		    !done; Tcl_DictObjNext(&s, &key, NULL, &done)) {
		Tcl_ListObjAppendElement(NULL, listPtr, key);

	    }
	}

	Tcl_SetObjResult(interp, listPtr);
	return TCL_OK;

    default:

Changes to generic/tclDTrace.d.

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
    /*
     *	tcl*:::proc-entry probe
     *	    triggered immediately before proc bytecode execution
     *		arg0: proc name				(string)
     *		arg1: number of arguments		(int)
     *		arg2: array of proc argument objects	(Tcl_Obj**)
     */
    probe proc__entry(TclDTraceStr name, int objc, Tcl_Obj **objv);
    /*
     *	tcl*:::proc-return probe
     *	    triggered immediately after proc bytecode execution
     *		arg0: proc name				(string)
     *		arg1: return code			(int)
     */
    probe proc__return(TclDTraceStr name, int code);
    /*
     *	tcl*:::proc-result probe
     *	    triggered after proc-return probe and result processing
     *		arg0: proc name				(string)
     *		arg1: return code			(int)
     *		arg2: proc result			(string)
     *		arg3: proc result object		(Tcl_Obj*)
     */
    probe proc__result(TclDTraceStr name, int code, TclDTraceStr result,
	    Tcl_Obj *resultobj);
    /*
     *	tcl*:::proc-args probe
     *	    triggered before proc-entry probe, gives access to string
     *	    representation of proc arguments
     *		arg0: proc name				(string)
     *		arg1-arg9: proc arguments or NULL	(strings)
     */







|
















|







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
    /*
     *	tcl*:::proc-entry probe
     *	    triggered immediately before proc bytecode execution
     *		arg0: proc name				(string)
     *		arg1: number of arguments		(int)
     *		arg2: array of proc argument objects	(Tcl_Obj**)
     */
    probe proc__entry(TclDTraceStr name, int objc, struct Tcl_Obj **objv);
    /*
     *	tcl*:::proc-return probe
     *	    triggered immediately after proc bytecode execution
     *		arg0: proc name				(string)
     *		arg1: return code			(int)
     */
    probe proc__return(TclDTraceStr name, int code);
    /*
     *	tcl*:::proc-result probe
     *	    triggered after proc-return probe and result processing
     *		arg0: proc name				(string)
     *		arg1: return code			(int)
     *		arg2: proc result			(string)
     *		arg3: proc result object		(Tcl_Obj*)
     */
    probe proc__result(TclDTraceStr name, int code, TclDTraceStr result,
	    struct Tcl_Obj *resultobj);
    /*
     *	tcl*:::proc-args probe
     *	    triggered before proc-entry probe, gives access to string
     *	    representation of proc arguments
     *		arg0: proc name				(string)
     *		arg1-arg9: proc arguments or NULL	(strings)
     */
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
    /*
     *	tcl*:::cmd-entry probe
     *	    triggered immediately before commmand execution
     *		arg0: command name			(string)
     *		arg1: number of arguments		(int)
     *		arg2: array of command argument objects	(Tcl_Obj**)
     */
    probe cmd__entry(TclDTraceStr name, int objc, Tcl_Obj **objv);
    /*
     *	tcl*:::cmd-return probe
     *	    triggered immediately after commmand execution
     *		arg0: command name			(string)
     *		arg1: return code			(int)
     */
    probe cmd__return(TclDTraceStr name, int code);
    /*
     *	tcl*:::cmd-result probe
     *	    triggered after cmd-return probe and result processing
     *		arg0: command name			(string)
     *		arg1: return code			(int)
     *		arg2: command result			(string)
     *		arg3: command result object		(Tcl_Obj*)
     */
    probe cmd__result(TclDTraceStr name, int code, TclDTraceStr result,
	    Tcl_Obj *resultobj);
    /*
     *	tcl*:::cmd-args probe
     *	    triggered before cmd-entry probe, gives access to string
     *	    representation of command arguments
     *		arg0: command name			(string)
     *		arg1-arg9: command arguments or NULL	(strings)
     */







|
















|







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
    /*
     *	tcl*:::cmd-entry probe
     *	    triggered immediately before commmand execution
     *		arg0: command name			(string)
     *		arg1: number of arguments		(int)
     *		arg2: array of command argument objects	(Tcl_Obj**)
     */
    probe cmd__entry(TclDTraceStr name, int objc, struct Tcl_Obj **objv);
    /*
     *	tcl*:::cmd-return probe
     *	    triggered immediately after commmand execution
     *		arg0: command name			(string)
     *		arg1: return code			(int)
     */
    probe cmd__return(TclDTraceStr name, int code);
    /*
     *	tcl*:::cmd-result probe
     *	    triggered after cmd-return probe and result processing
     *		arg0: command name			(string)
     *		arg1: return code			(int)
     *		arg2: command result			(string)
     *		arg3: command result object		(Tcl_Obj*)
     */
    probe cmd__result(TclDTraceStr name, int code, TclDTraceStr result,
	    struct Tcl_Obj *resultobj);
    /*
     *	tcl*:::cmd-args probe
     *	    triggered before cmd-entry probe, gives access to string
     *	    representation of command arguments
     *		arg0: command name			(string)
     *		arg1-arg9: command arguments or NULL	(strings)
     */
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
    /*
     *	tcl*:::inst-start probe
     *	    triggered immediately before execution of a bytecode
     *		arg0: bytecode name			(string)
     *		arg1: depth of stack			(int)
     *		arg2: top of stack			(Tcl_Obj**)
     */
    probe inst__start(TclDTraceStr name, int depth, Tcl_Obj **stack);
    /*
     *	tcl*:::inst-done probe
     *	    triggered immediately after execution of a bytecode
     *		arg0: bytecode name			(string)
     *		arg1: depth of stack			(int)
     *		arg2: top of stack			(Tcl_Obj**)
     */
    probe inst__done(TclDTraceStr name, int depth, Tcl_Obj **stack);

    /***************************** obj probes ******************************/
    /*
     *	tcl*:::obj-create probe
     *	    triggered immediately after a new Tcl_Obj has been created
     *		arg0: object created			(Tcl_Obj*)
     */
    probe obj__create(Tcl_Obj* obj);
    /*
     *	tcl*:::obj-free probe
     *	    triggered immediately before a Tcl_Obj is freed
     *		arg0: object to be freed		(Tcl_Obj*)
     */
    probe obj__free(Tcl_Obj* obj);

    /***************************** tcl probes ******************************/
    /*
     *	tcl*:::tcl-probe probe
     *	    triggered when the ::tcl::dtrace command is called
     *		arg0-arg9: command arguments		(strings)
     */







|







|







|





|







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
    /*
     *	tcl*:::inst-start probe
     *	    triggered immediately before execution of a bytecode
     *		arg0: bytecode name			(string)
     *		arg1: depth of stack			(int)
     *		arg2: top of stack			(Tcl_Obj**)
     */
    probe inst__start(TclDTraceStr name, int depth, struct Tcl_Obj **stack);
    /*
     *	tcl*:::inst-done probe
     *	    triggered immediately after execution of a bytecode
     *		arg0: bytecode name			(string)
     *		arg1: depth of stack			(int)
     *		arg2: top of stack			(Tcl_Obj**)
     */
    probe inst__done(TclDTraceStr name, int depth, struct Tcl_Obj **stack);

    /***************************** obj probes ******************************/
    /*
     *	tcl*:::obj-create probe
     *	    triggered immediately after a new Tcl_Obj has been created
     *		arg0: object created			(Tcl_Obj*)
     */
    probe obj__create(struct Tcl_Obj* obj);
    /*
     *	tcl*:::obj-free probe
     *	    triggered immediately before a Tcl_Obj is freed
     *		arg0: object to be freed		(Tcl_Obj*)
     */
    probe obj__free(struct Tcl_Obj* obj);

    /***************************** tcl probes ******************************/
    /*
     *	tcl*:::tcl-probe probe
     *	    triggered when the ::tcl::dtrace command is called
     *		arg0-arg9: command arguments		(strings)
     */

Changes to generic/tclDecls.h.

647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
				CONST84 char **startPtr,
				CONST84 char **endPtr);
/* 216 */
EXTERN void		Tcl_Release(ClientData clientData);
/* 217 */
EXTERN void		Tcl_ResetResult(Tcl_Interp *interp);
/* 218 */
EXTERN int		Tcl_ScanElement(const char *str, int *flagPtr);
/* 219 */
EXTERN int		Tcl_ScanCountedElement(const char *str, int length,
				int *flagPtr);
/* 220 */
EXTERN int		Tcl_SeekOld(Tcl_Channel chan, int offset, int mode);
/* 221 */
EXTERN int		Tcl_ServiceAll(void);
/* 222 */
EXTERN int		Tcl_ServiceEvent(int flags);







|

|







647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
				CONST84 char **startPtr,
				CONST84 char **endPtr);
/* 216 */
EXTERN void		Tcl_Release(ClientData clientData);
/* 217 */
EXTERN void		Tcl_ResetResult(Tcl_Interp *interp);
/* 218 */
EXTERN int		Tcl_ScanElement(const char *src, int *flagPtr);
/* 219 */
EXTERN int		Tcl_ScanCountedElement(const char *src, int length,
				int *flagPtr);
/* 220 */
EXTERN int		Tcl_SeekOld(Tcl_Channel chan, int offset, int mode);
/* 221 */
EXTERN int		Tcl_ServiceAll(void);
/* 222 */
EXTERN int		Tcl_ServiceEvent(int flags);
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
    void (*tcl_RegisterObjType) (const Tcl_ObjType *typePtr); /* 211 */
    Tcl_RegExp (*tcl_RegExpCompile) (Tcl_Interp *interp, const char *pattern); /* 212 */
    int (*tcl_RegExpExec) (Tcl_Interp *interp, Tcl_RegExp regexp, const char *text, const char *start); /* 213 */
    int (*tcl_RegExpMatch) (Tcl_Interp *interp, const char *text, const char *pattern); /* 214 */
    void (*tcl_RegExpRange) (Tcl_RegExp regexp, int index, CONST84 char **startPtr, CONST84 char **endPtr); /* 215 */
    void (*tcl_Release) (ClientData clientData); /* 216 */
    void (*tcl_ResetResult) (Tcl_Interp *interp); /* 217 */
    int (*tcl_ScanElement) (const char *str, int *flagPtr); /* 218 */
    int (*tcl_ScanCountedElement) (const char *str, int length, int *flagPtr); /* 219 */
    int (*tcl_SeekOld) (Tcl_Channel chan, int offset, int mode); /* 220 */
    int (*tcl_ServiceAll) (void); /* 221 */
    int (*tcl_ServiceEvent) (int flags); /* 222 */
    void (*tcl_SetAssocData) (Tcl_Interp *interp, const char *name, Tcl_InterpDeleteProc *proc, ClientData clientData); /* 223 */
    void (*tcl_SetChannelBufferSize) (Tcl_Channel chan, int sz); /* 224 */
    int (*tcl_SetChannelOption) (Tcl_Interp *interp, Tcl_Channel chan, const char *optionName, const char *newValue); /* 225 */
    int (*tcl_SetCommandInfo) (Tcl_Interp *interp, const char *cmdName, const Tcl_CmdInfo *infoPtr); /* 226 */







|
|







2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
    void (*tcl_RegisterObjType) (const Tcl_ObjType *typePtr); /* 211 */
    Tcl_RegExp (*tcl_RegExpCompile) (Tcl_Interp *interp, const char *pattern); /* 212 */
    int (*tcl_RegExpExec) (Tcl_Interp *interp, Tcl_RegExp regexp, const char *text, const char *start); /* 213 */
    int (*tcl_RegExpMatch) (Tcl_Interp *interp, const char *text, const char *pattern); /* 214 */
    void (*tcl_RegExpRange) (Tcl_RegExp regexp, int index, CONST84 char **startPtr, CONST84 char **endPtr); /* 215 */
    void (*tcl_Release) (ClientData clientData); /* 216 */
    void (*tcl_ResetResult) (Tcl_Interp *interp); /* 217 */
    int (*tcl_ScanElement) (const char *src, int *flagPtr); /* 218 */
    int (*tcl_ScanCountedElement) (const char *src, int length, int *flagPtr); /* 219 */
    int (*tcl_SeekOld) (Tcl_Channel chan, int offset, int mode); /* 220 */
    int (*tcl_ServiceAll) (void); /* 221 */
    int (*tcl_ServiceEvent) (int flags); /* 222 */
    void (*tcl_SetAssocData) (Tcl_Interp *interp, const char *name, Tcl_InterpDeleteProc *proc, ClientData clientData); /* 223 */
    void (*tcl_SetChannelBufferSize) (Tcl_Channel chan, int sz); /* 224 */
    int (*tcl_SetChannelOption) (Tcl_Interp *interp, Tcl_Channel chan, const char *optionName, const char *newValue); /* 225 */
    int (*tcl_SetCommandInfo) (Tcl_Interp *interp, const char *cmdName, const Tcl_CmdInfo *infoPtr); /* 226 */
3787
3788
3789
3790
3791
3792
3793
3794
3795
3796
3797
3798
3799
3800
3801
#endif

#if defined(_WIN32) && defined(UNICODE)
#   define Tcl_FindExecutable(arg) ((Tcl_FindExecutable)((const char *)(arg)))
#   define Tcl_MainEx Tcl_MainExW
    EXTERN void Tcl_MainExW(int argc, wchar_t **argv,
	    Tcl_AppInitProc *appInitProc, Tcl_Interp *interp);
#   define Tcl_Main(argc, argv, proc) Tcl_MainExW(argc, argv, proc, \
	    (Tcl_FindExecutable(argv[0]), (Tcl_CreateInterp)()))
#endif

#undef TCL_STORAGE_CLASS
#define TCL_STORAGE_CLASS DLLIMPORT

#endif /* _TCLDECLS */







<
<






3787
3788
3789
3790
3791
3792
3793


3794
3795
3796
3797
3798
3799
#endif

#if defined(_WIN32) && defined(UNICODE)
#   define Tcl_FindExecutable(arg) ((Tcl_FindExecutable)((const char *)(arg)))
#   define Tcl_MainEx Tcl_MainExW
    EXTERN void Tcl_MainExW(int argc, wchar_t **argv,
	    Tcl_AppInitProc *appInitProc, Tcl_Interp *interp);


#endif

#undef TCL_STORAGE_CLASS
#define TCL_STORAGE_CLASS DLLIMPORT

#endif /* _TCLDECLS */

Changes to generic/tclDictObj.c.

99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
    {"remove",	DictRemoveCmd, NULL, NULL, NULL, 0 },
    {"replace",	DictReplaceCmd, NULL, NULL, NULL, 0 },
    {"set",	DictSetCmd,	TclCompileDictSetCmd, NULL, NULL, 0 },
    {"size",	DictSizeCmd, NULL, NULL, NULL, 0 },
    {"unset",	DictUnsetCmd, NULL, NULL, NULL, 0 },
    {"update",	DictUpdateCmd,	TclCompileDictUpdateCmd, NULL, NULL, 0 },
    {"values",	DictValuesCmd, NULL, NULL, NULL, 0 },
    {"with",	DictWithCmd, NULL, NULL, NULL, 0 },
    {NULL, NULL, NULL, NULL, NULL, 0}
};

/*
 * Internal representation of the entries in the hash table that backs a
 * dictionary.
 */







|







99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
    {"remove",	DictRemoveCmd, NULL, NULL, NULL, 0 },
    {"replace",	DictReplaceCmd, NULL, NULL, NULL, 0 },
    {"set",	DictSetCmd,	TclCompileDictSetCmd, NULL, NULL, 0 },
    {"size",	DictSizeCmd, NULL, NULL, NULL, 0 },
    {"unset",	DictUnsetCmd, NULL, NULL, NULL, 0 },
    {"update",	DictUpdateCmd,	TclCompileDictUpdateCmd, NULL, NULL, 0 },
    {"values",	DictValuesCmd, NULL, NULL, NULL, 0 },
    {"with",	DictWithCmd,	TclCompileDictWithCmd, NULL, NULL, 0 },
    {NULL, NULL, NULL, NULL, NULL, 0}
};

/*
 * Internal representation of the entries in the hash table that backs a
 * dictionary.
 */
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
 */

static void
UpdateStringOfDict(
    Tcl_Obj *dictPtr)
{
#define LOCAL_SIZE 20
    int localFlags[LOCAL_SIZE], *flagPtr;
    Dict *dict = dictPtr->internalRep.otherValuePtr;
    ChainEntry *cPtr;
    Tcl_Obj *keyPtr, *valuePtr;
    int numElems, i, length;
    const char *elem;
    char *dst;


    /*
     * This field is the most useful one in the whole hash structure, and it
     * is not exposed by any API function...
     */

    numElems = dict->table.numEntries * 2;








    /*
     * Pass 1: estimate space, gather flags.
     */

    if (numElems <= LOCAL_SIZE) {
	flagPtr = localFlags;


    } else {
	flagPtr = ckalloc(numElems * sizeof(int));
    }
    dictPtr->length = 1;
    for (i=0,cPtr=dict->entryChainHead; i<numElems; i+=2,cPtr=cPtr->nextPtr) {
	/*
	 * Assume that cPtr is never NULL since we know the number of array
	 * elements already.
	 */


	keyPtr = Tcl_GetHashKey(&dict->table, &cPtr->entry);
	elem = TclGetStringFromObj(keyPtr, &length);
	dictPtr->length += Tcl_ScanCountedElement(elem, length,
		&flagPtr[i]) + 1;




	valuePtr = Tcl_GetHashValue(&cPtr->entry);
	elem = TclGetStringFromObj(valuePtr, &length);
	dictPtr->length += Tcl_ScanCountedElement(elem, length,
		&flagPtr[i+1]) + 1;

    }






    /*
     * Pass 2: copy into string rep buffer.
     */


    dictPtr->bytes = ckalloc(dictPtr->length);
    dst = dictPtr->bytes;
    for (i=0,cPtr=dict->entryChainHead; i<numElems; i+=2,cPtr=cPtr->nextPtr) {

	keyPtr = Tcl_GetHashKey(&dict->table, &cPtr->entry);
	elem = TclGetStringFromObj(keyPtr, &length);
	dst += Tcl_ConvertCountedElement(elem, length, dst,
		flagPtr[i] | (i==0 ? 0 : TCL_DONT_QUOTE_HASH));
	*(dst++) = ' ';


	valuePtr = Tcl_GetHashValue(&cPtr->entry);
	elem = TclGetStringFromObj(valuePtr, &length);
	dst += Tcl_ConvertCountedElement(elem, length, dst,
		flagPtr[i+1] | TCL_DONT_QUOTE_HASH);
	*(dst++) = ' ';
    }


    if (flagPtr != localFlags) {
	ckfree(flagPtr);
    }
    if (dst == dictPtr->bytes) {
	*dst = 0;
    } else {
	*(--dst) = 0;
    }
    dictPtr->length = dst - dictPtr->bytes;
}

/*
 *----------------------------------------------------------------------
 *
 * SetDictFromAny --
 *







|



|


>






|
>
>
>
>
>
>
>







>
>



<






>


|
|
>
|
>
>


|
|
>
|
>
>
>
>
>





>
|


>


|
<
|

>


|
<
|

>
>



<
<
<
<
<
<







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
 */

static void
UpdateStringOfDict(
    Tcl_Obj *dictPtr)
{
#define LOCAL_SIZE 20
    int localFlags[LOCAL_SIZE], *flagPtr = NULL;
    Dict *dict = dictPtr->internalRep.otherValuePtr;
    ChainEntry *cPtr;
    Tcl_Obj *keyPtr, *valuePtr;
    int i, length, bytesNeeded = 0;
    const char *elem;
    char *dst;
    const int maxFlags = UINT_MAX / sizeof(int);

    /*
     * This field is the most useful one in the whole hash structure, and it
     * is not exposed by any API function...
     */

    int numElems = dict->table.numEntries * 2;

    /* Handle empty list case first, simplifies what follows */
    if (numElems == 0) {
	dictPtr->bytes = tclEmptyStringRep;
	dictPtr->length = 0;
	return;
    }

    /*
     * Pass 1: estimate space, gather flags.
     */

    if (numElems <= LOCAL_SIZE) {
	flagPtr = localFlags;
    } else if (numElems > maxFlags) {
	Tcl_Panic("max size for a Tcl value (%d bytes) exceeded", INT_MAX);
    } else {
	flagPtr = ckalloc(numElems * sizeof(int));
    }

    for (i=0,cPtr=dict->entryChainHead; i<numElems; i+=2,cPtr=cPtr->nextPtr) {
	/*
	 * Assume that cPtr is never NULL since we know the number of array
	 * elements already.
	 */

	flagPtr[i] = ( i ? TCL_DONT_QUOTE_HASH : 0 );
	keyPtr = Tcl_GetHashKey(&dict->table, &cPtr->entry);
	elem = TclGetStringFromObj(keyPtr, &length);
	bytesNeeded += TclScanElement(elem, length, flagPtr+i);
	if (bytesNeeded < 0) {
	    Tcl_Panic("max size for a Tcl value (%d bytes) exceeded", INT_MAX);
	}

	flagPtr[i+1] = TCL_DONT_QUOTE_HASH;
	valuePtr = Tcl_GetHashValue(&cPtr->entry);
	elem = TclGetStringFromObj(valuePtr, &length);
	bytesNeeded += TclScanElement(elem, length, flagPtr+i+1);
	if (bytesNeeded < 0) {
	    Tcl_Panic("max size for a Tcl value (%d bytes) exceeded", INT_MAX);
	}
    }
    if (bytesNeeded > INT_MAX - numElems + 1) {
	Tcl_Panic("max size for a Tcl value (%d bytes) exceeded", INT_MAX);
    }
    bytesNeeded += numElems;

    /*
     * Pass 2: copy into string rep buffer.
     */

    dictPtr->length = bytesNeeded - 1;
    dictPtr->bytes = ckalloc(bytesNeeded);
    dst = dictPtr->bytes;
    for (i=0,cPtr=dict->entryChainHead; i<numElems; i+=2,cPtr=cPtr->nextPtr) {
	flagPtr[i] |= ( i ? TCL_DONT_QUOTE_HASH : 0 );
	keyPtr = Tcl_GetHashKey(&dict->table, &cPtr->entry);
	elem = TclGetStringFromObj(keyPtr, &length);
	dst += TclConvertElement(elem, length, dst, flagPtr[i]);

	*dst++ = ' ';

	flagPtr[i+1] |= TCL_DONT_QUOTE_HASH;
	valuePtr = Tcl_GetHashValue(&cPtr->entry);
	elem = TclGetStringFromObj(valuePtr, &length);
	dst += TclConvertElement(elem, length, dst, flagPtr[i+1]);

	*dst++ = ' ';
    }
    dictPtr->bytes[dictPtr->length] = '\0';

    if (flagPtr != localFlags) {
	ckfree(flagPtr);
    }






}

/*
 *----------------------------------------------------------------------
 *
 * SetDictFromAny --
 *
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
 */

static int
SetDictFromAny(
    Tcl_Interp *interp,
    Tcl_Obj *objPtr)
{
    const char *string;
    char *s;
    const char *elemStart, *nextElem;
    int lenRemain, length, elemSize, hasBrace, result, isNew;
    const char *limit;	/* Points just after string's last byte. */
    register const char *p;
    register Tcl_Obj *keyPtr, *valuePtr;
    Dict *dict;
    Tcl_HashEntry *hPtr;


    /*
     * Since lists and dictionaries have very closely-related string
     * representations (i.e. the same parsing code) we can safely special-case
     * the conversion from lists to dictionaries.
     */

    if (objPtr->typePtr == &tclListType) {
	int objc, i;
	Tcl_Obj **objv;


	if (TclListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) {
	    return TCL_ERROR;
	}
	if (objc & 1) {
	    if (interp != NULL) {
		Tcl_SetResult(interp, "missing value to go with key",
			TCL_STATIC);
		Tcl_SetErrorCode(interp, "TCL", "VALUE", "DICTIONARY", NULL);
	    }
	    return TCL_ERROR;
	}

	/*
	 * Build the hash of key/value pairs.
	 */

	dict = ckalloc(sizeof(Dict));
	InitChainTable(dict);
	for (i=0 ; i<objc ; i+=2) {
	    /*
	     * Store key and value in the hash table we're building.
	     */

	    hPtr = CreateChainEntry(dict, objv[i], &isNew);
	    if (!isNew) {
		Tcl_Obj *discardedValue = Tcl_GetHashValue(hPtr);

		/*
		 * Not really a well-formed dictionary as there are duplicate
		 * keys, so better get the string rep here so that we can
		 * convert back.
		 */

		(void) Tcl_GetString(objPtr);

		TclDecrRefCount(discardedValue);
	    }
	    Tcl_SetHashValue(hPtr, objv[i+1]);
	    Tcl_IncrRefCount(objv[i+1]); /* Since hash now holds ref to it */
	}

	/*
	 * Share type-setting code with the string-conversion case.
	 */

	goto installHash;
    }

    /*
     * Get the string representation. Make it up-to-date if necessary.
     */

    string = TclGetStringFromObj(objPtr, &length);
    limit = (string + length);

    /*
     * Allocate a new HashTable that has objects for keys and objects for

     * values.
     */

    dict = ckalloc(sizeof(Dict));
    InitChainTable(dict);
    for (p = string, lenRemain = length;
	    lenRemain > 0;
	    p = nextElem, lenRemain = (limit - nextElem)) {
	result = TclFindElement(interp, p, lenRemain,
		&elemStart, &nextElem, &elemSize, &hasBrace);
	if (result != TCL_OK) {
	    if (interp != NULL) {
		Tcl_SetErrorCode(interp, "TCL", "VALUE", "DICTIONARY", NULL);
	    }
	    goto errorExit;
	}
	if (elemStart >= limit) {
	    break;
	}



	/*
	 * Allocate a Tcl object for the element and initialize it from the
	 * "elemSize" bytes starting at "elemStart".
	 */

	s = ckalloc(elemSize + 1);
	if (hasBrace) {
	    memcpy(s, elemStart, (size_t) elemSize);
	    s[elemSize] = 0;
	} else {



	    elemSize = TclCopyAndCollapse(elemSize, elemStart, s);
	}

	TclNewObj(keyPtr);
	keyPtr->bytes = s;
	keyPtr->length = elemSize;

	p = nextElem;
	lenRemain = (limit - nextElem);
	if (lenRemain <= 0) {
	    goto missingKey;
	}

	result = TclFindElement(interp, p, lenRemain,
		&elemStart, &nextElem, &elemSize, &hasBrace);
	if (result != TCL_OK) {
	    if (interp != NULL) {
		Tcl_SetErrorCode(interp, "TCL", "VALUE", "DICTIONARY", NULL);
	    }
	    TclDecrRefCount(keyPtr);
	    goto errorExit;
	}
	if (elemStart >= limit) {
	    goto missingKey;
	}

	/*
	 * Allocate a Tcl object for the element and initialize it from the
	 * "elemSize" bytes starting at "elemStart".
	 */

	s = ckalloc(elemSize + 1);
	if (hasBrace) {
	    memcpy(s, elemStart, (size_t) elemSize);
	    s[elemSize] = 0;
	} else {
	    elemSize = TclCopyAndCollapse(elemSize, elemStart, s);
	}

	TclNewObj(valuePtr);
	valuePtr->bytes = s;

	valuePtr->length = elemSize;

	/*
	 * Store key and value in the hash table we're building.
	 */

	hPtr = CreateChainEntry(dict, keyPtr, &isNew);
	if (!isNew) {
	    Tcl_Obj *discardedValue = Tcl_GetHashValue(hPtr);

	    TclDecrRefCount(keyPtr);
	    TclDecrRefCount(discardedValue);
	}
	Tcl_SetHashValue(hPtr, valuePtr);
	Tcl_IncrRefCount(valuePtr);	/* Since hash now holds ref to it. */
    }

  installHash:
    /*
     * Free the old internalRep before setting the new one. We do this as late
     * as possible to allow the conversion code, in particular
     * Tcl_GetStringFromObj, to use that old internalRep.
     */

    TclFreeIntRep(objPtr);
    dict->epoch = 0;
    dict->chain = NULL;
    dict->refcount = 1;
    objPtr->internalRep.otherValuePtr = dict;
    objPtr->typePtr = &tclDictType;
    return TCL_OK;

  missingKey:
    if (interp != NULL) {
	Tcl_SetResult(interp, "missing value to go with key", TCL_STATIC);
	Tcl_SetErrorCode(interp, "TCL", "VALUE", "DICTIONARY", NULL);
    }
    TclDecrRefCount(keyPtr);
    result = TCL_ERROR;

  errorExit:



    DeleteChainTable(dict);
    ckfree(dict);
    return result;
}

/*
 *----------------------------------------------------------------------







<
|
<
|
<
<
<
|
|
>











>
|
<
<

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

















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

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

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

|
|
|
|
|
|
|
|














|




<



>
>
>







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
 */

static int
SetDictFromAny(
    Tcl_Interp *interp,
    Tcl_Obj *objPtr)
{

    Tcl_HashEntry *hPtr;

    int isNew, result;



    Dict *dict = ckalloc(sizeof(Dict));

    InitChainTable(dict);

    /*
     * Since lists and dictionaries have very closely-related string
     * representations (i.e. the same parsing code) we can safely special-case
     * the conversion from lists to dictionaries.
     */

    if (objPtr->typePtr == &tclListType) {
	int objc, i;
	Tcl_Obj **objv;

	/* Cannot fail, we already know the Tcl_ObjType is "list". */
	TclListObjGetElements(NULL, objPtr, &objc, &objv);


	if (objc & 1) {

	    goto missingValue;


	}


	for (i=0 ; i<objc ; i+=2) {



	




	    /* Store key and value in the hash table we're building. */


	    hPtr = CreateChainEntry(dict, objv[i], &isNew);
	    if (!isNew) {
		Tcl_Obj *discardedValue = Tcl_GetHashValue(hPtr);

		/*
		 * Not really a well-formed dictionary as there are duplicate
		 * keys, so better get the string rep here so that we can
		 * convert back.
		 */

		(void) Tcl_GetString(objPtr);

		TclDecrRefCount(discardedValue);
	    }
	    Tcl_SetHashValue(hPtr, objv[i+1]);
	    Tcl_IncrRefCount(objv[i+1]); /* Since hash now holds ref to it */
	}
    } else {



	int length;







	const char *nextElem = TclGetStringFromObj(objPtr, &length);
	const char *limit = (nextElem + length);



	while (nextElem < limit) {
	    Tcl_Obj *keyPtr, *valuePtr;

	    const char *elemStart;

	    int elemSize, literal;



	    result = TclFindElement(interp, nextElem, (limit - nextElem),
		    &elemStart, &nextElem, &elemSize, &literal);
	    if (result != TCL_OK) {



		goto errorExit;
	    }
	    if (elemStart == limit) {
		break;
	    }
	    if (nextElem == limit) {
		goto missingValue;
	    }






	    if (literal) {
		TclNewStringObj(keyPtr, elemStart, elemSize);

	    } else {
		/* Avoid double copy */
		TclNewObj(keyPtr);
		keyPtr->bytes = ckalloc((unsigned) elemSize + 1);
		keyPtr->length = TclCopyAndCollapse(elemSize, elemStart,



			keyPtr->bytes);

	    }






	    result = TclFindElement(interp, nextElem, (limit - nextElem),
		    &elemStart, &nextElem, &elemSize, &literal);
	    if (result != TCL_OK) {



		TclDecrRefCount(keyPtr);
		goto errorExit;
	    }



	    if (literal) {




		TclNewStringObj(valuePtr, elemStart, elemSize);




	    } else {


		/* Avoid double copy */
		TclNewObj(valuePtr);
		valuePtr->bytes = ckalloc((unsigned) elemSize + 1);
		valuePtr->length = TclCopyAndCollapse(elemSize, elemStart,
			valuePtr->bytes);
	    }

	    /* Store key and value in the hash table we're building. */


	    hPtr = CreateChainEntry(dict, keyPtr, &isNew);
	    if (!isNew) {
		Tcl_Obj *discardedValue = Tcl_GetHashValue(hPtr);

		TclDecrRefCount(keyPtr);
		TclDecrRefCount(discardedValue);
	    }
	    Tcl_SetHashValue(hPtr, valuePtr);
	    Tcl_IncrRefCount(valuePtr); /* since hash now holds ref to it */
	}
    }

    /*
     * Free the old internalRep before setting the new one. We do this as late
     * as possible to allow the conversion code, in particular
     * Tcl_GetStringFromObj, to use that old internalRep.
     */

    TclFreeIntRep(objPtr);
    dict->epoch = 0;
    dict->chain = NULL;
    dict->refcount = 1;
    objPtr->internalRep.otherValuePtr = dict;
    objPtr->typePtr = &tclDictType;
    return TCL_OK;

  missingValue:
    if (interp != NULL) {
	Tcl_SetResult(interp, "missing value to go with key", TCL_STATIC);
	Tcl_SetErrorCode(interp, "TCL", "VALUE", "DICTIONARY", NULL);
    }

    result = TCL_ERROR;

  errorExit:
    if (interp != NULL) {
	Tcl_SetErrorCode(interp, "TCL", "VALUE", "DICTIONARY", NULL);
    }
    DeleteChainTable(dict);
    ckfree(dict);
    return result;
}

/*
 *----------------------------------------------------------------------
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477

    /*
     * Stop the value from getting hit in any way by any traces on the key
     * variable.
     */

    Tcl_IncrRefCount(valueObj);
    if (Tcl_ObjSetVar2(interp, keyVarObj, NULL, keyObj, 0) == NULL) {
	Tcl_ResetResult(interp);
	Tcl_AppendResult(interp, "couldn't set key variable: \"",
		TclGetString(keyVarObj), "\"", NULL);
	TclDecrRefCount(valueObj);
	goto error;
    }
    TclDecrRefCount(valueObj);
    if (Tcl_ObjSetVar2(interp, valueVarObj, NULL, valueObj, 0) == NULL) {
	Tcl_ResetResult(interp);
	Tcl_AppendResult(interp, "couldn't set value variable: \"",
		TclGetString(valueVarObj), "\"", NULL);
	goto error;
    }

    /*
     * Run the script.
     */








|
<
<
<




|
<
<
<







2408
2409
2410
2411
2412
2413
2414
2415



2416
2417
2418
2419
2420



2421
2422
2423
2424
2425
2426
2427

    /*
     * Stop the value from getting hit in any way by any traces on the key
     * variable.
     */

    Tcl_IncrRefCount(valueObj);
    if (Tcl_ObjSetVar2(interp, keyVarObj, NULL, keyObj, TCL_LEAVE_ERR_MSG) == NULL) {



	TclDecrRefCount(valueObj);
	goto error;
    }
    TclDecrRefCount(valueObj);
    if (Tcl_ObjSetVar2(interp, valueVarObj, NULL, valueObj, TCL_LEAVE_ERR_MSG) == NULL) {



	goto error;
    }

    /*
     * Run the script.
     */

2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562

    /*
     * Stop the value from getting hit in any way by any traces on the key
     * variable.
     */

    Tcl_IncrRefCount(valueObj);
    if (Tcl_ObjSetVar2(interp, keyVarObj, NULL, keyObj, 0) == NULL) {
	Tcl_ResetResult(interp);
	Tcl_AppendResult(interp, "couldn't set key variable: \"",
		TclGetString(keyVarObj), "\"", NULL);
	TclDecrRefCount(valueObj);
	result = TCL_ERROR;
	goto done;
    }
    TclDecrRefCount(valueObj);
    if (Tcl_ObjSetVar2(interp, valueVarObj, NULL, valueObj, 0) == NULL) {
	Tcl_ResetResult(interp);
	Tcl_AppendResult(interp, "couldn't set value variable: \"",
		TclGetString(valueVarObj), "\"", NULL);
	result = TCL_ERROR;
	goto done;
    }

    /*
     * Run the script.
     */







|
<
<
<





|
<
<
<







2486
2487
2488
2489
2490
2491
2492
2493



2494
2495
2496
2497
2498
2499



2500
2501
2502
2503
2504
2505
2506

    /*
     * Stop the value from getting hit in any way by any traces on the key
     * variable.
     */

    Tcl_IncrRefCount(valueObj);
    if (Tcl_ObjSetVar2(interp, keyVarObj, NULL, keyObj, TCL_LEAVE_ERR_MSG) == NULL) {



	TclDecrRefCount(valueObj);
	result = TCL_ERROR;
	goto done;
    }
    TclDecrRefCount(valueObj);
    if (Tcl_ObjSetVar2(interp, valueVarObj, NULL, valueObj, TCL_LEAVE_ERR_MSG) == NULL) {



	result = TCL_ERROR;
	goto done;
    }

    /*
     * Run the script.
     */
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
DictWithCmd(
    ClientData dummy,
    Tcl_Interp *interp,
    int objc,
    Tcl_Obj *const *objv)
{
    Interp *iPtr = (Interp *) interp;
    Tcl_Obj *dictPtr, *keysPtr, *keyPtr = NULL, *valPtr = NULL, *pathPtr;
    Tcl_DictSearch s;
    int done;

    if (objc < 3) {
	Tcl_WrongNumArgs(interp, 1, objv, "dictVar ?key ...? script");
	return TCL_ERROR;
    }

    /*
     * Get the dictionary to open out.
     */

    dictPtr = Tcl_ObjGetVar2(interp, objv[1], NULL, TCL_LEAVE_ERR_MSG);
    if (dictPtr == NULL) {
	return TCL_ERROR;
    }
    if (objc > 3) {
	dictPtr = TclTraceDictPath(interp, dictPtr, objc-3, objv+2,
		DICT_PATH_READ);
	if (dictPtr == NULL) {
	    return TCL_ERROR;
	}
    }

    /*
     * Go over the list of keys and write each corresponding value to a
     * variable in the current context with the same name. Also keep a copy of
     * the keys so we can write back properly later on even if the dictionary
     * has been structurally modified.
     */

    if (Tcl_DictObjFirst(interp, dictPtr, &s, &keyPtr, &valPtr,
	    &done) != TCL_OK) {
	return TCL_ERROR;
    }

    TclNewObj(keysPtr);
    Tcl_IncrRefCount(keysPtr);

    for (; !done ; Tcl_DictObjNext(&s, &keyPtr, &valPtr, &done)) {
	Tcl_ListObjAppendElement(NULL, keysPtr, keyPtr);
	if (Tcl_ObjSetVar2(interp, keyPtr, NULL, valPtr,
		TCL_LEAVE_ERR_MSG) == NULL) {
	    TclDecrRefCount(keysPtr);
	    Tcl_DictObjDone(&s);
	    return TCL_ERROR;
	}
    }

    /*
     * Execute the body, while making the invoking context available to the
     * loop body (TIP#280) and postponing the cleanup until later (NRE).
     */

    pathPtr = NULL;







|
<
<














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


<
<

<
<
<
<
<
<
<
<
<
<







3106
3107
3108
3109
3110
3111
3112
3113


3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127





3128

3129






3130


3131
3132


3133










3134
3135
3136
3137
3138
3139
3140
DictWithCmd(
    ClientData dummy,
    Tcl_Interp *interp,
    int objc,
    Tcl_Obj *const *objv)
{
    Interp *iPtr = (Interp *) interp;
    Tcl_Obj *dictPtr, *keysPtr, *pathPtr;



    if (objc < 3) {
	Tcl_WrongNumArgs(interp, 1, objv, "dictVar ?key ...? script");
	return TCL_ERROR;
    }

    /*
     * Get the dictionary to open out.
     */

    dictPtr = Tcl_ObjGetVar2(interp, objv[1], NULL, TCL_LEAVE_ERR_MSG);
    if (dictPtr == NULL) {
	return TCL_ERROR;
    }







    keysPtr = TclDictWithInit(interp, dictPtr, objc-3, objv+2);






    if (keysPtr == NULL) {


	return TCL_ERROR;
    }


    Tcl_IncrRefCount(keysPtr);











    /*
     * Execute the body, while making the invoking context available to the
     * loop body (TIP#280) and postponing the cleanup until later (NRE).
     */

    pathPtr = NULL;
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247

3248
3249
3250
3251
3252




























































































































































3253
3254
3255
3256
3257

3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284


3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304

3305

3306


3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326

static int
FinalizeDictWith(
    ClientData data[],
    Tcl_Interp *interp,
    int result)
{
    Tcl_Obj **keyv, *leafPtr, *dictPtr, *valPtr;
    int keyc, i, allocdict = 0;
    Tcl_InterpState state;
    Tcl_Obj *varName = data[0];
    Tcl_Obj *keysPtr = data[1];
    Tcl_Obj *pathPtr = data[2];


    if (result == TCL_ERROR) {
	Tcl_AddErrorInfo(interp, "\n    (body of \"dict with\")");
    }





























































































































































    /*
     * If the dictionary variable doesn't exist, drop everything silently.
     */

    dictPtr = Tcl_ObjGetVar2(interp, varName, NULL, 0);

    if (dictPtr == NULL) {
	TclDecrRefCount(varName);
	TclDecrRefCount(keysPtr);
	if (pathPtr) {
	    TclDecrRefCount(pathPtr);
	}
	return result;
    }

    /*
     * Double-check that it is still a dictionary.
     */

    state = Tcl_SaveInterpState(interp, result);
    if (Tcl_DictObjSize(interp, dictPtr, &i) != TCL_OK) {
	TclDecrRefCount(varName);
	TclDecrRefCount(keysPtr);
	if (pathPtr) {
	    TclDecrRefCount(pathPtr);
	}
	Tcl_DiscardInterpState(state);
	return TCL_ERROR;
    }

    if (Tcl_IsShared(dictPtr)) {
	dictPtr = Tcl_DuplicateObj(dictPtr);
	allocdict = 1;


    }

    if (pathPtr != NULL) {
	Tcl_Obj **pathv;
	int pathc;

	/*
	 * Want to get to the dictionary which we will update; need to do
	 * prepare-for-update de-sharing along the path *but* avoid generating
	 * an error on a non-existant path (we'll treat that the same as a
	 * non-existant variable. Luckily, the de-sharing operation isn't
	 * deeply damaging if we don't go on to update; it's just less than
	 * perfectly efficient (but no memory should be leaked).
	 */

	Tcl_ListObjGetElements(NULL, pathPtr, &pathc, &pathv);
	leafPtr = TclTraceDictPath(interp, dictPtr, pathc, pathv,
		DICT_PATH_EXISTS | DICT_PATH_UPDATE);
	TclDecrRefCount(pathPtr);
	if (leafPtr == NULL) {

	    TclDecrRefCount(varName);

	    TclDecrRefCount(keysPtr);


	    if (allocdict) {
		TclDecrRefCount(dictPtr);
	    }
	    Tcl_DiscardInterpState(state);
	    return TCL_ERROR;
	}
	if (leafPtr == DICT_PATH_NON_EXISTENT) {
	    TclDecrRefCount(varName);
	    TclDecrRefCount(keysPtr);
	    if (allocdict) {
		TclDecrRefCount(dictPtr);
	    }
	    return Tcl_RestoreInterpState(interp, state);
	}
    } else {
	leafPtr = dictPtr;
    }

    /*
     * Now process our updates on the leaf dictionary.







|
|




>





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




|
>

<
<
<
<
<
|






<

<
<
<
<
<
<






>
>


|
<
<
<









<


<

>
|
>
|
>
>



<
|
<
<
<
<
<
<
<
<







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
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332





3333
3334
3335
3336
3337
3338
3339

3340






3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351



3352
3353
3354
3355
3356
3357
3358
3359
3360

3361
3362

3363
3364
3365
3366
3367
3368
3369
3370
3371
3372

3373








3374
3375
3376
3377
3378
3379
3380

static int
FinalizeDictWith(
    ClientData data[],
    Tcl_Interp *interp,
    int result)
{
    Tcl_Obj **pathv;
    int pathc;
    Tcl_InterpState state;
    Tcl_Obj *varName = data[0];
    Tcl_Obj *keysPtr = data[1];
    Tcl_Obj *pathPtr = data[2];
    Var *varPtr, *arrayPtr;

    if (result == TCL_ERROR) {
	Tcl_AddErrorInfo(interp, "\n    (body of \"dict with\")");
    }

    /*
     * Save the result state; TDWF doesn't guarantee to not modify that on
     * TCL_OK result.
     */

    state = Tcl_SaveInterpState(interp, result);
    if (pathPtr != NULL) {
	Tcl_ListObjGetElements(NULL, pathPtr, &pathc, &pathv);
    } else {
	pathc = 0;
	pathv = NULL;
    }

    /*
     * Pack from local variables back into the dictionary.
     */

    varPtr = TclObjLookupVarEx(interp, varName, NULL, TCL_LEAVE_ERR_MSG, "set",
	    /*createPart1*/ 1, /*createPart2*/ 1, &arrayPtr);
    if (varPtr == NULL) {
	result = TCL_ERROR;
    } else {
	result = TclDictWithFinish(interp, varPtr, arrayPtr, varName, NULL, -1,
		pathc, pathv, keysPtr);
    }

    /*
     * Tidy up and return the real result (unless we had an error).
     */

    TclDecrRefCount(varName);
    TclDecrRefCount(keysPtr);
    if (pathPtr != NULL) {
	TclDecrRefCount(pathPtr);
    }
    if (result != TCL_OK) {
	Tcl_DiscardInterpState(state);
	return TCL_ERROR;
    }
    return Tcl_RestoreInterpState(interp, state);
}

/*
 *----------------------------------------------------------------------
 *
 * TclDictWithInit --
 *
 *	Part of the core of [dict with]. Pokes into a dictionary and converts
 *	the mappings there into assignments to (presumably) local variables.
 *	Returns a list of all the names that were mapped so that removal of
 *	either the variable or the dictionary entry won't surprise us when we
 *	come to stuffing everything back.
 *
 * Result:
 *	List of mapped names, or NULL if there was an error.
 *
 * Side effects:
 *	Assigns to variables, so potentially legion due to traces.
 *
 *----------------------------------------------------------------------
 */

Tcl_Obj *
TclDictWithInit(
    Tcl_Interp *interp,
    Tcl_Obj *dictPtr,
    int pathc,
    Tcl_Obj *const pathv[])
{
    Tcl_DictSearch s;
    Tcl_Obj *keyPtr, *valPtr, *keysPtr;
    int done;

    if (pathc > 0) {
	dictPtr = TclTraceDictPath(interp, dictPtr, pathc, pathv,
		DICT_PATH_READ);
	if (dictPtr == NULL) {
	    return NULL;
	}
    }

    /*
     * Go over the list of keys and write each corresponding value to a
     * variable in the current context with the same name. Also keep a copy of
     * the keys so we can write back properly later on even if the dictionary
     * has been structurally modified.
     */

    if (Tcl_DictObjFirst(interp, dictPtr, &s, &keyPtr, &valPtr,
	    &done) != TCL_OK) {
	return NULL;
    }

    TclNewObj(keysPtr);

    for (; !done ; Tcl_DictObjNext(&s, &keyPtr, &valPtr, &done)) {
	Tcl_ListObjAppendElement(NULL, keysPtr, keyPtr);
	if (Tcl_ObjSetVar2(interp, keyPtr, NULL, valPtr,
		TCL_LEAVE_ERR_MSG) == NULL) {
	    TclDecrRefCount(keysPtr);
	    Tcl_DictObjDone(&s);
	    return NULL;
	}
    }

    return keysPtr;
}

/*
 *----------------------------------------------------------------------
 *
 * TclDictWithFinish --
 *
 *	Part of the core of [dict with]. Reassembles the piece of the dict (in
 *	varName, location given by pathc/pathv) from the variables named in
 *	the keysPtr argument. NB, does not try to preserve errors or manage
 *	argument lifetimes.
 *
 * Result:
 *	TCL_OK if we succeeded, or TCL_ERROR if we failed.
 *
 * Side effects:
 *	Assigns to a variable, so potentially legion due to traces. Updates
 *	the dictionary in the named variable.
 *
 *----------------------------------------------------------------------
 */

int
TclDictWithFinish(
    Tcl_Interp *interp,		/* Command interpreter in which variable
				 * exists. Used for state management, traces
				 * and error reporting. */
    Var *varPtr,		/* Reference to the variable holding the
				 * dictionary. */
    Var *arrayPtr,		/* Reference to the array containing the
				 * variable, or NULL if the variable is a
				 * scalar. */
    Tcl_Obj *part1Ptr,		/* Name of an array (if part2 is non-NULL) or
				 * the name of a variable. NULL if the 'index'
				 * parameter is >= 0 */
    Tcl_Obj *part2Ptr,		/* If non-NULL, gives the name of an element
				 * in the array part1. */
    int index,			/* Index into the local variable table of the
				 * variable, or -1. Only used when part1Ptr is
				 * NULL. */
    int pathc,			/* The number of elements in the path into the
				 * dictionary. */
    Tcl_Obj *const pathv[],	/* The elements of the path to the subdict. */
    Tcl_Obj *keysPtr)		/* List of keys to be synchronized. This is
				 * the result value from TclDictWithInit. */
{
    Tcl_Obj *dictPtr, *leafPtr, *valPtr;
    int i, allocdict, keyc;
    Tcl_Obj **keyv;

    /*
     * If the dictionary variable doesn't exist, drop everything silently.
     */

    dictPtr = TclPtrGetVar(interp, varPtr, arrayPtr, part1Ptr, part2Ptr,
	    TCL_LEAVE_ERR_MSG, index);
    if (dictPtr == NULL) {





	return TCL_OK;
    }

    /*
     * Double-check that it is still a dictionary.
     */


    if (Tcl_DictObjSize(interp, dictPtr, &i) != TCL_OK) {






	return TCL_ERROR;
    }

    if (Tcl_IsShared(dictPtr)) {
	dictPtr = Tcl_DuplicateObj(dictPtr);
	allocdict = 1;
    } else {
	allocdict = 0;
    }

    if (pathc > 0) {



	/*
	 * Want to get to the dictionary which we will update; need to do
	 * prepare-for-update de-sharing along the path *but* avoid generating
	 * an error on a non-existant path (we'll treat that the same as a
	 * non-existant variable. Luckily, the de-sharing operation isn't
	 * deeply damaging if we don't go on to update; it's just less than
	 * perfectly efficient (but no memory should be leaked).
	 */


	leafPtr = TclTraceDictPath(interp, dictPtr, pathc, pathv,
		DICT_PATH_EXISTS | DICT_PATH_UPDATE);

	if (leafPtr == NULL) {
	    if (allocdict) {
		TclDecrRefCount(dictPtr);
	    }
	    return TCL_ERROR;
	}
	if (leafPtr == DICT_PATH_NON_EXISTENT) {
	    if (allocdict) {
		TclDecrRefCount(dictPtr);
	    }

	    return TCL_OK;








	}
    } else {
	leafPtr = dictPtr;
    }

    /*
     * Now process our updates on the leaf dictionary.
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361

3362

3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
	     */

	    Tcl_DictObjPut(NULL, leafPtr, keyv[i], Tcl_DuplicateObj(valPtr));
	} else {
	    Tcl_DictObjPut(NULL, leafPtr, keyv[i], valPtr);
	}
    }
    TclDecrRefCount(keysPtr);

    /*
     * Ensure that none of the dictionaries in the chain still have a string
     * rep.
     */

    if (pathPtr != NULL) {
	InvalidateDictChain(leafPtr);
    }

    /*
     * Write back the outermost dictionary to the variable.
     */

    if (Tcl_ObjSetVar2(interp, varName, NULL, dictPtr,
	    TCL_LEAVE_ERR_MSG) == NULL) {

	Tcl_DiscardInterpState(state);

	return TCL_ERROR;
    }
    TclDecrRefCount(varName);
    return Tcl_RestoreInterpState(interp, state);
}

/*
 *----------------------------------------------------------------------
 *
 * TclInitDictCmd --
 *







<






|







|
|
>
|
>


<
|







3392
3393
3394
3395
3396
3397
3398

3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419

3420
3421
3422
3423
3424
3425
3426
3427
	     */

	    Tcl_DictObjPut(NULL, leafPtr, keyv[i], Tcl_DuplicateObj(valPtr));
	} else {
	    Tcl_DictObjPut(NULL, leafPtr, keyv[i], valPtr);
	}
    }


    /*
     * Ensure that none of the dictionaries in the chain still have a string
     * rep.
     */

    if (pathc > 0) {
	InvalidateDictChain(leafPtr);
    }

    /*
     * Write back the outermost dictionary to the variable.
     */

    if (TclPtrSetVar(interp, varPtr, arrayPtr, part1Ptr, part2Ptr, dictPtr,
	    TCL_LEAVE_ERR_MSG, index) == NULL) {
	if (allocdict) {
	    TclDecrRefCount(dictPtr);
	}
	return TCL_ERROR;
    }

    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * TclInitDictCmd --
 *

Changes to generic/tclEvent.c.

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
	 * on Tcl_Exit never returning. In fact, we will Tcl_Panic if anyone
	 * returns, so critical is this dependcy.
	 */

	currentAppExitPtr(INT2PTR(status));
	Tcl_Panic("AppExitProc returned unexpectedly");
    } else {



	/*


	 * Use default handling.






	 */

	InvokeExitHandlers();

	/*
	 * Ensure the thread-specific data is initialised as it is used in
	 * Tcl_FinalizeThread()
	 */
	
	(void) TCL_TSD_INIT(&dataKey);
	
	/*
	 * Now finalize the calling thread only (others are not safely
	 * reachable).  Among other things, this triggers a flush of the
	 * Tcl_Channels that may have data enqueued.
	 */
	
	Tcl_FinalizeThread();
	
	TclpExit(status);
	Tcl_Panic("OS exit failed!");
    }
}

/*
 *-------------------------------------------------------------------------







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







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
	 * on Tcl_Exit never returning. In fact, we will Tcl_Panic if anyone
	 * returns, so critical is this dependcy.
	 */

	currentAppExitPtr(INT2PTR(status));
	Tcl_Panic("AppExitProc returned unexpectedly");
    } else {

	if (TclFullFinalizationRequested()) {

	    /*
	     * Thorough finalization for Valgrind et al.
	     */

	    Tcl_Finalize();

	} else {

	    /*
	     * Fast and deterministic exit (default behavior)
	     */
	    
	    InvokeExitHandlers();
	    
	    /*
	     * Ensure the thread-specific data is initialised as it is used in
	     * Tcl_FinalizeThread()
	     */
	    
	    (void) TCL_TSD_INIT(&dataKey);
	    
	    /*
	     * Now finalize the calling thread only (others are not safely
	     * reachable).  Among other things, this triggers a flush of the
	     * Tcl_Channels that may have data enqueued.
	     */
	    
	    Tcl_FinalizeThread();
	}
	TclpExit(status);
	Tcl_Panic("OS exit failed!");
    }
}

/*
 *-------------------------------------------------------------------------

Changes to generic/tclExecute.c.

49
50
51
52
53
54
55


56
57
58
59
60
61
62
 * Boolean flag indicating whether the Tcl bytecode interpreter has been
 * initialized.
 */

static int execInitialized = 0;
TCL_DECLARE_MUTEX(execMutex)



#ifdef TCL_COMPILE_DEBUG
/*
 * Variable that controls whether execution tracing is enabled and, if so,
 * what level of tracing is desired:
 *    0: no execution tracing
 *    1: trace invocations of Tcl procs only
 *    2: trace invocations of all (not compiled away) commands







>
>







49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
 * Boolean flag indicating whether the Tcl bytecode interpreter has been
 * initialized.
 */

static int execInitialized = 0;
TCL_DECLARE_MUTEX(execMutex)

static int cachedInExit = 0;

#ifdef TCL_COMPILE_DEBUG
/*
 * Variable that controls whether execution tracing is enabled and, if so,
 * what level of tracing is desired:
 *    0: no execution tracing
 *    1: trace invocations of Tcl procs only
 *    2: trace invocations of all (not compiled away) commands
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345

#define OBJ_AT_TOS	*tosPtr

#define OBJ_UNDER_TOS	*(tosPtr-1)

#define OBJ_AT_DEPTH(n)	*(tosPtr-(n))

#define CURR_DEPTH	(tosPtr - initTosPtr)

/*
 * Macros used to trace instruction execution. The macros TRACE,
 * TRACE_WITH_OBJ, and O2S are only used inside TclNRExecuteByteCode. O2S is
 * only used in TRACE* calls to get a string from an object.
 */








|







333
334
335
336
337
338
339
340
341
342
343
344
345
346
347

#define OBJ_AT_TOS	*tosPtr

#define OBJ_UNDER_TOS	*(tosPtr-1)

#define OBJ_AT_DEPTH(n)	*(tosPtr-(n))

#define CURR_DEPTH	((ptrdiff_t) (tosPtr - initTosPtr))

/*
 * Macros used to trace instruction execution. The macros TRACE,
 * TRACE_WITH_OBJ, and O2S are only used inside TclNRExecuteByteCode. O2S is
 * only used in TRACE* calls to get a string from an object.
 */

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
 *----------------------------------------------------------------------
 */

static void
DeleteExecStack(
    ExecStack *esPtr)
{
    if (esPtr->markerPtr) {
	Tcl_Panic("freeing an execStack which is still in use");
    }

    if (esPtr->prevPtr) {
	esPtr->prevPtr->nextPtr = esPtr->nextPtr;
    }
    if (esPtr->nextPtr) {
	esPtr->nextPtr->prevPtr = esPtr->prevPtr;
    }
    ckfree(esPtr);
}

void
TclDeleteExecEnv(
    ExecEnv *eePtr)		/* Execution environment to free. */
{
    ExecStack *esPtr = eePtr->execStackPtr, *tmpPtr;



    /*
     * Delete all stacks in this exec env.
     */

    while (esPtr->nextPtr) {
	esPtr = esPtr->nextPtr;
    }
    while (esPtr) {
	tmpPtr = esPtr;
	esPtr = tmpPtr->prevPtr;
	DeleteExecStack(tmpPtr);
    }

    TclDecrRefCount(eePtr->constants[0]);
    TclDecrRefCount(eePtr->constants[1]);
    if (eePtr->callbackPtr) {
	Tcl_Panic("Deleting execEnv with pending NRE callbacks!");
    }
    if (eePtr->corPtr) {
	Tcl_Panic("Deleting execEnv with existing coroutine");
    }
    ckfree(eePtr);
}

/*
 *----------------------------------------------------------------------







|


















>
>















|
|

|







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
 *----------------------------------------------------------------------
 */

static void
DeleteExecStack(
    ExecStack *esPtr)
{
    if (esPtr->markerPtr && !cachedInExit) {
	Tcl_Panic("freeing an execStack which is still in use");
    }

    if (esPtr->prevPtr) {
	esPtr->prevPtr->nextPtr = esPtr->nextPtr;
    }
    if (esPtr->nextPtr) {
	esPtr->nextPtr->prevPtr = esPtr->prevPtr;
    }
    ckfree(esPtr);
}

void
TclDeleteExecEnv(
    ExecEnv *eePtr)		/* Execution environment to free. */
{
    ExecStack *esPtr = eePtr->execStackPtr, *tmpPtr;

	cachedInExit = TclInExit();

    /*
     * Delete all stacks in this exec env.
     */

    while (esPtr->nextPtr) {
	esPtr = esPtr->nextPtr;
    }
    while (esPtr) {
	tmpPtr = esPtr;
	esPtr = tmpPtr->prevPtr;
	DeleteExecStack(tmpPtr);
    }

    TclDecrRefCount(eePtr->constants[0]);
    TclDecrRefCount(eePtr->constants[1]);
    if (eePtr->callbackPtr && !cachedInExit) {
	Tcl_Panic("Deleting execEnv with pending TEOV callbacks!");
    }
    if (eePtr->corPtr && !cachedInExit) {
	Tcl_Panic("Deleting execEnv with existing coroutine");
    }
    ckfree(eePtr);
}

/*
 *----------------------------------------------------------------------
1684
1685
1686
1687
1688
1689
1690




1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
	 *     offset between saved starting line and actual one. Then modify
	 *     the users to adjust the locations they have by this offset.
	 *
	 * (3) Alternative 2: Do not fully recompile, adjust just the location
	 *     information.
	 */





	{
	    Tcl_HashEntry *hePtr =
		    Tcl_FindHashEntry(iPtr->lineBCPtr, codePtr);
	    ExtCmdLoc *eclPtr;
	    CmdFrame *ctxPtr;
	    int redo;

	    if (!hePtr || !invoker) {
		return codePtr;
	    }

	    eclPtr = Tcl_GetHashValue(hePtr);
	    redo = 0;
	    ctxPtr = TclStackAlloc(interp, sizeof(CmdFrame));
	    *ctxPtr = *invoker;







>
>
>
>







|







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
	 *     offset between saved starting line and actual one. Then modify
	 *     the users to adjust the locations they have by this offset.
	 *
	 * (3) Alternative 2: Do not fully recompile, adjust just the location
	 *     information.
	 */

	if (!invoker) {
	    return codePtr;
	}
	
	{
	    Tcl_HashEntry *hePtr =
		    Tcl_FindHashEntry(iPtr->lineBCPtr, codePtr);
	    ExtCmdLoc *eclPtr;
	    CmdFrame *ctxPtr;
	    int redo;

	    if (!hePtr) {
		return codePtr;
	    }

	    eclPtr = Tcl_GetHashValue(hePtr);
	    redo = 0;
	    ctxPtr = TclStackAlloc(interp, sizeof(CmdFrame));
	    *ctxPtr = *invoker;
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
    iPtr->stats.numExecutions++;
#endif

    /*
     * Push the callback for bytecode execution
     */
    
    TclNRAddCallback(interp, TEBCresume, TD,
	    /*resume*/ INT2PTR(0), NULL, NULL);
    
    return TCL_OK;
}

static int
TEBCresume(
    ClientData data[],
    Tcl_Interp *interp,







|
|
<







1988
1989
1990
1991
1992
1993
1994
1995
1996

1997
1998
1999
2000
2001
2002
2003
    iPtr->stats.numExecutions++;
#endif

    /*
     * Push the callback for bytecode execution
     */
    
    TclNRAddCallback(interp, TEBCresume, TD, /*resume*/ INT2PTR(0),
	    NULL, NULL);

    return TCL_OK;
}

static int
TEBCresume(
    ClientData data[],
    Tcl_Interp *interp,
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
		/* TODO: convert panic to error ? */
		Tcl_Panic("max size for a Tcl value (%d bytes) exceeded",
			INT_MAX);
	    }
#if !TCL_COMPILE_DEBUG
	    if (bytes != tclEmptyStringRep && !Tcl_IsShared(objResultPtr)) {
		TclFreeIntRep(objResultPtr);
		objResultPtr->typePtr = NULL;
		objResultPtr->bytes = ckrealloc(bytes, length+appendLen+1);
		objResultPtr->length = length + appendLen;
		p = TclGetString(objResultPtr) + length;
		currPtr = &OBJ_AT_DEPTH(opnd - 2);
	    } else
#endif
	    {







<







2548
2549
2550
2551
2552
2553
2554

2555
2556
2557
2558
2559
2560
2561
		/* TODO: convert panic to error ? */
		Tcl_Panic("max size for a Tcl value (%d bytes) exceeded",
			INT_MAX);
	    }
#if !TCL_COMPILE_DEBUG
	    if (bytes != tclEmptyStringRep && !Tcl_IsShared(objResultPtr)) {
		TclFreeIntRep(objResultPtr);

		objResultPtr->bytes = ckrealloc(bytes, length+appendLen+1);
		objResultPtr->length = length + appendLen;
		p = TclGetString(objResultPtr) + length;
		currPtr = &OBJ_AT_DEPTH(opnd - 2);
	    } else
#endif
	    {
5614
5615
5616
5617
5618
5619
5620
5621
5622
5623
5624
5625
5626
5627
5628
    /*
     * -----------------------------------------------------------------
     *	   Start of dictionary-related instructions.
     */

    {
	int opnd2, allocateDict, done, i, allocdict;
	Tcl_Obj *dictPtr, *statePtr, *keyPtr;
	Tcl_Obj *emptyPtr, **keyPtrPtr;
	Tcl_DictSearch *searchPtr;
	DictUpdateInfo *duiPtr;

    case INST_DICT_GET:
	opnd = TclGetUInt4AtPtr(pc+1);
	TRACE(("%u => ", opnd));







|







5620
5621
5622
5623
5624
5625
5626
5627
5628
5629
5630
5631
5632
5633
5634
    /*
     * -----------------------------------------------------------------
     *	   Start of dictionary-related instructions.
     */

    {
	int opnd2, allocateDict, done, i, allocdict;
	Tcl_Obj *dictPtr, *statePtr, *keyPtr, *listPtr, *varNamePtr, *keysPtr;
	Tcl_Obj *emptyPtr, **keyPtrPtr;
	Tcl_DictSearch *searchPtr;
	DictUpdateInfo *duiPtr;

    case INST_DICT_GET:
	opnd = TclGetUInt4AtPtr(pc+1);
	TRACE(("%u => ", opnd));
6094
6095
6096
6097
6098
6099
6100








































































6101
6102
6103
6104
6105
6106
6107
		if (allocdict) {
		    TclDecrRefCount(dictPtr);
		}
		goto gotError;
	    }
	}
	NEXT_INST_F(9, 1, 0);








































































    }

    /*
     *	   End of dictionary-related instructions.
     * -----------------------------------------------------------------
     */








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







6100
6101
6102
6103
6104
6105
6106
6107
6108
6109
6110
6111
6112
6113
6114
6115
6116
6117
6118
6119
6120
6121
6122
6123
6124
6125
6126
6127
6128
6129
6130
6131
6132
6133
6134
6135
6136
6137
6138
6139
6140
6141
6142
6143
6144
6145
6146
6147
6148
6149
6150
6151
6152
6153
6154
6155
6156
6157
6158
6159
6160
6161
6162
6163
6164
6165
6166
6167
6168
6169
6170
6171
6172
6173
6174
6175
6176
6177
6178
6179
6180
6181
6182
6183
6184
6185
		if (allocdict) {
		    TclDecrRefCount(dictPtr);
		}
		goto gotError;
	    }
	}
	NEXT_INST_F(9, 1, 0);

    case INST_DICT_EXPAND:
	dictPtr = OBJ_UNDER_TOS;
	listPtr = OBJ_AT_TOS;
	if (TclListObjGetElements(interp, listPtr, &objc, &objv) != TCL_OK) {
	    TRACE_WITH_OBJ(("%.30s %.30s => ERROR: ",
		    O2S(dictPtr), O2S(listPtr)), Tcl_GetObjResult(interp));
	    goto gotError;
	}
	objResultPtr = TclDictWithInit(interp, dictPtr, objc, objv);
	if (objResultPtr == NULL) {
	    TRACE_WITH_OBJ(("%.30s %.30s => ERROR: ",
		    O2S(dictPtr), O2S(listPtr)), Tcl_GetObjResult(interp));
	    goto gotError;
	}
	TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
	NEXT_INST_F(1, 2, 1);

    case INST_DICT_RECOMBINE_STK:
	keysPtr = POP_OBJECT();
	varNamePtr = OBJ_UNDER_TOS;
	listPtr = OBJ_AT_TOS;
	TRACE(("\"%.30s\" \"%.30s\" \"%.30s\" => ",
		O2S(varNamePtr), O2S(valuePtr), O2S(keysPtr)));
	if (TclListObjGetElements(interp, listPtr, &objc, &objv) != TCL_OK) {
	    TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp))));
	    TclDecrRefCount(keysPtr);
	    goto gotError;
	}
	varPtr = TclObjLookupVarEx(interp, varNamePtr, NULL,
		TCL_LEAVE_ERR_MSG, "set", 1, 1, &arrayPtr);
	if (varPtr == NULL) {
	    TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp))));
	    TclDecrRefCount(keysPtr);
	    goto gotError;
	}
	DECACHE_STACK_INFO();
	result = TclDictWithFinish(interp, varPtr,arrayPtr,varNamePtr,NULL,-1,
		objc, objv, keysPtr);
	CACHE_STACK_INFO();
	TclDecrRefCount(keysPtr);
	if (result != TCL_OK) {
	    TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp))));
	    goto gotError;
	}
	TRACE_APPEND(("OK\n"));
	NEXT_INST_F(1, 2, 0);

    case INST_DICT_RECOMBINE_IMM:
	opnd = TclGetUInt4AtPtr(pc+1);
	listPtr = OBJ_UNDER_TOS;
	keysPtr = OBJ_AT_TOS;
	varPtr = LOCAL(opnd);
	TRACE(("%u <- \"%.30s\" \"%.30s\" => ", opnd, O2S(valuePtr),
		O2S(keysPtr)));
	if (TclListObjGetElements(interp, listPtr, &objc, &objv) != TCL_OK) {
	    TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp))));
	    goto gotError;
	}
	while (TclIsVarLink(varPtr)) {
	    varPtr = varPtr->value.linkPtr;
	}
	DECACHE_STACK_INFO();
	result = TclDictWithFinish(interp, varPtr, NULL, NULL, NULL, opnd,
		objc, objv, keysPtr);
	CACHE_STACK_INFO();
	if (result != TCL_OK) {
	    TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp))));
	    goto gotError;
	}
	TRACE_APPEND(("OK\n"));
	NEXT_INST_F(5, 2, 0);
    }

    /*
     *	   End of dictionary-related instructions.
     * -----------------------------------------------------------------
     */

6258
6259
6260
6261
6262
6263
6264
6265
6266
6267
6268
6269
6270
6271
6272
	/*
	 * Clear all expansions that may have started after the last
	 * INST_BEGIN_CATCH.
	 */

	while (auxObjList) {
	    if ((catchTop != initCatchTop) &&
		    (*catchTop>auxObjList->internalRep.ptrAndLongRep.value)) {
		break;
	    }
	    POP_TAUX_OBJ();
	}

	/*
	 * We must not catch if the script in progress has been canceled with







|







6336
6337
6338
6339
6340
6341
6342
6343
6344
6345
6346
6347
6348
6349
6350
	/*
	 * Clear all expansions that may have started after the last
	 * INST_BEGIN_CATCH.
	 */

	while (auxObjList) {
	    if ((catchTop != initCatchTop) &&
		(*catchTop > ((ptrdiff_t) auxObjList->internalRep.ptrAndLongRep.value))) {
		break;
	    }
	    POP_TAUX_OBJ();
	}

	/*
	 * We must not catch if the script in progress has been canceled with
8434
8435
8436
8437
8438
8439
8440
8441
8442
8443
8444
8445
8446
8447
8448
    /*
     * Summary statistics, total and current source and ByteCode sizes.
     */

    Tcl_AppendPrintfToObj(objPtr, "\n----------------------------------------------------------------\n");
    Tcl_AppendPrintfToObj(objPtr,
	    "Compilation and execution statistics for interpreter %#lx\n",
	    iPtr);

    Tcl_AppendPrintfToObj(objPtr, "\nNumber ByteCodes executed\t%ld\n",
	    statsPtr->numExecutions);
    Tcl_AppendPrintfToObj(objPtr, "Number ByteCodes compiled\t%ld\n",
	    statsPtr->numCompilations);
    Tcl_AppendPrintfToObj(objPtr, "  Mean executions/compile\t%.1f\n",
	    statsPtr->numExecutions / (float)statsPtr->numCompilations);







|







8512
8513
8514
8515
8516
8517
8518
8519
8520
8521
8522
8523
8524
8525
8526
    /*
     * Summary statistics, total and current source and ByteCode sizes.
     */

    Tcl_AppendPrintfToObj(objPtr, "\n----------------------------------------------------------------\n");
    Tcl_AppendPrintfToObj(objPtr,
	    "Compilation and execution statistics for interpreter %#lx\n",
	    (long int)iPtr);

    Tcl_AppendPrintfToObj(objPtr, "\nNumber ByteCodes executed\t%ld\n",
	    statsPtr->numExecutions);
    Tcl_AppendPrintfToObj(objPtr, "Number ByteCodes compiled\t%ld\n",
	    statsPtr->numCompilations);
    Tcl_AppendPrintfToObj(objPtr, "  Mean executions/compile\t%.1f\n",
	    statsPtr->numExecutions / (float)statsPtr->numCompilations);

Changes to generic/tclFCmd.c.

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
    }

    objc -= 2;
    objv += 2;
    result = TCL_ERROR;
    Tcl_SetErrno(0);





    attributeStrings = Tcl_FSFileAttrStrings(filePtr, &objStrings);
    if (attributeStrings == NULL) {
	int index;
	Tcl_Obj *objPtr;

	if (objStrings == NULL) {
	    if (Tcl_GetErrno() != 0) {
		/*
		 * There was an error, probably that the filePtr is not
		 * accepted by any filesystem
		 */
		Tcl_AppendResult(interp, "could not read \"",
			TclGetString(filePtr), "\": ", Tcl_PosixError(interp),
			NULL);
		return TCL_ERROR;
	    }
	    goto end;

	}

	/*
	 * We own the object now.
	 */

	Tcl_IncrRefCount(objStrings);







>
>
>
>














<

<
>







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
    }

    objc -= 2;
    objv += 2;
    result = TCL_ERROR;
    Tcl_SetErrno(0);

    /*
     * Get the set of attribute names from the filesystem.
     */

    attributeStrings = Tcl_FSFileAttrStrings(filePtr, &objStrings);
    if (attributeStrings == NULL) {
	int index;
	Tcl_Obj *objPtr;

	if (objStrings == NULL) {
	    if (Tcl_GetErrno() != 0) {
		/*
		 * There was an error, probably that the filePtr is not
		 * accepted by any filesystem
		 */
		Tcl_AppendResult(interp, "could not read \"",
			TclGetString(filePtr), "\": ", Tcl_PosixError(interp),
			NULL);

	    }

	    return TCL_ERROR;
	}

	/*
	 * We own the object now.
	 */

	Tcl_IncrRefCount(objStrings);
1002
1003
1004
1005
1006
1007
1008


1009







1010
1011
1012
1013
1014
1015
1016
		TclStackAlloc(interp, (1+numObjStrings) * sizeof(char *));
	for (index = 0; index < numObjStrings; index++) {
	    Tcl_ListObjIndex(interp, objStrings, index, &objPtr);
	    attributeStringsAllocated[index] = TclGetString(objPtr);
	}
	attributeStringsAllocated[index] = NULL;
	attributeStrings = attributeStringsAllocated;


    }







    if (objc == 0) {
	/*
	 * Get all attributes.
	 */

	int index, res = TCL_OK, nbAtts = 0;
	Tcl_Obj *listPtr;







>
>

>
>
>
>
>
>
>







1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
		TclStackAlloc(interp, (1+numObjStrings) * sizeof(char *));
	for (index = 0; index < numObjStrings; index++) {
	    Tcl_ListObjIndex(interp, objStrings, index, &objPtr);
	    attributeStringsAllocated[index] = TclGetString(objPtr);
	}
	attributeStringsAllocated[index] = NULL;
	attributeStrings = attributeStringsAllocated;
    } else if (objStrings != NULL) {
	Tcl_Panic("must not update objPtrRef's variable and return non-NULL");
    }

    /*
     * Process the attributes to produce a list of all of them, the value of a
     * particular attribute, or to set one or more attributes (depending on
     * the number of arguments).
     */

    if (objc == 0) {
	/*
	 * Get all attributes.
	 */

	int index, res = TCL_OK, nbAtts = 0;
	Tcl_Obj *listPtr;
1056
1057
1058
1059
1060
1061
1062

1063
1064
1065
1066
1067
1068
1069
	int index;
	Tcl_Obj *objPtr = NULL;

	if (numObjStrings == 0) {
	    Tcl_AppendResult(interp, "bad option \"", TclGetString(objv[0]),
		    "\", there are no file attributes in this filesystem.",
		    NULL);

	    goto end;
	}

	if (Tcl_GetIndexFromObj(interp, objv[0], attributeStrings,
		"option", 0, &index) != TCL_OK) {
	    goto end;
	}







>







1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
	int index;
	Tcl_Obj *objPtr = NULL;

	if (numObjStrings == 0) {
	    Tcl_AppendResult(interp, "bad option \"", TclGetString(objv[0]),
		    "\", there are no file attributes in this filesystem.",
		    NULL);
	    Tcl_SetErrorCode(interp, "TCL","OPERATION","FATTR","NONE", NULL);
	    goto end;
	}

	if (Tcl_GetIndexFromObj(interp, objv[0], attributeStrings,
		"option", 0, &index) != TCL_OK) {
	    goto end;
	}
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

	int i, index;

	if (numObjStrings == 0) {
	    Tcl_AppendResult(interp, "bad option \"", TclGetString(objv[0]),
		    "\", there are no file attributes in this filesystem.",
		    NULL);

	    goto end;
	}

	for (i = 0; i < objc ; i += 2) {
	    if (Tcl_GetIndexFromObj(interp, objv[i], attributeStrings,
		    "option", 0, &index) != TCL_OK) {
		goto end;
	    }
	    if (attributeStringsAllocated != NULL) {
		TclFreeIntRep(objv[i]);
	    }
	    if (i + 1 == objc) {
		Tcl_AppendResult(interp, "value for \"",
			TclGetString(objv[i]), "\" missing", NULL);


		goto end;
	    }
	    if (Tcl_FSFileAttrsSet(interp, index, filePtr,
		    objv[i + 1]) != TCL_OK) {
		goto end;
	    }
	}
    }
    result = TCL_OK;

  end:
    if (attributeStringsAllocated != NULL) {
	/*
	 * Free up the array we allocated.

	 */



	TclStackFree(interp, (void *) attributeStringsAllocated);

	/*
	 * We don't need this object that was passed to us any more.
	 */

	if (objStrings != NULL) {
	    Tcl_DecrRefCount(objStrings);
	}
    }
    return result;
}

/*
 *----------------------------------------------------------------------
 *







>














>
>










<
<
|
|
>
|

>
>

|
<
<
<
<
|
|
<







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

	int i, index;

	if (numObjStrings == 0) {
	    Tcl_AppendResult(interp, "bad option \"", TclGetString(objv[0]),
		    "\", there are no file attributes in this filesystem.",
		    NULL);
	    Tcl_SetErrorCode(interp, "TCL","OPERATION","FATTR","NONE", NULL);
	    goto end;
	}

	for (i = 0; i < objc ; i += 2) {
	    if (Tcl_GetIndexFromObj(interp, objv[i], attributeStrings,
		    "option", 0, &index) != TCL_OK) {
		goto end;
	    }
	    if (attributeStringsAllocated != NULL) {
		TclFreeIntRep(objv[i]);
	    }
	    if (i + 1 == objc) {
		Tcl_AppendResult(interp, "value for \"",
			TclGetString(objv[i]), "\" missing", NULL);
		Tcl_SetErrorCode(interp, "TCL", "OPERATION", "FATTR",
			"NOVALUE", NULL);
		goto end;
	    }
	    if (Tcl_FSFileAttrsSet(interp, index, filePtr,
		    objv[i + 1]) != TCL_OK) {
		goto end;
	    }
	}
    }
    result = TCL_OK;



    /*
     * Free up the array we allocated and drop our reference to any list of
     * attribute names issued by the filesystem.
     */

  end:
    if (attributeStringsAllocated != NULL) {
	TclStackFree(interp, (void *) attributeStringsAllocated);
    }




    if (objStrings != NULL) {
	Tcl_DecrRefCount(objStrings);

    }
    return result;
}

/*
 *----------------------------------------------------------------------
 *
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
	     * errors, we use the standard posix error message.
	     */

	    if (errno == EEXIST) {
		Tcl_AppendResult(interp, "could not create new link \"",
			TclGetString(objv[index]),
			"\": that path already exists", NULL);

	    } else if (errno == ENOENT) {
		/*
		 * There are two cases here: either the target doesn't exist,
		 * or the directory of the src doesn't exist.
		 */

		int access;
		Tcl_Obj *dirPtr = TclPathPart(interp, objv[index],
			TCL_PATH_DIRNAME);

		if (dirPtr == NULL) {
		    return TCL_ERROR;
		}
		access = Tcl_FSAccess(dirPtr, F_OK);
		Tcl_DecrRefCount(dirPtr);
		if (access != 0) {
		    Tcl_AppendResult(interp, "could not create new link \"",
			    TclGetString(objv[index]),
			    "\": no such file or directory", NULL);

		} else {
		    Tcl_AppendResult(interp, "could not create new link \"",
			    TclGetString(objv[index]), "\": target \"",
			    TclGetString(objv[index+1]), "\" doesn't exist",
			    NULL);


		}
	    } else {
		Tcl_AppendResult(interp, "could not create new link \"",
			TclGetString(objv[index]), "\" pointing to \"",
			TclGetString(objv[index+1]), "\": ",
			Tcl_PosixError(interp), NULL);
	    }







>



















>





>
>







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
	     * errors, we use the standard posix error message.
	     */

	    if (errno == EEXIST) {
		Tcl_AppendResult(interp, "could not create new link \"",
			TclGetString(objv[index]),
			"\": that path already exists", NULL);
		Tcl_PosixError(interp);
	    } else if (errno == ENOENT) {
		/*
		 * There are two cases here: either the target doesn't exist,
		 * or the directory of the src doesn't exist.
		 */

		int access;
		Tcl_Obj *dirPtr = TclPathPart(interp, objv[index],
			TCL_PATH_DIRNAME);

		if (dirPtr == NULL) {
		    return TCL_ERROR;
		}
		access = Tcl_FSAccess(dirPtr, F_OK);
		Tcl_DecrRefCount(dirPtr);
		if (access != 0) {
		    Tcl_AppendResult(interp, "could not create new link \"",
			    TclGetString(objv[index]),
			    "\": no such file or directory", NULL);
		    Tcl_PosixError(interp);
		} else {
		    Tcl_AppendResult(interp, "could not create new link \"",
			    TclGetString(objv[index]), "\": target \"",
			    TclGetString(objv[index+1]), "\" doesn't exist",
			    NULL);
		    errno = ENOENT;
		    Tcl_PosixError(interp);
		}
	    } else {
		Tcl_AppendResult(interp, "could not create new link \"",
			TclGetString(objv[index]), "\" pointing to \"",
			TclGetString(objv[index+1]), "\": ",
			Tcl_PosixError(interp), NULL);
	    }

Changes to generic/tclFileName.c.

1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
    Tcl_Interp *interp,		/* Current interpreter. */
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    int index, i, globFlags, length, join, dir, result;
    char *string;
    const char *separators;
    Tcl_Obj *typePtr, *resultPtr, *look;
    Tcl_Obj *pathOrDir = NULL;
    Tcl_DString prefix;
    static const char *const options[] = {
	"-directory", "-join", "-nocomplain", "-path", "-tails",
	"-types", "--", NULL
    };
    enum options {







|







1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
    Tcl_Interp *interp,		/* Current interpreter. */
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    int index, i, globFlags, length, join, dir, result;
    char *string;
    const char *separators;
    Tcl_Obj *typePtr, *look;
    Tcl_Obj *pathOrDir = NULL;
    Tcl_DString prefix;
    static const char *const options[] = {
	"-directory", "-join", "-nocomplain", "-path", "-tails",
	"-types", "--", NULL
    };
    enum options {
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
		}
		globTypes->macType = look;
		Tcl_IncrRefCount(look);

	    } else {
		Tcl_Obj *item;

		if ((Tcl_ListObjLength(NULL, look, &len) == TCL_OK) &&
			(len == 3)) {
		    Tcl_ListObjIndex(interp, look, 0, &item);
		    if (!strcmp("macintosh", Tcl_GetString(item))) {
			Tcl_ListObjIndex(interp, look, 1, &item);
			if (!strcmp("type", Tcl_GetString(item))) {
			    Tcl_ListObjIndex(interp, look, 2, &item);
			    if (globTypes->macType != NULL) {
				goto badMacTypesArg;







|
|







1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
		}
		globTypes->macType = look;
		Tcl_IncrRefCount(look);

	    } else {
		Tcl_Obj *item;

		if ((Tcl_ListObjLength(NULL, look, &len) == TCL_OK)
			&& (len == 3)) {
		    Tcl_ListObjIndex(interp, look, 0, &item);
		    if (!strcmp("macintosh", Tcl_GetString(item))) {
			Tcl_ListObjIndex(interp, look, 1, &item);
			if (!strcmp("type", Tcl_GetString(item))) {
			    Tcl_ListObjIndex(interp, look, 2, &item);
			    if (globTypes->macType != NULL) {
				goto badMacTypesArg;
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534


1535
1536
1537
1538
1539
1540
1541

		/*
		 * Error cases. We reset the 'join' flag to zero, since we
		 * haven't yet made use of it.
		 */

	    badTypesArg:
		TclNewObj(resultPtr);
		Tcl_AppendToObj(resultPtr, "bad argument to \"-types\": ", -1);
		Tcl_AppendObjToObj(resultPtr, look);
		Tcl_SetObjResult(interp, resultPtr);


		Tcl_SetErrorCode(interp, "TCL", "ARGUMENT", "BAD", NULL);
		result = TCL_ERROR;
		join = 0;
		goto endOfGlob;

	    badMacTypesArg:
		Tcl_SetObjResult(interp, Tcl_NewStringObj(







<
<
<
|
>
>







1524
1525
1526
1527
1528
1529
1530



1531
1532
1533
1534
1535
1536
1537
1538
1539
1540

		/*
		 * Error cases. We reset the 'join' flag to zero, since we
		 * haven't yet made use of it.
		 */

	    badTypesArg:



		Tcl_SetObjResult(interp, Tcl_ObjPrintf(
			"bad argument to \"-types\": %s",
			Tcl_GetString(look)));
		Tcl_SetErrorCode(interp, "TCL", "ARGUMENT", "BAD", NULL);
		result = TCL_ERROR;
		join = 0;
		goto endOfGlob;

	    badMacTypesArg:
		Tcl_SetObjResult(interp, Tcl_NewStringObj(
1620
1621
1622
1623
1624
1625
1626

1627
1628
1629
1630
1631
1632
1633
	if (length == 0) {
	    Tcl_AppendResult(interp, "no files matched glob pattern",
		    (join || (objc == 1)) ? " \"" : "s \"", NULL);
	    if (join) {
		Tcl_AppendResult(interp, Tcl_DStringValue(&prefix), NULL);
	    } else {
		const char *sep = "";

		for (i = 0; i < objc; i++) {
		    string = Tcl_GetString(objv[i]);
		    Tcl_AppendResult(interp, sep, string, NULL);
		    sep = " ";
		}
	    }
	    Tcl_AppendResult(interp, "\"", NULL);







>







1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
	if (length == 0) {
	    Tcl_AppendResult(interp, "no files matched glob pattern",
		    (join || (objc == 1)) ? " \"" : "s \"", NULL);
	    if (join) {
		Tcl_AppendResult(interp, Tcl_DStringValue(&prefix), NULL);
	    } else {
		const char *sep = "";

		for (i = 0; i < objc; i++) {
		    string = Tcl_GetString(objv[i]);
		    Tcl_AppendResult(interp, sep, string, NULL);
		    sep = " ";
		}
	    }
	    Tcl_AppendResult(interp, "\"", NULL);

Changes to generic/tclGet.c.

49
50
51
52
53
54
55

56
57
58
59
60
61
62
    obj.length = strlen(src);
    obj.typePtr = NULL;

    code = Tcl_GetIntFromObj(interp, &obj, intPtr);
    if (obj.refCount > 1) {
	Tcl_Panic("invalid sharing of Tcl_Obj on C stack");
    }

    return code;
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_GetDouble --







>







49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
    obj.length = strlen(src);
    obj.typePtr = NULL;

    code = Tcl_GetIntFromObj(interp, &obj, intPtr);
    if (obj.refCount > 1) {
	Tcl_Panic("invalid sharing of Tcl_Obj on C stack");
    }
    TclFreeIntRep(&obj);
    return code;
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_GetDouble --
92
93
94
95
96
97
98

99
100
101
102
103
104
105
    obj.length = strlen(src);
    obj.typePtr = NULL;

    code = Tcl_GetDoubleFromObj(interp, &obj, doublePtr);
    if (obj.refCount > 1) {
	Tcl_Panic("invalid sharing of Tcl_Obj on C stack");
    }

    return code;
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_GetBoolean --







>







93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
    obj.length = strlen(src);
    obj.typePtr = NULL;

    code = Tcl_GetDoubleFromObj(interp, &obj, doublePtr);
    if (obj.refCount > 1) {
	Tcl_Panic("invalid sharing of Tcl_Obj on C stack");
    }
    TclFreeIntRep(&obj);
    return code;
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_GetBoolean --

Changes to generic/tclIO.c.

75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
			    Tcl_Interp *interp);
static void		DeleteScriptRecord(Tcl_Interp *interp,
			    Channel *chanPtr, int mask);
static int		DetachChannel(Tcl_Interp *interp, Tcl_Channel chan);
static void		DiscardInputQueued(ChannelState *statePtr,
			    int discardSavedBuffers);
static void		DiscardOutputQueued(ChannelState *chanPtr);
static int		DoRead(Channel *chanPtr, char *srcPtr, int slen);
static int		DoWrite(Channel *chanPtr, const char *src, int srcLen);
static int		DoReadChars(Channel *chan, Tcl_Obj *objPtr, int toRead,
			    int appendFlag);
static int		DoWriteChars(Channel *chan, const char *src, int len);
static int		FilterInputBytes(Channel *chanPtr,
			    GetsState *statePtr);
static int		FlushChannel(Tcl_Interp *interp, Channel *chanPtr,







|







75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
			    Tcl_Interp *interp);
static void		DeleteScriptRecord(Tcl_Interp *interp,
			    Channel *chanPtr, int mask);
static int		DetachChannel(Tcl_Interp *interp, Tcl_Channel chan);
static void		DiscardInputQueued(ChannelState *statePtr,
			    int discardSavedBuffers);
static void		DiscardOutputQueued(ChannelState *chanPtr);
static int		DoRead(Channel *chanPtr, char *srcPtr, int slen, int allowShortReads);
static int		DoWrite(Channel *chanPtr, const char *src, int srcLen);
static int		DoReadChars(Channel *chan, Tcl_Obj *objPtr, int toRead,
			    int appendFlag);
static int		DoWriteChars(Channel *chan, const char *src, int len);
static int		FilterInputBytes(Channel *chanPtr,
			    GetsState *statePtr);
static int		FlushChannel(Tcl_Interp *interp, Channel *chanPtr,
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
	 */

	active = 0;
	for (statePtr = tsdPtr->firstCSPtr;
		statePtr != NULL;
		statePtr = statePtr->nextCSPtr) {
	    chanPtr = statePtr->topChanPtr;
	    if (!GotFlag(statePtr, CHANNEL_INCLOSE | CHANNEL_CLOSED |
		    CHANNEL_DEAD)) {
		active = 1;
		break;
	    }
	}

	/*
	 * We've found a live channel. Close it.







|
|







410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
	 */

	active = 0;
	for (statePtr = tsdPtr->firstCSPtr;
		statePtr != NULL;
		statePtr = statePtr->nextCSPtr) {
	    chanPtr = statePtr->topChanPtr;
            if (!GotFlag(statePtr, CHANNEL_INCLOSE | CHANNEL_CLOSED | CHANNEL_DEAD)
                || GotFlag(statePtr, BG_FLUSH_SCHEDULED)) {
		active = 1;
		break;
	    }
	}

	/*
	 * We've found a live channel. Close it.
454
455
456
457
458
459
460

461
462
463
464
465
466
467

		(void) Tcl_Close(NULL, (Tcl_Channel) chanPtr);
	    } else {
		/*
		 * The refcount is greater than zero, so flush the channel.
		 */


		Tcl_Flush((Tcl_Channel) chanPtr);

		/*
		 * Call the device driver to actually close the underlying
		 * device for this channel.
		 */








>







454
455
456
457
458
459
460
461
462
463
464
465
466
467
468

		(void) Tcl_Close(NULL, (Tcl_Channel) chanPtr);
	    } else {
		/*
		 * The refcount is greater than zero, so flush the channel.
		 */

                ResetFlag(statePtr, BG_FLUSH_SCHEDULED);
		Tcl_Flush((Tcl_Channel) chanPtr);

		/*
		 * Call the device driver to actually close the underlying
		 * device for this channel.
		 */

2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
{
    Channel *chanPtr;		/* The actual channel. */
    ClientData handle;
    int result;

    chanPtr = ((Channel *) chan)->state->bottomChanPtr;
    if (!chanPtr->typePtr->getHandleProc) {
	Tcl_Obj *err;

	TclNewLiteralStringObj(err, "channel \"");
	Tcl_AppendToObj(err, Tcl_GetChannelName(chan), -1);
	Tcl_AppendToObj(err, "\" does not support OS handles", -1);
	Tcl_SetChannelError(chan, err);
	return TCL_ERROR;
    }
    result = chanPtr->typePtr->getHandleProc(chanPtr->instanceData, direction,
	    &handle);
    if (handlePtr) {
	*handlePtr = handle;
    }







<
|
<
<
|
|







2092
2093
2094
2095
2096
2097
2098

2099


2100
2101
2102
2103
2104
2105
2106
2107
2108
{
    Channel *chanPtr;		/* The actual channel. */
    ClientData handle;
    int result;

    chanPtr = ((Channel *) chan)->state->bottomChanPtr;
    if (!chanPtr->typePtr->getHandleProc) {

        Tcl_SetChannelError(chan, Tcl_ObjPrintf(


                "channel \"%s\" does not support OS handles",
                Tcl_GetChannelName(chan)));
	return TCL_ERROR;
    }
    result = chanPtr->typePtr->getHandleProc(chanPtr->instanceData, direction,
	    &handle);
    if (handlePtr) {
	*handlePtr = handle;
    }
2354
2355
2356
2357
2358
2359
2360

2361
2362
2363
2364
2365
2366
2367
    }

    /*
     * Loop over the queued buffers and attempt to flush as much as possible
     * of the queued output to the channel.
     */


    while (1) {
	/*
	 * If the queue is empty and there is a ready current buffer, OR if
	 * the current buffer is full, then move the current buffer to the
	 * queue.
	 */








>







2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
    }

    /*
     * Loop over the queued buffers and attempt to flush as much as possible
     * of the queued output to the channel.
     */

    Tcl_Preserve(chanPtr);
    while (1) {
	/*
	 * If the queue is empty and there is a ready current buffer, OR if
	 * the current buffer is full, then move the current buffer to the
	 * queue.
	 */

2383
2384
2385
2386
2387
2388
2389
2390

2391
2392
2393
2394
2395
2396
2397

	/*
	 * If we are not being called from an async flush and an async flush
	 * is active, we just return without producing any output.
	 */

	if (!calledFromAsyncFlush && GotFlag(statePtr, BG_FLUSH_SCHEDULED)) {
	    return 0;

	}

	/*
	 * If the output queue is still empty, break out of the while loop.
	 */

	if (bufPtr == NULL) {







|
>







2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397

	/*
	 * If we are not being called from an async flush and an async flush
	 * is active, we just return without producing any output.
	 */

	if (!calledFromAsyncFlush && GotFlag(statePtr, BG_FLUSH_SCHEDULED)) {
	    errorCode = 0;
	    goto done;
	}

	/*
	 * If the output queue is still empty, break out of the while loop.
	 */

	if (bufPtr == NULL) {
2506
2507
2508
2509
2510
2511
2512

2513

2514
2515
2516
2517
2518
2519
2520

	    DiscardOutputQueued(statePtr);
	    continue;
	} else {
	    wroteSome = 1;
	}


	bufPtr->nextRemoved += written;


	/*
	 * If this buffer is now empty, recycle it.
	 */

	if (IsBufferEmpty(bufPtr)) {
	    statePtr->outQueueHead = bufPtr->nextPtr;







>
|
>







2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522

	    DiscardOutputQueued(statePtr);
	    continue;
	} else {
	    wroteSome = 1;
	}

	if (!IsBufferEmpty(bufPtr)) {
	    bufPtr->nextRemoved += written;
	}

	/*
	 * If this buffer is now empty, recycle it.
	 */

	if (IsBufferEmpty(bufPtr)) {
	    statePtr->outQueueHead = bufPtr->nextPtr;
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
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
     * We can't finish the background flush until we run out of data and the
     * channel becomes writable again. This ensures that all of the pending
     * data has been flushed at the system level.
     */

    if (GotFlag(statePtr, BG_FLUSH_SCHEDULED)) {
	if (wroteSome) {
	    return errorCode;
	} else if (statePtr->outQueueHead == NULL) {
	    ResetFlag(statePtr, BG_FLUSH_SCHEDULED);
	    ChanWatch(chanPtr, statePtr->interestMask);
	}
    }

    /*
     * If the channel is flagged as closed, delete it when the refCount drops
     * to zero, the output queue is empty and there is no output in the
     * current output buffer.
     */

    if (GotFlag(statePtr, CHANNEL_CLOSED) && (statePtr->refCount <= 0) &&
	    (statePtr->outQueueHead == NULL) &&
	    ((statePtr->curOutPtr == NULL) ||
	    IsBufferEmpty(statePtr->curOutPtr))) {
	return CloseChannel(interp, chanPtr, errorCode);

    }

    /*
     * If the write-side of the channel is flagged as closed, delete it when
     * the output queue is empty and there is no output in the current output
     * buffer.
     */

    if (GotFlag(statePtr, CHANNEL_CLOSEDWRITE) &&
	    (statePtr->outQueueHead == NULL) &&
	    ((statePtr->curOutPtr == NULL) ||
	    IsBufferEmpty(statePtr->curOutPtr))) {
	return CloseChannelPart(interp, chanPtr, errorCode, TCL_CLOSE_WRITE);

    }



    return errorCode;
}

/*
 *----------------------------------------------------------------------
 *
 * CloseChannel --







|
















|
>












|
>

>
>
>







2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
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
2581
2582
     * We can't finish the background flush until we run out of data and the
     * channel becomes writable again. This ensures that all of the pending
     * data has been flushed at the system level.
     */

    if (GotFlag(statePtr, BG_FLUSH_SCHEDULED)) {
	if (wroteSome) {
	    goto done;
	} else if (statePtr->outQueueHead == NULL) {
	    ResetFlag(statePtr, BG_FLUSH_SCHEDULED);
	    ChanWatch(chanPtr, statePtr->interestMask);
	}
    }

    /*
     * If the channel is flagged as closed, delete it when the refCount drops
     * to zero, the output queue is empty and there is no output in the
     * current output buffer.
     */

    if (GotFlag(statePtr, CHANNEL_CLOSED) && (statePtr->refCount <= 0) &&
	    (statePtr->outQueueHead == NULL) &&
	    ((statePtr->curOutPtr == NULL) ||
	    IsBufferEmpty(statePtr->curOutPtr))) {
	errorCode = CloseChannel(interp, chanPtr, errorCode);
	goto done;
    }

    /*
     * If the write-side of the channel is flagged as closed, delete it when
     * the output queue is empty and there is no output in the current output
     * buffer.
     */

    if (GotFlag(statePtr, CHANNEL_CLOSEDWRITE) &&
	    (statePtr->outQueueHead == NULL) &&
	    ((statePtr->curOutPtr == NULL) ||
	    IsBufferEmpty(statePtr->curOutPtr))) {
	errorCode = CloseChannelPart(interp, chanPtr, errorCode, TCL_CLOSE_WRITE);
	goto done;
    }

  done:
    Tcl_Release(chanPtr);
    return errorCode;
}

/*
 *----------------------------------------------------------------------
 *
 * CloseChannel --
5442
5443
5444
5445
5446
5447
5448
5449
5450
5451
5452
5453
5454
5455
5456

    chanPtr = statePtr->topChanPtr;

    if (CheckChannelErrors(statePtr, TCL_READABLE) != 0) {
	return -1;
    }

    return DoRead(chanPtr, dst, bytesToRead);
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_ReadRaw --
 *







|







5449
5450
5451
5452
5453
5454
5455
5456
5457
5458
5459
5460
5461
5462
5463

    chanPtr = statePtr->topChanPtr;

    if (CheckChannelErrors(statePtr, TCL_READABLE) != 0) {
	return -1;
    }

    return DoRead(chanPtr, dst, bytesToRead, 0);
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_ReadRaw --
 *
9167
9168
9169
9170
9171
9172
9173
9174

9175
9176
9177
9178
9179
9180
9181
                    || (csPtr->toRead > (Tcl_WideInt) csPtr->bufSize)) {
		sizeb = csPtr->bufSize;
	    } else {
		sizeb = (int) csPtr->toRead;
	    }

	    if (inBinary || sameEncoding) {
		size = DoRead(inStatePtr->topChanPtr, csPtr->buffer, sizeb);

	    } else {
		size = DoReadChars(inStatePtr->topChanPtr, bufObj, sizeb,
			0 /* No append */);
	    }
	    underflow = (size >= 0) && (size < sizeb);	/* Input underflow */
	}








|
>







9174
9175
9176
9177
9178
9179
9180
9181
9182
9183
9184
9185
9186
9187
9188
9189
                    || (csPtr->toRead > (Tcl_WideInt) csPtr->bufSize)) {
		sizeb = csPtr->bufSize;
	    } else {
		sizeb = (int) csPtr->toRead;
	    }

	    if (inBinary || sameEncoding) {
		size = DoRead(inStatePtr->topChanPtr, csPtr->buffer, sizeb,
                              !GotFlag(inStatePtr, CHANNEL_NONBLOCKING));
	    } else {
		size = DoReadChars(inStatePtr->topChanPtr, bufObj, sizeb,
			0 /* No append */);
	    }
	    underflow = (size >= 0) && (size < sizeb);	/* Input underflow */
	}

9203
9204
9205
9206
9207
9208
9209
9210
9211
9212
9213
9214
9215
9216
9217
9218
	     * copying is done, otherwise set up a channel handler to detect
	     * when the channel becomes readable again.
	     */

	    if ((size == 0) && Tcl_Eof(inChan) && !(cmdPtr && (mask == 0))) {
		break;
	    }
	    if (((!Tcl_Eof(inChan)) || (cmdPtr && (mask == 0))) &&
		    !(mask & TCL_READABLE)) {
		if (mask & TCL_WRITABLE) {
		    Tcl_DeleteChannelHandler(outChan, CopyEventProc, csPtr);
		}
		Tcl_CreateChannelHandler(inChan, TCL_READABLE, CopyEventProc,
			csPtr);
	    }
	    if (size == 0) {







|
|







9211
9212
9213
9214
9215
9216
9217
9218
9219
9220
9221
9222
9223
9224
9225
9226
	     * copying is done, otherwise set up a channel handler to detect
	     * when the channel becomes readable again.
	     */

	    if ((size == 0) && Tcl_Eof(inChan) && !(cmdPtr && (mask == 0))) {
		break;
	    }
	    if (cmdPtr && (!Tcl_Eof(inChan) || (mask == 0)) &&
                !(mask & TCL_READABLE)) {
		if (mask & TCL_WRITABLE) {
		    Tcl_DeleteChannelHandler(outChan, CopyEventProc, csPtr);
		}
		Tcl_CreateChannelHandler(inChan, TCL_READABLE, CopyEventProc,
			csPtr);
	    }
	    if (size == 0) {
9406
9407
9408
9409
9410
9411
9412
9413

9414
9415
9416
9417
9418
9419
9420
 *----------------------------------------------------------------------
 */

static int
DoRead(
    Channel *chanPtr,		/* The channel from which to read. */
    char *bufPtr,		/* Where to store input read. */
    int toRead)			/* Maximum number of bytes to read. */

{
    ChannelState *statePtr = chanPtr->state;
				/* State info for channel */
    int copied;			/* How many characters were copied into the
				 * result string? */
    int copiedNow;		/* How many characters were copied from the
				 * current input buffer? */







|
>







9414
9415
9416
9417
9418
9419
9420
9421
9422
9423
9424
9425
9426
9427
9428
9429
 *----------------------------------------------------------------------
 */

static int
DoRead(
    Channel *chanPtr,		/* The channel from which to read. */
    char *bufPtr,		/* Where to store input read. */
    int toRead,			/* Maximum number of bytes to read. */
    int allowShortReads)	/* Allow half-blocking (pipes,sockets) */
{
    ChannelState *statePtr = chanPtr->state;
				/* State info for channel */
    int copied;			/* How many characters were copied into the
				 * result string? */
    int copiedNow;		/* How many characters were copied from the
				 * current input buffer? */
9447
9448
9449
9450
9451
9452
9453



9454
9455
9456
9457
9458
9459
9460
9461
	    result = GetInput(chanPtr);
	    if (result != 0) {
		if (result != EAGAIN) {
		    copied = -1;
		}
		goto done;
	    }



	}
    }

    ResetFlag(statePtr, CHANNEL_BLOCKED);

    /*
     * Update the notifier state so we don't block while there is still data
     * in the buffers.







>
>
>
|







9456
9457
9458
9459
9460
9461
9462
9463
9464
9465
9466
9467
9468
9469
9470
9471
9472
9473
	    result = GetInput(chanPtr);
	    if (result != 0) {
		if (result != EAGAIN) {
		    copied = -1;
		}
		goto done;
	    }
	} else if (allowShortReads) {
            copied += copiedNow;
            break;
        }
    }

    ResetFlag(statePtr, CHANNEL_BLOCKED);

    /*
     * Update the notifier state so we don't block while there is still data
     * in the buffers.
11192
11193
11194
11195
11196
11197
11198



11199
11200
11201
11202
11203
11204
11205
SetChannelFromAny(
    Tcl_Interp *interp,		/* Used for error reporting if not NULL. */
    register Tcl_Obj *objPtr)	/* The object to convert. */
{
    ChannelState *statePtr;
    Interp *interpPtr;




    if (objPtr->typePtr == &tclChannelType) {
	/*
	 * The channel is valid until any call to DetachChannel occurs.
	 * Ensure consistency checks are done.
	 */

	statePtr = GET_CHANNELSTATE(objPtr);







>
>
>







11204
11205
11206
11207
11208
11209
11210
11211
11212
11213
11214
11215
11216
11217
11218
11219
11220
SetChannelFromAny(
    Tcl_Interp *interp,		/* Used for error reporting if not NULL. */
    register Tcl_Obj *objPtr)	/* The object to convert. */
{
    ChannelState *statePtr;
    Interp *interpPtr;

    if (interp == NULL) {
	return TCL_ERROR;
    }
    if (objPtr->typePtr == &tclChannelType) {
	/*
	 * The channel is valid until any call to DetachChannel occurs.
	 * Ensure consistency checks are done.
	 */

	statePtr = GET_CHANNELSTATE(objPtr);

Changes to generic/tclIOCmd.c.

136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
				 * [puts $chan $x nonewline] */
	newline = 0;
	if (strcmp(TclGetString(objv[1]), "-nonewline") == 0) {
	    chanObjPtr = objv[2];
	    string = objv[3];
	    break;
#if TCL_MAJOR_VERSION < 9
	} else if (strcmp(TclGetString(objv[2]), "nonewline") == 0) {
	    /*
	     * The code below provides backwards compatibility with an old
	     * form of the command that is no longer recommended or
	     * documented. See also [Bug #3151675]. Will be removed in Tcl 9,
	     * maybe even earlier.
	     */








|







136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
				 * [puts $chan $x nonewline] */
	newline = 0;
	if (strcmp(TclGetString(objv[1]), "-nonewline") == 0) {
	    chanObjPtr = objv[2];
	    string = objv[3];
	    break;
#if TCL_MAJOR_VERSION < 9
	} else if (strcmp(TclGetString(objv[3]), "nonewline") == 0) {
	    /*
	     * The code below provides backwards compatibility with an old
	     * form of the command that is no longer recommended or
	     * documented. See also [Bug #3151675]. Will be removed in Tcl 9,
	     * maybe even earlier.
	     */

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
     * Most commands are plugged directly together, but some are done via
     * alias-like rewriting; [chan configure] is this way for security reasons
     * (want overwriting of [fconfigure] to control that nicely), and [chan
     * names] because the functionality isn't available as a separate command
     * function at the moment.
     */
    static const EnsembleImplMap initMap[] = {
	{"blocked",	Tcl_FblockedObjCmd},
	{"close",	Tcl_CloseObjCmd},
	{"copy",	Tcl_FcopyObjCmd},
	{"create",	TclChanCreateObjCmd},		/* TIP #219 */
	{"eof",		Tcl_EofObjCmd},
	{"event",	Tcl_FileEventObjCmd},
	{"flush",	Tcl_FlushObjCmd},
	{"gets",	Tcl_GetsObjCmd},
	{"names",	TclChannelNamesCmd},
	{"pending",	ChanPendingObjCmd},		/* TIP #287 */
	{"pop",		TclChanPopObjCmd},		/* TIP #230 */
	{"postevent",	TclChanPostEventObjCmd},	/* TIP #219 */
	{"push",	TclChanPushObjCmd},		/* TIP #230 */
	{"puts",	Tcl_PutsObjCmd},
	{"read",	Tcl_ReadObjCmd},
	{"seek",	Tcl_SeekObjCmd},
	{"pipe",	ChanPipeObjCmd},		/* TIP #304 */
	{"tell",	Tcl_TellObjCmd},
	{"truncate",	ChanTruncateObjCmd},		/* TIP #208 */
	{NULL, NULL, NULL, NULL, NULL, 0}
    };
    static const char *const extras[] = {
	"configure",	"::fconfigure",
	NULL
    };
    Tcl_Command ensemble;







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







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
     * Most commands are plugged directly together, but some are done via
     * alias-like rewriting; [chan configure] is this way for security reasons
     * (want overwriting of [fconfigure] to control that nicely), and [chan
     * names] because the functionality isn't available as a separate command
     * function at the moment.
     */
    static const EnsembleImplMap initMap[] = {
	{"blocked",	Tcl_FblockedObjCmd, NULL, NULL, NULL, 0},
	{"close",	Tcl_CloseObjCmd, NULL, NULL, NULL, 0},
	{"copy",	Tcl_FcopyObjCmd, NULL, NULL, NULL, 0},
	{"create",	TclChanCreateObjCmd, NULL, NULL, NULL, 0},		/* TIP #219 */
	{"eof",		Tcl_EofObjCmd, NULL, NULL, NULL, 0},
	{"event",	Tcl_FileEventObjCmd, NULL, NULL, NULL, 0},
	{"flush",	Tcl_FlushObjCmd, NULL, NULL, NULL, 0},
	{"gets",	Tcl_GetsObjCmd, NULL, NULL, NULL, 0},
	{"names",	TclChannelNamesCmd, NULL, NULL, NULL, 0},
	{"pending",	ChanPendingObjCmd, NULL, NULL, NULL, 0},		/* TIP #287 */
	{"pop",		TclChanPopObjCmd, NULL, NULL, NULL, 0},		/* TIP #230 */
	{"postevent",	TclChanPostEventObjCmd, NULL, NULL, NULL, 0},	/* TIP #219 */
	{"push",	TclChanPushObjCmd, NULL, NULL, NULL, 0},		/* TIP #230 */
	{"puts",	Tcl_PutsObjCmd, NULL, NULL, NULL, 0},
	{"read",	Tcl_ReadObjCmd, NULL, NULL, NULL, 0},
	{"seek",	Tcl_SeekObjCmd, NULL, NULL, NULL, 0},
	{"pipe",	ChanPipeObjCmd, NULL, NULL, NULL, 0},		/* TIP #304 */
	{"tell",	Tcl_TellObjCmd, NULL, NULL, NULL, 0},
	{"truncate",	ChanTruncateObjCmd, NULL, NULL, NULL, 0},		/* TIP #208 */
	{NULL, NULL, NULL, NULL, NULL, 0}
    };
    static const char *const extras[] = {
	"configure",	"::fconfigure",
	NULL
    };
    Tcl_Command ensemble;

Changes to generic/tclIORChan.c.

117
118
119
120
121
122
123



124
125
126
127
128
129
130
     * names?
     */

    int mode;			/* Mask of R/W mode */
    int interest;		/* Mask of events the channel is interested
				 * in. */




    /*
     * Note regarding the usage of timers.
     *
     * Most channel implementations need a timer in the C level to ensure that
     * data in buffers is flushed out through the generation of fake file
     * events.
     *







>
>
>







117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
     * names?
     */

    int mode;			/* Mask of R/W mode */
    int interest;		/* Mask of events the channel is interested
				 * in. */

    int dead;			/* Boolean signal that some operations
				 * should no longer be attempted. */

    /*
     * Note regarding the usage of timers.
     *
     * Most channel implementations need a timer in the C level to ensure that
     * data in buffers is flushed out through the generation of fake file
     * events.
     *
435
436
437
438
439
440
441

442
443
444
445
446
447
448
static int		EncodeEventMask(Tcl_Interp *interp,
			    const char *objName, Tcl_Obj *obj, int *mask);
static Tcl_Obj *	DecodeEventMask(int mask);
static ReflectedChannel * NewReflectedChannel(Tcl_Interp *interp,
			    Tcl_Obj *cmdpfxObj, int mode, Tcl_Obj *handleObj);
static Tcl_Obj *	NextHandle(void);
static void		FreeReflectedChannel(ReflectedChannel *rcPtr);

static int		InvokeTclMethod(ReflectedChannel *rcPtr,
			    const char *method, Tcl_Obj *argOneObj,
			    Tcl_Obj *argTwoObj, Tcl_Obj **resultObjPtr);

static ReflectedChannelMap *	GetReflectedChannelMap(Tcl_Interp *interp);
static void		DeleteReflectedChannelMap(ClientData clientData,
			    Tcl_Interp *interp);







>







438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
static int		EncodeEventMask(Tcl_Interp *interp,
			    const char *objName, Tcl_Obj *obj, int *mask);
static Tcl_Obj *	DecodeEventMask(int mask);
static ReflectedChannel * NewReflectedChannel(Tcl_Interp *interp,
			    Tcl_Obj *cmdpfxObj, int mode, Tcl_Obj *handleObj);
static Tcl_Obj *	NextHandle(void);
static void		FreeReflectedChannel(ReflectedChannel *rcPtr);
static void		FreeReflectedChannelArgs(ReflectedChannel *rcPtr);
static int		InvokeTclMethod(ReflectedChannel *rcPtr,
			    const char *method, Tcl_Obj *argOneObj,
			    Tcl_Obj *argTwoObj, Tcl_Obj **resultObjPtr);

static ReflectedChannelMap *	GetReflectedChannelMap(Tcl_Interp *interp);
static void		DeleteReflectedChannelMap(ClientData clientData,
			    Tcl_Interp *interp);
601
602
603
604
605
606
607
608
609
610
611
612


613
614
615
616
617
618
619
     * Verify the result.
     * - List, of method names. Convert to mask.
     *   Check for non-optionals through the mask.
     *   Compare open mode against optional r/w.
     */

    if (Tcl_ListObjGetElements(NULL, resObj, &listc, &listv) != TCL_OK) {
	TclNewLiteralStringObj(err, "chan handler \"");
	Tcl_AppendObjToObj(err, cmdObj);
	Tcl_AppendToObj(err, " initialize\" returned non-list: ", -1);
	Tcl_AppendObjToObj(err, resObj);
	Tcl_SetObjResult(interp, err);


	Tcl_DecrRefCount(resObj);
	goto error;
    }

    methods = 0;
    while (listc > 0) {
	if (Tcl_GetIndexFromObj(interp, listv[listc-1], methodNames,







<
<
<
<
|
>
>







605
606
607
608
609
610
611




612
613
614
615
616
617
618
619
620
621
     * Verify the result.
     * - List, of method names. Convert to mask.
     *   Check for non-optionals through the mask.
     *   Compare open mode against optional r/w.
     */

    if (Tcl_ListObjGetElements(NULL, resObj, &listc, &listv) != TCL_OK) {




        Tcl_SetObjResult(interp, Tcl_ObjPrintf(
                "chan handler \"%s initialize\" returned non-list: %s",
                Tcl_GetString(cmdObj), Tcl_GetString(resObj)));
	Tcl_DecrRefCount(resObj);
	goto error;
    }

    methods = 0;
    while (listc > 0) {
	if (Tcl_GetIndexFromObj(interp, listv[listc-1], methodNames,
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

	methods |= FLAG(methIndex);
	listc--;
    }
    Tcl_DecrRefCount(resObj);

    if ((REQUIRED_METHODS & methods) != REQUIRED_METHODS) {
	TclNewLiteralStringObj(err, "chan handler \"");
	Tcl_AppendObjToObj(err, cmdObj);
	Tcl_AppendToObj(err, "\" does not support all required methods", -1);
	Tcl_SetObjResult(interp, err);


	goto error;
    }

    if ((mode & TCL_READABLE) && !HAS(methods, METH_READ)) {
	TclNewLiteralStringObj(err, "chan handler \"");
	Tcl_AppendObjToObj(err, cmdObj);
	Tcl_AppendToObj(err, "\" lacks a \"read\" method", -1);
	Tcl_SetObjResult(interp, err);


	goto error;
    }

    if ((mode & TCL_WRITABLE) && !HAS(methods, METH_WRITE)) {
	TclNewLiteralStringObj(err, "chan handler \"");
	Tcl_AppendObjToObj(err, cmdObj);
	Tcl_AppendToObj(err, "\" lacks a \"write\" method", -1);
	Tcl_SetObjResult(interp, err);


	goto error;
    }

    if (!IMPLIES(HAS(methods, METH_CGET), HAS(methods, METH_CGETALL))) {
	TclNewLiteralStringObj(err, "chan handler \"");
	Tcl_AppendObjToObj(err, cmdObj);
	Tcl_AppendToObj(err, "\" supports \"cget\" but not \"cgetall\"", -1);
	Tcl_SetObjResult(interp, err);


	goto error;
    }

    if (!IMPLIES(HAS(methods, METH_CGETALL), HAS(methods, METH_CGET))) {
	TclNewLiteralStringObj(err, "chan handler \"");
	Tcl_AppendObjToObj(err, cmdObj);
	Tcl_AppendToObj(err, "\" supports \"cgetall\" but not \"cget\"", -1);
	Tcl_SetObjResult(interp, err);


	goto error;
    }

    Tcl_ResetResult(interp);

    /*
     * Everything is fine now.







<
<
<
|
>
>




<
<
<
|
>
>




<
<
<
|
>
>




<
<
<
|
>
>




<
<
<
|
>
>







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

	methods |= FLAG(methIndex);
	listc--;
    }
    Tcl_DecrRefCount(resObj);

    if ((REQUIRED_METHODS & methods) != REQUIRED_METHODS) {



        Tcl_SetObjResult(interp, Tcl_ObjPrintf(
                "chan handler \"%s\" does not support all required methods",
                Tcl_GetString(cmdObj)));
	goto error;
    }

    if ((mode & TCL_READABLE) && !HAS(methods, METH_READ)) {



        Tcl_SetObjResult(interp, Tcl_ObjPrintf(
                "chan handler \"%s\" lacks a \"read\" method",
                Tcl_GetString(cmdObj)));
	goto error;
    }

    if ((mode & TCL_WRITABLE) && !HAS(methods, METH_WRITE)) {



        Tcl_SetObjResult(interp, Tcl_ObjPrintf(
                "chan handler \"%s\" lacks a \"write\" method",
                Tcl_GetString(cmdObj)));
	goto error;
    }

    if (!IMPLIES(HAS(methods, METH_CGET), HAS(methods, METH_CGETALL))) {



        Tcl_SetObjResult(interp, Tcl_ObjPrintf(
                "chan handler \"%s\" supports \"cget\" but not \"cgetall\"",
                Tcl_GetString(cmdObj)));
	goto error;
    }

    if (!IMPLIES(HAS(methods, METH_CGETALL), HAS(methods, METH_CGET))) {



        Tcl_SetObjResult(interp, Tcl_ObjPrintf(
                "chan handler \"%s\" supports \"cgetall\" but not \"cget\"",
                Tcl_GetString(cmdObj)));
	goto error;
    }

    Tcl_ResetResult(interp);

    /*
     * Everything is fine now.
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
#ifdef TCL_THREADS
	if (rcPtr->thread != Tcl_GetCurrentThread()) {
	    ForwardParam p;

	    ForwardOpToOwnerThread(rcPtr, ForwardedClose, &p);
	    result = p.base.code;

	    /*
	     * FreeReflectedChannel is done in the forwarded operation!, in
	     * the other thread. rcPtr here is gone!
	     */

	    if (result != TCL_OK) {
		FreeReceivedError(&p);
	    }
	    return EOK;
	}
#endif

        Tcl_EventuallyFree (rcPtr, (Tcl_FreeProc *) FreeReflectedChannel);
	return EOK;
    }








<
<
<
<
<



<







1066
1067
1068
1069
1070
1071
1072





1073
1074
1075

1076
1077
1078
1079
1080
1081
1082
#ifdef TCL_THREADS
	if (rcPtr->thread != Tcl_GetCurrentThread()) {
	    ForwardParam p;

	    ForwardOpToOwnerThread(rcPtr, ForwardedClose, &p);
	    result = p.base.code;






	    if (result != TCL_OK) {
		FreeReceivedError(&p);
	    }

	}
#endif

        Tcl_EventuallyFree (rcPtr, (Tcl_FreeProc *) FreeReflectedChannel);
	return EOK;
    }

1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
#ifdef TCL_THREADS
    if (rcPtr->thread != Tcl_GetCurrentThread()) {
	ForwardParam p;

	ForwardOpToOwnerThread(rcPtr, ForwardedClose, &p);
	result = p.base.code;

	/*
	 * FreeReflectedChannel is done in the forwarded operation!, in the
	 * other thread. rcPtr here is gone!
	 */

	if (result != TCL_OK) {
	    PassReceivedErrorInterp(interp, &p);
	}
    } else {
#endif
	result = InvokeTclMethod(rcPtr, "finalize", NULL, NULL, &resObj);







<
|
<
<







1099
1100
1101
1102
1103
1104
1105

1106


1107
1108
1109
1110
1111
1112
1113
#ifdef TCL_THREADS
    if (rcPtr->thread != Tcl_GetCurrentThread()) {
	ForwardParam p;

	ForwardOpToOwnerThread(rcPtr, ForwardedClose, &p);
	result = p.base.code;


        Tcl_EventuallyFree (rcPtr, (Tcl_FreeProc *) FreeReflectedChannel);



	if (result != TCL_OK) {
	    PassReceivedErrorInterp(interp, &p);
	}
    } else {
#endif
	result = InvokeTclMethod(rcPtr, "finalize", NULL, NULL, &resObj);
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
	 * when the channel was created in a different interpreter and/or
	 * thread and then was moved here.
	 *
	 * NOTE: The channel may have been removed from the map already via
	 * the per-interp DeleteReflectedChannelMap exit-handler.
	 */

	if (rcPtr->interp) {
	    rcmPtr = GetReflectedChannelMap(rcPtr->interp);
	    hPtr = Tcl_FindHashEntry(&rcmPtr->map,
		    Tcl_GetChannelName(rcPtr->chan));
	    if (hPtr) {
		Tcl_DeleteHashEntry(hPtr);
	    }
	}







|







1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
	 * when the channel was created in a different interpreter and/or
	 * thread and then was moved here.
	 *
	 * NOTE: The channel may have been removed from the map already via
	 * the per-interp DeleteReflectedChannelMap exit-handler.
	 */

	if (!rcPtr->dead) {
	    rcmPtr = GetReflectedChannelMap(rcPtr->interp);
	    hPtr = Tcl_FindHashEntry(&rcmPtr->map,
		    Tcl_GetChannelName(rcPtr->chan));
	    if (hPtr) {
		Tcl_DeleteHashEntry(hPtr);
	    }
	}
2033
2034
2035
2036
2037
2038
2039

2040
2041
2042
2043
2044
2045
2046

    /* rcPtr->chan: Assigned by caller. Dummy data here. */
    /* rcPtr->methods: Assigned by caller. Dummy data here. */

    rcPtr->chan = NULL;
    rcPtr->methods = 0;
    rcPtr->interp = interp;

#ifdef TCL_THREADS
    rcPtr->thread = Tcl_GetCurrentThread();
#endif
    rcPtr->mode = mode;
    rcPtr->interest = 0;		/* Initially no interest registered */

    /*







>







2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035

    /* rcPtr->chan: Assigned by caller. Dummy data here. */
    /* rcPtr->methods: Assigned by caller. Dummy data here. */

    rcPtr->chan = NULL;
    rcPtr->methods = 0;
    rcPtr->interp = interp;
    rcPtr->dead = 0;
#ifdef TCL_THREADS
    rcPtr->thread = Tcl_GetCurrentThread();
#endif
    rcPtr->mode = mode;
    rcPtr->interest = 0;		/* Initially no interest registered */

    /*
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
    rcCounter++;
    Tcl_MutexUnlock(&rcCounterMutex);

    return resObj;
}

static void
FreeReflectedChannel(
    ReflectedChannel *rcPtr)
{
    Channel *chanPtr = (Channel *) rcPtr->chan;
    int i, n;

    if (chanPtr->typePtr != &tclRChannelType) {
	/*
	 * Delete a cloned ChannelType structure.
	 */

	ckfree(chanPtr->typePtr);
    }

    n = rcPtr->argc - 2;
    for (i=0; i<n; i++) {
	Tcl_DecrRefCount(rcPtr->argv[i]);
    }

    /*
     * [Bug 1667990]: See [x] in NewReflectedChannel for lock. n+1 = argc-1.
     */

    Tcl_DecrRefCount(rcPtr->argv[n+1]);





















    ckfree(rcPtr->argv);
    ckfree(rcPtr);
}

/*
 *----------------------------------------------------------------------
 *







|


<
|

|
<
<
<
|
<

<
<










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







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
    rcCounter++;
    Tcl_MutexUnlock(&rcCounterMutex);

    return resObj;
}

static void
FreeReflectedChannelArgs(
    ReflectedChannel *rcPtr)
{

    int i, n = rcPtr->argc - 2;

    if (n < 0) {



	return;

    }


    for (i=0; i<n; i++) {
	Tcl_DecrRefCount(rcPtr->argv[i]);
    }

    /*
     * [Bug 1667990]: See [x] in NewReflectedChannel for lock. n+1 = argc-1.
     */

    Tcl_DecrRefCount(rcPtr->argv[n+1]);

    rcPtr->argc = 1;
}

static void
FreeReflectedChannel(
    ReflectedChannel *rcPtr)
{
    Channel *chanPtr = (Channel *) rcPtr->chan;

    if (chanPtr->typePtr != &tclRChannelType) {
	/*
	 * Delete a cloned ChannelType structure.
	 */

	ckfree(chanPtr->typePtr);
	chanPtr->typePtr = NULL;
    }

    FreeReflectedChannelArgs(rcPtr);

    ckfree(rcPtr->argv);
    ckfree(rcPtr);
}

/*
 *----------------------------------------------------------------------
 *
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
{
    int cmdc;			/* #words in constructed command */
    Tcl_Obj *methObj = NULL;	/* Method name in object form */
    Tcl_InterpState sr;		/* State of handler interp */
    int result;			/* Result code of method invokation */
    Tcl_Obj *resObj = NULL;	/* Result of method invokation. */

    if (!rcPtr->interp) {
	/*
	 * The channel is marked as dead. Bail out immediately, with an
	 * appropriate error.
	 */

	if (resultObjPtr != NULL) {
	    resObj = Tcl_NewStringObj(msg_dstlost,-1);







|







2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
{
    int cmdc;			/* #words in constructed command */
    Tcl_Obj *methObj = NULL;	/* Method name in object form */
    Tcl_InterpState sr;		/* State of handler interp */
    int result;			/* Result code of method invokation */
    Tcl_Obj *resObj = NULL;	/* Result of method invokation. */

    if (rcPtr->dead) {
	/*
	 * The channel is marked as dead. Bail out immediately, with an
	 * appropriate error.
	 */

	if (resultObjPtr != NULL) {
	    resObj = Tcl_NewStringObj(msg_dstlost,-1);
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
ErrnoReturn(
    ReflectedChannel *rcPtr,
    Tcl_Obj *resObj)
{
    int code;
    Tcl_InterpState sr;		/* State of handler interp */

    if (!rcPtr->interp) {
	return 0;
    }

    sr = Tcl_SaveInterpState(rcPtr->interp, 0 /* Dummy */);
    UnmarshallErrorResult(rcPtr->interp, resObj);

    resObj = Tcl_GetObjResult(rcPtr->interp);







|







2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
ErrnoReturn(
    ReflectedChannel *rcPtr,
    Tcl_Obj *resObj)
{
    int code;
    Tcl_InterpState sr;		/* State of handler interp */

    if (rcPtr->dead) {
	return 0;
    }

    sr = Tcl_SaveInterpState(rcPtr->interp, 0 /* Dummy */);
    UnmarshallErrorResult(rcPtr->interp, resObj);

    resObj = Tcl_GetObjResult(rcPtr->interp);
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487

    for (hPtr = Tcl_FirstHashEntry(&rcmPtr->map, &hSearch);
	    hPtr != NULL;
	    hPtr = Tcl_FirstHashEntry(&rcmPtr->map, &hSearch)) {
	chan = Tcl_GetHashValue(hPtr);
	rcPtr = Tcl_GetChannelInstanceData(chan);

	rcPtr->interp = NULL;
	Tcl_DeleteHashEntry(hPtr);
    }
    Tcl_DeleteHashTable(&rcmPtr->map);
    ckfree(&rcmPtr->map);

#ifdef TCL_THREADS
    /*







|







2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489

    for (hPtr = Tcl_FirstHashEntry(&rcmPtr->map, &hSearch);
	    hPtr != NULL;
	    hPtr = Tcl_FirstHashEntry(&rcmPtr->map, &hSearch)) {
	chan = Tcl_GetHashValue(hPtr);
	rcPtr = Tcl_GetChannelInstanceData(chan);

	rcPtr->dead = 1;
	Tcl_DeleteHashEntry(hPtr);
    }
    Tcl_DeleteHashTable(&rcmPtr->map);
    ckfree(&rcmPtr->map);

#ifdef TCL_THREADS
    /*
2509
2510
2511
2512
2513
2514
2515





2516
2517
2518
2519
2520
2521
2522
2523
2524
2525

2526
2527
2528
2529
2530
2531
2532

	/*
	 * The receiver for the event exited, before processing the event. We
	 * detach the result now, wake the originator up and signal failure.
	 */

	evPtr = resultPtr->evPtr;





	paramPtr = evPtr->param;

	evPtr->resultPtr = NULL;
	resultPtr->evPtr = NULL;
	resultPtr->result = TCL_ERROR;

	ForwardSetStaticError(paramPtr, msg_send_dstlost);

	Tcl_ConditionNotify(&resultPtr->done);
    }


    /*
     * Get the map of all channels handled by the current thread. This is a
     * ReflectedChannelMap, but on a per-thread basis, not per-interp. Go
     * through the channels and remove all which were handled by this
     * interpreter. They have already been marked as dead.
     */







>
>
>
>
>










>







2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540

	/*
	 * The receiver for the event exited, before processing the event. We
	 * detach the result now, wake the originator up and signal failure.
	 */

	evPtr = resultPtr->evPtr;

	/* Basic crash safety until this routine can get revised [3411310] */
	if (evPtr == NULL) {
	    continue;
	}
	paramPtr = evPtr->param;

	evPtr->resultPtr = NULL;
	resultPtr->evPtr = NULL;
	resultPtr->result = TCL_ERROR;

	ForwardSetStaticError(paramPtr, msg_send_dstlost);

	Tcl_ConditionNotify(&resultPtr->done);
    }
    Tcl_MutexUnlock(&rcForwardMutex);

    /*
     * Get the map of all channels handled by the current thread. This is a
     * ReflectedChannelMap, but on a per-thread basis, not per-interp. Go
     * through the channels and remove all which were handled by this
     * interpreter. They have already been marked as dead.
     */
2542
2543
2544
2545
2546
2547
2548


2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
	    /*
	     * Ignore entries for other interpreters.
	     */

	    continue;
	}



	Tcl_DeleteHashEntry(hPtr);
    }

    Tcl_MutexUnlock(&rcForwardMutex);
#endif
}

#ifdef TCL_THREADS
/*
 *----------------------------------------------------------------------
 *







>
>


<
<







2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560


2561
2562
2563
2564
2565
2566
2567
	    /*
	     * Ignore entries for other interpreters.
	     */

	    continue;
	}

	rcPtr->dead = 1;
	FreeReflectedChannelArgs(rcPtr);
	Tcl_DeleteHashEntry(hPtr);
    }


#endif
}

#ifdef TCL_THREADS
/*
 *----------------------------------------------------------------------
 *
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
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

	/*
	 * The receiver for the event exited, before processing the event. We
	 * detach the result now, wake the originator up and signal failure.
	 */

	evPtr = resultPtr->evPtr;





	paramPtr = evPtr->param;

	evPtr->resultPtr = NULL;
	resultPtr->evPtr = NULL;
	resultPtr->result = TCL_ERROR;

	ForwardSetStaticError(paramPtr, msg_send_dstlost);

	Tcl_ConditionNotify(&resultPtr->done);
    }


    /*
     * Get the map of all channels handled by the current thread. This is a
     * ReflectedChannelMap, but on a per-thread basis, not per-interp. Go
     * through the channels, remove all, mark them as dead.
     */

    rcmPtr = GetThreadReflectedChannelMap();
    for (hPtr = Tcl_FirstHashEntry(&rcmPtr->map, &hSearch);
	    hPtr != NULL;
	    hPtr = Tcl_FirstHashEntry(&rcmPtr->map, &hSearch)) {
	Tcl_Channel chan = Tcl_GetHashValue(hPtr);
	ReflectedChannel *rcPtr = Tcl_GetChannelInstanceData(chan);

	rcPtr->interp = NULL;

	Tcl_DeleteHashEntry(hPtr);
    }

    Tcl_MutexUnlock(&rcForwardMutex);
}

static void
ForwardOpToOwnerThread(
    ReflectedChannel *rcPtr,	/* Channel instance */
    ForwardedOperation op,	/* Forwarded driver operation */
    const void *param)		/* Arguments */
{
    Tcl_ThreadId dst = rcPtr->thread;
    ForwardingEvent *evPtr;
    ForwardingResult *resultPtr;

    /*
     * We gather the lock early. This allows us to check the liveness of the
     * channel without interference from DeleteThreadReflectedChannelMap().
     */

    Tcl_MutexLock(&rcForwardMutex);

    if (rcPtr->interp == NULL) {
	/*
	 * The channel is marked as dead. Bail out immediately, with an
	 * appropriate error. Do not forget to unlock the mutex on this path.
	 */

	ForwardSetStaticError((ForwardParam *) param, msg_send_dstlost);
	Tcl_MutexUnlock(&rcForwardMutex);







>
>
>
>
>










>














|
>


|
<



















|







2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692

2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719

	/*
	 * The receiver for the event exited, before processing the event. We
	 * detach the result now, wake the originator up and signal failure.
	 */

	evPtr = resultPtr->evPtr;

	/* Basic crash safety until this routine can get revised [3411310] */
	if (evPtr == NULL ) {
	    continue;
	}
	paramPtr = evPtr->param;

	evPtr->resultPtr = NULL;
	resultPtr->evPtr = NULL;
	resultPtr->result = TCL_ERROR;

	ForwardSetStaticError(paramPtr, msg_send_dstlost);

	Tcl_ConditionNotify(&resultPtr->done);
    }
    Tcl_MutexUnlock(&rcForwardMutex);

    /*
     * Get the map of all channels handled by the current thread. This is a
     * ReflectedChannelMap, but on a per-thread basis, not per-interp. Go
     * through the channels, remove all, mark them as dead.
     */

    rcmPtr = GetThreadReflectedChannelMap();
    for (hPtr = Tcl_FirstHashEntry(&rcmPtr->map, &hSearch);
	    hPtr != NULL;
	    hPtr = Tcl_FirstHashEntry(&rcmPtr->map, &hSearch)) {
	Tcl_Channel chan = Tcl_GetHashValue(hPtr);
	ReflectedChannel *rcPtr = Tcl_GetChannelInstanceData(chan);

	rcPtr->dead = 1;
	FreeReflectedChannelArgs(rcPtr);
	Tcl_DeleteHashEntry(hPtr);
    }
    ckfree(rcmPtr);

}

static void
ForwardOpToOwnerThread(
    ReflectedChannel *rcPtr,	/* Channel instance */
    ForwardedOperation op,	/* Forwarded driver operation */
    const void *param)		/* Arguments */
{
    Tcl_ThreadId dst = rcPtr->thread;
    ForwardingEvent *evPtr;
    ForwardingResult *resultPtr;

    /*
     * We gather the lock early. This allows us to check the liveness of the
     * channel without interference from DeleteThreadReflectedChannelMap().
     */

    Tcl_MutexLock(&rcForwardMutex);

    if (rcPtr->dead) {
	/*
	 * The channel is marked as dead. Bail out immediately, with an
	 * appropriate error. Do not forget to unlock the mutex on this path.
	 */

	ForwardSetStaticError((ForwardParam *) param, msg_send_dstlost);
	Tcl_MutexUnlock(&rcForwardMutex);
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
	Tcl_DeleteHashEntry(hPtr);

	rcmPtr = GetThreadReflectedChannelMap();
	hPtr = Tcl_FindHashEntry(&rcmPtr->map,
                                 Tcl_GetChannelName(rcPtr->chan));
	Tcl_DeleteHashEntry(hPtr);

        Tcl_EventuallyFree (rcPtr, (Tcl_FreeProc *) FreeReflectedChannel);
	break;

    case ForwardedInput: {
	Tcl_Obj *toReadObj = Tcl_NewIntObj(paramPtr->input.toRead);
        Tcl_IncrRefCount(toReadObj);

        Tcl_Preserve(rcPtr);







|







2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
	Tcl_DeleteHashEntry(hPtr);

	rcmPtr = GetThreadReflectedChannelMap();
	hPtr = Tcl_FindHashEntry(&rcmPtr->map,
                                 Tcl_GetChannelName(rcPtr->chan));
	Tcl_DeleteHashEntry(hPtr);

	FreeReflectedChannelArgs(rcPtr);
	break;

    case ForwardedInput: {
	Tcl_Obj *toReadObj = Tcl_NewIntObj(paramPtr->input.toRead);
        Tcl_IncrRefCount(toReadObj);

        Tcl_Preserve(rcPtr);
2931
2932
2933
2934
2935
2936
2937


2938
2939
2940
2941
2942
2943
2944
2945
	    /*
	     * Process a regular result.
	     */

	    int written;

	    if (Tcl_GetIntFromObj(interp, resObj, &written) != TCL_OK) {


		ForwardSetObjError(paramPtr, MarshallError(interp));
		paramPtr->output.toWrite = -1;
	    } else if (written==0 || paramPtr->output.toWrite<written) {
		ForwardSetStaticError(paramPtr, msg_write_toomuch);
		paramPtr->output.toWrite = -1;
	    } else {
		paramPtr->output.toWrite = written;
	    }







>
>
|







2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
	    /*
	     * Process a regular result.
	     */

	    int written;

	    if (Tcl_GetIntFromObj(interp, resObj, &written) != TCL_OK) {
		Tcl_DecrRefCount(resObj);
		resObj = MarshallError(interp);
		ForwardSetObjError(paramPtr, resObj);
		paramPtr->output.toWrite = -1;
	    } else if (written==0 || paramPtr->output.toWrite<written) {
		ForwardSetStaticError(paramPtr, msg_write_toomuch);
		paramPtr->output.toWrite = -1;
	    } else {
		paramPtr->output.toWrite = written;
	    }
2974
2975
2976
2977
2978
2979
2980


2981
2982
2983
2984
2985
2986
2987
2988
		if (newLoc < Tcl_LongAsWide(0)) {
		    ForwardSetStaticError(paramPtr, msg_seek_beforestart);
		    paramPtr->seek.offset = -1;
		} else {
		    paramPtr->seek.offset = newLoc;
		}
	    } else {


		ForwardSetObjError(paramPtr, MarshallError(interp));
		paramPtr->seek.offset = -1;
	    }
	}
        Tcl_Release(rcPtr);
        Tcl_DecrRefCount(offObj);
        Tcl_DecrRefCount(baseObj);
	break;







>
>
|







2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
		if (newLoc < Tcl_LongAsWide(0)) {
		    ForwardSetStaticError(paramPtr, msg_seek_beforestart);
		    paramPtr->seek.offset = -1;
		} else {
		    paramPtr->seek.offset = newLoc;
		}
	    } else {
		Tcl_DecrRefCount(resObj);
		resObj = MarshallError(interp);
		ForwardSetObjError(paramPtr, resObj);
		paramPtr->seek.offset = -1;
	    }
	}
        Tcl_Release(rcPtr);
        Tcl_DecrRefCount(offObj);
        Tcl_DecrRefCount(baseObj);
	break;
3065
3066
3067
3068
3069
3070
3071


3072
3073
3074
3075
3076
3077
3078
3079
	     */

	    int listc;
	    Tcl_Obj **listv;

	    if (Tcl_ListObjGetElements(interp, resObj, &listc,
                                       &listv) != TCL_OK) {


		ForwardSetObjError(paramPtr, MarshallError(interp));
	    } else if ((listc % 2) == 1) {
		/*
		 * Odd number of elements is wrong. [x].
		 */

		char *buf = ckalloc(200);
		sprintf(buf,







>
>
|







3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
	     */

	    int listc;
	    Tcl_Obj **listv;

	    if (Tcl_ListObjGetElements(interp, resObj, &listc,
                                       &listv) != TCL_OK) {
		Tcl_DecrRefCount(resObj);
		resObj = MarshallError(interp);
		ForwardSetObjError(paramPtr, resObj);
	    } else if ((listc % 2) == 1) {
		/*
		 * Odd number of elements is wrong. [x].
		 */

		char *buf = ckalloc(200);
		sprintf(buf,

Changes to generic/tclIORTrans.c.

157
158
159
160
161
162
163


164
165
166
167
168
169
170
     * NOTE (9): Should we have predefined shared literals for the method
     * names?
     */

    int mode;			/* Mask of R/W mode */
    int nonblocking;		/* Flag: Channel is blocking or not. */
    int readIsDrained;		/* Flag: Read buffers are flushed. */


    ResultBuffer result;
} ReflectedTransform;

/*
 * Structure of the table mapping from transform handles to reflected
 * transform (channels). Each interpreter which has the handler command for
 * one or more reflected transforms records them in such a table, so that we







>
>







157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
     * NOTE (9): Should we have predefined shared literals for the method
     * names?
     */

    int mode;			/* Mask of R/W mode */
    int nonblocking;		/* Flag: Channel is blocking or not. */
    int readIsDrained;		/* Flag: Read buffers are flushed. */
    int dead;			/* Boolean signal that some operations
				 * should no longer be attempted. */
    ResultBuffer result;
} ReflectedTransform;

/*
 * Structure of the table mapping from transform handles to reflected
 * transform (channels). Each interpreter which has the handler command for
 * one or more reflected transforms records them in such a table, so that we
403
404
405
406
407
408
409

410
411
412
413
414
415
416

static Tcl_Obj *	DecodeEventMask(int mask);
static ReflectedTransform * NewReflectedTransform(Tcl_Interp *interp,
			    Tcl_Obj *cmdpfxObj, int mode, Tcl_Obj *handleObj,
			    Tcl_Channel parentChan);
static Tcl_Obj *	NextHandle(void);
static void		FreeReflectedTransform(ReflectedTransform *rtPtr);

static int		InvokeTclMethod(ReflectedTransform *rtPtr,
			    const char *method, Tcl_Obj *argOneObj,
			    Tcl_Obj *argTwoObj, Tcl_Obj **resultObjPtr);

static ReflectedTransformMap *	GetReflectedTransformMap(Tcl_Interp *interp);
static void		DeleteReflectedTransformMap(ClientData clientData,
			    Tcl_Interp *interp);







>







405
406
407
408
409
410
411
412
413
414
415
416
417
418
419

static Tcl_Obj *	DecodeEventMask(int mask);
static ReflectedTransform * NewReflectedTransform(Tcl_Interp *interp,
			    Tcl_Obj *cmdpfxObj, int mode, Tcl_Obj *handleObj,
			    Tcl_Channel parentChan);
static Tcl_Obj *	NextHandle(void);
static void		FreeReflectedTransform(ReflectedTransform *rtPtr);
static void		FreeReflectedTransformArgs(ReflectedTransform *rtPtr);
static int		InvokeTclMethod(ReflectedTransform *rtPtr,
			    const char *method, Tcl_Obj *argOneObj,
			    Tcl_Obj *argTwoObj, Tcl_Obj **resultObjPtr);

static ReflectedTransformMap *	GetReflectedTransformMap(Tcl_Interp *interp);
static void		DeleteReflectedTransformMap(ClientData clientData,
			    Tcl_Interp *interp);
597
598
599
600
601
602
603
604
605
606
607
608


609
610
611
612
613
614
615
    /*
     * Verify the result.
     * - List, of method names. Convert to mask. Check for non-optionals
     *   through the mask. Compare open mode against optional r/w.
     */

    if (Tcl_ListObjGetElements(NULL, resObj, &listc, &listv) != TCL_OK) {
	TclNewLiteralStringObj(err, "chan handler \"");
	Tcl_AppendObjToObj(err, cmdObj);
	Tcl_AppendToObj(err, " initialize\" returned non-list: ", -1);
	Tcl_AppendObjToObj(err, resObj);
	Tcl_SetObjResult(interp, err);


	Tcl_DecrRefCount(resObj);
	goto error;
    }

    methods = 0;
    while (listc > 0) {
	if (Tcl_GetIndexFromObj(interp, listv[listc-1], methodNames,







<
<
<
<
|
>
>







600
601
602
603
604
605
606




607
608
609
610
611
612
613
614
615
616
    /*
     * Verify the result.
     * - List, of method names. Convert to mask. Check for non-optionals
     *   through the mask. Compare open mode against optional r/w.
     */

    if (Tcl_ListObjGetElements(NULL, resObj, &listc, &listv) != TCL_OK) {




        Tcl_SetObjResult(interp, Tcl_ObjPrintf(
                "chan handler \"%s initialize\" returned non-list: %s",
                Tcl_GetString(cmdObj), Tcl_GetString(resObj)));
	Tcl_DecrRefCount(resObj);
	goto error;
    }

    methods = 0;
    while (listc > 0) {
	if (Tcl_GetIndexFromObj(interp, listv[listc-1], methodNames,
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

	methods |= FLAG(methIndex);
	listc--;
    }
    Tcl_DecrRefCount(resObj);

    if ((REQUIRED_METHODS & methods) != REQUIRED_METHODS) {
	TclNewLiteralStringObj(err, "chan handler \"");
	Tcl_AppendObjToObj(err, cmdObj);
	Tcl_AppendToObj(err, "\" does not support all required methods", -1);
	Tcl_SetObjResult(interp, err);


	goto error;
    }

    /*
     * Mode tell us what the parent channel supports. The methods tell us what
     * the handler supports. We remove the non-supported bits from the mode
     * and check that the channel is not completely inacessible. Afterward the
     * mode tells us which methods are still required, and these methods will
     * also be supported by the handler, by design of the check.
     */

    if (!HAS(methods, METH_READ)) {
	mode &= ~TCL_READABLE;
    }
    if (!HAS(methods, METH_WRITE)) {
	mode &= ~TCL_WRITABLE;
    }

    if (!mode) {
	TclNewLiteralStringObj(err, "chan handler \"");
	Tcl_AppendObjToObj(err, cmdObj);
	Tcl_AppendToObj(err, "\" makes the channel inacessible", -1);
	Tcl_SetObjResult(interp, err);


	goto error;
    }

    /*
     * The mode and support for it is ok, now check the internal constraints.
     */

    if (!IMPLIES(HAS(methods, METH_DRAIN), HAS(methods, METH_READ))) {
	TclNewLiteralStringObj(err, "chan handler \"");
	Tcl_AppendObjToObj(err, cmdObj);
	Tcl_AppendToObj(err, "\" supports \"drain\" but not \"read\"", -1);
	Tcl_SetObjResult(interp, err);


	goto error;
    }

    if (!IMPLIES(HAS(methods, METH_FLUSH), HAS(methods, METH_WRITE))) {
	TclNewLiteralStringObj(err, "chan handler \"");
	Tcl_AppendObjToObj(err, cmdObj);
	Tcl_AppendToObj(err, "\" supports \"flush\" but not \"write\"", -1);
	Tcl_SetObjResult(interp, err);


	goto error;
    }

    Tcl_ResetResult(interp);

    /*
     * Everything is fine now.







<
<
<
|
>
>



















<
<
<
|
>
>








<
<
<
|
>
>




<
<
<
|
>
>







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

	methods |= FLAG(methIndex);
	listc--;
    }
    Tcl_DecrRefCount(resObj);

    if ((REQUIRED_METHODS & methods) != REQUIRED_METHODS) {



        Tcl_SetObjResult(interp, Tcl_ObjPrintf(
                "chan handler \"%s\" does not support all required methods",
                Tcl_GetString(cmdObj)));
	goto error;
    }

    /*
     * Mode tell us what the parent channel supports. The methods tell us what
     * the handler supports. We remove the non-supported bits from the mode
     * and check that the channel is not completely inacessible. Afterward the
     * mode tells us which methods are still required, and these methods will
     * also be supported by the handler, by design of the check.
     */

    if (!HAS(methods, METH_READ)) {
	mode &= ~TCL_READABLE;
    }
    if (!HAS(methods, METH_WRITE)) {
	mode &= ~TCL_WRITABLE;
    }

    if (!mode) {



        Tcl_SetObjResult(interp, Tcl_ObjPrintf(
                "chan handler \"%s\" makes the channel inaccessible",
                Tcl_GetString(cmdObj)));
	goto error;
    }

    /*
     * The mode and support for it is ok, now check the internal constraints.
     */

    if (!IMPLIES(HAS(methods, METH_DRAIN), HAS(methods, METH_READ))) {



        Tcl_SetObjResult(interp, Tcl_ObjPrintf(
                "chan handler \"%s\" supports \"drain\" but not \"read\"",
                Tcl_GetString(cmdObj)));
	goto error;
    }

    if (!IMPLIES(HAS(methods, METH_FLUSH), HAS(methods, METH_WRITE))) {



        Tcl_SetObjResult(interp, Tcl_ObjPrintf(
                "chan handler \"%s\" supports \"flush\" but not \"write\"",
                Tcl_GetString(cmdObj)));
	goto error;
    }

    Tcl_ResetResult(interp);

    /*
     * Everything is fine now.
883
884
885
886
887
888
889

890
891
892
893
894
895
896
897

static int
ReflectClose(
    ClientData clientData,
    Tcl_Interp *interp)
{
    ReflectedTransform *rtPtr = clientData;

    int result;			/* Result code for 'close' */
    Tcl_Obj *resObj;		/* Result data for 'close' */
    ReflectedTransformMap *rtmPtr;
				/* Map of reflected transforms with handlers
				 * in this interp. */
    Tcl_HashEntry *hPtr;	/* Entry in the above map */

    if (TclInThreadExit()) {







>
|







880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895

static int
ReflectClose(
    ClientData clientData,
    Tcl_Interp *interp)
{
    ReflectedTransform *rtPtr = clientData;
    int errorCode, errorCodeSet = 0;
    int result = TCL_OK;	/* Result code for 'close' */
    Tcl_Obj *resObj;		/* Result data for 'close' */
    ReflectedTransformMap *rtmPtr;
				/* Map of reflected transforms with handlers
				 * in this interp. */
    Tcl_HashEntry *hPtr;	/* Entry in the above map */

    if (TclInThreadExit()) {
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
#ifdef TCL_THREADS
	if (rtPtr->thread != Tcl_GetCurrentThread()) {
	    ForwardParam p;

	    ForwardOpToOwnerThread(rtPtr, ForwardedClose, &p);
	    result = p.base.code;

	    /*
	     * FreeReflectedTransform is done in the forwarded operation!, in
	     * the other thread. rtPtr here is gone!
	     */

	    if (result != TCL_OK) {
		FreeReceivedError(&p);
	    }
	    return EOK;
	}
#endif

	Tcl_EventuallyFree (rtPtr, (Tcl_FreeProc *) FreeReflectedTransform);
	return EOK;
    }

    /*
     * In the reflected channel implementation a cleaned method mask here
     * implies that the channel creation was aborted, and "finalize" must not
     * be called. for transformations however we are not going through here on
     * such an abort, but directly through FreeReflectedTransform. So for us
     * that check is not necessary. We always go through 'finalize'.
     */

    if (HAS(rtPtr->methods, METH_DRAIN) && !rtPtr->readIsDrained) {





	int errorCode;

	if (!TransformDrain(rtPtr, &errorCode)) {

	    return errorCode;

	}
    }

    if (HAS(rtPtr->methods, METH_FLUSH)) {





	int errorCode;

	if (!TransformFlush(rtPtr, &errorCode, FLUSH_WRITE)) {

	    return errorCode;

	}
    }

    /*
     * Are we in the correct thread?
     */

#ifdef TCL_THREADS
    if (rtPtr->thread != Tcl_GetCurrentThread()) {
	ForwardParam p;

	ForwardOpToOwnerThread(rtPtr, ForwardedClose, &p);
	result = p.base.code;

	/*
	 * FreeReflectedTransform is done in the forwarded operation!, in the
	 * other thread. rtPtr here is gone!
	 */

	if (result != TCL_OK) {
	    PassReceivedErrorInterp(interp, &p);
	    return EINVAL;
	}
	return EOK;
    }







<
<
<
<
<



<
















>
>
>
>
>
|
|
<
>
|
>




>
>
>
>
>
|
|
<
>
|
>














<
|
<
<







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
#ifdef TCL_THREADS
	if (rtPtr->thread != Tcl_GetCurrentThread()) {
	    ForwardParam p;

	    ForwardOpToOwnerThread(rtPtr, ForwardedClose, &p);
	    result = p.base.code;






	    if (result != TCL_OK) {
		FreeReceivedError(&p);
	    }

	}
#endif

	Tcl_EventuallyFree (rtPtr, (Tcl_FreeProc *) FreeReflectedTransform);
	return EOK;
    }

    /*
     * In the reflected channel implementation a cleaned method mask here
     * implies that the channel creation was aborted, and "finalize" must not
     * be called. for transformations however we are not going through here on
     * such an abort, but directly through FreeReflectedTransform. So for us
     * that check is not necessary. We always go through 'finalize'.
     */

    if (HAS(rtPtr->methods, METH_DRAIN) && !rtPtr->readIsDrained) {
	if (!TransformDrain(rtPtr, &errorCode)) {
#ifdef TCL_THREADS
	    if (rtPtr->thread != Tcl_GetCurrentThread()) {
		Tcl_EventuallyFree (rtPtr,
			(Tcl_FreeProc *) FreeReflectedTransform);
		return errorCode;
	    } 

#endif
	    errorCodeSet = 1;
	    goto cleanup;
	}
    }

    if (HAS(rtPtr->methods, METH_FLUSH)) {
	if (!TransformFlush(rtPtr, &errorCode, FLUSH_WRITE)) {
#ifdef TCL_THREADS
	    if (rtPtr->thread != Tcl_GetCurrentThread()) {
		Tcl_EventuallyFree (rtPtr,
			(Tcl_FreeProc *) FreeReflectedTransform);
		return errorCode;
	    } 

#endif
	    errorCodeSet = 1;
	    goto cleanup;
	}
    }

    /*
     * Are we in the correct thread?
     */

#ifdef TCL_THREADS
    if (rtPtr->thread != Tcl_GetCurrentThread()) {
	ForwardParam p;

	ForwardOpToOwnerThread(rtPtr, ForwardedClose, &p);
	result = p.base.code;


	Tcl_EventuallyFree (rtPtr, (Tcl_FreeProc *) FreeReflectedTransform);



	if (result != TCL_OK) {
	    PassReceivedErrorInterp(interp, &p);
	    return EINVAL;
	}
	return EOK;
    }
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
    if ((result != TCL_OK) && (interp != NULL)) {
	Tcl_SetChannelErrorInterp(interp, resObj);
    }

    Tcl_DecrRefCount(resObj);	/* Remove reference we held from the
				 * invoke. */



    /*
     * Remove the transform from the map before releasing the memory, to
     * prevent future accesses from finding and dereferencing a dangling
     * pointer.
     *
     * NOTE: The transform may not be in the map. This is ok, that happens
     * when the transform was created in a different interpreter and/or thread
     * and then was moved here.
     *
     * NOTE: The channel may have been removed from the map already via
     * the per-interp DeleteReflectedTransformMap exit-handler.
     */

    if (rtPtr->interp) {
	rtmPtr = GetReflectedTransformMap(rtPtr->interp);
	hPtr = Tcl_FindHashEntry(&rtmPtr->map, Tcl_GetString(rtPtr->handle));
	if (hPtr) {
	    Tcl_DeleteHashEntry(hPtr);
	}
    }

    /*
     * In a threaded interpreter we manage a per-thread map as well, to allow
     * us to survive if the script level pulls the rug out under a channel by
     * deleting the owning thread.
     */

#ifdef TCL_THREADS
    rtmPtr = GetThreadReflectedTransformMap();
    hPtr = Tcl_FindHashEntry(&rtmPtr->map, Tcl_GetString(rtPtr->handle));
    if (hPtr) {
	Tcl_DeleteHashEntry(hPtr);
    }
#endif


    Tcl_EventuallyFree (rtPtr, (Tcl_FreeProc *) FreeReflectedTransform);
    return (result == TCL_OK) ? EOK : EINVAL;
}

/*
 *----------------------------------------------------------------------
 *
 * ReflectInput --
 *







>
>













|





|
<
|
|
|
|
|


|
|
|
|
|

|
>

|







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
    if ((result != TCL_OK) && (interp != NULL)) {
	Tcl_SetChannelErrorInterp(interp, resObj);
    }

    Tcl_DecrRefCount(resObj);	/* Remove reference we held from the
				 * invoke. */

  cleanup:

    /*
     * Remove the transform from the map before releasing the memory, to
     * prevent future accesses from finding and dereferencing a dangling
     * pointer.
     *
     * NOTE: The transform may not be in the map. This is ok, that happens
     * when the transform was created in a different interpreter and/or thread
     * and then was moved here.
     *
     * NOTE: The channel may have been removed from the map already via
     * the per-interp DeleteReflectedTransformMap exit-handler.
     */

    if (!rtPtr->dead) {
	rtmPtr = GetReflectedTransformMap(rtPtr->interp);
	hPtr = Tcl_FindHashEntry(&rtmPtr->map, Tcl_GetString(rtPtr->handle));
	if (hPtr) {
	    Tcl_DeleteHashEntry(hPtr);
	}


	/*
	 * In a threaded interpreter we manage a per-thread map as well,
	 * to allow us to survive if the script level pulls the rug out
	 * under a channel by deleting the owning thread.
	 */

#ifdef TCL_THREADS
	rtmPtr = GetThreadReflectedTransformMap();
	hPtr = Tcl_FindHashEntry(&rtmPtr->map, Tcl_GetString(rtPtr->handle));
	if (hPtr) {
	    Tcl_DeleteHashEntry(hPtr);
	}
#endif
    }

    Tcl_EventuallyFree (rtPtr, (Tcl_FreeProc *) FreeReflectedTransform);
    return errorCodeSet ? errorCode : ((result == TCL_OK) ? EOK : EINVAL);
}

/*
 *----------------------------------------------------------------------
 *
 * ReflectInput --
 *
1766
1767
1768
1769
1770
1771
1772

1773
1774
1775
1776
1777
1778
1779
    rtPtr->handle = handleObj;
    Tcl_IncrRefCount(handleObj);
    rtPtr->timer = NULL;
    rtPtr->mode = 0;
    rtPtr->readIsDrained = 0;
    rtPtr->nonblocking =
	    (((Channel *) parentChan)->state->flags & CHANNEL_NONBLOCKING);


    /*
     * Query parent for current blocking mode.
     */

    ResultInit(&rtPtr->result);








>







1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
    rtPtr->handle = handleObj;
    Tcl_IncrRefCount(handleObj);
    rtPtr->timer = NULL;
    rtPtr->mode = 0;
    rtPtr->readIsDrained = 0;
    rtPtr->nonblocking =
	    (((Channel *) parentChan)->state->flags & CHANNEL_NONBLOCKING);
    rtPtr->dead = 0;

    /*
     * Query parent for current blocking mode.
     */

    ResultInit(&rtPtr->result);

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
    rtCounter++;
    Tcl_MutexUnlock(&rtCounterMutex);

    return resObj;
}

static void
FreeReflectedTransform(
    ReflectedTransform *rtPtr)
{
    int i, n;

    TimerKill(rtPtr);
    ResultClear(&rtPtr->result);


    Tcl_DecrRefCount(rtPtr->handle);
    rtPtr->handle = NULL;

    n = rtPtr->argc - 2;
    for (i=0; i<n; i++) {
	Tcl_DecrRefCount(rtPtr->argv[i]);
    }

    /*
     * See [x] in NewReflectedTransform for lock
     * n+1 = argc-1.
     */
    Tcl_DecrRefCount(rtPtr->argv[n+1]);













    ckfree(rtPtr->argv);
    ckfree(rtPtr);
}

/*
 *----------------------------------------------------------------------
 *







|


|

|
|
>




<










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







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
    rtCounter++;
    Tcl_MutexUnlock(&rtCounterMutex);

    return resObj;
}

static void
FreeReflectedTransformArgs(
    ReflectedTransform *rtPtr)
{
    int i, n = rtPtr->argc - 2;

    if (n < 0) {
	return;
    }

    Tcl_DecrRefCount(rtPtr->handle);
    rtPtr->handle = NULL;


    for (i=0; i<n; i++) {
	Tcl_DecrRefCount(rtPtr->argv[i]);
    }

    /*
     * See [x] in NewReflectedTransform for lock
     * n+1 = argc-1.
     */
    Tcl_DecrRefCount(rtPtr->argv[n+1]);

    rtPtr->argc = 1;
}

static void
FreeReflectedTransform(
    ReflectedTransform *rtPtr)
{
    TimerKill(rtPtr);
    ResultClear(&rtPtr->result);

    FreeReflectedTransformArgs(rtPtr);

    ckfree(rtPtr->argv);
    ckfree(rtPtr);
}

/*
 *----------------------------------------------------------------------
 *
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
{
    int cmdc;			/* #words in constructed command */
    Tcl_Obj *methObj = NULL;	/* Method name in object form */
    Tcl_InterpState sr;		/* State of handler interp */
    int result;			/* Result code of method invokation */
    Tcl_Obj *resObj = NULL;	/* Result of method invokation. */

    if (!rtPtr->interp) {
	/*
	 * The transform is marked as dead. Bail out immediately, with an
	 * appropriate error.
	 */

	if (resultObjPtr != NULL) {
	    resObj = Tcl_NewStringObj(msg_dstlost,-1);







|







1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
{
    int cmdc;			/* #words in constructed command */
    Tcl_Obj *methObj = NULL;	/* Method name in object form */
    Tcl_InterpState sr;		/* State of handler interp */
    int result;			/* Result code of method invokation */
    Tcl_Obj *resObj = NULL;	/* Result of method invokation. */

    if (rtPtr->dead) {
	/*
	 * The transform is marked as dead. Bail out immediately, with an
	 * appropriate error.
	 */

	if (resultObjPtr != NULL) {
	    resObj = Tcl_NewStringObj(msg_dstlost,-1);
2146
2147
2148
2149
2150
2151
2152

2153
2154
2155
2156
2157
2158
2159
2160
2161
2162


























2163
2164
2165
2166
2167
2168
2169
     */

    rtmPtr = clientData;
    for (hPtr = Tcl_FirstHashEntry(&rtmPtr->map, &hSearch);
	    hPtr != NULL;
	    hPtr = Tcl_FirstHashEntry(&rtmPtr->map, &hSearch)) {
	rtPtr = Tcl_GetHashValue(hPtr);

	rtPtr->interp = NULL;
	Tcl_DeleteHashEntry(hPtr);
    }
    Tcl_DeleteHashTable(&rtmPtr->map);
    ckfree(&rtmPtr->map);

#ifdef TCL_THREADS
    /*
     * The origin interpreter for one or more reflected channels is gone.
     */



























    /*
     * Go through the list of pending results and cancel all whose events were
     * destined for this interpreter. While this is in progress we block any
     * other access to the list of pending results.
     */








>
|









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







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
     */

    rtmPtr = clientData;
    for (hPtr = Tcl_FirstHashEntry(&rtmPtr->map, &hSearch);
	    hPtr != NULL;
	    hPtr = Tcl_FirstHashEntry(&rtmPtr->map, &hSearch)) {
	rtPtr = Tcl_GetHashValue(hPtr);

	rtPtr->dead = 1;
	Tcl_DeleteHashEntry(hPtr);
    }
    Tcl_DeleteHashTable(&rtmPtr->map);
    ckfree(&rtmPtr->map);

#ifdef TCL_THREADS
    /*
     * The origin interpreter for one or more reflected channels is gone.
     */

    /*
     * Get the map of all channels handled by the current thread. This is a
     * ReflectedTransformMap, but on a per-thread basis, not per-interp. Go
     * through the channels and remove all which were handled by this
     * interpreter. They have already been marked as dead.
     */

    rtmPtr = GetThreadReflectedTransformMap();
    for (hPtr = Tcl_FirstHashEntry(&rtmPtr->map, &hSearch);
	    hPtr != NULL;
	    hPtr = Tcl_NextHashEntry(&hSearch)) {
	rtPtr = Tcl_GetHashValue(hPtr);

	if (rtPtr->interp != interp) {
	    /*
	     * Ignore entries for other interpreters.
	     */

	    continue;
	}

	rtPtr->dead = 1;
	FreeReflectedTransformArgs(rtPtr);
	Tcl_DeleteHashEntry(hPtr);
    }

    /*
     * Go through the list of pending results and cancel all whose events were
     * destined for this interpreter. While this is in progress we block any
     * other access to the list of pending results.
     */

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
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
	resultPtr->evPtr = NULL;
	resultPtr->result = TCL_ERROR;

	ForwardSetStaticError(paramPtr, msg_send_dstlost);

	Tcl_ConditionNotify(&resultPtr->done);
    }

    /*
     * Get the map of all channels handled by the current thread. This is a
     * ReflectedTransformMap, but on a per-thread basis, not per-interp. Go
     * through the channels and remove all which were handled by this
     * interpreter. They have already been marked as dead.
     */

    rtmPtr = GetThreadReflectedTransformMap();
    for (hPtr = Tcl_FirstHashEntry(&rtmPtr->map, &hSearch);
	    hPtr != NULL;
	    hPtr = Tcl_NextHashEntry(&hSearch)) {
	rtPtr = Tcl_GetHashValue(hPtr);

	if (rtPtr->interp != interp) {
	    /*
	     * Ignore entries for other interpreters.
	     */

	    continue;
	}

	Tcl_DeleteHashEntry(hPtr);
    }

    Tcl_MutexUnlock(&rtForwardMutex);
#endif
}

#ifdef TCL_THREADS
/*
 *----------------------------------------------------------------------
 *







|
<
<
<
<
<
<

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







2234
2235
2236
2237
2238
2239
2240
2241






2242


















2243
2244
2245
2246
2247
2248
2249
	resultPtr->evPtr = NULL;
	resultPtr->result = TCL_ERROR;

	ForwardSetStaticError(paramPtr, msg_send_dstlost);

	Tcl_ConditionNotify(&resultPtr->done);
    }
    Tcl_MutexUnlock(&rtForwardMutex);

























#endif
}

#ifdef TCL_THREADS
/*
 *----------------------------------------------------------------------
 *
2286
2287
2288
2289
2290
2291
2292


















2293
2294
2295
2296
2297
2298
2299

    /*
     * The origin thread for one or more reflected channels is gone.
     * NOTE: If this function is called due to a thread getting killed the
     *       per-interp DeleteReflectedTransformMap is apparently not called.
     */



















    /*
     * Go through the list of pending results and cancel all whose events were
     * destined for this thread. While this is in progress we block any
     * other access to the list of pending results.
     */

    Tcl_MutexLock(&rtForwardMutex);







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







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

    /*
     * The origin thread for one or more reflected channels is gone.
     * NOTE: If this function is called due to a thread getting killed the
     *       per-interp DeleteReflectedTransformMap is apparently not called.
     */

    /*
     * Get the map of all channels handled by the current thread. This is a
     * ReflectedTransformMap, but on a per-thread basis, not per-interp. Go
     * through the channels, remove all, mark them as dead.
     */

    rtmPtr = GetThreadReflectedTransformMap();
    for (hPtr = Tcl_FirstHashEntry(&rtmPtr->map, &hSearch);
	    hPtr != NULL;
	    hPtr = Tcl_FirstHashEntry(&rtmPtr->map, &hSearch)) {
	ReflectedTransform *rtPtr = Tcl_GetHashValue(hPtr);

	rtPtr->dead = 1;
	FreeReflectedTransformArgs(rtPtr);
	Tcl_DeleteHashEntry(hPtr);
    }
    ckfree(rtmPtr);

    /*
     * Go through the list of pending results and cancel all whose events were
     * destined for this thread. While this is in progress we block any
     * other access to the list of pending results.
     */

    Tcl_MutexLock(&rtForwardMutex);
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
	resultPtr->evPtr = NULL;
	resultPtr->result = TCL_ERROR;

	ForwardSetStaticError(paramPtr, msg_send_dstlost);

	Tcl_ConditionNotify(&resultPtr->done);
    }

    /*
     * Get the map of all channels handled by the current thread. This is a
     * ReflectedTransformMap, but on a per-thread basis, not per-interp. Go
     * through the channels, remove all, mark them as dead.
     */

    rtmPtr = GetThreadReflectedTransformMap();
    for (hPtr = Tcl_FirstHashEntry(&rtmPtr->map, &hSearch);
	    hPtr != NULL;
	    hPtr = Tcl_FirstHashEntry(&rtmPtr->map, &hSearch)) {
	ReflectedTransform *rtPtr = Tcl_GetHashValue(hPtr);

	rtPtr->interp = NULL;
	Tcl_DeleteHashEntry(hPtr);
    }

    Tcl_MutexUnlock(&rtForwardMutex);
}

static void
ForwardOpToOwnerThread(
    ReflectedTransform *rtPtr,	/* Channel instance */
    ForwardedOperation op,	/* Forwarded driver operation */
    const void *param)		/* Arguments */
{
    Tcl_ThreadId dst = rtPtr->thread;
    ForwardingEvent *evPtr;
    ForwardingResult *resultPtr;

    /*
     * We gather the lock early. This allows us to check the liveness of the
     * channel without interference from DeleteThreadReflectedTransformMap().
     */

    Tcl_MutexLock(&rtForwardMutex);

    if (rtPtr->interp == NULL) {
	/*
	 * The channel is marked as dead. Bail out immediately, with an
	 * appropriate error. Do not forget to unlock the mutex on this path.
	 */

	ForwardSetStaticError((ForwardParam *) param, msg_send_dstlost);
	Tcl_MutexUnlock(&rtForwardMutex);







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




















|







2360
2361
2362
2363
2364
2365
2366

















2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
	resultPtr->evPtr = NULL;
	resultPtr->result = TCL_ERROR;

	ForwardSetStaticError(paramPtr, msg_send_dstlost);

	Tcl_ConditionNotify(&resultPtr->done);
    }

















    Tcl_MutexUnlock(&rtForwardMutex);
}

static void
ForwardOpToOwnerThread(
    ReflectedTransform *rtPtr,	/* Channel instance */
    ForwardedOperation op,	/* Forwarded driver operation */
    const void *param)		/* Arguments */
{
    Tcl_ThreadId dst = rtPtr->thread;
    ForwardingEvent *evPtr;
    ForwardingResult *resultPtr;

    /*
     * We gather the lock early. This allows us to check the liveness of the
     * channel without interference from DeleteThreadReflectedTransformMap().
     */

    Tcl_MutexLock(&rtForwardMutex);

    if (rtPtr->dead) {
	/*
	 * The channel is marked as dead. Bail out immediately, with an
	 * appropriate error. Do not forget to unlock the mutex on this path.
	 */

	ForwardSetStaticError((ForwardParam *) param, msg_send_dstlost);
	Tcl_MutexUnlock(&rtForwardMutex);
2386
2387
2388
2389
2390
2391
2392

2393
2394
2395
2396
2397
2398
2399
    evPtr->resultPtr = resultPtr;
    evPtr->op = op;
    evPtr->rtPtr = rtPtr;
    evPtr->param = (ForwardParam *) param;

    resultPtr->src = Tcl_GetCurrentThread();
    resultPtr->dst = dst;

    resultPtr->done = NULL;
    resultPtr->result = -1;
    resultPtr->evPtr = evPtr;

    /*
     * Now execute the forward.
     */







>







2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
    evPtr->resultPtr = resultPtr;
    evPtr->op = op;
    evPtr->rtPtr = rtPtr;
    evPtr->param = (ForwardParam *) param;

    resultPtr->src = Tcl_GetCurrentThread();
    resultPtr->dst = dst;
    resultPtr->dsti = rtPtr->interp;
    resultPtr->done = NULL;
    resultPtr->result = -1;
    resultPtr->evPtr = evPtr;

    /*
     * Now execute the forward.
     */
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
	 * channel by deleting the owning thread.
	 */

	rtmPtr = GetThreadReflectedTransformMap();
	hPtr = Tcl_FindHashEntry(&rtmPtr->map, Tcl_GetString(rtPtr->handle));
	Tcl_DeleteHashEntry(hPtr);

	Tcl_EventuallyFree (rtPtr, (Tcl_FreeProc *) FreeReflectedTransform);
	break;

    case ForwardedInput: {
	Tcl_Obj *bufObj = Tcl_NewByteArrayObj((unsigned char *)
		paramPtr->transform.buf, paramPtr->transform.size);
	Tcl_IncrRefCount(bufObj);








|







2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
	 * channel by deleting the owning thread.
	 */

	rtmPtr = GetThreadReflectedTransformMap();
	hPtr = Tcl_FindHashEntry(&rtmPtr->map, Tcl_GetString(rtPtr->handle));
	Tcl_DeleteHashEntry(hPtr);

	FreeReflectedTransformArgs(rtPtr);
	break;

    case ForwardedInput: {
	Tcl_Obj *bufObj = Tcl_NewByteArrayObj((unsigned char *)
		paramPtr->transform.buf, paramPtr->transform.size);
	Tcl_IncrRefCount(bufObj);

Changes to generic/tclIOSock.c.

174
175
176
177
178
179
180








181


182

183

184
185
186
187
188
189
190
            } else if (strcmp(family, "inet6") == 0) {
                hints.ai_family = AF_INET6;
            }
        }
    }

    hints.ai_socktype = SOCK_STREAM;








#if defined(AI_ADDRCONFIG) && !defined(_AIX)


    /* Missing on: OpenBSD, NetBSD.  Causes failure when used on AIX 5.1 */

    hints.ai_flags |= AI_ADDRCONFIG;

#endif
    if (willBind) {
	hints.ai_flags |= AI_PASSIVE;
    } 

    result = getaddrinfo(native, portstring, &hints, addrlist);








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

>







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
            } else if (strcmp(family, "inet6") == 0) {
                hints.ai_family = AF_INET6;
            }
        }
    }

    hints.ai_socktype = SOCK_STREAM;
#if 0
    /*
     * We found some problems when using AI_ADDRCONFIG, e.g. on systems that
     * have no networking besides the loopback interface and want to resolve
     * localhost. See bugs 3385024, 3382419, 3382431. As the advantage of
     * using AI_ADDRCONFIG in situations where it works, is probably low,
     * we'll leave it out for now. After all, it is just an optimisation.
     */
#if defined(AI_ADDRCONFIG) && !defined(_AIX) && !defined(__hpux)
    /*
     * Missing on: OpenBSD, NetBSD.
     * Causes failure when used on AIX 5.1 and HP-UX
     */
    hints.ai_flags |= AI_ADDRCONFIG;
#endif
#endif
    if (willBind) {
	hints.ai_flags |= AI_PASSIVE;
    } 

    result = getaddrinfo(native, portstring, &hints, addrlist);

Changes to generic/tclIndexObj.c.

213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
	    sizeof(char *), msg, flags, indexPtr);

    /*
     * The internal rep must be cleared since tablePtr will go away.
     */

    TclFreeIntRep(objPtr);
    objPtr->typePtr = NULL;
    ckfree(tablePtr);

    return result;
}

/*
 *----------------------------------------------------------------------







<







213
214
215
216
217
218
219

220
221
222
223
224
225
226
	    sizeof(char *), msg, flags, indexPtr);

    /*
     * The internal rep must be cleared since tablePtr will go away.
     */

    TclFreeIntRep(objPtr);

    ckfree(tablePtr);

    return result;
}

/*
 *----------------------------------------------------------------------
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
	/*
	 * Produce a fancy error message.
	 */

	int count;

	TclNewObj(resultPtr);
	Tcl_SetObjResult(interp, resultPtr);
	Tcl_AppendStringsToObj(resultPtr,
		(numAbbrev>1 && !(flags & TCL_EXACT) ? "ambiguous " : "bad "),
		msg, " \"", key, NULL);
	if (STRING_AT(tablePtr, offset, 0) == NULL) {
	    Tcl_AppendStringsToObj(resultPtr, "\": no valid options", NULL);
	} else {
	    Tcl_AppendStringsToObj(resultPtr, "\": must be ",
		    STRING_AT(tablePtr, offset, 0), NULL);
	    for (entryPtr = NEXT_ENTRY(tablePtr, offset), count = 0;
		    *entryPtr != NULL;
		    entryPtr = NEXT_ENTRY(entryPtr, offset), count++) {
		if (*NEXT_ENTRY(entryPtr, offset) == NULL) {
		    Tcl_AppendStringsToObj(resultPtr, (count > 0 ? "," : ""),
			    " or ", *entryPtr, NULL);
		} else {
		    Tcl_AppendStringsToObj(resultPtr, ", ", *entryPtr, NULL);
		}
	    }
	}

	Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "INDEX", msg, key, NULL);
    }
    return TCL_ERROR;
}

/*
 *----------------------------------------------------------------------







<



















>







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
	/*
	 * Produce a fancy error message.
	 */

	int count;

	TclNewObj(resultPtr);

	Tcl_AppendStringsToObj(resultPtr,
		(numAbbrev>1 && !(flags & TCL_EXACT) ? "ambiguous " : "bad "),
		msg, " \"", key, NULL);
	if (STRING_AT(tablePtr, offset, 0) == NULL) {
	    Tcl_AppendStringsToObj(resultPtr, "\": no valid options", NULL);
	} else {
	    Tcl_AppendStringsToObj(resultPtr, "\": must be ",
		    STRING_AT(tablePtr, offset, 0), NULL);
	    for (entryPtr = NEXT_ENTRY(tablePtr, offset), count = 0;
		    *entryPtr != NULL;
		    entryPtr = NEXT_ENTRY(entryPtr, offset), count++) {
		if (*NEXT_ENTRY(entryPtr, offset) == NULL) {
		    Tcl_AppendStringsToObj(resultPtr, (count > 0 ? "," : ""),
			    " or ", *entryPtr, NULL);
		} else {
		    Tcl_AppendStringsToObj(resultPtr, ", ", *entryPtr, NULL);
		}
	    }
	}
	Tcl_SetObjResult(interp, resultPtr);
	Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "INDEX", msg, key, NULL);
    }
    return TCL_ERROR;
}

/*
 *----------------------------------------------------------------------
406
407
408
409
410
411
412

413
414
415

416
417
418
419
420
421
422
 */

static int
SetIndexFromAny(
    Tcl_Interp *interp,		/* Used for error reporting if not NULL. */
    register Tcl_Obj *objPtr)	/* The object to convert. */
{

    Tcl_SetObjResult(interp, Tcl_NewStringObj(
	    "can't convert value to index except via Tcl_GetIndexFromObj API",
	    -1));

    return TCL_ERROR;
}

/*
 *----------------------------------------------------------------------
 *
 * UpdateStringOfIndex --







>
|


>







405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
 */

static int
SetIndexFromAny(
    Tcl_Interp *interp,		/* Used for error reporting if not NULL. */
    register Tcl_Obj *objPtr)	/* The object to convert. */
{
    if (interp) {
	Tcl_SetObjResult(interp, Tcl_NewStringObj(
	    "can't convert value to index except via Tcl_GetIndexFromObj API",
	    -1));
    }
    return TCL_ERROR;
}

/*
 *----------------------------------------------------------------------
 *
 * UpdateStringOfIndex --
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
	switch ((enum matchOptions) index) {
	case PRFMATCH_EXACT:
	    flags |= TCL_EXACT;
	    break;
	case PRFMATCH_MESSAGE:
	    if (i > (objc - 4)) {
		Tcl_AppendResult(interp, "missing message", NULL);

		return TCL_ERROR;
	    }
	    i++;
	    message = Tcl_GetString(objv[i]);
	    break;
	case PRFMATCH_ERROR:
	    if (i > (objc - 4)) {
		Tcl_AppendResult(interp, "missing error options", NULL);

		return TCL_ERROR;
	    }
	    i++;
	    result = Tcl_ListObjLength(interp, objv[i], &errorLength);
	    if (result != TCL_OK) {
		return TCL_ERROR;
	    }
	    if ((errorLength % 2) != 0) {
		Tcl_AppendResult(interp, "error options must have an even"
			" number of elements", NULL);

		return TCL_ERROR;
	    }
	    errorPtr = objv[i];
	    break;
	}
    }








>






|

>










>







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
	switch ((enum matchOptions) index) {
	case PRFMATCH_EXACT:
	    flags |= TCL_EXACT;
	    break;
	case PRFMATCH_MESSAGE:
	    if (i > (objc - 4)) {
		Tcl_AppendResult(interp, "missing message", NULL);
		Tcl_SetErrorCode(interp, "TCL", "OPERATION", "NOARG", NULL);
		return TCL_ERROR;
	    }
	    i++;
	    message = Tcl_GetString(objv[i]);
	    break;
	case PRFMATCH_ERROR:
	    if (i > objc-4) {
		Tcl_AppendResult(interp, "missing error options", NULL);
		Tcl_SetErrorCode(interp, "TCL", "OPERATION", "NOARG", NULL);
		return TCL_ERROR;
	    }
	    i++;
	    result = Tcl_ListObjLength(interp, objv[i], &errorLength);
	    if (result != TCL_OK) {
		return TCL_ERROR;
	    }
	    if ((errorLength % 2) != 0) {
		Tcl_AppendResult(interp, "error options must have an even"
			" number of elements", NULL);
		Tcl_SetErrorCode(interp, "TCL", "VALUE", "DICTIONARY", NULL);
		return TCL_ERROR;
	    }
	    errorPtr = objv[i];
	    break;
	}
    }

945
946
947
948
949
950
951

952
953
954
955

956
957
958
959
960
961
962
963
964
			origObjv[i]->internalRep.otherValuePtr;

		elementStr = ecrPtr->fullSubcmdName;
		elemLen = strlen(elementStr);
	    } else {
		elementStr = TclGetStringFromObj(origObjv[i], &elemLen);
	    }

	    len = Tcl_ScanCountedElement(elementStr, elemLen, &flags);

	    if (MAY_QUOTE_WORD && len != elemLen) {
		char *quotedElementStr = TclStackAlloc(interp, (unsigned)len);


		len = Tcl_ConvertCountedElement(elementStr, elemLen,
			quotedElementStr, flags);
		Tcl_AppendToObj(objPtr, quotedElementStr, len);
		TclStackFree(interp, quotedElementStr);
	    } else {
		Tcl_AppendToObj(objPtr, elementStr, elemLen);
	    }








>
|


|
>

|







949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
			origObjv[i]->internalRep.otherValuePtr;

		elementStr = ecrPtr->fullSubcmdName;
		elemLen = strlen(elementStr);
	    } else {
		elementStr = TclGetStringFromObj(origObjv[i], &elemLen);
	    }
	    flags = 0;
	    len = TclScanElement(elementStr, elemLen, &flags);

	    if (MAY_QUOTE_WORD && len != elemLen) {
		char *quotedElementStr = TclStackAlloc(interp,
			(unsigned)len + 1);

		len = TclConvertElement(elementStr, elemLen,
			quotedElementStr, flags);
		Tcl_AppendToObj(objPtr, quotedElementStr, len);
		TclStackFree(interp, quotedElementStr);
	    } else {
		Tcl_AppendToObj(objPtr, elementStr, elemLen);
	    }

999
1000
1001
1002
1003
1004
1005

1006
1007
1008
1009

1010
1011
1012
1013
1014
1015
1016
1017
1018
	    Tcl_AppendStringsToObj(objPtr, ecrPtr->fullSubcmdName, NULL);
	} else {
	    /*
	     * Quote the argument if it contains spaces (Bug 942757).
	     */

	    elementStr = TclGetStringFromObj(objv[i], &elemLen);

	    len = Tcl_ScanCountedElement(elementStr, elemLen, &flags);

	    if (MAY_QUOTE_WORD && len != elemLen) {
		char *quotedElementStr = TclStackAlloc(interp,(unsigned) len);


		len = Tcl_ConvertCountedElement(elementStr, elemLen,
			quotedElementStr, flags);
		Tcl_AppendToObj(objPtr, quotedElementStr, len);
		TclStackFree(interp, quotedElementStr);
	    } else {
		Tcl_AppendToObj(objPtr, elementStr, elemLen);
	    }
	}







>
|


|
>

|







1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
	    Tcl_AppendStringsToObj(objPtr, ecrPtr->fullSubcmdName, NULL);
	} else {
	    /*
	     * Quote the argument if it contains spaces (Bug 942757).
	     */

	    elementStr = TclGetStringFromObj(objv[i], &elemLen);
	    flags = 0;
	    len = TclScanElement(elementStr, elemLen, &flags);

	    if (MAY_QUOTE_WORD && len != elemLen) {
		char *quotedElementStr = TclStackAlloc(interp,
			(unsigned) len + 1);

		len = TclConvertElement(elementStr, elemLen,
			quotedElementStr, flags);
		Tcl_AppendToObj(objPtr, quotedElementStr, len);
		TclStackFree(interp, quotedElementStr);
	    } else {
		Tcl_AppendToObj(objPtr, elementStr, elemLen);
	    }
	}
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
				 * successful exit. Will include the name of
				 * the command. */
    int nrem;			/* Size of leftovers.*/
    register const Tcl_ArgvInfo *infoPtr;
				/* Pointer to the current entry in the table
				 * of argument descriptions. */
    const Tcl_ArgvInfo *matchPtr;
				/* Descriptor that matches current argument. */
    Tcl_Obj *curArg;		/* Current argument */
    const char *str = NULL;
    register char c;		/* Second character of current arg (used for
				 * quick check for matching; use 2nd char.
				 * because first char. will almost always be
				 * '-'). */
    int srcIndex;		/* Location from which to read next argument
				 * from objv. */
    int dstIndex;		/* Used to keep track of current arguments
				 * being processed, primarily for error
				 * reporting. */
    int objc;			/* # arguments in objv still to process. */
    int length;			/* Number of characters in current argument. */

    if (remObjv != NULL) {
	/*
	 * Then we should copy the name of the command (0th argument).



	 */

	nrem = 1;
	leftovers = ckalloc((nrem + 1) * sizeof(Tcl_Obj *));
	leftovers[nrem-1] = objv[0];
	leftovers[nrem] = NULL;
    } else {
	nrem = 0;
	leftovers = NULL;
    }

    /*
     * OK, now start processing from the second element (1st argument).







|












|



|
>
>
>



|
|
<







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
				 * successful exit. Will include the name of
				 * the command. */
    int nrem;			/* Size of leftovers.*/
    register const Tcl_ArgvInfo *infoPtr;
				/* Pointer to the current entry in the table
				 * of argument descriptions. */
    const Tcl_ArgvInfo *matchPtr;
				/* Descriptor that matches current argument */
    Tcl_Obj *curArg;		/* Current argument */
    const char *str = NULL;
    register char c;		/* Second character of current arg (used for
				 * quick check for matching; use 2nd char.
				 * because first char. will almost always be
				 * '-'). */
    int srcIndex;		/* Location from which to read next argument
				 * from objv. */
    int dstIndex;		/* Used to keep track of current arguments
				 * being processed, primarily for error
				 * reporting. */
    int objc;			/* # arguments in objv still to process. */
    int length;			/* Number of characters in current argument */

    if (remObjv != NULL) {
	/*
	 * Then we should copy the name of the command (0th argument). The
	 * upper bound on the number of elements is known, and (undocumented,
	 * but historically true) there should be a NULL argument after the
	 * last result. [Bug 3413857]
	 */

	nrem = 1;
	leftovers = ckalloc((1 + *objcPtr) * sizeof(Tcl_Obj *));
	leftovers[0] = objv[0];

    } else {
	nrem = 0;
	leftovers = NULL;
    }

    /*
     * OK, now start processing from the second element (1st argument).
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
	/*
	 * Loop throught the argument descriptors searching for one with the
	 * matching key string. If found, leave a pointer to it in matchPtr.
	 */

	matchPtr = NULL;
	infoPtr = argTable;
	for (; (infoPtr != NULL) && (infoPtr->type != TCL_ARGV_END);
		infoPtr++) {
	    if (infoPtr->keyStr == NULL) {
		continue;
	    }
	    if ((infoPtr->keyStr[1] != c)
		    || (strncmp(infoPtr->keyStr, str, length) != 0)) {
		continue;
	    }







|
<







1148
1149
1150
1151
1152
1153
1154
1155

1156
1157
1158
1159
1160
1161
1162
	/*
	 * Loop throught the argument descriptors searching for one with the
	 * matching key string. If found, leave a pointer to it in matchPtr.
	 */

	matchPtr = NULL;
	infoPtr = argTable;
	for (; infoPtr != NULL && infoPtr->type != TCL_ARGV_END ; infoPtr++) {

	    if (infoPtr->keyStr == NULL) {
		continue;
	    }
	    if ((infoPtr->keyStr[1] != c)
		    || (strncmp(infoPtr->keyStr, str, length) != 0)) {
		continue;
	    }
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
	    if (remObjv == NULL) {
		Tcl_AppendResult(interp, "unrecognized argument \"", str,
			"\"", NULL);
		goto error;
	    }

	    dstIndex++;		/* This argument is now handled */
	    nrem++;

	    /*
	     * Allocate nrem (+1 extra for NULL terminator) pointers.
	     */

	    leftovers = ckrealloc(leftovers, (nrem+1) * sizeof(Tcl_Obj *));
	    leftovers[nrem-1] = curArg;
	    continue;
	}

	/*
	 * Take the appropriate action based on the option type
	 */








<
<
<
<
<
<
<
|







1180
1181
1182
1183
1184
1185
1186







1187
1188
1189
1190
1191
1192
1193
1194
	    if (remObjv == NULL) {
		Tcl_AppendResult(interp, "unrecognized argument \"", str,
			"\"", NULL);
		goto error;
	    }

	    dstIndex++;		/* This argument is now handled */







	    leftovers[nrem++] = curArg;
	    continue;
	}

	/*
	 * Take the appropriate action based on the option type
	 */

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
	    }
	    *((const char **) infoPtr->dstPtr) =
		    Tcl_GetString(objv[srcIndex]);
	    srcIndex++;
	    objc--;
	    break;
	case TCL_ARGV_REST:






	    *((int *) infoPtr->dstPtr) = dstIndex;

	    goto argsDone;
	case TCL_ARGV_FLOAT:
	    if (objc == 0) {
		goto missingArg;
	    }
	    if (Tcl_GetDoubleFromObj(interp, objv[srcIndex],
		    (double *) infoPtr->dstPtr) == TCL_ERROR) {
		Tcl_AppendResult(interp, "expected floating-point argument ",
			"for \"", infoPtr->keyStr, "\" but got \"",
			Tcl_GetString(objv[srcIndex]), "\"", NULL);
		goto error;
	    }
	    srcIndex++;
	    objc--;
	    break;
	case TCL_ARGV_FUNC: {
	    Tcl_ArgvFuncProc *handlerProc;

	    Tcl_Obj *argObj;

	    if (objc == 0) {
		argObj = NULL;
	    } else {
		argObj = objv[srcIndex];
	    }
	    handlerProc = (Tcl_ArgvFuncProc *) infoPtr->srcPtr;
	    if (handlerProc(infoPtr->clientData, argObj, infoPtr->dstPtr)) {
		srcIndex++;
		objc--;
	    }
	    break;
	}
	case TCL_ARGV_GENFUNC: {
	    Tcl_ArgvGenFuncProc *handlerProc;


	    handlerProc = (Tcl_ArgvGenFuncProc *) infoPtr->srcPtr;
	    objc = handlerProc(infoPtr->clientData, interp, objc,
		    &objv[srcIndex], infoPtr->dstPtr);
	    if (objc < 0) {
		goto error;
	    }
	    break;
	}
	case TCL_ARGV_HELP:
	    PrintUsage(interp, argTable);
	    goto error;
	default: {
	    char buf[64 + TCL_INTEGER_SPACE];

	    sprintf(buf, "bad argument type %d in Tcl_ArgvInfo",
		    infoPtr->type);
	    Tcl_SetObjResult(interp, Tcl_NewStringObj(buf, -1));
	    goto error;
	}
	}
    }

    /*
     * If we broke out of the loop because of an OPT_REST argument, copy the
     * remaining arguments down.


     */

  argsDone:
    if (remObjv == NULL) {
	/*
	 * Nothing to do.
	 */

	return TCL_OK;
    }

    if (objc > 0) {
	leftovers = ckrealloc(leftovers, (nrem+objc+1) * sizeof(Tcl_Obj *));
	while (objc) {
	    leftovers[nrem] = objv[srcIndex];
	    nrem++;
	    srcIndex++;
	    objc--;
	}
    } else if (leftovers != NULL) {
	ckfree(leftovers);
    }
    leftovers[nrem] = NULL;
    *objcPtr = nrem;
    *remObjv = leftovers;
    return TCL_OK;

    /*
     * Make sure to handle freeing any temporary space we've allocated on the
     * way to an error.
     */








>
>
>
>
>
>
|
>
















|
>







<







|
>

<










|
<
|
|
<
<

<





|
>
>












|
<
<
|
<
<
|
<
<
<

|
|







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
	    }
	    *((const char **) infoPtr->dstPtr) =
		    Tcl_GetString(objv[srcIndex]);
	    srcIndex++;
	    objc--;
	    break;
	case TCL_ARGV_REST:
	    /*
	     * Only store the point where we got to if it's not to be written
	     * to NULL, so that TCL_ARGV_AUTO_REST works.
	     */

	    if (infoPtr->dstPtr != NULL) {
		*((int *) infoPtr->dstPtr) = dstIndex;
	    }
	    goto argsDone;
	case TCL_ARGV_FLOAT:
	    if (objc == 0) {
		goto missingArg;
	    }
	    if (Tcl_GetDoubleFromObj(interp, objv[srcIndex],
		    (double *) infoPtr->dstPtr) == TCL_ERROR) {
		Tcl_AppendResult(interp, "expected floating-point argument ",
			"for \"", infoPtr->keyStr, "\" but got \"",
			Tcl_GetString(objv[srcIndex]), "\"", NULL);
		goto error;
	    }
	    srcIndex++;
	    objc--;
	    break;
	case TCL_ARGV_FUNC: {
	    Tcl_ArgvFuncProc *handlerProc = (Tcl_ArgvFuncProc *)
		    infoPtr->srcPtr;
	    Tcl_Obj *argObj;

	    if (objc == 0) {
		argObj = NULL;
	    } else {
		argObj = objv[srcIndex];
	    }

	    if (handlerProc(infoPtr->clientData, argObj, infoPtr->dstPtr)) {
		srcIndex++;
		objc--;
	    }
	    break;
	}
	case TCL_ARGV_GENFUNC: {
	    Tcl_ArgvGenFuncProc *handlerProc = (Tcl_ArgvGenFuncProc *)
		    infoPtr->srcPtr;


	    objc = handlerProc(infoPtr->clientData, interp, objc,
		    &objv[srcIndex], infoPtr->dstPtr);
	    if (objc < 0) {
		goto error;
	    }
	    break;
	}
	case TCL_ARGV_HELP:
	    PrintUsage(interp, argTable);
	    goto error;
	default:

	    Tcl_SetObjResult(interp, Tcl_ObjPrintf(
		    "bad argument type %d in Tcl_ArgvInfo", infoPtr->type));


	    goto error;

	}
    }

    /*
     * If we broke out of the loop because of an OPT_REST argument, copy the
     * remaining arguments down. Note that there is always at least one
     * argument left over - the command name - so we always have a result if
     * our caller is willing to receive it. [Bug 3413857]
     */

  argsDone:
    if (remObjv == NULL) {
	/*
	 * Nothing to do.
	 */

	return TCL_OK;
    }

    if (objc > 0) {
	memcpy(leftovers+nrem, objv+srcIndex, objc*sizeof(Tcl_Obj *));


	nrem += objc;


    }



    leftovers[nrem] = NULL;
    *objcPtr = nrem++;
    *remObjv = ckrealloc(leftovers, nrem * sizeof(Tcl_Obj *));
    return TCL_OK;

    /*
     * Make sure to handle freeing any temporary space we've allocated on the
     * way to an error.
     */

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
 *----------------------------------------------------------------------
 */

int
TclGetCompletionCodeFromObj(
    Tcl_Interp *interp,		/* Current interpreter. */
    Tcl_Obj *value,
    int *code)	/* Argument objects. */
{
    static const char *const returnCodes[] = {
	    "ok", "error", "return", "break", "continue", NULL
    };

    if ((value->typePtr != &indexType)
	    && (TCL_OK == TclGetIntFromObj(NULL, value, code))) {
	return TCL_OK;
    }
    if (TCL_OK == Tcl_GetIndexFromObj(
	    NULL, value, returnCodes, NULL, TCL_EXACT, code)) {
	return TCL_OK;
    }
    /*
     * Value is not a legal completion code.
     */

    if (interp != NULL) {
	Tcl_ResetResult(interp);
	Tcl_AppendResult(interp, "bad completion code \"",
		TclGetString(value),
		"\": must be ok, error, return, break, "
		"continue, or an integer", NULL);
	Tcl_SetErrorCode(interp, "TCL", "RESULT", "ILLEGAL_CODE", NULL);
    }
    return TCL_ERROR;
}

/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78
 * End:
 */







|


|






|
|
















|







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
 *----------------------------------------------------------------------
 */

int
TclGetCompletionCodeFromObj(
    Tcl_Interp *interp,		/* Current interpreter. */
    Tcl_Obj *value,
    int *code)			/* Argument objects. */
{
    static const char *const returnCodes[] = {
	"ok", "error", "return", "break", "continue", NULL
    };

    if ((value->typePtr != &indexType)
	    && (TCL_OK == TclGetIntFromObj(NULL, value, code))) {
	return TCL_OK;
    }
    if (TCL_OK == Tcl_GetIndexFromObj(NULL, value, returnCodes, NULL,
		TCL_EXACT, code)) {
	return TCL_OK;
    }
    /*
     * Value is not a legal completion code.
     */

    if (interp != NULL) {
	Tcl_ResetResult(interp);
	Tcl_AppendResult(interp, "bad completion code \"",
		TclGetString(value),
		"\": must be ok, error, return, break, "
		"continue, or an integer", NULL);
	Tcl_SetErrorCode(interp, "TCL", "RESULT", "ILLEGAL_CODE", NULL);
    }
    return TCL_ERROR;
}

/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78
 * End:
 */

Changes to generic/tclInt.h.

2437
2438
2439
2440
2441
2442
2443





2444
2445
2446
2447
2448
2449






2450
2451
2452
2453
2454
2455
2456
2457



2458
2459
2460
2461
2462
2463
2464
2465
2466
2467



2468
2469
2470
2471
2472
2473
2474
				 * derived from the list representation. May
				 * be ignored if there is no string rep at
				 * all.*/
    Tcl_Obj *elements;		/* First list element; the struct is grown to
				 * accomodate all elements. */
} List;






/*
 * Macro used to get the elements of a list object.
 */

#define ListRepPtr(listPtr) \
    ((List *) (listPtr)->internalRep.twoPtrValue.ptr1)







#define ListObjGetElements(listPtr, objc, objv) \
    ((objv) = &(ListRepPtr(listPtr)->elements), \
     (objc) = ListRepPtr(listPtr)->elemCount)

#define ListObjLength(listPtr, len) \
    ((len) = ListRepPtr(listPtr)->elemCount)




#define TclListObjGetElements(interp, listPtr, objcPtr, objvPtr) \
    (((listPtr)->typePtr == &tclListType) \
	    ? ((ListObjGetElements((listPtr), *(objcPtr), *(objvPtr))), TCL_OK)\
	    : Tcl_ListObjGetElements((interp), (listPtr), (objcPtr), (objvPtr)))

#define TclListObjLength(interp, listPtr, lenPtr) \
    (((listPtr)->typePtr == &tclListType) \
	    ? ((ListObjLength((listPtr), *(lenPtr))), TCL_OK)\
	    : Tcl_ListObjLength((interp), (listPtr), (lenPtr)))




/*
 * Macros providing a faster path to integers: Tcl_GetLongFromObj everywhere,
 * Tcl_GetIntFromObj and TclGetIntForIndex on platforms where longs are ints.
 *
 * WARNING: these macros eval their args more than once.
 */








>
>
>
>
>






>
>
>
>
>
>








>
>
>










>
>
>







2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
				 * derived from the list representation. May
				 * be ignored if there is no string rep at
				 * all.*/
    Tcl_Obj *elements;		/* First list element; the struct is grown to
				 * accomodate all elements. */
} List;

#define LIST_MAX \
	(1 + (int)(((size_t)UINT_MAX - sizeof(List))/sizeof(Tcl_Obj *)))
#define LIST_SIZE(numElems) \
	(unsigned)(sizeof(List) + (((numElems) - 1) * sizeof(Tcl_Obj *)))

/*
 * Macro used to get the elements of a list object.
 */

#define ListRepPtr(listPtr) \
    ((List *) (listPtr)->internalRep.twoPtrValue.ptr1)

#define ListSetIntRep(objPtr, listRepPtr) \
    (objPtr)->internalRep.twoPtrValue.ptr1 = (void *)(listRepPtr), \
    (objPtr)->internalRep.twoPtrValue.ptr2 = NULL, \
    (listRepPtr)->refCount++, \
    (objPtr)->typePtr = &tclListType

#define ListObjGetElements(listPtr, objc, objv) \
    ((objv) = &(ListRepPtr(listPtr)->elements), \
     (objc) = ListRepPtr(listPtr)->elemCount)

#define ListObjLength(listPtr, len) \
    ((len) = ListRepPtr(listPtr)->elemCount)

#define ListObjIsCanonical(listPtr) \
    (((listPtr)->bytes == NULL) || ListRepPtr(listPtr)->canonicalFlag)

#define TclListObjGetElements(interp, listPtr, objcPtr, objvPtr) \
    (((listPtr)->typePtr == &tclListType) \
	    ? ((ListObjGetElements((listPtr), *(objcPtr), *(objvPtr))), TCL_OK)\
	    : Tcl_ListObjGetElements((interp), (listPtr), (objcPtr), (objvPtr)))

#define TclListObjLength(interp, listPtr, lenPtr) \
    (((listPtr)->typePtr == &tclListType) \
	    ? ((ListObjLength((listPtr), *(lenPtr))), TCL_OK)\
	    : Tcl_ListObjLength((interp), (listPtr), (lenPtr)))

#define TclListObjIsCanonical(listPtr) \
    (((listPtr)->typePtr == &tclListType) ? ListObjIsCanonical((listPtr)) : 0)

/*
 * Macros providing a faster path to integers: Tcl_GetLongFromObj everywhere,
 * Tcl_GetIntFromObj and TclGetIntForIndex on platforms where longs are ints.
 *
 * WARNING: these macros eval their args more than once.
 */

2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763

2764
2765
2766
2767
2768
2769
2770
 *----------------------------------------------------------------
 * Procedures shared among Tcl modules but not used by the outside world,
 * introduced by/for NRE.
 *----------------------------------------------------------------
 */

MODULE_SCOPE Tcl_ObjCmdProc TclNRApplyObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclNRUplevelObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclNRCatchObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclNRExprObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclNRForObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclNRForeachCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclNRIfObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclNRSourceObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclNRSubstObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclNRSwitchObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclNRTryObjCmd;

MODULE_SCOPE Tcl_ObjCmdProc TclNRWhileObjCmd;

MODULE_SCOPE Tcl_NRPostProc TclNRForIterCallback;
MODULE_SCOPE Tcl_ObjCmdProc TclNRTailcallObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclNRCoroutineObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclNRYieldObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclNRYieldmObjCmd;







|









>







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
 *----------------------------------------------------------------
 * Procedures shared among Tcl modules but not used by the outside world,
 * introduced by/for NRE.
 *----------------------------------------------------------------
 */

MODULE_SCOPE Tcl_ObjCmdProc TclNRApplyObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclNREvalObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclNRCatchObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclNRExprObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclNRForObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclNRForeachCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclNRIfObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclNRSourceObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclNRSubstObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclNRSwitchObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclNRTryObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclNRUplevelObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclNRWhileObjCmd;

MODULE_SCOPE Tcl_NRPostProc TclNRForIterCallback;
MODULE_SCOPE Tcl_ObjCmdProc TclNRTailcallObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclNRCoroutineObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclNRYieldObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclNRYieldmObjCmd;
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887


2888
2889
2890
2891
2892
2893
2894
MODULE_SCOPE int	TclCheckBadOctal(Tcl_Interp *interp,
			    const char *value);
MODULE_SCOPE int	TclChanCaughtErrorBypass(Tcl_Interp *interp,
			    Tcl_Channel chan);
MODULE_SCOPE Tcl_ObjCmdProc TclChannelNamesCmd;
MODULE_SCOPE int	TclClearRootEnsemble(ClientData data[],
			    Tcl_Interp *interp, int result);
MODULE_SCOPE void	TclCleanupLiteralTable(Tcl_Interp *interp,
			    LiteralTable *tablePtr);
MODULE_SCOPE ContLineLoc *TclContinuationsEnter(Tcl_Obj *objPtr, int num,
			    int *loc);
MODULE_SCOPE void	TclContinuationsEnterDerived(Tcl_Obj *objPtr,
			    int start, int *clNext);
MODULE_SCOPE ContLineLoc *TclContinuationsGet(Tcl_Obj *objPtr);
MODULE_SCOPE void	TclContinuationsCopy(Tcl_Obj *objPtr,
			    Tcl_Obj *originObjPtr);


MODULE_SCOPE void	TclDeleteNamespaceVars(Namespace *nsPtr);
/* TIP #280 - Modified token based evulation, with line information. */
MODULE_SCOPE int	TclEvalEx(Tcl_Interp *interp, const char *script,
			    int numBytes, int flags, int line,
			    int *clNextOuter, const char *outerScript);
MODULE_SCOPE Tcl_ObjCmdProc TclFileAttrsCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclFileCopyCmd;







<
<







>
>







2890
2891
2892
2893
2894
2895
2896


2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
MODULE_SCOPE int	TclCheckBadOctal(Tcl_Interp *interp,
			    const char *value);
MODULE_SCOPE int	TclChanCaughtErrorBypass(Tcl_Interp *interp,
			    Tcl_Channel chan);
MODULE_SCOPE Tcl_ObjCmdProc TclChannelNamesCmd;
MODULE_SCOPE int	TclClearRootEnsemble(ClientData data[],
			    Tcl_Interp *interp, int result);


MODULE_SCOPE ContLineLoc *TclContinuationsEnter(Tcl_Obj *objPtr, int num,
			    int *loc);
MODULE_SCOPE void	TclContinuationsEnterDerived(Tcl_Obj *objPtr,
			    int start, int *clNext);
MODULE_SCOPE ContLineLoc *TclContinuationsGet(Tcl_Obj *objPtr);
MODULE_SCOPE void	TclContinuationsCopy(Tcl_Obj *objPtr,
			    Tcl_Obj *originObjPtr);
MODULE_SCOPE int	TclConvertElement(const char *src, int length,
			    char *dst, int flags);
MODULE_SCOPE void	TclDeleteNamespaceVars(Namespace *nsPtr);
/* TIP #280 - Modified token based evulation, with line information. */
MODULE_SCOPE int	TclEvalEx(Tcl_Interp *interp, const char *script,
			    int numBytes, int flags, int line,
			    int *clNextOuter, const char *outerScript);
MODULE_SCOPE Tcl_ObjCmdProc TclFileAttrsCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclFileCopyCmd;
2972
2973
2974
2975
2976
2977
2978

2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995


2996
2997
2998

2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
MODULE_SCOPE void	TclInitLimitSupport(Tcl_Interp *interp);
MODULE_SCOPE void	TclInitNamespaceSubsystem(void);
MODULE_SCOPE void	TclInitNotifier(void);
MODULE_SCOPE void	TclInitObjSubsystem(void);
MODULE_SCOPE void	TclInitSubsystems(void);
MODULE_SCOPE int	TclInterpReady(Tcl_Interp *interp);
MODULE_SCOPE int	TclIsLocalScalar(const char *src, int len);

MODULE_SCOPE int	TclJoinThread(Tcl_ThreadId id, int *result);
MODULE_SCOPE void	TclLimitRemoveAllHandlers(Tcl_Interp *interp);
MODULE_SCOPE Tcl_Obj *	TclLindexList(Tcl_Interp *interp,
			    Tcl_Obj *listPtr, Tcl_Obj *argPtr);
MODULE_SCOPE Tcl_Obj *	TclLindexFlat(Tcl_Interp *interp, Tcl_Obj *listPtr,
			    int indexCount, Tcl_Obj *const indexArray[]);
/* TIP #280 */
MODULE_SCOPE void	TclListLines(Tcl_Obj *listObj, int line, int n,
			    int *lines, Tcl_Obj *const *elems);
MODULE_SCOPE Tcl_Obj *	TclListObjCopy(Tcl_Interp *interp, Tcl_Obj *listPtr);
MODULE_SCOPE Tcl_Obj *	TclLsetList(Tcl_Interp *interp, Tcl_Obj *listPtr,
			    Tcl_Obj *indexPtr, Tcl_Obj *valuePtr);
MODULE_SCOPE Tcl_Obj *	TclLsetFlat(Tcl_Interp *interp, Tcl_Obj *listPtr,
			    int indexCount, Tcl_Obj *const indexArray[],
			    Tcl_Obj *valuePtr);
MODULE_SCOPE Tcl_Command TclMakeEnsemble(Tcl_Interp *interp, const char *name,
			    const EnsembleImplMap map[]);


MODULE_SCOPE int	TclMergeReturnOptions(Tcl_Interp *interp, int objc,
			    Tcl_Obj *const objv[], Tcl_Obj **optionsPtrPtr,
			    int *codePtr, int *levelPtr);

MODULE_SCOPE int	TclNokia770Doubles(void);
MODULE_SCOPE void	TclNsDecrRefCount(Namespace *nsPtr);
MODULE_SCOPE void	TclObjVarErrMsg(Tcl_Interp *interp, Tcl_Obj *part1Ptr,
			    Tcl_Obj *part2Ptr, const char *operation,
			    const char *reason, int index);
MODULE_SCOPE int	TclObjInvokeNamespace(Tcl_Interp *interp,
			    int objc, Tcl_Obj *const objv[],
			    Tcl_Namespace *nsPtr, int flags);
MODULE_SCOPE int	TclObjUnsetVar2(Tcl_Interp *interp,
			    Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, int flags);
MODULE_SCOPE int	TclParseBackslash(const char *src,
			    int numBytes, int *readPtr, char *dst);
MODULE_SCOPE int	TclParseHex(const char *src, int numBytes,
			    Tcl_UniChar *resultPtr);
MODULE_SCOPE int	TclParseNumber(Tcl_Interp *interp, Tcl_Obj *objPtr,
			    const char *expected, const char *bytes,
			    int numBytes, const char **endPtrPtr, int flags);
MODULE_SCOPE void	TclParseInit(Tcl_Interp *interp, const char *string,
			    int numBytes, Tcl_Parse *parsePtr);
MODULE_SCOPE int	TclParseAllWhiteSpace(const char *src, int numBytes);
MODULE_SCOPE int	TclProcessReturn(Tcl_Interp *interp,







>

















>
>



>













|







2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
MODULE_SCOPE void	TclInitLimitSupport(Tcl_Interp *interp);
MODULE_SCOPE void	TclInitNamespaceSubsystem(void);
MODULE_SCOPE void	TclInitNotifier(void);
MODULE_SCOPE void	TclInitObjSubsystem(void);
MODULE_SCOPE void	TclInitSubsystems(void);
MODULE_SCOPE int	TclInterpReady(Tcl_Interp *interp);
MODULE_SCOPE int	TclIsLocalScalar(const char *src, int len);
MODULE_SCOPE int	TclIsSpaceProc(char byte);
MODULE_SCOPE int	TclJoinThread(Tcl_ThreadId id, int *result);
MODULE_SCOPE void	TclLimitRemoveAllHandlers(Tcl_Interp *interp);
MODULE_SCOPE Tcl_Obj *	TclLindexList(Tcl_Interp *interp,
			    Tcl_Obj *listPtr, Tcl_Obj *argPtr);
MODULE_SCOPE Tcl_Obj *	TclLindexFlat(Tcl_Interp *interp, Tcl_Obj *listPtr,
			    int indexCount, Tcl_Obj *const indexArray[]);
/* TIP #280 */
MODULE_SCOPE void	TclListLines(Tcl_Obj *listObj, int line, int n,
			    int *lines, Tcl_Obj *const *elems);
MODULE_SCOPE Tcl_Obj *	TclListObjCopy(Tcl_Interp *interp, Tcl_Obj *listPtr);
MODULE_SCOPE Tcl_Obj *	TclLsetList(Tcl_Interp *interp, Tcl_Obj *listPtr,
			    Tcl_Obj *indexPtr, Tcl_Obj *valuePtr);
MODULE_SCOPE Tcl_Obj *	TclLsetFlat(Tcl_Interp *interp, Tcl_Obj *listPtr,
			    int indexCount, Tcl_Obj *const indexArray[],
			    Tcl_Obj *valuePtr);
MODULE_SCOPE Tcl_Command TclMakeEnsemble(Tcl_Interp *interp, const char *name,
			    const EnsembleImplMap map[]);
MODULE_SCOPE int	TclMaxListLength(const char *bytes, int numBytes,
			    const char **endPtr);
MODULE_SCOPE int	TclMergeReturnOptions(Tcl_Interp *interp, int objc,
			    Tcl_Obj *const objv[], Tcl_Obj **optionsPtrPtr,
			    int *codePtr, int *levelPtr);
MODULE_SCOPE Tcl_Obj *  TclNoErrorStack(Tcl_Interp *interp, Tcl_Obj *options);
MODULE_SCOPE int	TclNokia770Doubles(void);
MODULE_SCOPE void	TclNsDecrRefCount(Namespace *nsPtr);
MODULE_SCOPE void	TclObjVarErrMsg(Tcl_Interp *interp, Tcl_Obj *part1Ptr,
			    Tcl_Obj *part2Ptr, const char *operation,
			    const char *reason, int index);
MODULE_SCOPE int	TclObjInvokeNamespace(Tcl_Interp *interp,
			    int objc, Tcl_Obj *const objv[],
			    Tcl_Namespace *nsPtr, int flags);
MODULE_SCOPE int	TclObjUnsetVar2(Tcl_Interp *interp,
			    Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, int flags);
MODULE_SCOPE int	TclParseBackslash(const char *src,
			    int numBytes, int *readPtr, char *dst);
MODULE_SCOPE int	TclParseHex(const char *src, int numBytes,
			    int *resultPtr);
MODULE_SCOPE int	TclParseNumber(Tcl_Interp *interp, Tcl_Obj *objPtr,
			    const char *expected, const char *bytes,
			    int numBytes, const char **endPtrPtr, int flags);
MODULE_SCOPE void	TclParseInit(Tcl_Interp *interp, const char *string,
			    int numBytes, Tcl_Parse *parsePtr);
MODULE_SCOPE int	TclParseAllWhiteSpace(const char *src, int numBytes);
MODULE_SCOPE int	TclProcessReturn(Tcl_Interp *interp,
3083
3084
3085
3086
3087
3088
3089


3090
3091
3092
3093
3094
3095
3096
MODULE_SCOPE void	TclpThreadExit(int status);
MODULE_SCOPE void	TclRememberCondition(Tcl_Condition *mutex);
MODULE_SCOPE void	TclRememberJoinableThread(Tcl_ThreadId id);
MODULE_SCOPE void	TclRememberMutex(Tcl_Mutex *mutex);
MODULE_SCOPE void	TclRemoveScriptLimitCallbacks(Tcl_Interp *interp);
MODULE_SCOPE int	TclReToGlob(Tcl_Interp *interp, const char *reStr,
			    int reStrLen, Tcl_DString *dsPtr, int *flagsPtr);


MODULE_SCOPE void	TclSetBgErrorHandler(Tcl_Interp *interp,
			    Tcl_Obj *cmdPrefix);
MODULE_SCOPE void	TclSetBignumIntRep(Tcl_Obj *objPtr,
			    mp_int *bignumValue);
MODULE_SCOPE void	TclSetCmdNameObj(Tcl_Interp *interp, Tcl_Obj *objPtr,
			    Command *cmdPtr);
MODULE_SCOPE void	TclSetDuplicateObj(Tcl_Obj *dupPtr, Tcl_Obj *objPtr);







>
>







3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
MODULE_SCOPE void	TclpThreadExit(int status);
MODULE_SCOPE void	TclRememberCondition(Tcl_Condition *mutex);
MODULE_SCOPE void	TclRememberJoinableThread(Tcl_ThreadId id);
MODULE_SCOPE void	TclRememberMutex(Tcl_Mutex *mutex);
MODULE_SCOPE void	TclRemoveScriptLimitCallbacks(Tcl_Interp *interp);
MODULE_SCOPE int	TclReToGlob(Tcl_Interp *interp, const char *reStr,
			    int reStrLen, Tcl_DString *dsPtr, int *flagsPtr);
MODULE_SCOPE int	TclScanElement(const char *string, int length,
			    int *flagPtr);
MODULE_SCOPE void	TclSetBgErrorHandler(Tcl_Interp *interp,
			    Tcl_Obj *cmdPrefix);
MODULE_SCOPE void	TclSetBignumIntRep(Tcl_Obj *objPtr,
			    mp_int *bignumValue);
MODULE_SCOPE void	TclSetCmdNameObj(Tcl_Interp *interp, Tcl_Obj *objPtr,
			    Command *cmdPtr);
MODULE_SCOPE void	TclSetDuplicateObj(Tcl_Obj *dupPtr, Tcl_Obj *objPtr);
3111
3112
3113
3114
3115
3116
3117




3118
3119
3120
3121
3122
3123
3124
			    Tcl_Obj *const opts[], int *flagPtr);
MODULE_SCOPE void	TclSubstParse(Tcl_Interp *interp, const char *bytes,
			    int numBytes, int flags, Tcl_Parse *parsePtr,
			    Tcl_InterpState *statePtr);
MODULE_SCOPE int	TclSubstTokens(Tcl_Interp *interp, Tcl_Token *tokenPtr,
			    int count, int *tokensLeftPtr, int line,
			    int *clNextOuter, const char *outerScript);




MODULE_SCOPE Tcl_Obj *	TclpNativeToNormalized(ClientData clientData);
MODULE_SCOPE Tcl_Obj *	TclpFilesystemPathType(Tcl_Obj *pathPtr);
MODULE_SCOPE int	TclpDlopen(Tcl_Interp *interp, Tcl_Obj *pathPtr,
			    Tcl_LoadHandle *loadHandle,
			    Tcl_FSUnloadFileProc **unloadProcPtr);
MODULE_SCOPE int	TclpUtime(Tcl_Obj *pathPtr, struct utimbuf *tval);
#ifdef TCL_LOAD_FROM_MEMORY







>
>
>
>







3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
			    Tcl_Obj *const opts[], int *flagPtr);
MODULE_SCOPE void	TclSubstParse(Tcl_Interp *interp, const char *bytes,
			    int numBytes, int flags, Tcl_Parse *parsePtr,
			    Tcl_InterpState *statePtr);
MODULE_SCOPE int	TclSubstTokens(Tcl_Interp *interp, Tcl_Token *tokenPtr,
			    int count, int *tokensLeftPtr, int line,
			    int *clNextOuter, const char *outerScript);
MODULE_SCOPE int	TclTrimLeft(const char *bytes, int numBytes,
			    const char *trim, int numTrim);
MODULE_SCOPE int	TclTrimRight(const char *bytes, int numBytes,
			    const char *trim, int numTrim);
MODULE_SCOPE Tcl_Obj *	TclpNativeToNormalized(ClientData clientData);
MODULE_SCOPE Tcl_Obj *	TclpFilesystemPathType(Tcl_Obj *pathPtr);
MODULE_SCOPE int	TclpDlopen(Tcl_Interp *interp, Tcl_Obj *pathPtr,
			    Tcl_LoadHandle *loadHandle,
			    Tcl_FSUnloadFileProc **unloadProcPtr);
MODULE_SCOPE int	TclpUtime(Tcl_Obj *pathPtr, struct utimbuf *tval);
#ifdef TCL_LOAD_FROM_MEMORY
3199
3200
3201
3202
3203
3204
3205






3206
3207
3208
3209
3210
3211
3212
MODULE_SCOPE Tcl_TimerToken TclCreateAbsoluteTimerHandler(
			    Tcl_Time *timePtr, Tcl_TimerProc *proc,
			    ClientData clientData);
MODULE_SCOPE int	TclDefaultBgErrorHandlerObjCmd(
			    ClientData clientData, Tcl_Interp *interp,
			    int objc, Tcl_Obj *const objv[]);
MODULE_SCOPE Tcl_Command TclInitDictCmd(Tcl_Interp *interp);






MODULE_SCOPE int	Tcl_DisassembleObjCmd(ClientData clientData,
			    Tcl_Interp *interp, int objc,
			    Tcl_Obj *const objv[]);
			    
/* Assemble command function */			    
MODULE_SCOPE int	Tcl_AssembleObjCmd(ClientData clientData,
			    Tcl_Interp *interp, int objc,







>
>
>
>
>
>







3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
MODULE_SCOPE Tcl_TimerToken TclCreateAbsoluteTimerHandler(
			    Tcl_Time *timePtr, Tcl_TimerProc *proc,
			    ClientData clientData);
MODULE_SCOPE int	TclDefaultBgErrorHandlerObjCmd(
			    ClientData clientData, Tcl_Interp *interp,
			    int objc, Tcl_Obj *const objv[]);
MODULE_SCOPE Tcl_Command TclInitDictCmd(Tcl_Interp *interp);
MODULE_SCOPE int	TclDictWithFinish(Tcl_Interp *interp, Var *varPtr,
			    Var *arrayPtr, Tcl_Obj *part1Ptr,
			    Tcl_Obj *part2Ptr, int index, int pathc,
			    Tcl_Obj *const pathv[], Tcl_Obj *keysPtr);
MODULE_SCOPE Tcl_Obj *	TclDictWithInit(Tcl_Interp *interp, Tcl_Obj *dictPtr,
			    int pathc, Tcl_Obj *const pathv[]);
MODULE_SCOPE int	Tcl_DisassembleObjCmd(ClientData clientData,
			    Tcl_Interp *interp, int objc,
			    Tcl_Obj *const objv[]);
			    
/* Assemble command function */			    
MODULE_SCOPE int	Tcl_AssembleObjCmd(ClientData clientData,
			    Tcl_Interp *interp, int objc,
3462
3463
3464
3465
3466
3467
3468



3469
3470
3471
3472
3473
3474
3475
			    Tcl_Parse *parsePtr, Command *cmdPtr,
			    struct CompileEnv *envPtr);
MODULE_SCOPE int	TclCompileDictSetCmd(Tcl_Interp *interp,
			    Tcl_Parse *parsePtr, Command *cmdPtr,
			    struct CompileEnv *envPtr);
MODULE_SCOPE int	TclCompileDictUpdateCmd(Tcl_Interp *interp,
			    Tcl_Parse *parsePtr, Command *cmdPtr,



			    struct CompileEnv *envPtr);
MODULE_SCOPE int	TclCompileEnsemble(Tcl_Interp *interp,
			    Tcl_Parse *parsePtr, Command *cmdPtr,
			    struct CompileEnv *envPtr);
MODULE_SCOPE int	TclCompileErrorCmd(Tcl_Interp *interp,
			    Tcl_Parse *parsePtr, Command *cmdPtr,
			    struct CompileEnv *envPtr);







>
>
>







3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
3512
			    Tcl_Parse *parsePtr, Command *cmdPtr,
			    struct CompileEnv *envPtr);
MODULE_SCOPE int	TclCompileDictSetCmd(Tcl_Interp *interp,
			    Tcl_Parse *parsePtr, Command *cmdPtr,
			    struct CompileEnv *envPtr);
MODULE_SCOPE int	TclCompileDictUpdateCmd(Tcl_Interp *interp,
			    Tcl_Parse *parsePtr, Command *cmdPtr,
			    struct CompileEnv *envPtr);
MODULE_SCOPE int	TclCompileDictWithCmd(Tcl_Interp *interp,
			    Tcl_Parse *parsePtr, Command *cmdPtr,
			    struct CompileEnv *envPtr);
MODULE_SCOPE int	TclCompileEnsemble(Tcl_Interp *interp,
			    Tcl_Parse *parsePtr, Command *cmdPtr,
			    struct CompileEnv *envPtr);
MODULE_SCOPE int	TclCompileErrorCmd(Tcl_Interp *interp,
			    Tcl_Parse *parsePtr, Command *cmdPtr,
			    struct CompileEnv *envPtr);
3756
3757
3758
3759
3760
3761
3762


3763
3764
3765
3766
3767
3768
3769
 * So tclObj.c and tclDictObj.c can share these implementations.
 */

MODULE_SCOPE int	TclCompareObjKeys(void *keyPtr, Tcl_HashEntry *hPtr);
MODULE_SCOPE void	TclFreeObjEntry(Tcl_HashEntry *hPtr);
MODULE_SCOPE unsigned	TclHashObjKey(Tcl_HashTable *tablePtr, void *keyPtr);



/*
 *----------------------------------------------------------------
 * Macros used by the Tcl core to create and release Tcl objects.
 * TclNewObj(objPtr) creates a new object denoting an empty string.
 * TclDecrRefCount(objPtr) decrements the object's reference count, and frees
 * the object if its reference count is zero. These macros are inline versions
 * of Tcl_NewObj() and Tcl_DecrRefCount(). Notice that the names differ in not







>
>







3793
3794
3795
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805
3806
3807
3808
 * So tclObj.c and tclDictObj.c can share these implementations.
 */

MODULE_SCOPE int	TclCompareObjKeys(void *keyPtr, Tcl_HashEntry *hPtr);
MODULE_SCOPE void	TclFreeObjEntry(Tcl_HashEntry *hPtr);
MODULE_SCOPE unsigned	TclHashObjKey(Tcl_HashTable *tablePtr, void *keyPtr);

MODULE_SCOPE int	TclFullFinalizationRequested(void);

/*
 *----------------------------------------------------------------
 * Macros used by the Tcl core to create and release Tcl objects.
 * TclNewObj(objPtr) creates a new object denoting an empty string.
 * TclDecrRefCount(objPtr) decrements the object's reference count, and frees
 * the object if its reference count is zero. These macros are inline versions
 * of Tcl_NewObj() and Tcl_DecrRefCount(). Notice that the names differ in not
3913
3914
3915
3916
3917
3918
3919







3920
3921
3922
3923
3924
3925
3926
	    (objPtr)->internalRep.otherValuePtr = cachePtr->firstObjPtr; \
	    cachePtr->firstObjPtr = objPtr;				\
	    ++cachePtr->numObjects;					\
	}								\
    } while (0)

#else /* not PURIFY or USE_THREAD_ALLOC */








#ifdef TCL_THREADS
/* declared in tclObj.c */
MODULE_SCOPE Tcl_Mutex	tclObjMutex;
#endif

#  define TclAllocObjStorageEx(interp, objPtr) \







>
>
>
>
>
>
>







3952
3953
3954
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
	    (objPtr)->internalRep.otherValuePtr = cachePtr->firstObjPtr; \
	    cachePtr->firstObjPtr = objPtr;				\
	    ++cachePtr->numObjects;					\
	}								\
    } while (0)

#else /* not PURIFY or USE_THREAD_ALLOC */

#if defined(USE_TCLALLOC) && USE_TCLALLOC
    MODULE_SCOPE void TclFinalizeAllocSubsystem();
    MODULE_SCOPE void TclInitAlloc();
#else
#   define USE_TCLALLOC 0
#endif

#ifdef TCL_THREADS
/* declared in tclObj.c */
MODULE_SCOPE Tcl_Mutex	tclObjMutex;
#endif

#  define TclAllocObjStorageEx(interp, objPtr) \
4022
4023
4024
4025
4026
4027
4028
4029
4030
4031

4032
4033
4034
4035
4036
4037
4038
 * "prototype" for this macro is:
 *
 * MODULE_SCOPE void	TclFreeIntRep(Tcl_Obj *objPtr);
 *----------------------------------------------------------------
 */

#define TclFreeIntRep(objPtr) \
    if ((objPtr)->typePtr != NULL && \
	    (objPtr)->typePtr->freeIntRepProc != NULL) { \
	(objPtr)->typePtr->freeIntRepProc(objPtr); \

	(objPtr)->typePtr = NULL; \
    }

/*
 *----------------------------------------------------------------
 * Macro used by the Tcl core to clean out an object's string representation.
 * The ANSI C "prototype" for this macro is:







|
|
|
>







4068
4069
4070
4071
4072
4073
4074
4075
4076
4077
4078
4079
4080
4081
4082
4083
4084
4085
 * "prototype" for this macro is:
 *
 * MODULE_SCOPE void	TclFreeIntRep(Tcl_Obj *objPtr);
 *----------------------------------------------------------------
 */

#define TclFreeIntRep(objPtr) \
    if ((objPtr)->typePtr != NULL) { \
	if ((objPtr)->typePtr->freeIntRepProc != NULL) { \
	    (objPtr)->typePtr->freeIntRepProc(objPtr); \
	} \
	(objPtr)->typePtr = NULL; \
    }

/*
 *----------------------------------------------------------------
 * Macro used by the Tcl core to clean out an object's string representation.
 * The ANSI C "prototype" for this macro is:
4058
4059
4060
4061
4062
4063
4064
4065









4066


4067



4068
4069
4070
4071
4072
4073
4074
 * MODULE_SCOPE void	TclGrowTokenArray(Tcl_Token *tokenPtr, int used,
 *				int available, int append,
 *				Tcl_Token *staticPtr);
 * MODULE_SCOPE void	TclGrowParseTokenArray(Tcl_Parse *parsePtr,
 *				int append);
 *----------------------------------------------------------------
 */










#define TCL_MAX_TOKENS (int)(UINT_MAX / sizeof(Tcl_Token))


#define TCL_MIN_TOKEN_GROWTH 50



#define TclGrowTokenArray(tokenPtr, used, available, append, staticPtr)	\
    do {								\
	int needed = (used) + (append);					\
	if (needed > TCL_MAX_TOKENS) {					\
	    Tcl_Panic("max # of tokens for a Tcl parse (%d) exceeded",	\
		    TCL_MAX_TOKENS);					\
	}								\








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







4105
4106
4107
4108
4109
4110
4111
4112
4113
4114
4115
4116
4117
4118
4119
4120
4121
4122
4123
4124
4125
4126
4127
4128
4129
4130
4131
4132
4133
4134
4135
 * MODULE_SCOPE void	TclGrowTokenArray(Tcl_Token *tokenPtr, int used,
 *				int available, int append,
 *				Tcl_Token *staticPtr);
 * MODULE_SCOPE void	TclGrowParseTokenArray(Tcl_Parse *parsePtr,
 *				int append);
 *----------------------------------------------------------------
 */

/* General tuning for minimum growth in Tcl growth algorithms */
#ifndef TCL_MIN_GROWTH
#  ifdef TCL_GROWTH_MIN_ALLOC
     /* Support for any legacy tuners */
#    define TCL_MIN_GROWTH TCL_GROWTH_MIN_ALLOC
#  else
#    define TCL_MIN_GROWTH 1024
#  endif
#endif

/* Token growth tuning, default to the general value. */
#ifndef TCL_MIN_TOKEN_GROWTH
#define TCL_MIN_TOKEN_GROWTH TCL_MIN_GROWTH/sizeof(Tcl_Token)
#endif

#define TCL_MAX_TOKENS (int)(UINT_MAX / sizeof(Tcl_Token))
#define TclGrowTokenArray(tokenPtr, used, available, append, staticPtr)	\
    do {								\
	int needed = (used) + (append);					\
	if (needed > TCL_MAX_TOKENS) {					\
	    Tcl_Panic("max # of tokens for a Tcl parse (%d) exceeded",	\
		    TCL_MAX_TOKENS);					\
	}								\
4115
4116
4117
4118
4119
4120
4121
4122
4123
4124
4125
4126
4127
4128
4129
4130
 * the result of Tcl_UtfToUniChar. The ANSI C "prototype" for this macro is:
 *
 * MODULE_SCOPE int	TclUtfToUniChar(const char *string, Tcl_UniChar *ch);
 *----------------------------------------------------------------
 */

#define TclUtfToUniChar(str, chPtr) \
	((((unsigned char) *(str)) < 0xC0) ? \
	    ((*(chPtr) = (Tcl_UniChar) *(str)), 1) \
	    : Tcl_UtfToUniChar(str, chPtr))

/*
 *----------------------------------------------------------------
 * Macro counterpart of the Tcl_NumUtfChars() function. To be used in speed-
 * -sensitive points where it pays to avoid a function call in the common case
 * of counting along a string of all one-byte characters.  The ANSI C







|
|







4176
4177
4178
4179
4180
4181
4182
4183
4184
4185
4186
4187
4188
4189
4190
4191
 * the result of Tcl_UtfToUniChar. The ANSI C "prototype" for this macro is:
 *
 * MODULE_SCOPE int	TclUtfToUniChar(const char *string, Tcl_UniChar *ch);
 *----------------------------------------------------------------
 */

#define TclUtfToUniChar(str, chPtr) \
	((((unsigned char) *(str)) < 0xC0) ?		\
	    ((*(chPtr) = (Tcl_UniChar) *(str)), 1)	\
	    : Tcl_UtfToUniChar(str, chPtr))

/*
 *----------------------------------------------------------------
 * Macro counterpart of the Tcl_NumUtfChars() function. To be used in speed-
 * -sensitive points where it pays to avoid a function call in the common case
 * of counting along a string of all one-byte characters.  The ANSI C
4189
4190
4191
4192
4193
4194
4195
4196
4197



4198
4199
4200
4201
4202
4203
4204
 * counter. The ANSI C "prototype" for this macro is:
 *
 * MODULE_SCOPE void	TclInvalidateNsCmdLookup(Namespace *nsPtr);
 *----------------------------------------------------------------
 */

#define TclInvalidateNsCmdLookup(nsPtr) \
    if ((nsPtr)->numExportPatterns) {	\
	(nsPtr)->exportLookupEpoch++;	\



    }

/*
 *----------------------------------------------------------------------
 *
 * Core procedures added to libtommath for bignum manipulation.
 *







|
|
>
>
>







4250
4251
4252
4253
4254
4255
4256
4257
4258
4259
4260
4261
4262
4263
4264
4265
4266
4267
4268
 * counter. The ANSI C "prototype" for this macro is:
 *
 * MODULE_SCOPE void	TclInvalidateNsCmdLookup(Namespace *nsPtr);
 *----------------------------------------------------------------
 */

#define TclInvalidateNsCmdLookup(nsPtr) \
    if ((nsPtr)->numExportPatterns) {		\
	(nsPtr)->exportLookupEpoch++;		\
    }						\
    if ((nsPtr)->commandPathLength) {		\
	(nsPtr)->cmdRefEpoch++;			\
    }

/*
 *----------------------------------------------------------------------
 *
 * Core procedures added to libtommath for bignum manipulation.
 *

Changes to generic/tclInterp.c.

4340
4341
4342
4343
4344
4345
4346













4347
4348
4349
4350
4351
4352
4353
	OPT_CMD, OPT_GRAN, OPT_VAL
    };
    Interp *iPtr = (Interp *) interp;
    int index;
    ScriptLimitCallbackKey key;
    ScriptLimitCallback *limitCBPtr;
    Tcl_HashEntry *hPtr;














    if (objc == consumedObjc) {
	Tcl_Obj *dictPtr;

	TclNewObj(dictPtr);
	key.interp = slaveInterp;
	key.type = TCL_LIMIT_COMMANDS;







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







4340
4341
4342
4343
4344
4345
4346
4347
4348
4349
4350
4351
4352
4353
4354
4355
4356
4357
4358
4359
4360
4361
4362
4363
4364
4365
4366
	OPT_CMD, OPT_GRAN, OPT_VAL
    };
    Interp *iPtr = (Interp *) interp;
    int index;
    ScriptLimitCallbackKey key;
    ScriptLimitCallback *limitCBPtr;
    Tcl_HashEntry *hPtr;

    /*
     * First, ensure that we are not reading or writing the calling
     * interpreter's limits; it may only manipulate its children. Note that
     * the low level API enforces this with Tcl_Panic, which we want to
     * avoid. [Bug 3398794]
     */

    if (interp == slaveInterp) {
	Tcl_AppendResult(interp,
		"limits on current interpreter inaccessible", NULL);
	return TCL_ERROR;
    }

    if (objc == consumedObjc) {
	Tcl_Obj *dictPtr;

	TclNewObj(dictPtr);
	key.interp = slaveInterp;
	key.type = TCL_LIMIT_COMMANDS;
4514
4515
4516
4517
4518
4519
4520













4521
4522
4523
4524
4525
4526
4527
	OPT_CMD, OPT_GRAN, OPT_MILLI, OPT_SEC
    };
    Interp *iPtr = (Interp *) interp;
    int index;
    ScriptLimitCallbackKey key;
    ScriptLimitCallback *limitCBPtr;
    Tcl_HashEntry *hPtr;














    if (objc == consumedObjc) {
	Tcl_Obj *dictPtr;

	TclNewObj(dictPtr);
	key.interp = slaveInterp;
	key.type = TCL_LIMIT_TIME;







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







4527
4528
4529
4530
4531
4532
4533
4534
4535
4536
4537
4538
4539
4540
4541
4542
4543
4544
4545
4546
4547
4548
4549
4550
4551
4552
4553
	OPT_CMD, OPT_GRAN, OPT_MILLI, OPT_SEC
    };
    Interp *iPtr = (Interp *) interp;
    int index;
    ScriptLimitCallbackKey key;
    ScriptLimitCallback *limitCBPtr;
    Tcl_HashEntry *hPtr;

    /*
     * First, ensure that we are not reading or writing the calling
     * interpreter's limits; it may only manipulate its children. Note that
     * the low level API enforces this with Tcl_Panic, which we want to
     * avoid. [Bug 3398794]
     */

    if (interp == slaveInterp) {
	Tcl_AppendResult(interp,
		"limits on current interpreter inaccessible", NULL);
	return TCL_ERROR;
    }

    if (objc == consumedObjc) {
	Tcl_Obj *dictPtr;

	TclNewObj(dictPtr);
	key.interp = slaveInterp;
	key.type = TCL_LIMIT_TIME;

Changes to generic/tclLink.c.

107
108
109
110
111
112
113








114
115
116
117
118
119
120
				 * varName. */
    int type)			/* Type of C variable: TCL_LINK_INT, etc. Also
				 * may have TCL_LINK_READ_ONLY OR'ed in. */
{
    Tcl_Obj *objPtr;
    Link *linkPtr;
    int code;









    linkPtr = ckalloc(sizeof(Link));
    linkPtr->interp = interp;
    linkPtr->varName = Tcl_NewStringObj(varName, -1);
    Tcl_IncrRefCount(linkPtr->varName);
    linkPtr->addr = addr;
    linkPtr->type = type & ~TCL_LINK_READ_ONLY;







>
>
>
>
>
>
>
>







107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
				 * varName. */
    int type)			/* Type of C variable: TCL_LINK_INT, etc. Also
				 * may have TCL_LINK_READ_ONLY OR'ed in. */
{
    Tcl_Obj *objPtr;
    Link *linkPtr;
    int code;

    linkPtr = (Link *) Tcl_VarTraceInfo(interp, varName, TCL_GLOBAL_ONLY,
	    LinkTraceProc, (ClientData) NULL);
    if (linkPtr != NULL) {
	Tcl_SetObjResult(interp, Tcl_ObjPrintf(
		"variable '%s' is already linked", varName));
	return TCL_ERROR;
    }

    linkPtr = ckalloc(sizeof(Link));
    linkPtr->interp = interp;
    linkPtr->varName = Tcl_NewStringObj(varName, -1);
    Tcl_IncrRefCount(linkPtr->varName);
    linkPtr->addr = addr;
    linkPtr->type = type & ~TCL_LINK_READ_ONLY;

Changes to generic/tclListObj.c.

13
14
15
16
17
18
19


20
21
22
23
24
25
26
27

#include "tclInt.h"

/*
 * Prototypes for functions defined later in this file:
 */



static List *		NewListIntRep(int objc, Tcl_Obj *const objv[]);
static void		DupListInternalRep(Tcl_Obj *srcPtr, Tcl_Obj *copyPtr);
static void		FreeListInternalRep(Tcl_Obj *listPtr);
static int		SetListFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr);
static void		UpdateStringOfList(Tcl_Obj *listPtr);

/*
 * The structure below defines the list Tcl object type by means of functions







>
>
|







13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

#include "tclInt.h"

/*
 * Prototypes for functions defined later in this file:
 */

static List *		AttemptNewList(Tcl_Interp *interp, int objc,
			    Tcl_Obj *const objv[]);
static List *		NewListIntRep(int objc, Tcl_Obj *const objv[], int p);
static void		DupListInternalRep(Tcl_Obj *srcPtr, Tcl_Obj *copyPtr);
static void		FreeListInternalRep(Tcl_Obj *listPtr);
static int		SetListFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr);
static void		UpdateStringOfList(Tcl_Obj *listPtr);

/*
 * The structure below defines the list Tcl object type by means of functions
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
const Tcl_ObjType tclListType = {
    "list",			/* name */
    FreeListInternalRep,	/* freeIntRepProc */
    DupListInternalRep,		/* dupIntRepProc */
    UpdateStringOfList,		/* updateStringProc */
    SetListFromAny		/* setFromAnyProc */
};





/*
 *----------------------------------------------------------------------
 *
 * NewListIntRep --
 *
 *	If objc>0 and objv!=NULL, this function creates a list internal rep
 *	with objc elements given in the array objv. If objc>0 and objv==NULL
 *	it creates the list internal rep of a list with 0 elements, where
 *	enough space has been preallocated to store objc elements. If objc<=0,
 *	it returns NULL.
 *
 * Results:
 *	A new List struct is returned. If objc<=0 or if the allocation fails
 *	for lack of memory, NULL is returned. The list returned has refCount
 *	0.
 *
 * Side effects:
 *	The ref counts of the elements in objv are incremented since the
 *	resulting list now refers to them.
 *
 *----------------------------------------------------------------------
 */

static List *
NewListIntRep(
    int objc,
    Tcl_Obj *const objv[])

{
    List *listRepPtr;

    if (objc <= 0) {
	return NULL;
    }

    /*
     * First check to see if we'd overflow and try to allocate an object
     * larger than our memory allocator allows. Note that this is actually a
     * fairly small value when you're on a serious 64-bit machine, but that
     * requires API changes to fix. See [Bug 219196] for a discussion.
     */

    if ((size_t)objc > INT_MAX/sizeof(Tcl_Obj *)) {




	return NULL;
    }

    listRepPtr = attemptckalloc(sizeof(List) + ((objc-1) * sizeof(Tcl_Obj*)));
    if (listRepPtr == NULL) {




	return NULL;
    }

    listRepPtr->canonicalFlag = 0;
    listRepPtr->refCount = 0;
    listRepPtr->maxElemCount = objc;








>
>
>
>






|
|
|
|
|


|
|
|











|
>




|









|
>
>
>
>



|

>
>
>
>







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
const Tcl_ObjType tclListType = {
    "list",			/* name */
    FreeListInternalRep,	/* freeIntRepProc */
    DupListInternalRep,		/* dupIntRepProc */
    UpdateStringOfList,		/* updateStringProc */
    SetListFromAny		/* setFromAnyProc */
};

#ifndef TCL_MIN_ELEMENT_GROWTH
#define TCL_MIN_ELEMENT_GROWTH TCL_MIN_GROWTH/sizeof(Tcl_Obj *)
#endif

/*
 *----------------------------------------------------------------------
 *
 * NewListIntRep --
 *
 *	Creates a list internal rep with space for objc elements.  objc
 *	must be > 0.  If objv!=NULL, initializes with the first objc values
 *	in that array.  If objv==NULL, initalize list internal rep to have
 *	0 elements, with space to add objc more.  Flag value "p" indicates
 *	how to behave on failure.
 *
 * Results:
 *	A new List struct with refCount 0 is returned. If some failure
 *	prevents this then if p=0, NULL is returned and otherwise the
 *	routine panics.
 *
 * Side effects:
 *	The ref counts of the elements in objv are incremented since the
 *	resulting list now refers to them.
 *
 *----------------------------------------------------------------------
 */

static List *
NewListIntRep(
    int objc,
    Tcl_Obj *const objv[],
    int p)
{
    List *listRepPtr;

    if (objc <= 0) {
	Tcl_Panic("NewListIntRep: expects postive element count");
    }

    /*
     * First check to see if we'd overflow and try to allocate an object
     * larger than our memory allocator allows. Note that this is actually a
     * fairly small value when you're on a serious 64-bit machine, but that
     * requires API changes to fix. See [Bug 219196] for a discussion.
     */

    if ((size_t)objc > LIST_MAX) {
	if (p) {
	    Tcl_Panic("max length of a Tcl list (%d elements) exceeded",
		    LIST_MAX);
	}
	return NULL;
    }

    listRepPtr = attemptckalloc(LIST_SIZE(objc));
    if (listRepPtr == NULL) {
	if (p) {
	    Tcl_Panic("list creation failed: unable to alloc %u bytes",
		    LIST_SIZE(objc));
	}
	return NULL;
    }

    listRepPtr->canonicalFlag = 0;
    listRepPtr->refCount = 0;
    listRepPtr->maxElemCount = objc;

109
110
111
112
113
114
115













































116
117
118
119
120
121
122
	    Tcl_IncrRefCount(elemPtrs[i]);
	}
    } else {
	listRepPtr->elemCount = 0;
    }
    return listRepPtr;
}














































/*
 *----------------------------------------------------------------------
 *
 * Tcl_NewListObj --
 *
 *	This function is normally called when not debugging: i.e., when







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







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
	    Tcl_IncrRefCount(elemPtrs[i]);
	}
    } else {
	listRepPtr->elemCount = 0;
    }
    return listRepPtr;
}

/*
 *----------------------------------------------------------------------
 *
 * AttemptNewList --
 *
 *	Creates a list internal rep with space for objc elements.  objc
 *	must be > 0.  If objv!=NULL, initializes with the first objc values
 *	in that array.  If objv==NULL, initalize list internal rep to have
 *	0 elements, with space to add objc more.  
 *
 * Results:
 *	A new List struct with refCount 0 is returned. If some failure
 *	prevents this then NULL is returned, and an error message is left
 *	in the interp result, unless interp is NULL.
 *
 * Side effects:
 *	The ref counts of the elements in objv are incremented since the
 *	resulting list now refers to them.
 *
 *----------------------------------------------------------------------
 */

static List *
AttemptNewList(
    Tcl_Interp *interp,
    int objc,
    Tcl_Obj *const objv[])
{
    List *listRepPtr = NewListIntRep(objc, objv, 0);

    if (interp != NULL && listRepPtr == NULL) {
	if (objc > LIST_MAX) {
	    Tcl_SetObjResult(interp, Tcl_ObjPrintf(
		    "max length of a Tcl list (%d elements) exceeded",
		    LIST_MAX));
	} else {
	    Tcl_SetObjResult(interp, Tcl_ObjPrintf(
		    "list creation failed: unable to alloc %u bytes",
		    LIST_SIZE(objc)));
	}
	Tcl_SetErrorCode(interp, "TCL", "MEMORY", NULL);
    }
    return listRepPtr;
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_NewListObj --
 *
 *	This function is normally called when not debugging: i.e., when
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
	return listPtr;
    }

    /*
     * Create the internal rep.
     */

    listRepPtr = NewListIntRep(objc, objv);
    if (!listRepPtr) {
	Tcl_Panic("Not enough memory to allocate list");
    }

    /*
     * Now create the object.
     */

    Tcl_InvalidateStringRep(listPtr);
    listPtr->internalRep.twoPtrValue.ptr1 = listRepPtr;
    listPtr->internalRep.twoPtrValue.ptr2 = NULL;
    listPtr->typePtr = &tclListType;
    listRepPtr->refCount++;

    return listPtr;
}
#endif /* if TCL_MEM_DEBUG */

/*
 *----------------------------------------------------------------------
 *







|
<
<
<






<
<
<
|
<







227
228
229
230
231
232
233
234



235
236
237
238
239
240



241

242
243
244
245
246
247
248
	return listPtr;
    }

    /*
     * Create the internal rep.
     */

    listRepPtr = NewListIntRep(objc, objv, 1);




    /*
     * Now create the object.
     */

    Tcl_InvalidateStringRep(listPtr);



    ListSetIntRep(listPtr, listRepPtr);

    return listPtr;
}
#endif /* if TCL_MEM_DEBUG */

/*
 *----------------------------------------------------------------------
 *
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
	return listPtr;
    }

    /*
     * Create the internal rep.
     */

    listRepPtr = NewListIntRep(objc, objv);
    if (!listRepPtr) {
	Tcl_Panic("Not enough memory to allocate list");
    }

    /*
     * Now create the object.
     */

    Tcl_InvalidateStringRep(listPtr);
    listPtr->internalRep.twoPtrValue.ptr1 = listRepPtr;
    listPtr->internalRep.twoPtrValue.ptr2 = NULL;
    listPtr->typePtr = &tclListType;
    listRepPtr->refCount++;

    return listPtr;
}

#else /* if not TCL_MEM_DEBUG */

Tcl_Obj *







|
<
<
<






<
<
<
|







292
293
294
295
296
297
298
299



300
301
302
303
304
305



306
307
308
309
310
311
312
313
	return listPtr;
    }

    /*
     * Create the internal rep.
     */

    listRepPtr = NewListIntRep(objc, objv, 1);




    /*
     * Now create the object.
     */

    Tcl_InvalidateStringRep(listPtr);



    ListSetIntRep(listPtr, listRepPtr);

    return listPtr;
}

#else /* if not TCL_MEM_DEBUG */

Tcl_Obj *
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
    }

    /*
     * Free any old string rep and any internal rep for the old type.
     */

    TclFreeIntRep(objPtr);
    objPtr->typePtr = NULL;
    Tcl_InvalidateStringRep(objPtr);

    /*
     * Set the object's type to "list" and initialize the internal rep.
     * However, if there are no elements to put in the list, just give the
     * object an empty string rep and a NULL type.
     */

    if (objc > 0) {
	listRepPtr = NewListIntRep(objc, objv);
	if (!listRepPtr) {
	    Tcl_Panic("Cannot allocate enough memory for Tcl_SetListObj");
	}
	objPtr->internalRep.twoPtrValue.ptr1 = listRepPtr;
	objPtr->internalRep.twoPtrValue.ptr2 = NULL;
	objPtr->typePtr = &tclListType;
	listRepPtr->refCount++;
    } else {
	objPtr->bytes = tclEmptyStringRep;
	objPtr->length = 0;
    }
}

/*







<









|
|
<
<
<
<
<
<







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
    }

    /*
     * Free any old string rep and any internal rep for the old type.
     */

    TclFreeIntRep(objPtr);

    Tcl_InvalidateStringRep(objPtr);

    /*
     * Set the object's type to "list" and initialize the internal rep.
     * However, if there are no elements to put in the list, just give the
     * object an empty string rep and a NULL type.
     */

    if (objc > 0) {
	listRepPtr = NewListIntRep(objc, objv, 1);
	ListSetIntRep(objPtr, listRepPtr);






    } else {
	objPtr->bytes = tclEmptyStringRep;
	objPtr->length = 0;
    }
}

/*
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
				 * referenced by objv. */
    Tcl_Obj ***objvPtr)		/* Where to store the pointer to an array of
				 * pointers to the list's objects. */
{
    register List *listRepPtr;

    if (listPtr->typePtr != &tclListType) {
	int result, length;

	/*
	 * Don't get the string version of a dictionary; that transformation
	 * is not lossy, but is expensive.
	 */

	if (listPtr->typePtr == &tclDictType) {
	    (void) Tcl_DictObjSize(NULL, listPtr, &length);
	} else {
	    (void) TclGetStringFromObj(listPtr, &length);
	}
	if (!length) {
	    *objcPtr = 0;
	    *objvPtr = NULL;
	    return TCL_OK;
	}

	result = SetListFromAny(interp, listPtr);
	if (result != TCL_OK) {
	    return result;
	}
    }
    listRepPtr = listPtr->internalRep.twoPtrValue.ptr1;
    *objcPtr = listRepPtr->elemCount;
    *objvPtr = &listRepPtr->elements;
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_ListObjAppendList --
 *
 *	This function appends the objects in the list referenced by
 *	elemListPtr to the list object referenced by listPtr. If listPtr is
 *	not already a list object, an attempt will be made to convert it to
 *	one.
 *
 * Results:
 *	The return value is normally TCL_OK. If listPtr or elemListPtr do not
 *	refer to list objects and they can not be converted to one, TCL_ERROR
 *	is returned and an error message is left in the interpreter's result
 *	if interp is not NULL.
 *
 * Side effects:
 *	The reference counts of the elements in elemListPtr are incremented
 *	since the list now refers to them. listPtr and elemListPtr are
 *	converted, if necessary, to list objects. Also, appending the new
 *	elements may cause listObj's array of element pointers to grow.
 *	listPtr's old string representation, if any, is invalidated.
 *
 *----------------------------------------------------------------------
 */

int
Tcl_ListObjAppendList(
    Tcl_Interp *interp,		/* Used to report errors if not NULL. */
    register Tcl_Obj *listPtr,	/* List object to append elements to. */
    Tcl_Obj *elemListPtr)	/* List obj with elements to append. */
{
    int listLen, objc, result;
    Tcl_Obj **objv;

    if (Tcl_IsShared(listPtr)) {
	Tcl_Panic("%s called with shared object", "Tcl_ListObjAppendList");
    }


    result = TclListObjLength(interp, listPtr, &listLen);
    if (result != TCL_OK) {
	return result;

    }

    result = TclListObjGetElements(interp, elemListPtr, &objc, &objv);
    if (result != TCL_OK) {
	return result;
    }

    /*
     * Insert objc new elements starting after the lists's last element.
     * Delete zero existing elements.
     */

    return Tcl_ListObjReplace(interp, listPtr, listLen, 0, objc, objv);
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_ListObjAppendElement --
 *







|

<
<
<
<
|
<
<
<
<
<
<




<





|










|
|
<
<



|
|
<

















|






>
|
<
<
>
|
<
|
<
|



|



|







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
				 * referenced by objv. */
    Tcl_Obj ***objvPtr)		/* Where to store the pointer to an array of
				 * pointers to the list's objects. */
{
    register List *listRepPtr;

    if (listPtr->typePtr != &tclListType) {
	int result;





	if (listPtr->bytes == tclEmptyStringRep) {






	    *objcPtr = 0;
	    *objvPtr = NULL;
	    return TCL_OK;
	}

	result = SetListFromAny(interp, listPtr);
	if (result != TCL_OK) {
	    return result;
	}
    }
    listRepPtr = ListRepPtr(listPtr);
    *objcPtr = listRepPtr->elemCount;
    *objvPtr = &listRepPtr->elements;
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_ListObjAppendList --
 *
 *	This function appends the elements in the list value referenced by
 *	elemListPtr to the list value referenced by listPtr.


 *
 * Results:
 *	The return value is normally TCL_OK. If listPtr or elemListPtr do not
 *	refer to list values, TCL_ERROR is returned and an error message is
 *	left in the interpreter's result if interp is not NULL.

 *
 * Side effects:
 *	The reference counts of the elements in elemListPtr are incremented
 *	since the list now refers to them. listPtr and elemListPtr are
 *	converted, if necessary, to list objects. Also, appending the new
 *	elements may cause listObj's array of element pointers to grow.
 *	listPtr's old string representation, if any, is invalidated.
 *
 *----------------------------------------------------------------------
 */

int
Tcl_ListObjAppendList(
    Tcl_Interp *interp,		/* Used to report errors if not NULL. */
    register Tcl_Obj *listPtr,	/* List object to append elements to. */
    Tcl_Obj *elemListPtr)	/* List obj with elements to append. */
{
    int objc;
    Tcl_Obj **objv;

    if (Tcl_IsShared(listPtr)) {
	Tcl_Panic("%s called with shared object", "Tcl_ListObjAppendList");
    }

    /*
     * Pull the elements to append from elemListPtr.


     */


    if (TCL_OK != TclListObjGetElements(interp, elemListPtr, &objc, &objv)) {

	return TCL_ERROR;
    }

    /*
     * Insert the new elements starting after the lists's last element.
     * Delete zero existing elements.
     */

    return Tcl_ListObjReplace(interp, listPtr, LIST_MAX, 0, objc, objv);
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_ListObjAppendElement --
 *
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

int
Tcl_ListObjAppendElement(
    Tcl_Interp *interp,		/* Used to report errors if not NULL. */
    Tcl_Obj *listPtr,		/* List object to append objPtr to. */
    Tcl_Obj *objPtr)		/* Object to append to listPtr's list. */
{
    register List *listRepPtr;
    register Tcl_Obj **elemPtrs;
    int numElems, numRequired, newMax, newSize, i;

    if (Tcl_IsShared(listPtr)) {
	Tcl_Panic("%s called with shared object", "Tcl_ListObjAppendElement");
    }
    if (listPtr->typePtr != &tclListType) {
	int result, length;

	(void) TclGetStringFromObj(listPtr, &length);
	if (!length) {
	    Tcl_SetListObj(listPtr, 1, &objPtr);
	    return TCL_OK;
	}

	result = SetListFromAny(interp, listPtr);
	if (result != TCL_OK) {
	    return result;
	}
    }

    listRepPtr = listPtr->internalRep.twoPtrValue.ptr1;
    numElems = listRepPtr->elemCount;
    numRequired = numElems + 1 ;














    /*
     * If there is no room in the current array of element pointers, allocate
     * a new, larger array and copy the pointers to it. If the List struct is
     * shared, allocate a new one.
     */

    if (numRequired > listRepPtr->maxElemCount){
	newMax = 2 * numRequired;



	newSize = sizeof(List) + ((newMax-1) * sizeof(Tcl_Obj *));










    } else {

	newMax = listRepPtr->maxElemCount;
	newSize = 0;
    }


    if (listRepPtr->refCount > 1) {
	List *oldListRepPtr = listRepPtr;



	Tcl_Obj **oldElems;


	listRepPtr = NewListIntRep(newMax, NULL);
	if (!listRepPtr) {














	    Tcl_Panic("Not enough memory to allocate list");

	}

	oldElems = &oldListRepPtr->elements;


	elemPtrs = &listRepPtr->elements;
	for (i=0; i<numElems; i++) {





	    elemPtrs[i] = oldElems[i];

	    Tcl_IncrRefCount(elemPtrs[i]);
	}
	listRepPtr->elemCount = numElems;
	listRepPtr->refCount++;
	oldListRepPtr->refCount--;
    } else if (newSize) {





	listRepPtr = ckrealloc(listRepPtr, newSize);

	listRepPtr->maxElemCount = newMax;
    }
    listPtr->internalRep.twoPtrValue.ptr1 = listRepPtr;

    /*
     * Add objPtr to the end of listPtr's array of element pointers. Increment
     * the ref count for the (now shared) objPtr.
     */

    elemPtrs = &listRepPtr->elements;
    elemPtrs[numElems] = objPtr;
    Tcl_IncrRefCount(objPtr);
    listRepPtr->elemCount++;

    /*
     * Invalidate any old string representation since the list's internal
     * representation has changed.
     */







|
<
|





|

|
<



<






|


>
>

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

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

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

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








|
<







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

int
Tcl_ListObjAppendElement(
    Tcl_Interp *interp,		/* Used to report errors if not NULL. */
    Tcl_Obj *listPtr,		/* List object to append objPtr to. */
    Tcl_Obj *objPtr)		/* Object to append to listPtr's list. */
{
    register List *listRepPtr, *newPtr = NULL;

    int numElems, numRequired, needGrow, isShared, attempt;

    if (Tcl_IsShared(listPtr)) {
	Tcl_Panic("%s called with shared object", "Tcl_ListObjAppendElement");
    }
    if (listPtr->typePtr != &tclListType) {
	int result;

	if (listPtr->bytes == tclEmptyStringRep) {

	    Tcl_SetListObj(listPtr, 1, &objPtr);
	    return TCL_OK;
	}

	result = SetListFromAny(interp, listPtr);
	if (result != TCL_OK) {
	    return result;
	}
    }

    listRepPtr = ListRepPtr(listPtr);
    numElems = listRepPtr->elemCount;
    numRequired = numElems + 1 ;
    needGrow = (numRequired > listRepPtr->maxElemCount);
    isShared = (listRepPtr->refCount > 1);

    if (numRequired > LIST_MAX) {
	if (interp != NULL) {
	    Tcl_SetObjResult(interp, Tcl_ObjPrintf(
		    "max length of a Tcl list (%d elements) exceeded",
		    LIST_MAX));
	    Tcl_SetErrorCode(interp, "TCL", "MEMORY", NULL);
	}
	return TCL_ERROR;
    }

    if (needGrow && !isShared) {
	/*


	 * Need to grow + unshared intrep => try to realloc
	 */


	attempt = 2 * numRequired;
	if (attempt <= LIST_MAX) {
	    newPtr = attemptckrealloc(listRepPtr, LIST_SIZE(attempt));
	}
	if (newPtr == NULL) {
	    attempt = numRequired + 1 + TCL_MIN_ELEMENT_GROWTH;
	    if (attempt > LIST_MAX) {
		attempt = LIST_MAX;
	    }
	    newPtr = attemptckrealloc(listRepPtr, LIST_SIZE(attempt));
	}
	if (newPtr == NULL) {
	    attempt = numRequired;
	    newPtr = attemptckrealloc(listRepPtr, LIST_SIZE(attempt));
	}
	if (newPtr) {
	    listRepPtr = newPtr;
	    listRepPtr->maxElemCount = attempt;
	    needGrow = 0;
	}
    }
    if (isShared || needGrow) {
	Tcl_Obj **dst, **src = &listRepPtr->elements;

	/*
	 * Either we have a shared intrep and we must copy to write, or we
	 * need to grow and realloc attempts failed.  Attempt intrep copy.
	 */

	attempt = 2 * numRequired;
	newPtr = AttemptNewList(NULL, attempt, NULL);
	if (newPtr == NULL) {
	    attempt = numRequired + 1 + TCL_MIN_ELEMENT_GROWTH;
	    if (attempt > LIST_MAX) {
		attempt = LIST_MAX;
	    }
	    newPtr = AttemptNewList(NULL, attempt, NULL);
	}
	if (newPtr == NULL) {
	    attempt = numRequired;
	    newPtr = AttemptNewList(interp, attempt, NULL);
	}
	if (newPtr == NULL) {
	    /*
	     * All growth attempts failed; throw the error.
	     */

	    return TCL_ERROR;
	}

	dst = &newPtr->elements;
	newPtr->refCount++;
	newPtr->canonicalFlag = listRepPtr->canonicalFlag;
	newPtr->elemCount = listRepPtr->elemCount;

	if (isShared) {
	    /*
	     * The original intrep must remain undisturbed.  Copy into the new
	     * one and bump refcounts
	     */
	    while (numElems--) {
		*dst = *src++;
		Tcl_IncrRefCount(*dst++);
	    }


	    listRepPtr->refCount--;
	} else {
	    /*
	     * Old intrep to be freed, re-use refCounts.
	     */

	    memcpy(dst, src, (size_t) numElems * sizeof(Tcl_Obj *));
	    ckfree(listRepPtr);
	}
	listRepPtr = newPtr;
    }
    listPtr->internalRep.twoPtrValue.ptr1 = listRepPtr;

    /*
     * Add objPtr to the end of listPtr's array of element pointers. Increment
     * the ref count for the (now shared) objPtr.
     */

    *(&listRepPtr->elements + listRepPtr->elemCount) = objPtr;

    Tcl_IncrRefCount(objPtr);
    listRepPtr->elemCount++;

    /*
     * Invalidate any old string representation since the list's internal
     * representation has changed.
     */
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
    register Tcl_Obj *listPtr,	/* List object to index into. */
    register int index,		/* Index of element to return. */
    Tcl_Obj **objPtrPtr)	/* The resulting Tcl_Obj* is stored here. */
{
    register List *listRepPtr;

    if (listPtr->typePtr != &tclListType) {
	int result, length;

	(void) TclGetStringFromObj(listPtr, &length);
	if (!length) {
	    *objPtrPtr = NULL;
	    return TCL_OK;
	}

	result = SetListFromAny(interp, listPtr);
	if (result != TCL_OK) {
	    return result;
	}
    }

    listRepPtr = listPtr->internalRep.twoPtrValue.ptr1;
    if ((index < 0) || (index >= listRepPtr->elemCount)) {
	*objPtrPtr = NULL;
    } else {
	*objPtrPtr = (&listRepPtr->elements)[index];
    }

    return TCL_OK;







|

|
<



<






|







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
    register Tcl_Obj *listPtr,	/* List object to index into. */
    register int index,		/* Index of element to return. */
    Tcl_Obj **objPtrPtr)	/* The resulting Tcl_Obj* is stored here. */
{
    register List *listRepPtr;

    if (listPtr->typePtr != &tclListType) {
	int result;

	if (listPtr->bytes == tclEmptyStringRep) {

	    *objPtrPtr = NULL;
	    return TCL_OK;
	}

	result = SetListFromAny(interp, listPtr);
	if (result != TCL_OK) {
	    return result;
	}
    }

    listRepPtr = ListRepPtr(listPtr);
    if ((index < 0) || (index >= listRepPtr->elemCount)) {
	*objPtrPtr = NULL;
    } else {
	*objPtrPtr = (&listRepPtr->elements)[index];
    }

    return TCL_OK;
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
    Tcl_Interp *interp,		/* Used to report errors if not NULL. */
    register Tcl_Obj *listPtr,	/* List object whose #elements to return. */
    register int *intPtr)	/* The resulting int is stored here. */
{
    register List *listRepPtr;

    if (listPtr->typePtr != &tclListType) {
	int result, length;

	(void) TclGetStringFromObj(listPtr, &length);
	if (!length) {
	    *intPtr = 0;
	    return TCL_OK;
	}

	result = SetListFromAny(interp, listPtr);
	if (result != TCL_OK) {
	    return result;
	}
    }

    listRepPtr = listPtr->internalRep.twoPtrValue.ptr1;
    *intPtr = listRepPtr->elemCount;
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *







|

|
<



<






|







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
    Tcl_Interp *interp,		/* Used to report errors if not NULL. */
    register Tcl_Obj *listPtr,	/* List object whose #elements to return. */
    register int *intPtr)	/* The resulting int is stored here. */
{
    register List *listRepPtr;

    if (listPtr->typePtr != &tclListType) {
	int result;

	if (listPtr->bytes == tclEmptyStringRep) {

	    *intPtr = 0;
	    return TCL_OK;
	}

	result = SetListFromAny(interp, listPtr);
	if (result != TCL_OK) {
	    return result;
	}
    }

    listRepPtr = ListRepPtr(listPtr);
    *intPtr = listRepPtr->elemCount;
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
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
    register Tcl_Obj **elemPtrs;
    int numElems, numRequired, numAfterLast, start, i, j, isShared;

    if (Tcl_IsShared(listPtr)) {
	Tcl_Panic("%s called with shared object", "Tcl_ListObjReplace");
    }
    if (listPtr->typePtr != &tclListType) {
	int length;

	(void) TclGetStringFromObj(listPtr, &length);
	if (!length) {
	    if (objc) {
		Tcl_SetListObj(listPtr, objc, NULL);
	    } else {
		return TCL_OK;
	    }

	} else {
	    int result = SetListFromAny(interp, listPtr);

	    if (result != TCL_OK) {
		return result;
	    }
	}
    }

    /*
     * Note that when count == 0 and objc == 0, this routine is logically a
     * no-op, removing and adding no elements to the list. However, by flowing
     * through this routine anyway, we get the important side effect that the
     * resulting listPtr is a list in canoncial form. This is important.
     * Resist any temptation to optimize this case.
     */

    listRepPtr = listPtr->internalRep.twoPtrValue.ptr1;
    elemPtrs = &listRepPtr->elements;
    numElems = listRepPtr->elemCount;

    if (first < 0) {
	first = 0;
    }
    if (first >= numElems) {
	first = numElems;	/* So we'll insert after last element. */
    }
    if (count < 0) {
	count = 0;
    } else if (numElems < first+count || first+count < 0) {
	/*
	 * The 'first+count < 0' condition here guards agains integer
	 * overflow in determining 'first+count'
	 */

	count = numElems - first;
    }

    isShared = (listRepPtr->refCount > 1);
    numRequired = numElems - count + objc;

    if ((numRequired <= listRepPtr->maxElemCount) && !isShared) {







<
|
<
<
|
<
<


>

















|














|

>







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
    register Tcl_Obj **elemPtrs;
    int numElems, numRequired, numAfterLast, start, i, j, isShared;

    if (Tcl_IsShared(listPtr)) {
	Tcl_Panic("%s called with shared object", "Tcl_ListObjReplace");
    }
    if (listPtr->typePtr != &tclListType) {

	if (listPtr->bytes == tclEmptyStringRep) {


	    if (!objc) {


		return TCL_OK;
	    }
	    Tcl_SetListObj(listPtr, objc, NULL);
	} else {
	    int result = SetListFromAny(interp, listPtr);

	    if (result != TCL_OK) {
		return result;
	    }
	}
    }

    /*
     * Note that when count == 0 and objc == 0, this routine is logically a
     * no-op, removing and adding no elements to the list. However, by flowing
     * through this routine anyway, we get the important side effect that the
     * resulting listPtr is a list in canoncial form. This is important.
     * Resist any temptation to optimize this case.
     */

    listRepPtr = ListRepPtr(listPtr);
    elemPtrs = &listRepPtr->elements;
    numElems = listRepPtr->elemCount;

    if (first < 0) {
	first = 0;
    }
    if (first >= numElems) {
	first = numElems;	/* So we'll insert after last element. */
    }
    if (count < 0) {
	count = 0;
    } else if (numElems < first+count || first+count < 0) {
	/*
	 * The 'first+count < 0' condition here guards agains integer
	 * overflow in determining 'first+count'.
	 */

	count = numElems - first;
    }

    isShared = (listRepPtr->refCount > 1);
    numRequired = numElems - count + objc;

    if ((numRequired <= listRepPtr->maxElemCount) && !isShared) {
878
879
880
881
882
883
884
885
886




887







888
889
890
891
892
893
894

	if (numRequired > listRepPtr->maxElemCount){
	    newMax = 2 * numRequired;
	} else {
	    newMax = listRepPtr->maxElemCount;
	}

	listRepPtr = NewListIntRep(newMax, NULL);
	if (!listRepPtr) {




	    Tcl_Panic("Not enough memory to allocate list");







	}

	listPtr->internalRep.twoPtrValue.ptr1 = listRepPtr;
	listRepPtr->refCount++;

	elemPtrs = &listRepPtr->elements;








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







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

	if (numRequired > listRepPtr->maxElemCount){
	    newMax = 2 * numRequired;
	} else {
	    newMax = listRepPtr->maxElemCount;
	}

	listRepPtr = AttemptNewList(NULL, newMax, NULL);
	if (listRepPtr == NULL) {
	    unsigned int limit = LIST_MAX - numRequired;
	    unsigned int extra = numRequired - numElems
		    + TCL_MIN_ELEMENT_GROWTH;
	    int growth = (int) ((extra > limit) ? limit : extra);

	    listRepPtr = AttemptNewList(NULL, numRequired + growth, NULL);
	    if (listRepPtr == NULL) {
		listRepPtr = AttemptNewList(interp, numRequired, NULL);
		if (listRepPtr == NULL) {
		    return TCL_ERROR;
		}
	    }
	}

	listPtr->internalRep.twoPtrValue.ptr1 = listRepPtr;
	listRepPtr->refCount++;

	elemPtrs = &listRepPtr->elements;

1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
TclLindexList(
    Tcl_Interp *interp,		/* Tcl interpreter. */
    Tcl_Obj *listPtr,		/* List being unpacked. */
    Tcl_Obj *argPtr)		/* Index or index list. */
{

    int index;			/* Index into the list. */
    Tcl_Obj **indices;		/* Array of list indices. */
    int indexCount;		/* Size of the array of list indices. */
    Tcl_Obj *indexListCopy;

    /*
     * Determine whether argPtr designates a list or a single index. We have
     * to be careful about the order of the checks to avoid repeated
     * shimmering; see TIP#22 and TIP#33 for the details.
     */







<
<







1081
1082
1083
1084
1085
1086
1087


1088
1089
1090
1091
1092
1093
1094
TclLindexList(
    Tcl_Interp *interp,		/* Tcl interpreter. */
    Tcl_Obj *listPtr,		/* List being unpacked. */
    Tcl_Obj *argPtr)		/* Index or index list. */
{

    int index;			/* Index into the list. */


    Tcl_Obj *indexListCopy;

    /*
     * Determine whether argPtr designates a list or a single index. We have
     * to be careful about the order of the checks to avoid repeated
     * shimmering; see TIP#22 and TIP#33 for the details.
     */
1041
1042
1043
1044
1045
1046
1047










1048
1049

1050
1051
1052
1053
1054
1055
1056
	 * argPtr designates something that is neither an index nor a
	 * well-formed list. Report the error via TclLindexFlat.
	 */

	return TclLindexFlat(interp, listPtr, 1, &argPtr);
    }











    TclListObjGetElements(NULL, indexListCopy, &indexCount, &indices);
    listPtr = TclLindexFlat(interp, listPtr, indexCount, indices);

    Tcl_DecrRefCount(indexListCopy);
    return listPtr;
}

/*
 *----------------------------------------------------------------------
 *







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







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
	 * argPtr designates something that is neither an index nor a
	 * well-formed list. Report the error via TclLindexFlat.
	 */

	return TclLindexFlat(interp, listPtr, 1, &argPtr);
    }

    if (indexListCopy->typePtr == &tclListType) {
	List *listRepPtr = ListRepPtr(indexListCopy);

	listPtr = TclLindexFlat(interp, listPtr, listRepPtr->elemCount,
		&listRepPtr->elements);
    } else {
	int indexCount = -1;	/* Size of the array of list indices. */
	Tcl_Obj **indices = NULL;
				/* Array of list indices. */

	Tcl_ListObjGetElements(NULL, indexListCopy, &indexCount, &indices);
	listPtr = TclLindexFlat(interp, listPtr, indexCount, indices);
    }
    Tcl_DecrRefCount(indexListCopy);
    return listPtr;
}

/*
 *----------------------------------------------------------------------
 *
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
    /*
     * Anchor the linked list of Tcl_Obj's whose string reps must be
     * invalidated if the operation succeeds.
     */

    retValuePtr = subListPtr;
    chainPtr = NULL;


    /*
     * Loop through all the index arguments, and for each one dive into the
     * appropriate sublist.
     */

    do {
	int elemCount;
	Tcl_Obj *parentList, **elemPtrs;


	/* Check for the possible error conditions... */

	result = TCL_ERROR;
	if (TclListObjGetElements(interp, subListPtr, &elemCount, &elemPtrs)
		!= TCL_OK) {
	    /* ...the sublist we're indexing into isn't a list at all. */

	    break;
	}

	/*
	 * WARNING: the macro TclGetIntForIndexM is not safe for
	 * post-increments, avoid '*indexArray++' here.
	 */

	if (TclGetIntForIndexM(interp, *indexArray, elemCount - 1, &index)
		!= TCL_OK)  {
	    /* ...the index we're trying to use isn't an index at all. */

	    indexArray++;
	    break;
	}
	indexArray++;

	if (index < 0 || index > elemCount) {
	    /* ...the index points outside the sublist. */

	    Tcl_SetObjResult(interp,
		    Tcl_NewStringObj("list index out of range", -1));
	    Tcl_SetErrorCode(interp, "TCL", "OPERATION", "LSET", "BADINDEX",
		    NULL);


	    break;
	}

	/*
	 * No error conditions.  As long as we're not yet on the last index,
	 * determine the next sublist for the next pass through the loop, and
	 * take steps to make sure it is an unshared copy, as we intend to
	 * modify it.
	 */

	result = TCL_OK;
	if (--indexCount) {
	    parentList = subListPtr;
	    if (index == elemCount) {
		subListPtr = Tcl_NewObj();
	    } else {
		subListPtr = elemPtrs[index];
	    }







>










>
|
>
|



>











>







>
|
|
|
|
>
>










<







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
    /*
     * Anchor the linked list of Tcl_Obj's whose string reps must be
     * invalidated if the operation succeeds.
     */

    retValuePtr = subListPtr;
    chainPtr = NULL;
    result = TCL_OK;

    /*
     * Loop through all the index arguments, and for each one dive into the
     * appropriate sublist.
     */

    do {
	int elemCount;
	Tcl_Obj *parentList, **elemPtrs;

	/*
	 * Check for the possible error conditions...
	 */

	if (TclListObjGetElements(interp, subListPtr, &elemCount, &elemPtrs)
		!= TCL_OK) {
	    /* ...the sublist we're indexing into isn't a list at all. */
	    result = TCL_ERROR;
	    break;
	}

	/*
	 * WARNING: the macro TclGetIntForIndexM is not safe for
	 * post-increments, avoid '*indexArray++' here.
	 */

	if (TclGetIntForIndexM(interp, *indexArray, elemCount - 1, &index)
		!= TCL_OK)  {
	    /* ...the index we're trying to use isn't an index at all. */
	    result = TCL_ERROR;
	    indexArray++;
	    break;
	}
	indexArray++;

	if (index < 0 || index > elemCount) {
	    /* ...the index points outside the sublist. */
	    if (interp != NULL) {
		Tcl_SetObjResult(interp,
			Tcl_NewStringObj("list index out of range", -1));
		Tcl_SetErrorCode(interp, "TCL", "OPERATION", "LSET",
			"BADINDEX", NULL);
	    }
	    result = TCL_ERROR;
	    break;
	}

	/*
	 * No error conditions.  As long as we're not yet on the last index,
	 * determine the next sublist for the next pass through the loop, and
	 * take steps to make sure it is an unshared copy, as we intend to
	 * modify it.
	 */


	if (--indexCount) {
	    parentList = subListPtr;
	    if (index == elemCount) {
		subListPtr = Tcl_NewObj();
	    } else {
		subListPtr = elemPtrs[index];
	    }
1437
1438
1439
1440
1441
1442
1443
1444


1445
1446

1447
1448
1449
1450
1451
1452
1453
1454
	if (retValuePtr != listPtr) {
	    Tcl_DecrRefCount(retValuePtr);
	}
	return NULL;
    }

    /*
     * Store valuePtr in proper sublist and return.


     */


    Tcl_ListObjLength(NULL, subListPtr, &len);
    if (index == len) {
	Tcl_ListObjAppendElement(NULL, subListPtr, valuePtr);
    } else {
	TclListObjSetElement(NULL, subListPtr, index, valuePtr);
    }
    Tcl_InvalidateStringRep(subListPtr);
    Tcl_IncrRefCount(retValuePtr);







|
>
>


>
|







1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
	if (retValuePtr != listPtr) {
	    Tcl_DecrRefCount(retValuePtr);
	}
	return NULL;
    }

    /*
     * Store valuePtr in proper sublist and return. The -1 is to avoid a
     * compiler warning (not a problem because we checked that we have a
     * proper list - or something convertible to one - above).
     */

    len = -1;
    TclListObjLength(NULL, subListPtr, &len);
    if (index == len) {
	Tcl_ListObjAppendElement(NULL, subListPtr, valuePtr);
    } else {
	TclListObjSetElement(NULL, subListPtr, index, valuePtr);
    }
    Tcl_InvalidateStringRep(subListPtr);
    Tcl_IncrRefCount(retValuePtr);
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
     * Ensure that the listPtr parameter designates an unshared list.
     */

    if (Tcl_IsShared(listPtr)) {
	Tcl_Panic("%s called with shared object", "TclListObjSetElement");
    }
    if (listPtr->typePtr != &tclListType) {
	int length, result;

	(void) TclGetStringFromObj(listPtr, &length);
	if (!length) {
	    Tcl_SetObjResult(interp,
		    Tcl_NewStringObj("list index out of range", -1));
	    Tcl_SetErrorCode(interp, "TCL", "OPERATION", "LSET", "BADINDEX",
		    NULL);

	    return TCL_ERROR;
	}
	result = SetListFromAny(interp, listPtr);
	if (result != TCL_OK) {
	    return result;
	}
    }

    listRepPtr = listPtr->internalRep.twoPtrValue.ptr1;
    elemCount = listRepPtr->elemCount;
    elemPtrs = &listRepPtr->elements;

    /*
     * Ensure that the index is in bounds.
     */

    if (index<0 || index>=elemCount) {
	if (interp != NULL) {
	    Tcl_SetObjResult(interp,
		    Tcl_NewStringObj("list index out of range", -1));
	    Tcl_SetErrorCode(interp, "TCL", "OPERATION", "LSET", "BADINDEX",
		    NULL);
	}
	return TCL_ERROR;
    }

    /*
     * If the internal rep is shared, replace it with an unshared copy.
     */

    if (listRepPtr->refCount > 1) {
	List *oldListRepPtr = listRepPtr;
	Tcl_Obj **oldElemPtrs = elemPtrs;
	int i;


	listRepPtr = NewListIntRep(listRepPtr->maxElemCount, NULL);
	if (listRepPtr == NULL) {
	    Tcl_Panic("Not enough memory to allocate list");
	}



	listRepPtr->canonicalFlag = oldListRepPtr->canonicalFlag;

	elemPtrs = &listRepPtr->elements;
	for (i=0; i < elemCount; i++) {
	    elemPtrs[i] = oldElemPtrs[i];
	    Tcl_IncrRefCount(elemPtrs[i]);
	}

	listRepPtr->refCount++;
	listRepPtr->elemCount = elemCount;
	listPtr->internalRep.twoPtrValue.ptr1 = listRepPtr;
	oldListRepPtr->refCount--;
    }


    /*
     * Add a reference to the new list element.
     */

    Tcl_IncrRefCount(valuePtr);








|

|
|
|
|
|
|
>








|

<




















|
|
<

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

>
|
|
|
<

>







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
     * Ensure that the listPtr parameter designates an unshared list.
     */

    if (Tcl_IsShared(listPtr)) {
	Tcl_Panic("%s called with shared object", "TclListObjSetElement");
    }
    if (listPtr->typePtr != &tclListType) {
	int result;

	if (listPtr->bytes == tclEmptyStringRep) {
	    if (interp != NULL) {
		Tcl_SetObjResult(interp,
			Tcl_NewStringObj("list index out of range", -1));
		Tcl_SetErrorCode(interp, "TCL", "OPERATION", "LSET",
			"BADINDEX", NULL);
	    }
	    return TCL_ERROR;
	}
	result = SetListFromAny(interp, listPtr);
	if (result != TCL_OK) {
	    return result;
	}
    }

    listRepPtr = ListRepPtr(listPtr);
    elemCount = listRepPtr->elemCount;


    /*
     * Ensure that the index is in bounds.
     */

    if (index<0 || index>=elemCount) {
	if (interp != NULL) {
	    Tcl_SetObjResult(interp,
		    Tcl_NewStringObj("list index out of range", -1));
	    Tcl_SetErrorCode(interp, "TCL", "OPERATION", "LSET", "BADINDEX",
		    NULL);
	}
	return TCL_ERROR;
    }

    /*
     * If the internal rep is shared, replace it with an unshared copy.
     */

    if (listRepPtr->refCount > 1) {
	Tcl_Obj **dst, **src = &listRepPtr->elements;
	List *newPtr = AttemptNewList(NULL, listRepPtr->maxElemCount, NULL);


	if (newPtr == NULL) {
	    newPtr = AttemptNewList(interp, elemCount, NULL);
	    if (newPtr == NULL) {
		return TCL_ERROR;
	    }
	}
	newPtr->refCount++;
	newPtr->elemCount = elemCount;
	newPtr->canonicalFlag = listRepPtr->canonicalFlag;

	dst = &newPtr->elements;
	while (elemCount--) {
	    *dst = *src++;
	    Tcl_IncrRefCount(*dst++);
	}

	listRepPtr->refCount--;

	listPtr->internalRep.twoPtrValue.ptr1 = listRepPtr = newPtr;

    }
    elemPtrs = &listRepPtr->elements;

    /*
     * Add a reference to the new list element.
     */

    Tcl_IncrRefCount(valuePtr);

1606
1607
1608
1609
1610
1611
1612
1613


1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
 *----------------------------------------------------------------------
 */

static void
FreeListInternalRep(
    Tcl_Obj *listPtr)		/* List object with internal rep to free. */
{
    register List *listRepPtr = listPtr->internalRep.twoPtrValue.ptr1;


    register Tcl_Obj **elemPtrs = &listRepPtr->elements;
    register Tcl_Obj *objPtr;
    int numElems = listRepPtr->elemCount;
    int i;

    if (--listRepPtr->refCount <= 0) {
	for (i = 0;  i < numElems;  i++) {
	    objPtr = elemPtrs[i];
	    Tcl_DecrRefCount(objPtr);
	}
	ckfree(listRepPtr);
    }

    listPtr->internalRep.twoPtrValue.ptr1 = NULL;
    listPtr->internalRep.twoPtrValue.ptr2 = NULL;
    listPtr->typePtr = NULL;







|
>
>
|
<
|
<

<

<
|







1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721

1722

1723

1724

1725
1726
1727
1728
1729
1730
1731
1732
 *----------------------------------------------------------------------
 */

static void
FreeListInternalRep(
    Tcl_Obj *listPtr)		/* List object with internal rep to free. */
{
    List *listRepPtr = ListRepPtr(listPtr);

    if (--listRepPtr->refCount <= 0) {
	Tcl_Obj **elemPtrs = &listRepPtr->elements;

	int i, numElems = listRepPtr->elemCount;



	for (i = 0;  i < numElems;  i++) {

	    Tcl_DecrRefCount(elemPtrs[i]);
	}
	ckfree(listRepPtr);
    }

    listPtr->internalRep.twoPtrValue.ptr1 = NULL;
    listPtr->internalRep.twoPtrValue.ptr2 = NULL;
    listPtr->typePtr = NULL;
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
 */

static void
DupListInternalRep(
    Tcl_Obj *srcPtr,		/* Object with internal rep to copy. */
    Tcl_Obj *copyPtr)		/* Object with internal rep to set. */
{
    List *listRepPtr = srcPtr->internalRep.twoPtrValue.ptr1;

    listRepPtr->refCount++;
    copyPtr->internalRep.twoPtrValue.ptr1 = listRepPtr;
    copyPtr->internalRep.twoPtrValue.ptr2 = NULL;
    copyPtr->typePtr = &tclListType;
}

/*
 *----------------------------------------------------------------------
 *
 * SetListFromAny --
 *







|

|
<
<
<







1750
1751
1752
1753
1754
1755
1756
1757
1758
1759



1760
1761
1762
1763
1764
1765
1766
 */

static void
DupListInternalRep(
    Tcl_Obj *srcPtr,		/* Object with internal rep to copy. */
    Tcl_Obj *copyPtr)		/* Object with internal rep to set. */
{
    List *listRepPtr = ListRepPtr(srcPtr);

    ListSetIntRep(copyPtr, listRepPtr);



}

/*
 *----------------------------------------------------------------------
 *
 * SetListFromAny --
 *
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694

1695
1696
1697
1698
1699
1700
1701
 */

static int
SetListFromAny(
    Tcl_Interp *interp,		/* Used for error reporting if not NULL. */
    Tcl_Obj *objPtr)		/* The object to convert. */
{
    const char *string;
    char *s;
    const char *elemStart, *nextElem;
    int lenRemain, length, estCount, elemSize, hasBrace, i, j, result;
    const char *limit;		/* Points just after string's last byte. */
    register const char *p;
    register Tcl_Obj **elemPtrs;
    register Tcl_Obj *elemPtr;
    List *listRepPtr;


    /*
     * Dictionaries are a special case; they have a string representation such
     * that *all* valid dictionaries are valid lists. Hence we can convert
     * more directly. Only do this when there's no existing string rep; if
     * there is, it is the string rep that's authoritative (because it could
     * describe duplicate keys).







<
<
<
<
<
<
<
<

>







1779
1780
1781
1782
1783
1784
1785








1786
1787
1788
1789
1790
1791
1792
1793
1794
 */

static int
SetListFromAny(
    Tcl_Interp *interp,		/* Used for error reporting if not NULL. */
    Tcl_Obj *objPtr)		/* The object to convert. */
{








    List *listRepPtr;
    Tcl_Obj **elemPtrs;

    /*
     * Dictionaries are a special case; they have a string representation such
     * that *all* valid dictionaries are valid lists. Hence we can convert
     * more directly. Only do this when there's no existing string rep; if
     * there is, it is the string rep that's authoritative (because it could
     * describe duplicate keys).
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
	 * the reverse back to a dictionary) are both order-preserving. Also
	 * note that since we know we've got a valid dictionary (by
	 * representation) we also know that fetching the size of the
	 * dictionary or iterating over it will not fail.
	 */

	Tcl_DictObjSize(NULL, objPtr, &size);
	listRepPtr = NewListIntRep(size > 0 ? 2*size : 1, NULL);
	if (!listRepPtr) {
	    Tcl_SetResult(interp,
		    "insufficient memory to allocate list working space",
		    TCL_STATIC);
	    Tcl_SetErrorCode(interp, "TCL", "MEMORY", NULL);
	    return TCL_ERROR;
	}
	listRepPtr->elemCount = 2 * size;

	/*
	 * Populate the list representation.
	 */

	elemPtrs = &listRepPtr->elements;
	Tcl_DictObjFirst(NULL, objPtr, &search, &keyPtr, &valuePtr, &done);
	i = 0;
	while (!done) {
	    elemPtrs[i++] = keyPtr;
	    elemPtrs[i++] = valuePtr;
	    Tcl_IncrRefCount(keyPtr);
	    Tcl_IncrRefCount(valuePtr);
	    Tcl_DictObjNext(&search, &keyPtr, &valuePtr, &done);
	}

	/*
	 * Swap the representations.
	 */

	goto commitRepresentation;
    }

    /*
     * Get the string representation. Make it up-to-date if necessary.
     */

    string = TclGetStringFromObj(objPtr, &length);

    /*
     * Parse the string into separate string objects, and create a List
     * structure that points to the element string objects. We use a modified
     * version of Tcl_SplitList's implementation to avoid one malloc and a

     * string copy for each list element. First, estimate the number of
     * elements by counting the number of space characters in the list.
     */

    limit = string + length;
    estCount = 1;
    for (p = string;  p < limit;  p++) {
	if (isspace(UCHAR(*p))) { /* INTL: ISO space. */
	    estCount++;


	}

    }

    /*
     * Allocate a new List structure with enough room for "estCount" elements.
     * Each element is a pointer to a Tcl_Obj with the appropriate string rep.
     * The initial "estCount" elements are set using the corresponding "argv"
     * strings.
     */

    listRepPtr = NewListIntRep(estCount, NULL);

    if (!listRepPtr) {
	Tcl_SetObjResult(interp, Tcl_NewStringObj(
		"Not enough memory to allocate the list internal rep", -1));
	Tcl_SetErrorCode(interp, "TCL", "MEMORY", NULL);
	return TCL_ERROR;
    }
    elemPtrs = &listRepPtr->elements;

    for (p=string, lenRemain=length, i=0;
	    lenRemain > 0;
	    p=nextElem, lenRemain=limit-nextElem, i++) {
	result = TclFindElement(interp, p, lenRemain, &elemStart, &nextElem,
		&elemSize, &hasBrace);
	if (result != TCL_OK) {
	    for (j = 0;  j < i;  j++) {
		elemPtr = elemPtrs[j];
		Tcl_DecrRefCount(elemPtr);
	    }
	    ckfree(listRepPtr);
	    if (interp != NULL) {
		Tcl_SetErrorCode(interp, "TCL", "VALUE", "LIST", NULL);
	    }
	    return result;
	}
	if (elemStart >= limit) {
	    break;
	}
	if (i > estCount) {
	    Tcl_Panic("SetListFromAny: bad size estimate for list");
	}

	/*
	 * Allocate a Tcl object for the element and initialize it from the
	 * "elemSize" bytes starting at "elemStart".
	 */

	s = ckalloc(elemSize + 1);
	if (hasBrace) {
	    memcpy(s, elemStart, (size_t) elemSize);
	    s[elemSize] = 0;
	} else {


	    elemSize = TclCopyAndCollapse(elemSize, elemStart, s);

	}

	TclNewObj(elemPtr);
	elemPtr->bytes = s;
	elemPtr->length = elemSize;
	elemPtrs[i] = elemPtr;
	Tcl_IncrRefCount(elemPtr);	/* Since list now holds ref to it. */
    }

    listRepPtr->elemCount = i;


    /*
     * Free the old internalRep before setting the new one. We do this as late
     * as possible to allow the conversion code, in particular
     * Tcl_GetStringFromObj, to use that old internalRep.
     */

  commitRepresentation:
    listRepPtr->refCount++;
    TclFreeIntRep(objPtr);
    objPtr->internalRep.twoPtrValue.ptr1 = listRepPtr;
    objPtr->internalRep.twoPtrValue.ptr2 = NULL;
    objPtr->typePtr = &tclListType;
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * UpdateStringOfList --







|

<
<
<
<










<

|
|




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

|
<
<
<
>
|
<
|

|
|
<
|
|
>
>

>
|
<
|
<
|
<
<
|

<
>
|
<
<
<
<
<
|

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

<
<
<
<
|
|

|
>







<
<

|
<
<







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
	 * the reverse back to a dictionary) are both order-preserving. Also
	 * note that since we know we've got a valid dictionary (by
	 * representation) we also know that fetching the size of the
	 * dictionary or iterating over it will not fail.
	 */

	Tcl_DictObjSize(NULL, objPtr, &size);
	listRepPtr = AttemptNewList(interp, size > 0 ? 2*size : 1, NULL);
	if (!listRepPtr) {




	    return TCL_ERROR;
	}
	listRepPtr->elemCount = 2 * size;

	/*
	 * Populate the list representation.
	 */

	elemPtrs = &listRepPtr->elements;
	Tcl_DictObjFirst(NULL, objPtr, &search, &keyPtr, &valuePtr, &done);

	while (!done) {
	    *elemPtrs++ = keyPtr;
	    *elemPtrs++ = valuePtr;
	    Tcl_IncrRefCount(keyPtr);
	    Tcl_IncrRefCount(valuePtr);
	    Tcl_DictObjNext(&search, &keyPtr, &valuePtr, &done);
	}
    } else {



	int estCount, length;







	const char *limit, *nextElem = TclGetStringFromObj(objPtr, &length);

	/*



	 * Allocate enough space to hold a (Tcl_Obj *) for each
	 * (possible) list element.

	 */

	estCount = TclMaxListLength(nextElem, length, &limit);
	estCount += (estCount == 0);	/* Smallest list struct holds 1

					 * element. */
	listRepPtr = AttemptNewList(interp, estCount, NULL);
	if (listRepPtr == NULL) {
	    return TCL_ERROR;
	}
	elemPtrs = &listRepPtr->elements;


	/*

	 * Each iteration, parse and store a list element.


	 */


	while (nextElem < limit) {
	    const char *elemStart;





	    int elemSize, literal;



	    if (TCL_OK != TclFindElement(interp, nextElem, limit - nextElem,
		    &elemStart, &nextElem, &elemSize, &literal)) {



		while (--elemPtrs >= &listRepPtr->elements) {
		    Tcl_DecrRefCount(*elemPtrs);
		}
		ckfree((char *) listRepPtr);



		return TCL_ERROR;
	    }
	    if (elemStart == limit) {
		break;
	    }



	    /* TODO: replace panic with error on alloc failure? */




	    if (literal) {


		TclNewStringObj(*elemPtrs, elemStart, elemSize);

	    } else {
		TclNewObj(*elemPtrs);
		(*elemPtrs)->bytes = ckalloc((unsigned) elemSize + 1);
		(*elemPtrs)->length = TclCopyAndCollapse(elemSize, elemStart,
			(*elemPtrs)->bytes);
	    }





	    Tcl_IncrRefCount(*elemPtrs++);/* Since list now holds ref to it. */
	}

 	listRepPtr->elemCount = elemPtrs - &listRepPtr->elements;
    }

    /*
     * Free the old internalRep before setting the new one. We do this as late
     * as possible to allow the conversion code, in particular
     * Tcl_GetStringFromObj, to use that old internalRep.
     */



    TclFreeIntRep(objPtr);
    ListSetIntRep(objPtr, listRepPtr);


    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * UpdateStringOfList --
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
 */

static void
UpdateStringOfList(
    Tcl_Obj *listPtr)		/* List object with string rep to update. */
{
#   define LOCAL_SIZE 20
    int localFlags[LOCAL_SIZE], *flagPtr;
    List *listRepPtr = listPtr->internalRep.twoPtrValue.ptr1;
    int numElems = listRepPtr->elemCount;
    register int i;
    const char *elem;
    char *dst;
    int length;
    Tcl_Obj **elemPtrs;

    /*




     * Convert each element of the list to string form and then convert it to

     * proper list element form, adding it to the result buffer.


     */







    /*
     * Pass 1: estimate space, gather flags.
     */

    if (numElems <= LOCAL_SIZE) {
	flagPtr = localFlags;
    } else {




	flagPtr = ckalloc(numElems * sizeof(int));
    }
    listPtr->length = 1;
    elemPtrs = &listRepPtr->elements;
    for (i = 0; i < numElems; i++) {

	elem = TclGetStringFromObj(elemPtrs[i], &length);
	listPtr->length += Tcl_ScanCountedElement(elem, length, flagPtr+i)+1;

	/*
	 * Check for continued sanity. [Bug 1267380]
	 */


	if (listPtr->length < 1) {
	    Tcl_Panic("string representation size exceeds sane bounds");
	}


    }


    /*
     * Pass 2: copy into string rep buffer.
     */


    listPtr->bytes = ckalloc(listPtr->length);
    dst = listPtr->bytes;
    for (i = 0; i < numElems; i++) {

	elem = TclGetStringFromObj(elemPtrs[i], &length);
	dst += Tcl_ConvertCountedElement(elem, length, dst,
		flagPtr[i] | (i==0 ? 0 : TCL_DONT_QUOTE_HASH));
	*dst = ' ';
	dst++;
    }


    if (flagPtr != localFlags) {
	ckfree(flagPtr);
    }
    if (dst == listPtr->bytes) {
	*dst = 0;
    } else {
	dst--;
	*dst = 0;
    }
    listPtr->length = dst - listPtr->bytes;

    /*
     * Mark the list as being canonical; although it has a string rep, it is
     * one we derived through proper "canonical" quoting and so it's known to
     * be free from nasties relating to [concat] and [eval].
     */

    listRepPtr->canonicalFlag = 1;
}

/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78
 * End:
 */







|
|

|


<



>
>
>
>
|
>
|
>
>

>
>
>
>
>
>








>
>
>
>


<


>

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

>





>
|


>

|
<
|
<

>
>



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









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
 */

static void
UpdateStringOfList(
    Tcl_Obj *listPtr)		/* List object with string rep to update. */
{
#   define LOCAL_SIZE 20
    int localFlags[LOCAL_SIZE], *flagPtr = NULL;
    List *listRepPtr = ListRepPtr(listPtr);
    int numElems = listRepPtr->elemCount;
    int i, length, bytesNeeded = 0;
    const char *elem;
    char *dst;

    Tcl_Obj **elemPtrs;

    /*
     * Mark the list as being canonical; although it will now have a string
     * rep, it is one we derived through proper "canonical" quoting and so
     * it's known to be free from nasties relating to [concat] and [eval].
     */

    listRepPtr->canonicalFlag = 1;

    /*
     * Handle empty list case first, so rest of the routine is simpler.
     */

    if (numElems == 0) {
	listPtr->bytes = tclEmptyStringRep;
	listPtr->length = 0;
	return;
    }

    /*
     * Pass 1: estimate space, gather flags.
     */

    if (numElems <= LOCAL_SIZE) {
	flagPtr = localFlags;
    } else {
	/*
	 * We know numElems <= LIST_MAX, so this is safe.
	 */

	flagPtr = ckalloc(numElems * sizeof(int));
    }

    elemPtrs = &listRepPtr->elements;
    for (i = 0; i < numElems; i++) {
	flagPtr[i] = (i ? TCL_DONT_QUOTE_HASH : 0);
	elem = TclGetStringFromObj(elemPtrs[i], &length);
	bytesNeeded += TclScanElement(elem, length, flagPtr+i);
	if (bytesNeeded < 0) {



	    Tcl_Panic("max size for a Tcl value (%d bytes) exceeded", INT_MAX);
	}


    }
    if (bytesNeeded > INT_MAX - numElems + 1) {
	Tcl_Panic("max size for a Tcl value (%d bytes) exceeded", INT_MAX);
    }
    bytesNeeded += numElems;

    /*
     * Pass 2: copy into string rep buffer.
     */

    listPtr->length = bytesNeeded - 1;
    listPtr->bytes = ckalloc(bytesNeeded);
    dst = listPtr->bytes;
    for (i = 0; i < numElems; i++) {
	flagPtr[i] |= (i ? TCL_DONT_QUOTE_HASH : 0);
	elem = TclGetStringFromObj(elemPtrs[i], &length);
	dst += TclConvertElement(elem, length, dst, flagPtr[i]);

	*dst++ = ' ';

    }
    listPtr->bytes[listPtr->length] = '\0';

    if (flagPtr != localFlags) {
	ckfree(flagPtr);
    }















}

/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78
 * End:
 */

Changes to generic/tclLiteral.c.

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
    tablePtr->staticBuckets[0] = tablePtr->staticBuckets[1] = 0;
    tablePtr->staticBuckets[2] = tablePtr->staticBuckets[3] = 0;
    tablePtr->numBuckets = TCL_SMALL_HASH_TABLE;
    tablePtr->numEntries = 0;
    tablePtr->rebuildSize = TCL_SMALL_HASH_TABLE * REBUILD_MULTIPLIER;
    tablePtr->mask = 3;
}

/*
 *----------------------------------------------------------------------
 *
 * TclCleanupLiteralTable --
 *
 *	This function frees the internal representation of every literal in a
 *	literal table. It is called prior to deleting an interp, so that
 *	variable refs will be cleaned up properly.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Each literal in the table has its internal representation freed.
 *
 *----------------------------------------------------------------------
 */

void
TclCleanupLiteralTable(
    Tcl_Interp *interp,		/* Interpreter containing literals to purge */
    LiteralTable *tablePtr)	/* Points to the literal table being
				 * cleaned. */
{
    int i;
    LiteralEntry *entryPtr;	/* Pointer to the current entry in the hash
				 * table of literals. */
    LiteralEntry *nextPtr;	/* Pointer to the next entry in the bucket. */
    Tcl_Obj *objPtr;		/* Pointer to a literal object whose internal
				 * rep is being freed. */
    const Tcl_ObjType *typePtr;	/* Pointer to the object's type. */
    int didOne;			/* Flag for whether we've removed a literal in
				 * the current bucket. */

#ifdef TCL_COMPILE_DEBUG
    TclVerifyGlobalLiteralTable((Interp *) interp);
#endif /* TCL_COMPILE_DEBUG */

    for (i=0 ; i<tablePtr->numBuckets ; i++) {
	/*
	 * It is tempting simply to walk each hash bucket once and delete the
	 * internal representations of each literal in turn. It's also wrong.
	 * The problem is that freeing a literal's internal representation can
	 * delete other literals to which it refers, making nextPtr invalid.
	 * So each time we free an internal rep, we start its bucket over
	 * again.
	 */

	do {
	    didOne = 0;
	    entryPtr = tablePtr->buckets[i];
	    while (entryPtr != NULL) {
		objPtr = entryPtr->objPtr;
		nextPtr = entryPtr->nextPtr;
		typePtr = objPtr->typePtr;
		if ((typePtr != NULL) && (typePtr->freeIntRepProc != NULL)) {
		    if (objPtr->bytes == NULL) {
			Tcl_Panic("%s: literal without a string rep",
				"TclCleanupLiteralTable");
		    }
		    objPtr->typePtr = NULL;
		    typePtr->freeIntRepProc(objPtr);
		    didOne = 1;
		    break;
		}
		entryPtr = nextPtr;
	    }
	} while (didOne);
    }
}

/*
 *----------------------------------------------------------------------
 *
 * TclDeleteLiteralTable --
 *
 *	This function frees up everything associated with a literal table







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







67
68
69
70
71
72
73







































































74
75
76
77
78
79
80
    tablePtr->staticBuckets[0] = tablePtr->staticBuckets[1] = 0;
    tablePtr->staticBuckets[2] = tablePtr->staticBuckets[3] = 0;
    tablePtr->numBuckets = TCL_SMALL_HASH_TABLE;
    tablePtr->numEntries = 0;
    tablePtr->rebuildSize = TCL_SMALL_HASH_TABLE * REBUILD_MULTIPLIER;
    tablePtr->mask = 3;
}








































































/*
 *----------------------------------------------------------------------
 *
 * TclDeleteLiteralTable --
 *
 *	This function frees up everything associated with a literal table

Changes to generic/tclLoad.c.

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
	    Tcl_SetErrorCode(interp, "TCL", "OPERATION", "LOAD", "ENTRYPOINT",
		    NULL);
	    code = TCL_ERROR;
	    goto done;
	}
	code = pkgPtr->initProc(target);
    }

    /*
     * Record the fact that the package has been loaded in the target
     * interpreter.
     */

    if (code == TCL_OK) {




	/*



	 * Update the proper reference count.
	 */

	Tcl_MutexLock(&packageMutex);
	if (Tcl_IsSafe(target)) {
	    pkgPtr->safeInterpRefCount++;
	} else {
	    pkgPtr->interpRefCount++;
	}
	Tcl_MutexUnlock(&packageMutex);

	/*
	 * Refetch ipFirstPtr: loading the package may have introduced
	 * additional static packages at the head of the linked list!
	 */

	ipFirstPtr = Tcl_GetAssocData(target, "tclLoad", NULL);
	ipPtr = ckalloc(sizeof(InterpPackage));
	ipPtr->pkgPtr = pkgPtr;
	ipPtr->nextPtr = ipFirstPtr;
	Tcl_SetAssocData(target, "tclLoad", LoadCleanupProc, ipPtr);
    } else {
	Tcl_TransferResult(target, code, interp);
    }

  done:
    Tcl_DStringFree(&pkgName);
    Tcl_DStringFree(&initName);
    Tcl_DStringFree(&safeInitName);
    Tcl_DStringFree(&unloadName);
    Tcl_DStringFree(&safeUnloadName);









|
|


|
>
>
>
>
|
>
>
>
|
|

|
|
|
|
|
|
|

|
|
|
|

|
|
|
|
|
<
<
<







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
	    Tcl_SetErrorCode(interp, "TCL", "OPERATION", "LOAD", "ENTRYPOINT",
		    NULL);
	    code = TCL_ERROR;
	    goto done;
	}
	code = pkgPtr->initProc(target);
    }

    /*
     * Test for whether the initialization failed. If so, transfer the error
     * from the target interpreter to the originating one.
     */

    if (code != TCL_OK) {
	Tcl_TransferResult(target, code, interp);
	goto done;
    }

    /*
     * Record the fact that the package has been loaded in the target
     * interpreter.
     *
     * Update the proper reference count.
     */

    Tcl_MutexLock(&packageMutex);
    if (Tcl_IsSafe(target)) {
	pkgPtr->safeInterpRefCount++;
    } else {
	pkgPtr->interpRefCount++;
    }
    Tcl_MutexUnlock(&packageMutex);

    /*
     * Refetch ipFirstPtr: loading the package may have introduced additional
     * static packages at the head of the linked list!
     */

    ipFirstPtr = Tcl_GetAssocData(target, "tclLoad", NULL);
    ipPtr = ckalloc(sizeof(InterpPackage));
    ipPtr->pkgPtr = pkgPtr;
    ipPtr->nextPtr = ipFirstPtr;
    Tcl_SetAssocData(target, "tclLoad", LoadCleanupProc, ipPtr);




  done:
    Tcl_DStringFree(&pkgName);
    Tcl_DStringFree(&initName);
    Tcl_DStringFree(&safeInitName);
    Tcl_DStringFree(&unloadName);
    Tcl_DStringFree(&safeUnloadName);
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
    Tcl_Interp *interp,		/* Interpreter in which to return information
				 * or error message. */
    const char *targetName)	/* Name of target interpreter or NULL. If
				 * NULL, return info about all interps;
				 * otherwise, just return info about this
				 * interpreter. */
{
    /* TODO: Use Tcl_Obj APIs to generate this info for cleanliness. */
    Tcl_Interp *target;
    LoadedPackage *pkgPtr;
    InterpPackage *ipPtr;
    const char *prefix;

    if (targetName == NULL) {
	/*
	 * Return information about all of the available packages.
	 */

	prefix = "{";
	Tcl_MutexLock(&packageMutex);
	for (pkgPtr = firstPackagePtr; pkgPtr != NULL;
		pkgPtr = pkgPtr->nextPtr) {
	    Tcl_AppendResult(interp, prefix, NULL);
	    Tcl_AppendElement(interp, pkgPtr->fileName);
	    Tcl_AppendElement(interp, pkgPtr->packageName);
	    Tcl_AppendResult(interp, "}", NULL);
	    prefix = " {";

	}
	Tcl_MutexUnlock(&packageMutex);

	return TCL_OK;
    }

    /*
     * Return information about only the packages that are loaded in a given
     * interpreter.
     */

    target = Tcl_GetSlave(interp, targetName);
    if (target == NULL) {
	return TCL_ERROR;
    }
    ipPtr = Tcl_GetAssocData(target, "tclLoad", NULL);
    prefix = "{";
    for (; ipPtr != NULL; ipPtr = ipPtr->nextPtr) {
	pkgPtr = ipPtr->pkgPtr;
	Tcl_AppendResult(interp, prefix, NULL);
	Tcl_AppendElement(interp, pkgPtr->fileName);
	Tcl_AppendElement(interp, pkgPtr->packageName);
	Tcl_AppendResult(interp, "}", NULL);
	prefix = " {";
    }

    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * LoadCleanupProc --







<



|






|



<
|
|
|
<
>


>













|


<
|
|
|
<

>







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
    Tcl_Interp *interp,		/* Interpreter in which to return information
				 * or error message. */
    const char *targetName)	/* Name of target interpreter or NULL. If
				 * NULL, return info about all interps;
				 * otherwise, just return info about this
				 * interpreter. */
{

    Tcl_Interp *target;
    LoadedPackage *pkgPtr;
    InterpPackage *ipPtr;
    Tcl_Obj *resultObj, *pkgDesc[2];

    if (targetName == NULL) {
	/*
	 * Return information about all of the available packages.
	 */

	resultObj = Tcl_NewObj();
	Tcl_MutexLock(&packageMutex);
	for (pkgPtr = firstPackagePtr; pkgPtr != NULL;
		pkgPtr = pkgPtr->nextPtr) {

	    pkgDesc[0] = Tcl_NewStringObj(pkgPtr->fileName, -1);
	    pkgDesc[1] = Tcl_NewStringObj(pkgPtr->packageName, -1);
	    Tcl_ListObjAppendElement(NULL, resultObj,

		    Tcl_NewListObj(2, pkgDesc));
	}
	Tcl_MutexUnlock(&packageMutex);
	Tcl_SetObjResult(interp, resultObj);
	return TCL_OK;
    }

    /*
     * Return information about only the packages that are loaded in a given
     * interpreter.
     */

    target = Tcl_GetSlave(interp, targetName);
    if (target == NULL) {
	return TCL_ERROR;
    }
    ipPtr = Tcl_GetAssocData(target, "tclLoad", NULL);
    resultObj = Tcl_NewObj();
    for (; ipPtr != NULL; ipPtr = ipPtr->nextPtr) {
	pkgPtr = ipPtr->pkgPtr;

	pkgDesc[0] = Tcl_NewStringObj(pkgPtr->fileName, -1);
	pkgDesc[1] = Tcl_NewStringObj(pkgPtr->packageName, -1);
	Tcl_ListObjAppendElement(NULL, resultObj, Tcl_NewListObj(2, pkgDesc));

    }
    Tcl_SetObjResult(interp, resultObj);
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * LoadCleanupProc --

Changes to generic/tclMain.c.

121
122
123
124
125
126
127

128
129
130
131
132
133
134
/*
 * Forward declarations for functions defined later in this file.
 */

MODULE_SCOPE Tcl_MainLoopProc *TclGetMainLoop(void);
static void		Prompt(Tcl_Interp *interp, InteractiveState *isPtr);
static void		StdinProc(ClientData clientData, int mask);


#ifndef TCL_ASCII_MAIN
static Tcl_ThreadDataKey dataKey;
/*
 *----------------------------------------------------------------------
 *
 * Tcl_SetStartupScript --







>







121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/*
 * Forward declarations for functions defined later in this file.
 */

MODULE_SCOPE Tcl_MainLoopProc *TclGetMainLoop(void);
static void		Prompt(Tcl_Interp *interp, InteractiveState *isPtr);
static void		StdinProc(ClientData clientData, int mask);
static void     FreeMainInterp(ClientData clientData);

#ifndef TCL_ASCII_MAIN
static Tcl_ThreadDataKey dataKey;
/*
 *----------------------------------------------------------------------
 *
 * Tcl_SetStartupScript --
383
384
385
386
387
388
389







390
391
392
393
394
395
396
    }
    if (Tcl_InterpDeleted(interp)) {
	goto done;
    }
    if (Tcl_LimitExceeded(interp)) {
	goto done;
    }








    /*
     * Invoke the script specified on the command line, if any. Must fetch it
     * again, as the appInitProc might have reset it.
     */

    path = Tcl_GetStartupScript(&encodingName);







>
>
>
>
>
>
>







384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
    }
    if (Tcl_InterpDeleted(interp)) {
	goto done;
    }
    if (Tcl_LimitExceeded(interp)) {
	goto done;
    }
    if (TclFullFinalizationRequested()) {
	/*
	 * Arrange for final deletion of the main interp
	 */
	/* ARGH Munchhausen effect  */
	Tcl_CreateExitHandler(FreeMainInterp, (ClientData)interp);
    }

    /*
     * Invoke the script specified on the command line, if any. Must fetch it
     * again, as the appInitProc might have reset it.
     */

    path = Tcl_GetStartupScript(&encodingName);
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
     * replace "exit" with some other command to do additional cleanup on
     * exit. The Tcl_EvalObjEx call should never return.
     */

    if (!Tcl_InterpDeleted(interp)) {
	if (!Tcl_LimitExceeded(interp)) {
	    Tcl_Obj *cmd = Tcl_ObjPrintf("exit %d", exitCode);

	    Tcl_IncrRefCount(cmd);
	    Tcl_EvalObjEx(interp, cmd, TCL_EVAL_GLOBAL);
	    Tcl_DecrRefCount(cmd);
	}

	/*
	 * If Tcl_EvalObjEx returns, trying to eval [exit], something unusual
	 * is happening. Maybe interp has been deleted; maybe [exit] was
	 * redefined, maybe we've blown up because of an exceeded limit. We
	 * still want to cleanup and exit.
	 */

	if (!Tcl_InterpDeleted(interp)) {
	    Tcl_DeleteInterp(interp);
	}
    }
    Tcl_SetStartupScript(NULL, NULL);

    /*
     * If we get here, the master interp has been deleted. Allow its
     * destruction with the last matching Tcl_Release.
     */

    Tcl_Release(interp);
    Tcl_Exit(exitCode);
}


#ifndef UNICODE
void
Tcl_Main(
    int argc,			/* Number of arguments. */
    TCHAR **argv,		/* Array of argument strings. */
    Tcl_AppInitProc *appInitProc)
				/* Application-specific initialization
				 * function to call after most initialization
				 * but before starting to execute commands. */
{
    Tcl_FindExecutable(argv[0]);
	Tcl_MainEx(argc, argv, appInitProc, Tcl_CreateInterp());
}
#endif

#ifndef TCL_ASCII_MAIN

/*
 *---------------------------------------------------------------







|




|






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



>
|
|


|






|







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
     * replace "exit" with some other command to do additional cleanup on
     * exit. The Tcl_EvalObjEx call should never return.
     */

    if (!Tcl_InterpDeleted(interp)) {
	if (!Tcl_LimitExceeded(interp)) {
	    Tcl_Obj *cmd = Tcl_ObjPrintf("exit %d", exitCode);
	    
	    Tcl_IncrRefCount(cmd);
	    Tcl_EvalObjEx(interp, cmd, TCL_EVAL_GLOBAL);
	    Tcl_DecrRefCount(cmd);
	}
    }
	/*
	 * If Tcl_EvalObjEx returns, trying to eval [exit], something unusual
	 * is happening. Maybe interp has been deleted; maybe [exit] was
	 * redefined, maybe we've blown up because of an exceeded limit. We
	 * still want to cleanup and exit.
	 */













    Tcl_Exit(exitCode);
}

#if (TCL_MAJOR_VERSION == 8) && !defined(UNICODE)
#undef Tcl_Main
extern DLLEXPORT void
Tcl_Main(
    int argc,			/* Number of arguments. */
    char **argv,		/* Array of argument strings. */
    Tcl_AppInitProc *appInitProc)
				/* Application-specific initialization
				 * function to call after most initialization
				 * but before starting to execute commands. */
{
    Tcl_FindExecutable(argv[0]);
    Tcl_MainEx(argc, argv, appInitProc, Tcl_CreateInterp());
}
#endif

#ifndef TCL_ASCII_MAIN

/*
 *---------------------------------------------------------------
690
691
692
693
694
695
696




































697
698
699
700
701
702
703
Tcl_MainLoopProc *
TclGetMainLoop(void)
{
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);

    return tsdPtr->mainLoopProc;
}




































#endif /* !TCL_ASCII_MAIN */

/*
 *----------------------------------------------------------------------
 *
 * StdinProc --
 *







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







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
Tcl_MainLoopProc *
TclGetMainLoop(void)
{
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);

    return tsdPtr->mainLoopProc;
}

/*
 *----------------------------------------------------------------------
 *
 * TclFullFinalizationRequested --
 *
 *	This function returns true when either -DPURIFY is specified, or the
 *	environment variable TCL_FINALIZE_ON_EXIT is set and not "0". This
 *	predicate is called at places affecting the exit sequence, so that the
 *	default behavior is a fast and deadlock-free exit, and the modified
 *	behavior is a more thorough finalization for debugging purposes (leak
 *	hunting etc).
 *
 * Results:
 *	A boolean.
 *
 *----------------------------------------------------------------------
 */
MODULE_SCOPE int
TclFullFinalizationRequested(void)
{
#ifdef PURIFY
    return 1;
#else
    const char *fin;
    Tcl_DString ds;
    int finalize = 0;
    
    fin = TclGetEnv("TCL_FINALIZE_ON_EXIT", &ds);
    finalize = ((fin != NULL) && strcmp(fin, "0"));
    if (fin != NULL) {
	Tcl_DStringFree(&ds);
    }
    return finalize;
#endif
}
#endif /* !TCL_ASCII_MAIN */

/*
 *----------------------------------------------------------------------
 *
 * StdinProc --
 *
875
876
877
878
879
880
881


























882
883
884
885
886
887
888
889

    chan = Tcl_GetStdChannel(TCL_STDOUT);
    if (chan != NULL) {
	Tcl_Flush(chan);
    }
    isPtr->prompt = PROMPT_NONE;
}



























/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78
 * End:
 */







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








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

    chan = Tcl_GetStdChannel(TCL_STDOUT);
    if (chan != NULL) {
	Tcl_Flush(chan);
    }
    isPtr->prompt = PROMPT_NONE;
}

/*
 *----------------------------------------------------------------------
 *
 * FreeMainInterp --
 *
 *	Exit handler used to cleanup the main interpreter and ancillary startup
 *	script storage at exit.
 *
 *----------------------------------------------------------------------
 */

static void
FreeMainInterp(
    ClientData clientData)
{
	Tcl_Interp *interp = (Tcl_Interp *) clientData;

	/*if (TclInExit()) return;*/

	if (!Tcl_InterpDeleted(interp)) {
	    Tcl_DeleteInterp(interp);
	}
    Tcl_SetStartupScript(NULL, NULL);
    Tcl_Release(interp);
}

/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78
 * End:
 */

Changes to generic/tclNamesp.c.

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

/*
 * Array of values describing how to implement each standard subcommand of the
 * "namespace" command.
 */

static const EnsembleImplMap defaultNamespaceMap[] = {
    {"children",        NamespaceChildrenCmd},
    {"code",            NamespaceCodeCmd},
    {"current",         NamespaceCurrentCmd},
    {"delete",          NamespaceDeleteCmd},
    {"ensemble",        TclNamespaceEnsembleCmd},
    {"eval",            NamespaceEvalCmd,       NULL, NRNamespaceEvalCmd},
    {"exists",          NamespaceExistsCmd},
    {"export",          NamespaceExportCmd},
    {"forget",          NamespaceForgetCmd},
    {"import",          NamespaceImportCmd},
    {"inscope",         NamespaceInscopeCmd,    NULL, NRNamespaceInscopeCmd},
    {"origin",          NamespaceOriginCmd},
    {"parent",          NamespaceParentCmd},
    {"path",            NamespacePathCmd},
    {"qualifiers",      NamespaceQualifiersCmd},
    {"tail",            NamespaceTailCmd},
    {"unknown",         NamespaceUnknownCmd},
    {"upvar",           NamespaceUpvarCmd,      TclCompileNamespaceUpvarCmd},
    {"which",           NamespaceWhichCmd},
    {NULL, NULL, NULL, NULL, NULL, 0}
};

/*
 *----------------------------------------------------------------------
 *
 * TclInitNamespaceSubsystem --







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







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

/*
 * Array of values describing how to implement each standard subcommand of the
 * "namespace" command.
 */

static const EnsembleImplMap defaultNamespaceMap[] = {
    {"children",        NamespaceChildrenCmd, NULL, NULL, NULL, 0},
    {"code",            NamespaceCodeCmd, NULL, NULL, NULL, 0},
    {"current",         NamespaceCurrentCmd, NULL, NULL, NULL, 0},
    {"delete",          NamespaceDeleteCmd, NULL, NULL, NULL, 0},
    {"ensemble",        TclNamespaceEnsembleCmd, NULL, NULL, NULL, 0},
    {"eval",            NamespaceEvalCmd,       NULL, NRNamespaceEvalCmd, NULL, 0},
    {"exists",          NamespaceExistsCmd, NULL, NULL, NULL, 0},
    {"export",          NamespaceExportCmd, NULL, NULL, NULL, 0},
    {"forget",          NamespaceForgetCmd, NULL, NULL, NULL, 0},
    {"import",          NamespaceImportCmd, NULL, NULL, NULL, 0},
    {"inscope",         NamespaceInscopeCmd,    NULL, NULL, NRNamespaceInscopeCmd, 0},
    {"origin",          NamespaceOriginCmd, NULL, NULL, NULL, 0},
    {"parent",          NamespaceParentCmd, NULL, NULL, NULL, 0},
    {"path",            NamespacePathCmd, NULL, NULL, NULL, 0},
    {"qualifiers",      NamespaceQualifiersCmd, NULL, NULL, NULL, 0},
    {"tail",            NamespaceTailCmd, NULL, NULL, NULL, 0},
    {"unknown",         NamespaceUnknownCmd, NULL, NULL, NULL, 0},
    {"upvar",           NamespaceUpvarCmd,      TclCompileNamespaceUpvarCmd, NULL, NULL, 0},
    {"which",           NamespaceWhichCmd, NULL, NULL, NULL, 0},
    {NULL, NULL, NULL, NULL, NULL, 0}
};

/*
 *----------------------------------------------------------------------
 *
 * TclInitNamespaceSubsystem --
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971

3972
3973
3974
3975
3976
3977
3978
    }

    /*
     * If no path is given, return the current path.
     */

    if (objc == 1) {
	/*
	 * Not a very fast way to compute this, but easy to get right.
	 */

	for (i=0 ; i<nsPtr->commandPathLength ; i++) {
	    if (nsPtr->commandPathArray[i].nsPtr != NULL) {
		Tcl_AppendElement(interp,
			nsPtr->commandPathArray[i].nsPtr->fullName);
	    }
	}

	return TCL_OK;
    }

    /*
     * There is a path given, so parse it into an array of namespace pointers.
     */








|
<
<



|
|


>







3955
3956
3957
3958
3959
3960
3961
3962


3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
    }

    /*
     * If no path is given, return the current path.
     */

    if (objc == 1) {
        Tcl_Obj *resultObj = Tcl_NewObj();



	for (i=0 ; i<nsPtr->commandPathLength ; i++) {
	    if (nsPtr->commandPathArray[i].nsPtr != NULL) {
                Tcl_ListObjAppendElement(NULL, resultObj, Tcl_NewStringObj(
                        nsPtr->commandPathArray[i].nsPtr->fullName, -1));
	    }
	}
        Tcl_SetObjResult(interp, resultObj);
	return TCL_OK;
    }

    /*
     * There is a path given, so parse it into an array of namespace pointers.
     */

4711
4712
4713
4714
4715
4716
4717
4718
4719





4720
4721
4722
4723
4724
4725
4726
4727
4728
4729
4730
4731
4732
4733
4734
4735
4736
4737
4738
4739
4740
4741
4742
4743
4744
				 * name. Also used for error reporting if not
				 * NULL. */
    register Tcl_Obj *objPtr)	/* The object to convert. */
{
    const char *dummy;
    Namespace *nsPtr, *dummy1Ptr, *dummy2Ptr;
    register ResolvedNsName *resNamePtr;
    const char *name = TclGetString(objPtr);






    TclGetNamespaceForQualName(interp, name, NULL, TCL_FIND_ONLY_NS,
	     &nsPtr, &dummy1Ptr, &dummy2Ptr, &dummy);

    /*
     * If we found a namespace, then create a new ResolvedNsName structure
     * that holds a reference to it.
     */

    if ((nsPtr == NULL) || (nsPtr->flags & NS_DYING)) {
	/*
	 * Our failed lookup proves any previously cached nsName intrep is no
	 * longer valid. Get rid of it so we no longer waste memory storing
	 * it, nor time determining its invalidity again and again.
	 */

	if (objPtr->typePtr == &nsNameType) {
	    TclFreeIntRep(objPtr);
	    objPtr->typePtr = NULL;
	}
	return TCL_ERROR;
    }

    nsPtr->refCount++;
    resNamePtr = ckalloc(sizeof(ResolvedNsName));
    resNamePtr->nsPtr = nsPtr;







|

>
>
>
>
>

















<







4710
4711
4712
4713
4714
4715
4716
4717
4718
4719
4720
4721
4722
4723
4724
4725
4726
4727
4728
4729
4730
4731
4732
4733
4734
4735
4736
4737
4738
4739
4740

4741
4742
4743
4744
4745
4746
4747
				 * name. Also used for error reporting if not
				 * NULL. */
    register Tcl_Obj *objPtr)	/* The object to convert. */
{
    const char *dummy;
    Namespace *nsPtr, *dummy1Ptr, *dummy2Ptr;
    register ResolvedNsName *resNamePtr;
    const char *name;

    if (interp == NULL) {
	return TCL_ERROR;
    }

    name = TclGetString(objPtr);
    TclGetNamespaceForQualName(interp, name, NULL, TCL_FIND_ONLY_NS,
	     &nsPtr, &dummy1Ptr, &dummy2Ptr, &dummy);

    /*
     * If we found a namespace, then create a new ResolvedNsName structure
     * that holds a reference to it.
     */

    if ((nsPtr == NULL) || (nsPtr->flags & NS_DYING)) {
	/*
	 * Our failed lookup proves any previously cached nsName intrep is no
	 * longer valid. Get rid of it so we no longer waste memory storing
	 * it, nor time determining its invalidity again and again.
	 */

	if (objPtr->typePtr == &nsNameType) {
	    TclFreeIntRep(objPtr);

	}
	return TCL_ERROR;
    }

    nsPtr->refCount++;
    resNamePtr = ckalloc(sizeof(ResolvedNsName));
    resNamePtr->nsPtr = nsPtr;
4836
4837
4838
4839
4840
4841
4842
4843
4844

4845
4846
4847
4848
4849
4850
4851
    Tcl_Interp *interp,		/* Interpreter in which to log information. */
    const char *script,		/* First character in script containing
				 * command (must be <= command). */
    const char *command,	/* First character in command that generated
				 * the error. */
    int length,			/* Number of bytes in command (-1 means use
				 * all bytes up to first null byte). */
    const unsigned char *pc,    /* current pc of bytecode execution context */
    Tcl_Obj **tosPtr)           /* current stack of bytecode execution context */

{
    register const char *p;
    Interp *iPtr = (Interp *) interp;
    int overflow, limit = 150;
    Var *varPtr, *arrayPtr;

    if (iPtr->flags & ERR_ALREADY_LOGGED) {







|
|
>







4839
4840
4841
4842
4843
4844
4845
4846
4847
4848
4849
4850
4851
4852
4853
4854
4855
    Tcl_Interp *interp,		/* Interpreter in which to log information. */
    const char *script,		/* First character in script containing
				 * command (must be <= command). */
    const char *command,	/* First character in command that generated
				 * the error. */
    int length,			/* Number of bytes in command (-1 means use
				 * all bytes up to first null byte). */
    const unsigned char *pc,    /* Current pc of bytecode execution context */
    Tcl_Obj **tosPtr)           /* Current stack of bytecode execution
                                 * context */
{
    register const char *p;
    Interp *iPtr = (Interp *) interp;
    int overflow, limit = 150;
    Var *varPtr, *arrayPtr;

    if (iPtr->flags & ERR_ALREADY_LOGGED) {
4922
4923
4924
4925
4926
4927
4928


4929


4930
4931
4932
4933
4934
4935
4936

4937
4938
4939
4940

4941

4942
4943
4944
4945

4946

4947

4948

4949
4950
4951
4952
4953

4954


4955
4956
4957
4958
4959
4960
4961
        iPtr->errorStack = newObj;
    }
    if (iPtr->resetErrorStack) {
	int len;

        iPtr->resetErrorStack = 0;
	Tcl_ListObjLength(interp, iPtr->errorStack, &len);


        /* reset while keeping the list intrep as much as possible */


        Tcl_ListObjReplace(interp, iPtr->errorStack, 0, len, 0, NULL);
        if (pc != NULL) {
            Tcl_Obj *innerContext;

            innerContext = TclGetInnerContext(interp, pc, tosPtr);
            if (innerContext != NULL) {
                Tcl_ListObjAppendElement(NULL, iPtr->errorStack, iPtr->innerLiteral);

                Tcl_ListObjAppendElement(NULL, iPtr->errorStack, innerContext);
            }
        } else if (command != NULL) {
            Tcl_ListObjAppendElement(NULL, iPtr->errorStack, iPtr->innerLiteral);

            Tcl_ListObjAppendElement(NULL, iPtr->errorStack, Tcl_NewStringObj(command, length));

        }
    } 

    if (!iPtr->framePtr->objc) {

        /* special frame, nothing to report */

    } else if (iPtr->varFramePtr != iPtr->framePtr) {

        /* uplevel case, [lappend errorstack UP $relativelevel] */


        Tcl_ListObjAppendElement(NULL, iPtr->errorStack, iPtr->upLiteral);
        Tcl_ListObjAppendElement(NULL, iPtr->errorStack, Tcl_NewIntObj(
		iPtr->framePtr->level - iPtr->varFramePtr->level));
    } else if (iPtr->framePtr != iPtr->rootFramePtr) {

        /* normal case, [lappend errorstack CALL [info level 0]] */


        Tcl_ListObjAppendElement(NULL, iPtr->errorStack, iPtr->callLiteral);
        Tcl_ListObjAppendElement(NULL, iPtr->errorStack, Tcl_NewListObj(
		iPtr->framePtr->objc, iPtr->framePtr->objv));
    }
}

/*







>
>
|
>
>






|
>



|
>
|
>




>
|
>

>
|
>





>
|
>
>







4926
4927
4928
4929
4930
4931
4932
4933
4934
4935
4936
4937
4938
4939
4940
4941
4942
4943
4944
4945
4946
4947
4948
4949
4950
4951
4952
4953
4954
4955
4956
4957
4958
4959
4960
4961
4962
4963
4964
4965
4966
4967
4968
4969
4970
4971
4972
4973
4974
4975
4976
4977
4978
4979
        iPtr->errorStack = newObj;
    }
    if (iPtr->resetErrorStack) {
	int len;

        iPtr->resetErrorStack = 0;
	Tcl_ListObjLength(interp, iPtr->errorStack, &len);

        /*
         * Reset while keeping the list intrep as much as possible.
         */

        Tcl_ListObjReplace(interp, iPtr->errorStack, 0, len, 0, NULL);
        if (pc != NULL) {
            Tcl_Obj *innerContext;

            innerContext = TclGetInnerContext(interp, pc, tosPtr);
            if (innerContext != NULL) {
                Tcl_ListObjAppendElement(NULL, iPtr->errorStack,
                        iPtr->innerLiteral);
                Tcl_ListObjAppendElement(NULL, iPtr->errorStack, innerContext);
            }
        } else if (command != NULL) {
            Tcl_ListObjAppendElement(NULL, iPtr->errorStack,
                    iPtr->innerLiteral);
            Tcl_ListObjAppendElement(NULL, iPtr->errorStack,
                    Tcl_NewStringObj(command, length));
        }
    } 

    if (!iPtr->framePtr->objc) {
        /*
         * Special frame, nothing to report.
         */
    } else if (iPtr->varFramePtr != iPtr->framePtr) {
        /*
         * uplevel case, [lappend errorstack UP $relativelevel]
         */

        Tcl_ListObjAppendElement(NULL, iPtr->errorStack, iPtr->upLiteral);
        Tcl_ListObjAppendElement(NULL, iPtr->errorStack, Tcl_NewIntObj(
		iPtr->framePtr->level - iPtr->varFramePtr->level));
    } else if (iPtr->framePtr != iPtr->rootFramePtr) {
        /*
         * normal case, [lappend errorstack CALL [info level 0]]
         */

        Tcl_ListObjAppendElement(NULL, iPtr->errorStack, iPtr->callLiteral);
        Tcl_ListObjAppendElement(NULL, iPtr->errorStack, Tcl_NewListObj(
		iPtr->framePtr->objc, iPtr->framePtr->objv));
    }
}

/*
4971
4972
4973
4974
4975
4976
4977


4978



4979
4980
4981
4982
4983
4984
4985
4986
4987
4988
4989
4990
4991
4992
4993
4994


4995


4996
4997
4998

4999
5000
5001
5002
5003
5004
5005
 *
 * Side effects:
 *	Reset errorstack if it needs be, and in that case remember the
 *	passed-in error message as inner context.
 *
 *----------------------------------------------------------------------
 */


void TclErrorStackResetIf(Tcl_Interp *interp, const char *msg, int length)



{
    Interp *iPtr = (Interp *) interp;

    if (Tcl_IsShared(iPtr->errorStack)) {
        Tcl_Obj *newObj;
            
        newObj = Tcl_DuplicateObj(iPtr->errorStack);
        Tcl_DecrRefCount(iPtr->errorStack);
        Tcl_IncrRefCount(newObj);
        iPtr->errorStack = newObj;
    }
    if (iPtr->resetErrorStack) {
	int len;

        iPtr->resetErrorStack = 0;
	Tcl_ListObjLength(interp, iPtr->errorStack, &len);


        /* reset while keeping the list intrep as much as possible */


        Tcl_ListObjReplace(interp, iPtr->errorStack, 0, len, 0, NULL);
        Tcl_ListObjAppendElement(NULL, iPtr->errorStack, iPtr->innerLiteral);
        Tcl_ListObjAppendElement(NULL, iPtr->errorStack, Tcl_NewStringObj(msg, length));

    } 
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_LogCommandInfo --







>
>
|
>
>
>
















>
>
|
>
>


|
>







4989
4990
4991
4992
4993
4994
4995
4996
4997
4998
4999
5000
5001
5002
5003
5004
5005
5006
5007
5008
5009
5010
5011
5012
5013
5014
5015
5016
5017
5018
5019
5020
5021
5022
5023
5024
5025
5026
5027
5028
5029
5030
5031
5032
5033
 *
 * Side effects:
 *	Reset errorstack if it needs be, and in that case remember the
 *	passed-in error message as inner context.
 *
 *----------------------------------------------------------------------
 */

void
TclErrorStackResetIf(
    Tcl_Interp *interp,
    const char *msg,
    int length)
{
    Interp *iPtr = (Interp *) interp;

    if (Tcl_IsShared(iPtr->errorStack)) {
        Tcl_Obj *newObj;
            
        newObj = Tcl_DuplicateObj(iPtr->errorStack);
        Tcl_DecrRefCount(iPtr->errorStack);
        Tcl_IncrRefCount(newObj);
        iPtr->errorStack = newObj;
    }
    if (iPtr->resetErrorStack) {
	int len;

        iPtr->resetErrorStack = 0;
	Tcl_ListObjLength(interp, iPtr->errorStack, &len);

        /*
         * Reset while keeping the list intrep as much as possible.
         */

        Tcl_ListObjReplace(interp, iPtr->errorStack, 0, len, 0, NULL);
        Tcl_ListObjAppendElement(NULL, iPtr->errorStack, iPtr->innerLiteral);
        Tcl_ListObjAppendElement(NULL, iPtr->errorStack,
                Tcl_NewStringObj(msg, length));
    } 
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_LogCommandInfo --

Changes to generic/tclOO.c.

126
127
128
129
130
131
132

133
134
135
136
137
138
139
    DCM("create", 1,	TclOO_Class_Create),
    DCM("new", 1,	TclOO_Class_New),
    DCM("createWithNamespace", 0, TclOO_Class_CreateNs),
    {NULL, 0, {0, NULL, NULL, NULL, NULL}}
};

static char initScript[] =

    "namespace eval ::oo { variable version " TCLOO_VERSION " };"
    "namespace eval ::oo { variable patchlevel " TCLOO_PATCHLEVEL " };";
/*     "tcl_findLibrary tcloo $oo::version $oo::version" */
/*     " tcloo.tcl OO_LIBRARY oo::library;"; */

MODULE_SCOPE const TclOOStubs tclOOStubs;








>







126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
    DCM("create", 1,	TclOO_Class_Create),
    DCM("new", 1,	TclOO_Class_New),
    DCM("createWithNamespace", 0, TclOO_Class_CreateNs),
    {NULL, 0, {0, NULL, NULL, NULL, NULL}}
};

static char initScript[] =
    "package ifneeded TclOO " TCLOO_PATCHLEVEL " {# Already present, OK?};"
    "namespace eval ::oo { variable version " TCLOO_VERSION " };"
    "namespace eval ::oo { variable patchlevel " TCLOO_PATCHLEVEL " };";
/*     "tcl_findLibrary tcloo $oo::version $oo::version" */
/*     " tcloo.tcl OO_LIBRARY oo::library;"; */

MODULE_SCOPE const TclOOStubs tclOOStubs;

342
343
344
345
346
347
348


349
350
351
352
353
354
355
    /*
     * Create non-object commands and plug ourselves into the Tcl [info]
     * ensemble.
     */

    Tcl_CreateObjCommand(interp, "::oo::Helpers::next", TclOONextObjCmd, NULL,
	    NULL);


    Tcl_CreateObjCommand(interp, "::oo::Helpers::self", TclOOSelfObjCmd, NULL,
	    NULL);
    Tcl_CreateObjCommand(interp, "::oo::define", TclOODefineObjCmd, NULL,
	    NULL);
    Tcl_CreateObjCommand(interp, "::oo::objdefine", TclOOObjDefObjCmd, NULL,
	    NULL);
    Tcl_CreateObjCommand(interp, "::oo::copy", TclOOCopyObjectCmd, NULL,NULL);







>
>







343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
    /*
     * Create non-object commands and plug ourselves into the Tcl [info]
     * ensemble.
     */

    Tcl_CreateObjCommand(interp, "::oo::Helpers::next", TclOONextObjCmd, NULL,
	    NULL);
    Tcl_CreateObjCommand(interp, "::oo::Helpers::nextto", TclOONextToObjCmd,
	    NULL, NULL);
    Tcl_CreateObjCommand(interp, "::oo::Helpers::self", TclOOSelfObjCmd, NULL,
	    NULL);
    Tcl_CreateObjCommand(interp, "::oo::define", TclOODefineObjCmd, NULL,
	    NULL);
    Tcl_CreateObjCommand(interp, "::oo::objdefine", TclOOObjDefObjCmd, NULL,
	    NULL);
    Tcl_CreateObjCommand(interp, "::oo::copy", TclOOCopyObjectCmd, NULL,NULL);
1397
1398
1399
1400
1401
1402
1403

1404
1405
1406
1407
1408
1409
1410
     * that's not allowed.
     */

    if (nameStr && Tcl_FindCommand(interp, nameStr, NULL,
	    TCL_NAMESPACE_ONLY)) {
	Tcl_AppendResult(interp, "can't create object \"", nameStr,
		"\": command already exists with that name", NULL);

	return NULL;
    }

    /*
     * Create the object.
     */








>







1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
     * that's not allowed.
     */

    if (nameStr && Tcl_FindCommand(interp, nameStr, NULL,
	    TCL_NAMESPACE_ONLY)) {
	Tcl_AppendResult(interp, "can't create object \"", nameStr,
		"\": command already exists with that name", NULL);
	Tcl_SetErrorCode(interp, "TCL", "OO", "OVERWRITE_OBJECT", NULL);
	return NULL;
    }

    /*
     * Create the object.
     */

1455
1456
1457
1458
1459
1460
1461

1462
1463
1464
1465
1466
1467
1468
	     * Force this if it isn't already an error (don't want to lose
	     * errors by accident...) [Bug 2903011]
	     */

	    if (result != TCL_ERROR && (flags & OBJECT_DELETED)) {
		Tcl_SetResult(interp, "object deleted in constructor",
			TCL_STATIC);

		result = TCL_ERROR;
	    }
	    TclOODeleteContext(contextPtr);
	    if (result != TCL_OK) {
		Tcl_DiscardInterpState(state);

		/*







>







1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
	     * Force this if it isn't already an error (don't want to lose
	     * errors by accident...) [Bug 2903011]
	     */

	    if (result != TCL_ERROR && (flags & OBJECT_DELETED)) {
		Tcl_SetResult(interp, "object deleted in constructor",
			TCL_STATIC);
		Tcl_SetErrorCode(interp, "TCL", "OO", "STILLBORN", NULL);
		result = TCL_ERROR;
	    }
	    TclOODeleteContext(contextPtr);
	    if (result != TCL_OK) {
		Tcl_DiscardInterpState(state);

		/*
1510
1511
1512
1513
1514
1515
1516

1517
1518
1519
1520
1521
1522
1523
     * that's not allowed.
     */

    if (nameStr && Tcl_FindCommand(interp, nameStr, NULL,
	    TCL_NAMESPACE_ONLY)) {
	Tcl_AppendResult(interp, "can't create object \"", nameStr,
		"\": command already exists with that name", NULL);

	return TCL_ERROR;
    }

    /*
     * Create the object.
     */








>







1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
     * that's not allowed.
     */

    if (nameStr && Tcl_FindCommand(interp, nameStr, NULL,
	    TCL_NAMESPACE_ONLY)) {
	Tcl_AppendResult(interp, "can't create object \"", nameStr,
		"\": command already exists with that name", NULL);
	Tcl_SetErrorCode(interp, "TCL", "OO", "OVERWRITE_OBJECT", NULL);
	return TCL_ERROR;
    }

    /*
     * Create the object.
     */

1588
1589
1590
1591
1592
1593
1594

1595
1596
1597
1598
1599
1600
1601
     * It's an error if the object was whacked in the constructor. Force this
     * if it isn't already an error (don't want to lose errors by accident...)
     * [Bug 2903011]
     */

    if (result != TCL_ERROR && (flags & OBJECT_DELETED)) {
	Tcl_SetResult(interp, "object deleted in constructor", TCL_STATIC);

	result = TCL_ERROR;
    }
    TclOODeleteContext(contextPtr);
    if (result != TCL_OK) {
	Tcl_DiscardInterpState(state);

	/*







>







1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
     * It's an error if the object was whacked in the constructor. Force this
     * if it isn't already an error (don't want to lose errors by accident...)
     * [Bug 2903011]
     */

    if (result != TCL_ERROR && (flags & OBJECT_DELETED)) {
	Tcl_SetResult(interp, "object deleted in constructor", TCL_STATIC);
	Tcl_SetErrorCode(interp, "TCL", "OO", "STILLBORN", NULL);
	result = TCL_ERROR;
    }
    TclOODeleteContext(contextPtr);
    if (result != TCL_OK) {
	Tcl_DiscardInterpState(state);

	/*
1642
1643
1644
1645
1646
1647
1648

1649
1650
1651
1652

1653
1654
1655
1656
1657
1658
1659
    /*
     * Sanity checks.
     */

    if (targetName == NULL && oPtr->classPtr != NULL) {
	Tcl_AppendResult(interp, "must supply a name when copying a class",
		NULL);

	return NULL;
    }
    if (oPtr->flags & ROOT_CLASS) {
	Tcl_AppendResult(interp, "may not clone the class of classes", NULL);

	return NULL;
    }

    /*
     * Build the instance. Note that this does not run any constructors.
     */








>




>







1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
    /*
     * Sanity checks.
     */

    if (targetName == NULL && oPtr->classPtr != NULL) {
	Tcl_AppendResult(interp, "must supply a name when copying a class",
		NULL);
	Tcl_SetErrorCode(interp, "TCL", "OO", "NO_COPY_TARGET", NULL);
	return NULL;
    }
    if (oPtr->flags & ROOT_CLASS) {
	Tcl_AppendResult(interp, "may not clone the class of classes", NULL);
	Tcl_SetErrorCode(interp, "TCL", "OO", "CLONING_CLASS", NULL);
	return NULL;
    }

    /*
     * Build the instance. Note that this does not run any constructors.
     */

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
	contextPtr = TclOOGetCallContext(oPtr, mappedMethodName,
		flags | (oPtr->flags & FILTER_HANDLING), methodNamePtr);
	Tcl_DecrRefCount(mappedMethodName);
	if (contextPtr == NULL) {
	    Tcl_AppendResult(interp, "impossible to invoke method \"",
		    TclGetString(methodNamePtr),
		    "\": no defined method or unknown method", NULL);


	    return TCL_ERROR;
	}
    } else {
	/*
	 * Get the call chain.
	 */

    noMapping:
	contextPtr = TclOOGetCallContext(oPtr, methodNamePtr,
		flags | (oPtr->flags & FILTER_HANDLING), NULL);
	if (contextPtr == NULL) {
	    Tcl_AppendResult(interp, "impossible to invoke method \"",
		    TclGetString(methodNamePtr),
		    "\": no defined method or unknown method", NULL);


	    return TCL_ERROR;
	}
    }

    /*
     * Check to see if we need to apply magical tricks to start part way
     * through the call chain.







>
>














>
>







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
	contextPtr = TclOOGetCallContext(oPtr, mappedMethodName,
		flags | (oPtr->flags & FILTER_HANDLING), methodNamePtr);
	Tcl_DecrRefCount(mappedMethodName);
	if (contextPtr == NULL) {
	    Tcl_AppendResult(interp, "impossible to invoke method \"",
		    TclGetString(methodNamePtr),
		    "\": no defined method or unknown method", NULL);
	    Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "METHOD_MAPPED",
		    TclGetString(methodNamePtr), NULL);
	    return TCL_ERROR;
	}
    } else {
	/*
	 * Get the call chain.
	 */

    noMapping:
	contextPtr = TclOOGetCallContext(oPtr, methodNamePtr,
		flags | (oPtr->flags & FILTER_HANDLING), NULL);
	if (contextPtr == NULL) {
	    Tcl_AppendResult(interp, "impossible to invoke method \"",
		    TclGetString(methodNamePtr),
		    "\": no defined method or unknown method", NULL);
	    Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "METHOD",
		    TclGetString(methodNamePtr), NULL);
	    return TCL_ERROR;
	}
    }

    /*
     * Check to see if we need to apply magical tricks to start part way
     * through the call chain.
2300
2301
2302
2303
2304
2305
2306


2307
2308
2309
2310
2311
2312
2313
	    if (miPtr->mPtr->declaringClassPtr == startCls) {
		break;
	    }
	}
	if (contextPtr->index >= contextPtr->callPtr->numChain) {
	    Tcl_SetResult(interp, "no valid method implementation",
		    TCL_STATIC);


	    TclOODeleteContext(contextPtr);
	    return TCL_ERROR;
	}
    }

    /*
     * Invoke the call chain, locking the object structure against deletion







>
>







2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
	    if (miPtr->mPtr->declaringClassPtr == startCls) {
		break;
	    }
	}
	if (contextPtr->index >= contextPtr->callPtr->numChain) {
	    Tcl_SetResult(interp, "no valid method implementation",
		    TCL_STATIC);
	    Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "METHOD",
		    TclGetString(methodNamePtr), NULL);
	    TclOODeleteContext(contextPtr);
	    return TCL_ERROR;
	}
    }

    /*
     * Invoke the call chain, locking the object structure against deletion
2380
2381
2382
2383
2384
2385
2386

2387
2388
2389
2390
2391
2392
2393
	    methodType = "destructor";
	} else {
	    methodType = "method";
	}

	Tcl_AppendResult(interp, "no next ", methodType, " implementation",
		NULL);

	return TCL_ERROR;
    }

    /*
     * Advance to the next method implementation in the chain in the method
     * call context while we process the body. However, need to adjust the
     * argument-skip control because we're guaranteed to have a single prefix







>







2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
	    methodType = "destructor";
	} else {
	    methodType = "method";
	}

	Tcl_AppendResult(interp, "no next ", methodType, " implementation",
		NULL);
	Tcl_SetErrorCode(interp, "TCL", "OO", "NOTHING_NEXT", NULL);
	return TCL_ERROR;
    }

    /*
     * Advance to the next method implementation in the chain in the method
     * call context while we process the body. However, need to adjust the
     * argument-skip control because we're guaranteed to have a single prefix
2448
2449
2450
2451
2452
2453
2454

2455
2456
2457
2458
2459
2460
2461
	    methodType = "destructor";
	} else {
	    methodType = "method";
	}

	Tcl_AppendResult(interp, "no next ", methodType, " implementation",
		NULL);

	return TCL_ERROR;
    }

    /*
     * Advance to the next method implementation in the chain in the method
     * call context while we process the body. However, need to adjust the
     * argument-skip control because we're guaranteed to have a single prefix







>







2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
	    methodType = "destructor";
	} else {
	    methodType = "method";
	}

	Tcl_AppendResult(interp, "no next ", methodType, " implementation",
		NULL);
	Tcl_SetErrorCode(interp, "TCL", "OO", "NOTHING_NEXT", NULL);
	return TCL_ERROR;
    }

    /*
     * Advance to the next method implementation in the chain in the method
     * call context while we process the body. However, need to adjust the
     * argument-skip control because we're guaranteed to have a single prefix
2525
2526
2527
2528
2529
2530
2531


2532
2533
2534
2535
2536
2537
2538
	}
    }
    return cmdPtr->objClientData;

  notAnObject:
    Tcl_AppendResult(interp, TclGetString(objPtr),
	    " does not refer to an object", NULL);


    return NULL;
}

/*
 * ----------------------------------------------------------------------
 *
 * TclOOIsReachable --







>
>







2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
	}
    }
    return cmdPtr->objClientData;

  notAnObject:
    Tcl_AppendResult(interp, TclGetString(objPtr),
	    " does not refer to an object", NULL);
    Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "OBJECT", TclGetString(objPtr),
	    NULL);
    return NULL;
}

/*
 * ----------------------------------------------------------------------
 *
 * TclOOIsReachable --

Changes to generic/tclOO.decls.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
library tclOO

######################################################################
# public API
#

interface tclOO
hooks tclOOInt
scspec EXTERN

declare 0 {
    Tcl_Object Tcl_CopyObjectInstance(Tcl_Interp *interp,
	    Tcl_Object sourceObject, const char *targetName,
	    const char *targetNamespaceName)
}
declare 1 {








|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
library tclOO

######################################################################
# public API
#

interface tclOO
hooks tclOOInt
scspec TCLOOAPI

declare 0 {
    Tcl_Object Tcl_CopyObjectInstance(Tcl_Interp *interp,
	    Tcl_Object sourceObject, const char *targetName,
	    const char *targetNamespaceName)
}
declare 1 {

Changes to generic/tclOO.h.

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
 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
 */

#ifndef TCLOO_H_INCLUDED
#define TCLOO_H_INCLUDED
#include "tcl.h"















/*
 * Be careful when it comes to versioning; need to make sure that the
 * standalone TclOO version matches. Also make sure that this matches the
 * version in the files:
 *
 * tests/oo.test
 * unix/tclooConfig.sh
 * win/tclooConfig.sh
 */

#define TCLOO_VERSION "0.6.2"
#define TCLOO_PATCHLEVEL TCLOO_VERSION

/*
 * These are opaque types.
 */

typedef struct Tcl_Class_ *Tcl_Class;







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










|







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
 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
 */

#ifndef TCLOO_H_INCLUDED
#define TCLOO_H_INCLUDED
#include "tcl.h"

#ifndef TCLOOAPI
#   if defined(BUILD_tcl) || defined(BUILD_TclOO)
#	define TCLOOAPI MODULE_SCOPE
#   else
#	define TCLOOAPI extern
#	undef USE_TCLOO_STUBS
#	define USE_TCLOO_STUBS 1
#   endif
#endif

extern const char *TclOOInitializeStubs(
	Tcl_Interp *, const char *version);
#define Tcl_OOInitStubs(interp) TclOOInitializeStubs((interp), TCLOO_VERSION)

/*
 * Be careful when it comes to versioning; need to make sure that the
 * standalone TclOO version matches. Also make sure that this matches the
 * version in the files:
 *
 * tests/oo.test
 * unix/tclooConfig.sh
 * win/tclooConfig.sh
 */

#define TCLOO_VERSION "0.6.3"
#define TCLOO_PATCHLEVEL TCLOO_VERSION

/*
 * These are opaque types.
 */

typedef struct Tcl_Class_ *Tcl_Class;

Changes to generic/tclOOBasic.c.

96
97
98
99
100
101
102

103
104
105
106
107
108
109
     */

    if (oPtr->classPtr == NULL) {
	Tcl_Obj *cmdnameObj = TclOOObjectName(interp, oPtr);

	Tcl_AppendResult(interp, "object \"", TclGetString(cmdnameObj),
		"\" is not a class", NULL);

	return TCL_ERROR;
    }

    /*
     * Check we have the right number of (sensible) arguments.
     */








>







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

    if (oPtr->classPtr == NULL) {
	Tcl_Obj *cmdnameObj = TclOOObjectName(interp, oPtr);

	Tcl_AppendResult(interp, "object \"", TclGetString(cmdnameObj),
		"\" is not a class", NULL);
	Tcl_SetErrorCode(interp, "TCL", "OO", "INSTANTIATE_NONCLASS", NULL);
	return TCL_ERROR;
    }

    /*
     * Check we have the right number of (sensible) arguments.
     */

159
160
161
162
163
164
165

166
167
168
169
170
171
172
     */

    if (oPtr->classPtr == NULL) {
	Tcl_Obj *cmdnameObj = TclOOObjectName(interp, oPtr);

	Tcl_AppendResult(interp, "object \"", TclGetString(cmdnameObj),
		"\" is not a class", NULL);

	return TCL_ERROR;
    }

    /*
     * Check we have the right number of (sensible) arguments.
     */








>







160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
     */

    if (oPtr->classPtr == NULL) {
	Tcl_Obj *cmdnameObj = TclOOObjectName(interp, oPtr);

	Tcl_AppendResult(interp, "object \"", TclGetString(cmdnameObj),
		"\" is not a class", NULL);
	Tcl_SetErrorCode(interp, "TCL", "OO", "INSTANTIATE_NONCLASS", NULL);
	return TCL_ERROR;
    }

    /*
     * Check we have the right number of (sensible) arguments.
     */

227
228
229
230
231
232
233

234
235
236
237
238
239
240
     */

    if (oPtr->classPtr == NULL) {
	Tcl_Obj *cmdnameObj = TclOOObjectName(interp, oPtr);

	Tcl_AppendResult(interp, "object \"", TclGetString(cmdnameObj),
		"\" is not a class", NULL);

	return TCL_ERROR;
    }

    /*
     * Make the object and return its name.
     */








>







229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
     */

    if (oPtr->classPtr == NULL) {
	Tcl_Obj *cmdnameObj = TclOOObjectName(interp, oPtr);

	Tcl_AppendResult(interp, "object \"", TclGetString(cmdnameObj),
		"\" is not a class", NULL);
	Tcl_SetErrorCode(interp, "TCL", "OO", "INSTANTIATE_NONCLASS", NULL);
	return TCL_ERROR;
    }

    /*
     * Make the object and return its name.
     */

673
674
675
676
677
678
679
680
681
682
683

684
685
686
687
688
689
690
    Tcl_SetObjResult(interp, varNamePtr);
    return TCL_OK;
}

/*
 * ----------------------------------------------------------------------
 *
 * TclOONextObjCmd --
 *
 *	Implementation of the [next] command. Note that this command is only
 *	ever to be used inside the body of a procedure-like method.

 *
 * ----------------------------------------------------------------------
 */

int
TclOONextObjCmd(
    ClientData clientData,







|

|
|
>







676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
    Tcl_SetObjResult(interp, varNamePtr);
    return TCL_OK;
}

/*
 * ----------------------------------------------------------------------
 *
 * TclOONextObjCmd, TclOONextToObjCmd --
 *
 *	Implementation of the [next] and [nextto] commands. Note that these
 *	commands are only ever to be used inside the body of a procedure-like
 *	method.
 *
 * ----------------------------------------------------------------------
 */

int
TclOONextObjCmd(
    ClientData clientData,
715
716
717
718
719
720
721
722



























































































723
724
725
726
727
728
729

730
731



732
733
734
735
736
737
738
     * that this is like [uplevel 1] and not [eval].
     */

    TclNRAddCallback(interp, RestoreFrame, framePtr, NULL, NULL, NULL);
    iPtr->varFramePtr = framePtr->callerVarPtr;
    return TclNRObjectContextInvokeNext(interp, context, objc, objv, 1);
}




























































































static int
RestoreFrame(
    ClientData data[],
    Tcl_Interp *interp,
    int result)
{
    Interp *iPtr = (Interp *) interp;


    iPtr->varFramePtr = data[0];



    return result;
}

/*
 * ----------------------------------------------------------------------
 *
 * TclOOSelfObjCmd --








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







>


>
>
>







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
     * that this is like [uplevel 1] and not [eval].
     */

    TclNRAddCallback(interp, RestoreFrame, framePtr, NULL, NULL, NULL);
    iPtr->varFramePtr = framePtr->callerVarPtr;
    return TclNRObjectContextInvokeNext(interp, context, objc, objv, 1);
}

int
TclOONextToObjCmd(
    ClientData clientData,
    Tcl_Interp *interp,
    int objc,
    Tcl_Obj *const *objv)
{
    Interp *iPtr = (Interp *) interp;
    CallFrame *framePtr = iPtr->varFramePtr;
    Class *classPtr;
    CallContext *contextPtr;
    int i;
    Tcl_Object object;

    /*
     * Start with sanity checks on the calling context to make sure that we
     * are invoked from a suitable method context. If so, we can safely
     * retrieve the handle to the object call context.
     */

    if (framePtr == NULL || !(framePtr->isProcCallFrame & FRAME_IS_METHOD)) {
	Tcl_AppendResult(interp, TclGetString(objv[0]),
		" may only be called from inside a method", NULL);
	Tcl_SetErrorCode(interp, "TCL", "OO", "CONTEXT_REQUIRED", NULL);
	return TCL_ERROR;
    }
    contextPtr = framePtr->clientData;

    /*
     * Sanity check the arguments; we need the first one to refer to a class.
     */

    if (objc < 2) {
	Tcl_WrongNumArgs(interp, 1, objv, "class ?arg...?");
	return TCL_ERROR;
    }
    object = Tcl_GetObjectFromObj(interp, objv[1]);
    if (object == NULL) {
	return TCL_ERROR;
    }
    classPtr = ((Object *)object)->classPtr;
    if (classPtr == NULL) {
	Tcl_AppendResult(interp, "\"", TclGetString(objv[1]),
		"\" is not a class", NULL);
	return TCL_ERROR;
    }

    /*
     * Search for an implementation of a method associated with the current
     * call on the call chain past the point where we currently are. Do not
     * allow jumping backwards!
     */

    for (i=contextPtr->index+1 ; i<contextPtr->callPtr->numChain ; i++) {
	struct MInvoke *miPtr = contextPtr->callPtr->chain + i;

	if (!miPtr->isFilter && miPtr->mPtr->declaringClassPtr == classPtr) {
	    /*
	     * Invoke the (advanced) method call context in the caller
	     * context. Note that this is like [uplevel 1] and not [eval].
	     */

	    TclNRAddCallback(interp, RestoreFrame, framePtr, contextPtr,
		    INT2PTR(contextPtr->index), NULL);
	    contextPtr->index = i-1;
	    iPtr->varFramePtr = framePtr->callerVarPtr;
	    return TclNRObjectContextInvokeNext(interp,
		    (Tcl_ObjectContext) contextPtr, objc, objv, 2);
	}
    }

    /*
     * Generate an appropriate error message, depending on whether the value
     * is on the chain but unreachable, or not on the chain at all.
     */

    for (i=contextPtr->index ; i>=0 ; i--) {
	struct MInvoke *miPtr = contextPtr->callPtr->chain + i;

	if (!miPtr->isFilter && miPtr->mPtr->declaringClassPtr == classPtr) {
	    Tcl_AppendResult(interp, "method implementation by \"",
		    TclGetString(objv[1]), "\" not reachable from here",
		    NULL);
	    return TCL_ERROR;
	}
    }
    Tcl_AppendResult(interp, "method has no non-filter implementation by \"",
	    TclGetString(objv[1]), "\"", NULL);
    return TCL_ERROR;
}

static int
RestoreFrame(
    ClientData data[],
    Tcl_Interp *interp,
    int result)
{
    Interp *iPtr = (Interp *) interp;
    CallContext *contextPtr = data[1];

    iPtr->varFramePtr = data[0];
    if (contextPtr != NULL) {
	contextPtr->index = PTR2INT(data[2]);
    }
    return result;
}

/*
 * ----------------------------------------------------------------------
 *
 * TclOOSelfObjCmd --
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763

764
765
766
767
768
769
770
TclOOSelfObjCmd(
    ClientData clientData,
    Tcl_Interp *interp,
    int objc,
    Tcl_Obj *const *objv)
{
    static const char *const subcmds[] = {
	"caller", "class", "filter", "method", "namespace", "next", "object",
	"target", NULL
    };
    enum SelfCmds {
	SELF_CALLER, SELF_CLASS, SELF_FILTER, SELF_METHOD, SELF_NS, SELF_NEXT,
	SELF_OBJECT, SELF_TARGET
    };
    Interp *iPtr = (Interp *) interp;
    CallFrame *framePtr = iPtr->varFramePtr;
    CallContext *contextPtr;

    int index;

#define CurrentlyInvoked(contextPtr) \
    ((contextPtr)->callPtr->chain[(contextPtr)->index])

    /*
     * Start with sanity checks on the calling context and the method context.







|
|


|
|




>







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
TclOOSelfObjCmd(
    ClientData clientData,
    Tcl_Interp *interp,
    int objc,
    Tcl_Obj *const *objv)
{
    static const char *const subcmds[] = {
	"call", "caller", "class", "filter", "method", "namespace", "next",
	"object", "target", NULL
    };
    enum SelfCmds {
	SELF_CALL, SELF_CALLER, SELF_CLASS, SELF_FILTER, SELF_METHOD, SELF_NS,
	SELF_NEXT, SELF_OBJECT, SELF_TARGET
    };
    Interp *iPtr = (Interp *) interp;
    CallFrame *framePtr = iPtr->varFramePtr;
    CallContext *contextPtr;
    Tcl_Obj *result[3];
    int index;

#define CurrentlyInvoked(contextPtr) \
    ((contextPtr)->callPtr->chain[(contextPtr)->index])

    /*
     * Start with sanity checks on the calling context and the method context.
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
    case SELF_FILTER:
	if (!CurrentlyInvoked(contextPtr).isFilter) {
	    Tcl_AppendResult(interp, "not inside a filtering context", NULL);
	    Tcl_SetErrorCode(interp, "TCL", "OO", "UNMATCHED_CONTEXT", NULL);
	    return TCL_ERROR;
	} else {
	    register struct MInvoke *miPtr = &CurrentlyInvoked(contextPtr);
	    Tcl_Obj *result[3];
	    Object *oPtr;
	    const char *type;

	    if (miPtr->filterDeclarer != NULL) {
		oPtr = miPtr->filterDeclarer->thisPtr;
		type = "class";
	    } else {







<







927
928
929
930
931
932
933

934
935
936
937
938
939
940
    case SELF_FILTER:
	if (!CurrentlyInvoked(contextPtr).isFilter) {
	    Tcl_AppendResult(interp, "not inside a filtering context", NULL);
	    Tcl_SetErrorCode(interp, "TCL", "OO", "UNMATCHED_CONTEXT", NULL);
	    return TCL_ERROR;
	} else {
	    register struct MInvoke *miPtr = &CurrentlyInvoked(contextPtr);

	    Object *oPtr;
	    const char *type;

	    if (miPtr->filterDeclarer != NULL) {
		oPtr = miPtr->filterDeclarer->thisPtr;
		type = "class";
	    } else {
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
	    Tcl_AppendResult(interp, "caller is not an object", NULL);
	    Tcl_SetErrorCode(interp, "TCL", "OO", "CONTEXT_REQUIRED", NULL);
	    return TCL_ERROR;
	} else {
	    CallContext *callerPtr = framePtr->callerVarPtr->clientData;
	    Method *mPtr = callerPtr->callPtr->chain[callerPtr->index].mPtr;
	    Object *declarerPtr;
	    Tcl_Obj *result[3];

	    if (mPtr->declaringClassPtr != NULL) {
		declarerPtr = mPtr->declaringClassPtr->thisPtr;
	    } else if (mPtr->declaringObjectPtr != NULL) {
		declarerPtr = mPtr->declaringObjectPtr;
	    } else {
		/*







<







954
955
956
957
958
959
960

961
962
963
964
965
966
967
	    Tcl_AppendResult(interp, "caller is not an object", NULL);
	    Tcl_SetErrorCode(interp, "TCL", "OO", "CONTEXT_REQUIRED", NULL);
	    return TCL_ERROR;
	} else {
	    CallContext *callerPtr = framePtr->callerVarPtr->clientData;
	    Method *mPtr = callerPtr->callPtr->chain[callerPtr->index].mPtr;
	    Object *declarerPtr;


	    if (mPtr->declaringClassPtr != NULL) {
		declarerPtr = mPtr->declaringClassPtr->thisPtr;
	    } else if (mPtr->declaringObjectPtr != NULL) {
		declarerPtr = mPtr->declaringObjectPtr;
	    } else {
		/*
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
	    return TCL_OK;
	}
    case SELF_NEXT:
	if (contextPtr->index < contextPtr->callPtr->numChain-1) {
	    Method *mPtr =
		    contextPtr->callPtr->chain[contextPtr->index+1].mPtr;
	    Object *declarerPtr;
	    Tcl_Obj *result[2];

	    if (mPtr->declaringClassPtr != NULL) {
		declarerPtr = mPtr->declaringClassPtr->thisPtr;
	    } else if (mPtr->declaringObjectPtr != NULL) {
		declarerPtr = mPtr->declaringObjectPtr;
	    } else {
		/*







<







985
986
987
988
989
990
991

992
993
994
995
996
997
998
	    return TCL_OK;
	}
    case SELF_NEXT:
	if (contextPtr->index < contextPtr->callPtr->numChain-1) {
	    Method *mPtr =
		    contextPtr->callPtr->chain[contextPtr->index+1].mPtr;
	    Object *declarerPtr;


	    if (mPtr->declaringClassPtr != NULL) {
		declarerPtr = mPtr->declaringClassPtr->thisPtr;
	    } else if (mPtr->declaringObjectPtr != NULL) {
		declarerPtr = mPtr->declaringObjectPtr;
	    } else {
		/*
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
	if (!CurrentlyInvoked(contextPtr).isFilter) {
	    Tcl_AppendResult(interp, "not inside a filtering context", NULL);
	    Tcl_SetErrorCode(interp, "TCL", "OO", "UNMATCHED_CONTEXT", NULL);
	    return TCL_ERROR;
	} else {
	    Method *mPtr;
	    Object *declarerPtr;
	    Tcl_Obj *result[2];
	    int i;

	    for (i=contextPtr->index ; i<contextPtr->callPtr->numChain ; i++){
		if (!contextPtr->callPtr->chain[i].isFilter) {
		    break;
		}
	    }







<







1018
1019
1020
1021
1022
1023
1024

1025
1026
1027
1028
1029
1030
1031
	if (!CurrentlyInvoked(contextPtr).isFilter) {
	    Tcl_AppendResult(interp, "not inside a filtering context", NULL);
	    Tcl_SetErrorCode(interp, "TCL", "OO", "UNMATCHED_CONTEXT", NULL);
	    return TCL_ERROR;
	} else {
	    Method *mPtr;
	    Object *declarerPtr;

	    int i;

	    for (i=contextPtr->index ; i<contextPtr->callPtr->numChain ; i++){
		if (!contextPtr->callPtr->chain[i].isFilter) {
		    break;
		}
	    }
950
951
952
953
954
955
956





957
958
959
960
961
962
963
		return TCL_ERROR;
	    }
	    result[0] = TclOOObjectName(interp, declarerPtr);
	    result[1] = mPtr->namePtr;
	    Tcl_SetObjResult(interp, Tcl_NewListObj(2, result));
	    return TCL_OK;
	}





    }
    return TCL_ERROR;
}

/*
 * ----------------------------------------------------------------------
 *







>
>
>
>
>







1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
		return TCL_ERROR;
	    }
	    result[0] = TclOOObjectName(interp, declarerPtr);
	    result[1] = mPtr->namePtr;
	    Tcl_SetObjResult(interp, Tcl_NewListObj(2, result));
	    return TCL_OK;
	}
    case SELF_CALL:
	result[0] = TclOORenderCallChain(interp, contextPtr->callPtr);
	result[1] = Tcl_NewIntObj(contextPtr->index);
	Tcl_SetObjResult(interp, Tcl_NewListObj(2, result));
	return TCL_OK;
    }
    return TCL_ERROR;
}

/*
 * ----------------------------------------------------------------------
 *

Changes to generic/tclOOCall.c.

100
101
102
103
104
105
106

107
108

109
110
111
112
113
114
115
void
TclOODeleteContext(
    CallContext *contextPtr)
{
    register Object *oPtr = contextPtr->oPtr;

    TclOODeleteChain(contextPtr->callPtr);

    TclStackFree(oPtr->fPtr->interp, contextPtr);
    DelRef(oPtr);

}

/*
 * ----------------------------------------------------------------------
 *
 * TclOODeleteChainCache --
 *







>
|
|
>







100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
void
TclOODeleteContext(
    CallContext *contextPtr)
{
    register Object *oPtr = contextPtr->oPtr;

    TclOODeleteChain(contextPtr->callPtr);
    if (oPtr != NULL) {
	TclStackFree(oPtr->fPtr->interp, contextPtr);
	DelRef(oPtr);
    }
}

/*
 * ----------------------------------------------------------------------
 *
 * TclOODeleteChainCache --
 *
1095
1096
1097
1098
1099
1100
1101

































































































































1102
1103
1104
1105
1106
1107
1108
    contextPtr->index = 0;
    return contextPtr;
}

/*
 * ----------------------------------------------------------------------
 *

































































































































 * AddClassFiltersToCallContext --
 *
 *	Logic to make extracting all the filters from the class context much
 *	easier.
 *
 * ----------------------------------------------------------------------
 */







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







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
    contextPtr->index = 0;
    return contextPtr;
}

/*
 * ----------------------------------------------------------------------
 *
 * TclOOGetStereotypeCallChain --
 *
 *	Construct a call-chain for a method that would be used by a
 *	stereotypical instance of the given class (i.e., where the object has
 *	no definitions special to itself).
 *
 * ----------------------------------------------------------------------
 */

CallChain *
TclOOGetStereotypeCallChain(
    Class *clsPtr,		/* The object to get the context for. */
    Tcl_Obj *methodNameObj,	/* The name of the method to get the context
				 * for. NULL when getting a constructor or
				 * destructor chain. */
    int flags)			/* What sort of context are we looking for.
				 * Only the bits PUBLIC_METHOD, CONSTRUCTOR,
				 * PRIVATE_METHOD, DESTRUCTOR and
				 * FILTER_HANDLING are useful. */
{
    CallChain *callPtr;
    struct ChainBuilder cb;
    int i, count;
    Foundation *fPtr = clsPtr->thisPtr->fPtr;
    Tcl_HashEntry *hPtr;
    Tcl_HashTable doneFilters;
    Object obj;

    /*
     * Synthesize a temporary stereotypical object so that we can use existing
     * machinery to produce the stereotypical call chain.
     */

    memset(&obj, 0, sizeof(Object));
    obj.fPtr = fPtr;
    obj.selfCls = clsPtr;
    obj.refCount = 1;
    obj.flags = USE_CLASS_CACHE;

    /*
     * Check if we can get the chain out of the Tcl_Obj method name or out of
     * the cache. This is made a bit more complex by the fact that there are
     * multiple different layers of cache (in the Tcl_Obj, in the object, and
     * in the class).
     */

    if (clsPtr->classChainCache != NULL) {
	hPtr = Tcl_FindHashEntry(clsPtr->classChainCache,
		(char *) methodNameObj);
	if (hPtr != NULL && Tcl_GetHashValue(hPtr) != NULL) {
	    const int reuseMask =
		    ((flags & PUBLIC_METHOD) ? ~0 : ~PUBLIC_METHOD);

	    callPtr = Tcl_GetHashValue(hPtr);
	    if (IsStillValid(callPtr, &obj, flags, reuseMask)) {
		callPtr->refCount++;
		return callPtr;
	    }
	    Tcl_SetHashValue(hPtr, NULL);
	    TclOODeleteChain(callPtr);
	}
    } else {
	hPtr = NULL;
    }

    callPtr = ckalloc(sizeof(CallChain));
    memset(callPtr, 0, sizeof(CallChain));
    callPtr->flags = flags & (PUBLIC_METHOD|PRIVATE_METHOD|FILTER_HANDLING);
    callPtr->epoch = fPtr->epoch;
    callPtr->objectCreationEpoch = fPtr->tsdPtr->nsCount;
    callPtr->objectEpoch = clsPtr->thisPtr->epoch;
    callPtr->refCount = 1;
    callPtr->chain = callPtr->staticChain;

    cb.callChainPtr = callPtr;
    cb.filterLength = 0;
    cb.oPtr = &obj;

    /*
     * Add all defined filters (if any, and if we're going to be processing
     * them; they're not processed for constructors, destructors or when we're
     * in the middle of processing a filter).
     */

    Tcl_InitObjHashTable(&doneFilters);
    AddClassFiltersToCallContext(&obj, clsPtr, &cb, &doneFilters);
    Tcl_DeleteHashTable(&doneFilters);
    count = cb.filterLength = callPtr->numChain;

    /*
     * Add the actual method implementations.
     */

    AddSimpleChainToCallContext(&obj, methodNameObj, &cb, NULL, flags, NULL);

    /*
     * Check to see if the method has no implementation. If so, we probably
     * need to add in a call to the unknown method. Otherwise, set up the
     * cacheing of the method implementation (if relevant).
     */

    if (count == callPtr->numChain) {
	AddSimpleChainToCallContext(&obj, fPtr->unknownMethodNameObj, &cb,
		NULL, 0, NULL);
	callPtr->flags |= OO_UNKNOWN_METHOD;
	callPtr->epoch = -1;
	if (count == callPtr->numChain) {
	    TclOODeleteChain(callPtr);
	    return NULL;
	}
    } else {
	if (hPtr == NULL) {
	    if (clsPtr->classChainCache == NULL) {
		clsPtr->classChainCache = ckalloc(sizeof(Tcl_HashTable));
		Tcl_InitObjHashTable(clsPtr->classChainCache);
	    }
	    hPtr = Tcl_CreateHashEntry(clsPtr->classChainCache,
		    (char *) methodNameObj, &i);
	}
	callPtr->refCount++;
	Tcl_SetHashValue(hPtr, callPtr);
	StashCallChain(methodNameObj, callPtr);
    }
    return callPtr;
}

/*
 * ----------------------------------------------------------------------
 *
 * AddClassFiltersToCallContext --
 *
 *	Logic to make extracting all the filters from the class context much
 *	easier.
 *
 * ----------------------------------------------------------------------
 */
1250
1251
1252
1253
1254
1255
1256
1257
1258





















































































1259
1260
1261
1262
1263
1264
	    AddSimpleClassChainToCallContext(superPtr, methodNameObj, cbPtr,
		    doneFilters, flags, filterDecl);
	}
    case 0:
	return;
    }
}

/*





















































































 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78
 * End:
 */









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






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
	    AddSimpleClassChainToCallContext(superPtr, methodNameObj, cbPtr,
		    doneFilters, flags, filterDecl);
	}
    case 0:
	return;
    }
}

/*
 * ----------------------------------------------------------------------
 *
 * TclOORenderCallChain --
 *
 *	Create a description of a call chain. Used in [info object call],
 *	[info class call], and [self call].
 *
 * ----------------------------------------------------------------------
 */

Tcl_Obj *
TclOORenderCallChain(
    Tcl_Interp *interp,
    CallChain *callPtr)
{
    Tcl_Obj *filterLiteral, *methodLiteral, *objectLiteral;
    Tcl_Obj *resultObj, *descObjs[4], **objv;
    Foundation *fPtr = TclOOGetFoundation(interp);
    int i;

    /*
     * Allocate the literals (potentially) used in our description.
     */

    filterLiteral = Tcl_NewStringObj("filter", -1);
    Tcl_IncrRefCount(filterLiteral);
    methodLiteral = Tcl_NewStringObj("method", -1);
    Tcl_IncrRefCount(methodLiteral);
    objectLiteral = Tcl_NewStringObj("object", -1);
    Tcl_IncrRefCount(objectLiteral);

    /*
     * Do the actual construction of the descriptions. They consist of a list
     * of triples that describe the details of how a method is understood. For
     * each triple, the first word is the type of invokation ("method" is
     * normal, "unknown" is special because it adds the method name as an
     * extra argument when handled by some method types, and "filter" is
     * special because it's a filter method). The second word is the name of
     * the method in question (which differs for "unknown" and "filter" types)
     * and the third word is the full name of the class that declares the
     * method (or "object" if it is declared on the instance).
     */

    objv = TclStackAlloc(interp, callPtr->numChain * sizeof(Tcl_Obj *));
    for (i=0 ; i<callPtr->numChain ; i++) {
	struct MInvoke *miPtr = &callPtr->chain[i];

	descObjs[0] = miPtr->isFilter
		? filterLiteral
		: callPtr->flags & OO_UNKNOWN_METHOD
			? fPtr->unknownMethodNameObj
			: methodLiteral;
	descObjs[1] = callPtr->flags & CONSTRUCTOR
		? fPtr->constructorName
		: callPtr->flags & DESTRUCTOR
			? fPtr->destructorName
			: miPtr->mPtr->namePtr;
	descObjs[2] = miPtr->mPtr->declaringClassPtr
		? Tcl_GetObjectName(interp,
			(Tcl_Object) miPtr->mPtr->declaringClassPtr->thisPtr)
		: objectLiteral;
	descObjs[3] = Tcl_NewStringObj(miPtr->mPtr->typePtr->name, -1);

	objv[i] = Tcl_NewListObj(4, descObjs);
    }

    /*
     * Drop the local references to the literals; if they're actually used,
     * they'll live on the description itself.
     */

    Tcl_DecrRefCount(filterLiteral);
    Tcl_DecrRefCount(methodLiteral);
    Tcl_DecrRefCount(objectLiteral);

    /*
     * Finish building the description and return it.
     */

    resultObj = Tcl_NewListObj(callPtr->numChain, objv);
    TclStackFree(interp, objv);
    return resultObj;
}

/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78
 * End:
 */

Changes to generic/tclOODecls.h.

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
/*
 * This file is (mostly) automatically generated from tclOO.decls.
 */

#ifndef _TCLOODECLS
#define _TCLOODECLS

#undef TCL_STORAGE_CLASS
#ifdef BUILD_tcl
#   define TCL_STORAGE_CLASS DLLEXPORT
#else
#   ifdef USE_TCL_STUBS
#      define TCL_STORAGE_CLASS
#   else
#      define TCL_STORAGE_CLASS DLLIMPORT
#   endif
#endif

/*
 * WARNING: This file is automatically generated by the tools/genStubs.tcl
 * script. Any modifications to the function declarations below should be made
 * in the generic/tclOO.decls script.
 */

#if defined(USE_TCL_STUBS)
extern const char *TclOOInitializeStubs(Tcl_Interp *, const char *version);
#define Tcl_OOInitStubs(interp) TclOOInitializeStubs((interp),TCLOO_VERSION)
#else
#define Tcl_OOInitStubs(interp) \
	Tcl_PkgRequire((interp),"TclOO",TCLOO_VERSION,0)
#endif

/* !BEGIN!: Do not edit below this line. */

/*
 * Exported function declarations:
 */

/* 0 */
EXTERN Tcl_Object	Tcl_CopyObjectInstance(Tcl_Interp *interp,
				Tcl_Object sourceObject,
				const char *targetName,
				const char *targetNamespaceName);
/* 1 */
EXTERN Tcl_Object	Tcl_GetClassAsObject(Tcl_Class clazz);
/* 2 */
EXTERN Tcl_Class	Tcl_GetObjectAsClass(Tcl_Object object);
/* 3 */
EXTERN Tcl_Command	Tcl_GetObjectCommand(Tcl_Object object);
/* 4 */
EXTERN Tcl_Object	Tcl_GetObjectFromObj(Tcl_Interp *interp,
				Tcl_Obj *objPtr);
/* 5 */
EXTERN Tcl_Namespace *	Tcl_GetObjectNamespace(Tcl_Object object);
/* 6 */
EXTERN Tcl_Class	Tcl_MethodDeclarerClass(Tcl_Method method);
/* 7 */
EXTERN Tcl_Object	Tcl_MethodDeclarerObject(Tcl_Method method);
/* 8 */
EXTERN int		Tcl_MethodIsPublic(Tcl_Method method);
/* 9 */
EXTERN int		Tcl_MethodIsType(Tcl_Method method,
				const Tcl_MethodType *typePtr,
				ClientData *clientDataPtr);
/* 10 */
EXTERN Tcl_Obj *	Tcl_MethodName(Tcl_Method method);
/* 11 */
EXTERN Tcl_Method	Tcl_NewInstanceMethod(Tcl_Interp *interp,
				Tcl_Object object, Tcl_Obj *nameObj,
				int isPublic, const Tcl_MethodType *typePtr,
				ClientData clientData);
/* 12 */
EXTERN Tcl_Method	Tcl_NewMethod(Tcl_Interp *interp, Tcl_Class cls,
				Tcl_Obj *nameObj, int isPublic,
				const Tcl_MethodType *typePtr,
				ClientData clientData);
/* 13 */
EXTERN Tcl_Object	Tcl_NewObjectInstance(Tcl_Interp *interp,
				Tcl_Class cls, const char *nameStr,
				const char *nsNameStr, int objc,
				Tcl_Obj *const *objv, int skip);
/* 14 */
EXTERN int		Tcl_ObjectDeleted(Tcl_Object object);
/* 15 */
EXTERN int		Tcl_ObjectContextIsFiltering(
				Tcl_ObjectContext context);
/* 16 */
EXTERN Tcl_Method	Tcl_ObjectContextMethod(Tcl_ObjectContext context);
/* 17 */
EXTERN Tcl_Object	Tcl_ObjectContextObject(Tcl_ObjectContext context);
/* 18 */
EXTERN int		Tcl_ObjectContextSkippedArgs(
				Tcl_ObjectContext context);
/* 19 */
EXTERN ClientData	Tcl_ClassGetMetadata(Tcl_Class clazz,
				const Tcl_ObjectMetadataType *typePtr);
/* 20 */
EXTERN void		Tcl_ClassSetMetadata(Tcl_Class clazz,
				const Tcl_ObjectMetadataType *typePtr,
				ClientData metadata);
/* 21 */
EXTERN ClientData	Tcl_ObjectGetMetadata(Tcl_Object object,
				const Tcl_ObjectMetadataType *typePtr);
/* 22 */
EXTERN void		Tcl_ObjectSetMetadata(Tcl_Object object,
				const Tcl_ObjectMetadataType *typePtr,
				ClientData metadata);
/* 23 */
EXTERN int		Tcl_ObjectContextInvokeNext(Tcl_Interp *interp,
				Tcl_ObjectContext context, int objc,
				Tcl_Obj *const *objv, int skip);
/* 24 */
EXTERN Tcl_ObjectMapMethodNameProc * Tcl_ObjectGetMethodNameMapper(
				Tcl_Object object);
/* 25 */
EXTERN void		Tcl_ObjectSetMethodNameMapper(Tcl_Object object,
				Tcl_ObjectMapMethodNameProc *mapMethodNameProc);
/* 26 */
EXTERN void		Tcl_ClassSetConstructor(Tcl_Interp *interp,
				Tcl_Class clazz, Tcl_Method method);
/* 27 */
EXTERN void		Tcl_ClassSetDestructor(Tcl_Interp *interp,
				Tcl_Class clazz, Tcl_Method method);
/* 28 */
EXTERN Tcl_Obj *	Tcl_GetObjectName(Tcl_Interp *interp,
				Tcl_Object object);

typedef struct TclOOStubHooks {
    const struct TclOOIntStubs *tclOOIntStubs;
} TclOOStubHooks;

typedef struct TclOOStubs {







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







|




|

|

|

|


|

|

|

|

|



|

|




|




|




|

|


|

|

|


|


|



|


|



|



|


|


|


|


|







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
/*
 * This file is (mostly) automatically generated from tclOO.decls.
 */

#ifndef _TCLOODECLS
#define _TCLOODECLS


























/* !BEGIN!: Do not edit below this line. */

/*
 * Exported function declarations:
 */

/* 0 */
TCLOOAPI Tcl_Object	Tcl_CopyObjectInstance(Tcl_Interp *interp,
				Tcl_Object sourceObject,
				const char *targetName,
				const char *targetNamespaceName);
/* 1 */
TCLOOAPI Tcl_Object	Tcl_GetClassAsObject(Tcl_Class clazz);
/* 2 */
TCLOOAPI Tcl_Class	Tcl_GetObjectAsClass(Tcl_Object object);
/* 3 */
TCLOOAPI Tcl_Command	Tcl_GetObjectCommand(Tcl_Object object);
/* 4 */
TCLOOAPI Tcl_Object	Tcl_GetObjectFromObj(Tcl_Interp *interp,
				Tcl_Obj *objPtr);
/* 5 */
TCLOOAPI Tcl_Namespace * Tcl_GetObjectNamespace(Tcl_Object object);
/* 6 */
TCLOOAPI Tcl_Class	Tcl_MethodDeclarerClass(Tcl_Method method);
/* 7 */
TCLOOAPI Tcl_Object	Tcl_MethodDeclarerObject(Tcl_Method method);
/* 8 */
TCLOOAPI int		Tcl_MethodIsPublic(Tcl_Method method);
/* 9 */
TCLOOAPI int		Tcl_MethodIsType(Tcl_Method method,
				const Tcl_MethodType *typePtr,
				ClientData *clientDataPtr);
/* 10 */
TCLOOAPI Tcl_Obj *	Tcl_MethodName(Tcl_Method method);
/* 11 */
TCLOOAPI Tcl_Method	Tcl_NewInstanceMethod(Tcl_Interp *interp,
				Tcl_Object object, Tcl_Obj *nameObj,
				int isPublic, const Tcl_MethodType *typePtr,
				ClientData clientData);
/* 12 */
TCLOOAPI Tcl_Method	Tcl_NewMethod(Tcl_Interp *interp, Tcl_Class cls,
				Tcl_Obj *nameObj, int isPublic,
				const Tcl_MethodType *typePtr,
				ClientData clientData);
/* 13 */
TCLOOAPI Tcl_Object	Tcl_NewObjectInstance(Tcl_Interp *interp,
				Tcl_Class cls, const char *nameStr,
				const char *nsNameStr, int objc,
				Tcl_Obj *const *objv, int skip);
/* 14 */
TCLOOAPI int		Tcl_ObjectDeleted(Tcl_Object object);
/* 15 */
TCLOOAPI int		Tcl_ObjectContextIsFiltering(
				Tcl_ObjectContext context);
/* 16 */
TCLOOAPI Tcl_Method	Tcl_ObjectContextMethod(Tcl_ObjectContext context);
/* 17 */
TCLOOAPI Tcl_Object	Tcl_ObjectContextObject(Tcl_ObjectContext context);
/* 18 */
TCLOOAPI int		Tcl_ObjectContextSkippedArgs(
				Tcl_ObjectContext context);
/* 19 */
TCLOOAPI ClientData	Tcl_ClassGetMetadata(Tcl_Class clazz,
				const Tcl_ObjectMetadataType *typePtr);
/* 20 */
TCLOOAPI void		Tcl_ClassSetMetadata(Tcl_Class clazz,
				const Tcl_ObjectMetadataType *typePtr,
				ClientData metadata);
/* 21 */
TCLOOAPI ClientData	Tcl_ObjectGetMetadata(Tcl_Object object,
				const Tcl_ObjectMetadataType *typePtr);
/* 22 */
TCLOOAPI void		Tcl_ObjectSetMetadata(Tcl_Object object,
				const Tcl_ObjectMetadataType *typePtr,
				ClientData metadata);
/* 23 */
TCLOOAPI int		Tcl_ObjectContextInvokeNext(Tcl_Interp *interp,
				Tcl_ObjectContext context, int objc,
				Tcl_Obj *const *objv, int skip);
/* 24 */
TCLOOAPI Tcl_ObjectMapMethodNameProc * Tcl_ObjectGetMethodNameMapper(
				Tcl_Object object);
/* 25 */
TCLOOAPI void		Tcl_ObjectSetMethodNameMapper(Tcl_Object object,
				Tcl_ObjectMapMethodNameProc *mapMethodNameProc);
/* 26 */
TCLOOAPI void		Tcl_ClassSetConstructor(Tcl_Interp *interp,
				Tcl_Class clazz, Tcl_Method method);
/* 27 */
TCLOOAPI void		Tcl_ClassSetDestructor(Tcl_Interp *interp,
				Tcl_Class clazz, Tcl_Method method);
/* 28 */
TCLOOAPI Tcl_Obj *	Tcl_GetObjectName(Tcl_Interp *interp,
				Tcl_Object object);

typedef struct TclOOStubHooks {
    const struct TclOOIntStubs *tclOOIntStubs;
} TclOOStubHooks;

typedef struct TclOOStubs {
236
237
238
239
240
241
242
243
244
245
246
247
	(tclOOStubsPtr->tcl_ClassSetDestructor) /* 27 */
#define Tcl_GetObjectName \
	(tclOOStubsPtr->tcl_GetObjectName) /* 28 */

#endif /* defined(USE_TCLOO_STUBS) */

/* !END!: Do not edit above this line. */

#undef TCL_STORAGE_CLASS
#define TCL_STORAGE_CLASS DLLIMPORT

#endif /* _TCLOODECLS */







<
<
<
<

211
212
213
214
215
216
217




218
	(tclOOStubsPtr->tcl_ClassSetDestructor) /* 27 */
#define Tcl_GetObjectName \
	(tclOOStubsPtr->tcl_GetObjectName) /* 28 */

#endif /* defined(USE_TCLOO_STUBS) */

/* !END!: Do not edit above this line. */




#endif /* _TCLOODECLS */

Changes to generic/tclOODefineCmds.c.

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
    int isNew;

    if (!useClass) {
	if (!oPtr->methodsPtr) {
	noSuchMethod:
	    Tcl_AppendResult(interp, "method ", TclGetString(fromPtr),
		    " does not exist", NULL);


	    return TCL_ERROR;
	}
	hPtr = Tcl_FindHashEntry(oPtr->methodsPtr, (char *) fromPtr);
	if (hPtr == NULL) {
	    goto noSuchMethod;
	}
	if (toPtr) {
	    newHPtr = Tcl_CreateHashEntry(oPtr->methodsPtr, (char *) toPtr,
		    &isNew);
	    if (hPtr == newHPtr) {
	    renameToSelf:
		Tcl_AppendResult(interp, "cannot rename method to itself",
			NULL);

		return TCL_ERROR;
	    } else if (!isNew) {
	    renameToExisting:
		Tcl_AppendResult(interp, "method called ",
			TclGetString(toPtr), " already exists", NULL);

		return TCL_ERROR;
	    }
	}
    } else {
	hPtr = Tcl_FindHashEntry(&oPtr->classPtr->classMethods,
		(char *) fromPtr);
	if (hPtr == NULL) {







>
>













>





>







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
    int isNew;

    if (!useClass) {
	if (!oPtr->methodsPtr) {
	noSuchMethod:
	    Tcl_AppendResult(interp, "method ", TclGetString(fromPtr),
		    " does not exist", NULL);
	    Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "METHOD",
		    TclGetString(fromPtr), NULL);
	    return TCL_ERROR;
	}
	hPtr = Tcl_FindHashEntry(oPtr->methodsPtr, (char *) fromPtr);
	if (hPtr == NULL) {
	    goto noSuchMethod;
	}
	if (toPtr) {
	    newHPtr = Tcl_CreateHashEntry(oPtr->methodsPtr, (char *) toPtr,
		    &isNew);
	    if (hPtr == newHPtr) {
	    renameToSelf:
		Tcl_AppendResult(interp, "cannot rename method to itself",
			NULL);
		Tcl_SetErrorCode(interp, "TCL", "OO", "RENAME_TO_SELF", NULL);
		return TCL_ERROR;
	    } else if (!isNew) {
	    renameToExisting:
		Tcl_AppendResult(interp, "method called ",
			TclGetString(toPtr), " already exists", NULL);
		Tcl_SetErrorCode(interp, "TCL", "OO", "RENAME_OVER", NULL);
		return TCL_ERROR;
	    }
	}
    } else {
	hPtr = Tcl_FindHashEntry(&oPtr->classPtr->classMethods,
		(char *) fromPtr);
	if (hPtr == NULL) {
423
424
425
426
427
428
429

430
431
432
433
434
435
436
    Tcl_HashSearch search;
    Tcl_HashEntry *hPtr;
    int soughtLen;
    const char *soughtStr, *matchedStr = NULL;

    if (objc < 2) {
	Tcl_AppendResult(interp, "bad call of unknown handler", NULL);

	return TCL_ERROR;
    }
    if (TclOOGetDefineCmdContext(interp) == NULL) {
	return TCL_ERROR;
    }

    soughtStr = Tcl_GetStringFromObj(objv[1], &soughtLen);







>







427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
    Tcl_HashSearch search;
    Tcl_HashEntry *hPtr;
    int soughtLen;
    const char *soughtStr, *matchedStr = NULL;

    if (objc < 2) {
	Tcl_AppendResult(interp, "bad call of unknown handler", NULL);
	Tcl_SetErrorCode(interp, "TCL", "OO", "BAD_UNKNOWN", NULL);
	return TCL_ERROR;
    }
    if (TclOOGetDefineCmdContext(interp) == NULL) {
	return TCL_ERROR;
    }

    soughtStr = Tcl_GetStringFromObj(objv[1], &soughtLen);
467
468
469
470
471
472
473

474
475
476
477
478
479
480
	Tcl_DecrRefCount(newObjv[0]);
	TclStackFree(interp, newObjv);
	return result;
    }

  noMatch:
    Tcl_AppendResult(interp, "invalid command name \"",soughtStr,"\"", NULL);

    return TCL_ERROR;
}

/*
 * ----------------------------------------------------------------------
 *
 * FindCommand --







>







472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
	Tcl_DecrRefCount(newObjv[0]);
	TclStackFree(interp, newObjv);
	return result;
    }

  noMatch:
    Tcl_AppendResult(interp, "invalid command name \"",soughtStr,"\"", NULL);
    Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "COMMAND", soughtStr, NULL);
    return TCL_ERROR;
}

/*
 * ----------------------------------------------------------------------
 *
 * FindCommand --
556
557
558
559
560
561
562

563
564
565
566
567
568
569
    CallFrame *framePtr, **framePtrPtr = &framePtr;
    int result;

    if (namespacePtr == NULL) {
	Tcl_AppendResult(interp,
		"cannot process definitions; support namespace deleted",
		NULL);

	return TCL_ERROR;
    }

    /* framePtrPtr is needed to satisfy GCC 3.3's strict aliasing rules */

    result = TclPushStackFrame(interp, (Tcl_CallFrame **) framePtrPtr,
	    namespacePtr, FRAME_IS_OO_DEFINE);







>







562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
    CallFrame *framePtr, **framePtrPtr = &framePtr;
    int result;

    if (namespacePtr == NULL) {
	Tcl_AppendResult(interp,
		"cannot process definitions; support namespace deleted",
		NULL);
	Tcl_SetErrorCode(interp, "TCL", "OO", "MONKEY_BUSINESS", NULL);
	return TCL_ERROR;
    }

    /* framePtrPtr is needed to satisfy GCC 3.3's strict aliasing rules */

    result = TclPushStackFrame(interp, (Tcl_CallFrame **) framePtrPtr,
	    namespacePtr, FRAME_IS_OO_DEFINE);
594
595
596
597
598
599
600

601
602
603
604
605
606
607
    Interp *iPtr = (Interp *) interp;

    if ((iPtr->varFramePtr == NULL)
	    || (iPtr->varFramePtr->isProcCallFrame != FRAME_IS_OO_DEFINE)) {
	Tcl_AppendResult(interp, "this command may only be called from within"
		" the context of an ::oo::define or ::oo::objdefine command",
		NULL);

	return NULL;
    }
    return (Tcl_Object) iPtr->varFramePtr->clientData;
}

/*
 * ----------------------------------------------------------------------







>







601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
    Interp *iPtr = (Interp *) interp;

    if ((iPtr->varFramePtr == NULL)
	    || (iPtr->varFramePtr->isProcCallFrame != FRAME_IS_OO_DEFINE)) {
	Tcl_AppendResult(interp, "this command may only be called from within"
		" the context of an ::oo::define or ::oo::objdefine command",
		NULL);
	Tcl_SetErrorCode(interp, "TCL", "OO", "MONKEY_BUSINESS", NULL);
	return NULL;
    }
    return (Tcl_Object) iPtr->varFramePtr->clientData;
}

/*
 * ----------------------------------------------------------------------
634
635
636
637
638
639
640


641
642
643
644
645
646
647
    oPtr = (Object *) Tcl_GetObjectFromObj(interp, className);
    iPtr->varFramePtr = savedFramePtr;
    if (oPtr == NULL) {
	return NULL;
    }
    if (oPtr->classPtr == NULL) {
	Tcl_AppendResult(interp, errMsg, NULL);


	return NULL;
    }
    return oPtr->classPtr;
}

/*
 * ----------------------------------------------------------------------







>
>







642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
    oPtr = (Object *) Tcl_GetObjectFromObj(interp, className);
    iPtr->varFramePtr = savedFramePtr;
    if (oPtr == NULL) {
	return NULL;
    }
    if (oPtr->classPtr == NULL) {
	Tcl_AppendResult(interp, errMsg, NULL);
	Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "CLASS",
		TclGetString(className), NULL);
	return NULL;
    }
    return oPtr->classPtr;
}

/*
 * ----------------------------------------------------------------------
675
676
677
678
679
680
681


682
683
684
685
686
687
688
    oPtr = (Object *) Tcl_GetObjectFromObj(interp, objv[1]);
    if (oPtr == NULL) {
	return TCL_ERROR;
    }
    if (oPtr->classPtr == NULL) {
	Tcl_AppendResult(interp, TclGetString(objv[1]),
		" does not refer to a class", NULL);


	return TCL_ERROR;
    }

    /*
     * Make the oo::define namespace the current namespace and evaluate the
     * command(s).
     */







>
>







685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
    oPtr = (Object *) Tcl_GetObjectFromObj(interp, objv[1]);
    if (oPtr == NULL) {
	return TCL_ERROR;
    }
    if (oPtr->classPtr == NULL) {
	Tcl_AppendResult(interp, TclGetString(objv[1]),
		" does not refer to a class", NULL);
	Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "CLASS",
		TclGetString(objv[1]), NULL);
	return TCL_ERROR;
    }

    /*
     * Make the oo::define namespace the current namespace and evaluate the
     * command(s).
     */
1034
1035
1036
1037
1038
1039
1040

1041
1042
1043
1044
1045

1046
1047
1048
1049
1050
1051
1052
    oPtr = (Object *) TclOOGetDefineCmdContext(interp);
    if (oPtr == NULL) {
	return TCL_ERROR;
    }
    if (oPtr->flags & ROOT_OBJECT) {
	Tcl_AppendResult(interp,
		"may not modify the class of the root object class", NULL);

	return TCL_ERROR;
    }
    if (oPtr->flags & ROOT_CLASS) {
	Tcl_AppendResult(interp,
		"may not modify the class of the class of classes", NULL);

	return TCL_ERROR;
    }

    /*
     * Parse the argument to get the class to set the object's class to.
     */








>





>







1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
    oPtr = (Object *) TclOOGetDefineCmdContext(interp);
    if (oPtr == NULL) {
	return TCL_ERROR;
    }
    if (oPtr->flags & ROOT_OBJECT) {
	Tcl_AppendResult(interp,
		"may not modify the class of the root object class", NULL);
	Tcl_SetErrorCode(interp, "TCL", "OO", "MONKEY_BUSINESS", NULL);
	return TCL_ERROR;
    }
    if (oPtr->flags & ROOT_CLASS) {
	Tcl_AppendResult(interp,
		"may not modify the class of the class of classes", NULL);
	Tcl_SetErrorCode(interp, "TCL", "OO", "MONKEY_BUSINESS", NULL);
	return TCL_ERROR;
    }

    /*
     * Parse the argument to get the class to set the object's class to.
     */

1066
1067
1068
1069
1070
1071
1072

1073
1074
1075
1076
1077
1078
1079
     * produce an error if any attempt is made to swap from one to the other.
     */

    if ((oPtr->classPtr==NULL) == TclOOIsReachable(fPtr->classCls, clsPtr)) {
	Tcl_AppendResult(interp, "may not change a ",
		(oPtr->classPtr==NULL ? "non-" : ""), "class object into a ",
		(oPtr->classPtr==NULL ? "" : "non-"), "class object", NULL);

	return TCL_ERROR;
    }

    /*
     * Set the object's class.
     */








>







1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
     * produce an error if any attempt is made to swap from one to the other.
     */

    if ((oPtr->classPtr==NULL) == TclOOIsReachable(fPtr->classCls, clsPtr)) {
	Tcl_AppendResult(interp, "may not change a ",
		(oPtr->classPtr==NULL ? "non-" : ""), "class object into a ",
		(oPtr->classPtr==NULL ? "" : "non-"), "class object", NULL);
	Tcl_SetErrorCode(interp, "TCL", "OO", "TRANSMUTATION", NULL);
	return TCL_ERROR;
    }

    /*
     * Set the object's class.
     */

1186
1187
1188
1189
1190
1191
1192

1193
1194
1195
1196
1197
1198
1199

    oPtr = (Object *) TclOOGetDefineCmdContext(interp);
    if (oPtr == NULL) {
	return TCL_ERROR;
    }
    if (!isInstanceDeleteMethod && !oPtr->classPtr) {
	Tcl_AppendResult(interp, "attempt to misuse API", NULL);

	return TCL_ERROR;
    }

    for (i=1 ; i<objc ; i++) {
	/*
	 * Delete the method structure from the appropriate hash table.
	 */







>







1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215

    oPtr = (Object *) TclOOGetDefineCmdContext(interp);
    if (oPtr == NULL) {
	return TCL_ERROR;
    }
    if (!isInstanceDeleteMethod && !oPtr->classPtr) {
	Tcl_AppendResult(interp, "attempt to misuse API", NULL);
	Tcl_SetErrorCode(interp, "TCL", "OO", "MONKEY_BUSINESS", NULL);
	return TCL_ERROR;
    }

    for (i=1 ; i<objc ; i++) {
	/*
	 * Delete the method structure from the appropriate hash table.
	 */
1308
1309
1310
1311
1312
1313
1314

1315
1316
1317
1318
1319
1320
1321
    oPtr = (Object *) TclOOGetDefineCmdContext(interp);
    if (oPtr == NULL) {
	return TCL_ERROR;
    }
    clsPtr = oPtr->classPtr;
    if (!isInstanceExport && !clsPtr) {
	Tcl_AppendResult(interp, "attempt to misuse API", NULL);

	return TCL_ERROR;
    }

    for (i=1 ; i<objc ; i++) {
	/*
	 * Exporting is done by adding the PUBLIC_METHOD flag to the method
	 * record. If there is no such method in this object or class (i.e.







>







1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
    oPtr = (Object *) TclOOGetDefineCmdContext(interp);
    if (oPtr == NULL) {
	return TCL_ERROR;
    }
    clsPtr = oPtr->classPtr;
    if (!isInstanceExport && !clsPtr) {
	Tcl_AppendResult(interp, "attempt to misuse API", NULL);
	Tcl_SetErrorCode(interp, "TCL", "OO", "MONKEY_BUSINESS", NULL);
	return TCL_ERROR;
    }

    for (i=1 ; i<objc ; i++) {
	/*
	 * Exporting is done by adding the PUBLIC_METHOD flag to the method
	 * record. If there is no such method in this object or class (i.e.
1389
1390
1391
1392
1393
1394
1395

1396
1397
1398
1399
1400
1401
1402
    Object *oPtr = (Object *) TclOOGetDefineCmdContext(interp);

    if (oPtr == NULL) {
	return TCL_ERROR;
    }
    if (!isInstanceFilter && !oPtr->classPtr) {
	Tcl_AppendResult(interp, "attempt to misuse API", NULL);

	return TCL_ERROR;
    }

    if (!isInstanceFilter) {
	TclOOClassSetFilters(interp, oPtr->classPtr, objc-1, objv+1);
    } else {
	TclOOObjectSetFilters(oPtr, objc-1, objv+1);







>







1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
    Object *oPtr = (Object *) TclOOGetDefineCmdContext(interp);

    if (oPtr == NULL) {
	return TCL_ERROR;
    }
    if (!isInstanceFilter && !oPtr->classPtr) {
	Tcl_AppendResult(interp, "attempt to misuse API", NULL);
	Tcl_SetErrorCode(interp, "TCL", "OO", "MONKEY_BUSINESS", NULL);
	return TCL_ERROR;
    }

    if (!isInstanceFilter) {
	TclOOClassSetFilters(interp, oPtr->classPtr, objc-1, objv+1);
    } else {
	TclOOObjectSetFilters(oPtr, objc-1, objv+1);
1434
1435
1436
1437
1438
1439
1440

1441
1442
1443
1444
1445
1446
1447

    oPtr = (Object *) TclOOGetDefineCmdContext(interp);
    if (oPtr == NULL) {
	return TCL_ERROR;
    }
    if (!isInstanceForward && !oPtr->classPtr) {
	Tcl_AppendResult(interp, "attempt to misuse API", NULL);

	return TCL_ERROR;
    }
    isPublic = Tcl_StringMatch(TclGetString(objv[1]), "[a-z]*")
	    ? PUBLIC_METHOD : 0;

    /*
     * Create the method structure.







>







1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466

    oPtr = (Object *) TclOOGetDefineCmdContext(interp);
    if (oPtr == NULL) {
	return TCL_ERROR;
    }
    if (!isInstanceForward && !oPtr->classPtr) {
	Tcl_AppendResult(interp, "attempt to misuse API", NULL);
	Tcl_SetErrorCode(interp, "TCL", "OO", "MONKEY_BUSINESS", NULL);
	return TCL_ERROR;
    }
    isPublic = Tcl_StringMatch(TclGetString(objv[1]), "[a-z]*")
	    ? PUBLIC_METHOD : 0;

    /*
     * Create the method structure.
1490
1491
1492
1493
1494
1495
1496

1497
1498
1499
1500
1501
1502
1503

    oPtr = (Object *) TclOOGetDefineCmdContext(interp);
    if (oPtr == NULL) {
	return TCL_ERROR;
    }
    if (!isInstanceMethod && !oPtr->classPtr) {
	Tcl_AppendResult(interp, "attempt to misuse API", NULL);

	return TCL_ERROR;
    }
    isPublic = Tcl_StringMatch(TclGetString(objv[1]), "[a-z]*")
	    ? PUBLIC_METHOD : 0;

    /*
     * Create the method by using the right back-end API.







>







1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523

    oPtr = (Object *) TclOOGetDefineCmdContext(interp);
    if (oPtr == NULL) {
	return TCL_ERROR;
    }
    if (!isInstanceMethod && !oPtr->classPtr) {
	Tcl_AppendResult(interp, "attempt to misuse API", NULL);
	Tcl_SetErrorCode(interp, "TCL", "OO", "MONKEY_BUSINESS", NULL);
	return TCL_ERROR;
    }
    isPublic = Tcl_StringMatch(TclGetString(objv[1]), "[a-z]*")
	    ? PUBLIC_METHOD : 0;

    /*
     * Create the method by using the right back-end API.
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
    int i;

    if (oPtr == NULL) {
	return TCL_ERROR;
    }
    if (!isInstanceMixin && !oPtr->classPtr) {
	Tcl_AppendResult(interp, "attempt to misuse API", NULL);

	return TCL_ERROR;
    }
    mixins = TclStackAlloc(interp, sizeof(Class *) * (objc-1));

    for (i=1 ; i<objc ; i++) {
	Class *clsPtr = GetClassInOuterContext(interp, objv[i],
		"may only mix in classes");

	if (clsPtr == NULL) {
	    goto freeAndError;
	}
	if (!isInstanceMixin && TclOOIsReachable(oPtr->classPtr, clsPtr)) {
	    Tcl_AppendResult(interp, "may not mix a class into itself", NULL);

	    goto freeAndError;
	}
	mixins[i-1] = clsPtr;
    }

    if (isInstanceMixin) {
	TclOOObjectSetMixins(oPtr, objc-1, mixins);







>













>







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
    int i;

    if (oPtr == NULL) {
	return TCL_ERROR;
    }
    if (!isInstanceMixin && !oPtr->classPtr) {
	Tcl_AppendResult(interp, "attempt to misuse API", NULL);
	Tcl_SetErrorCode(interp, "TCL", "OO", "MONKEY_BUSINESS", NULL);
	return TCL_ERROR;
    }
    mixins = TclStackAlloc(interp, sizeof(Class *) * (objc-1));

    for (i=1 ; i<objc ; i++) {
	Class *clsPtr = GetClassInOuterContext(interp, objv[i],
		"may only mix in classes");

	if (clsPtr == NULL) {
	    goto freeAndError;
	}
	if (!isInstanceMixin && TclOOIsReachable(oPtr->classPtr, clsPtr)) {
	    Tcl_AppendResult(interp, "may not mix a class into itself", NULL);
	    Tcl_SetErrorCode(interp, "TCL", "OO", "SELF_MIXIN", NULL);
	    goto freeAndError;
	}
	mixins[i-1] = clsPtr;
    }

    if (isInstanceMixin) {
	TclOOObjectSetMixins(oPtr, objc-1, mixins);
1603
1604
1605
1606
1607
1608
1609

1610
1611
1612
1613
1614
1615
1616

    oPtr = (Object *) TclOOGetDefineCmdContext(interp);
    if (oPtr == NULL) {
	return TCL_ERROR;
    }
    if (!isInstanceRenameMethod && !oPtr->classPtr) {
	Tcl_AppendResult(interp, "attempt to misuse API", NULL);

	return TCL_ERROR;
    }

    /*
     * Delete the method entry from the appropriate hash table, and transfer
     * the thing it points to to its new entry. To do this, we first need to
     * get the entries from the appropriate hash tables (this can generate a







>







1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639

    oPtr = (Object *) TclOOGetDefineCmdContext(interp);
    if (oPtr == NULL) {
	return TCL_ERROR;
    }
    if (!isInstanceRenameMethod && !oPtr->classPtr) {
	Tcl_AppendResult(interp, "attempt to misuse API", NULL);
	Tcl_SetErrorCode(interp, "TCL", "OO", "MONKEY_BUSINESS", NULL);
	return TCL_ERROR;
    }

    /*
     * Delete the method entry from the appropriate hash table, and transfer
     * the thing it points to to its new entry. To do this, we first need to
     * get the entries from the appropriate hash tables (this can generate a
1663
1664
1665
1666
1667
1668
1669

1670
1671
1672
1673
1674

1675
1676
1677
1678
1679
1680
1681
    oPtr = (Object *) TclOOGetDefineCmdContext(interp);
    if (oPtr == NULL) {
	return TCL_ERROR;
    }
    if (oPtr->classPtr == NULL) {
	Tcl_AppendResult(interp, "only classes may have superclasses defined",
		NULL);

	return TCL_ERROR;
    }
    if (oPtr->flags & ROOT_OBJECT) {
	Tcl_AppendResult(interp,
		"may not modify the superclass of the root object", NULL);

	return TCL_ERROR;
    }

    /*
     * Allocate some working space.
     */








>





>







1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
    oPtr = (Object *) TclOOGetDefineCmdContext(interp);
    if (oPtr == NULL) {
	return TCL_ERROR;
    }
    if (oPtr->classPtr == NULL) {
	Tcl_AppendResult(interp, "only classes may have superclasses defined",
		NULL);
	Tcl_SetErrorCode(interp, "TCL", "OO", "OBJECT_NOT_CLASS", NULL);
	return TCL_ERROR;
    }
    if (oPtr->flags & ROOT_OBJECT) {
	Tcl_AppendResult(interp,
		"may not modify the superclass of the root object", NULL);
	Tcl_SetErrorCode(interp, "TCL", "OO", "MONKEY_BUSINESS", NULL);
	return TCL_ERROR;
    }

    /*
     * Allocate some working space.
     */

1692
1693
1694
1695
1696
1697
1698

1699
1700
1701
1702
1703
1704

1705
1706
1707
1708
1709
1710
1711
	if (clsPtr == NULL) {
	    goto failedAfterAlloc;
	}
	for (j=0 ; j<i ; j++) {
	    if (superclasses[j] == clsPtr) {
		Tcl_AppendResult(interp,
			"class should only be a direct superclass once",NULL);

		goto failedAfterAlloc;
	    }
	}
	if (TclOOIsReachable(oPtr->classPtr, clsPtr)) {
	    Tcl_AppendResult(interp,
		    "attempt to form circular dependency graph", NULL);

	failedAfterAlloc:
	    ckfree(superclasses);
	    return TCL_ERROR;
	}
	superclasses[i] = clsPtr;
    }








>






>







1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
	if (clsPtr == NULL) {
	    goto failedAfterAlloc;
	}
	for (j=0 ; j<i ; j++) {
	    if (superclasses[j] == clsPtr) {
		Tcl_AppendResult(interp,
			"class should only be a direct superclass once",NULL);
		Tcl_SetErrorCode(interp, "TCL", "OO", "REPETITIOUS", NULL);
		goto failedAfterAlloc;
	    }
	}
	if (TclOOIsReachable(oPtr->classPtr, clsPtr)) {
	    Tcl_AppendResult(interp,
		    "attempt to form circular dependency graph", NULL);
	    Tcl_SetErrorCode(interp, "TCL", "OO", "CIRCULARITY", NULL);
	failedAfterAlloc:
	    ckfree(superclasses);
	    return TCL_ERROR;
	}
	superclasses[i] = clsPtr;
    }

1764
1765
1766
1767
1768
1769
1770

1771
1772
1773
1774
1775
1776
1777
    oPtr = (Object *) TclOOGetDefineCmdContext(interp);
    if (oPtr == NULL) {
	return TCL_ERROR;
    }
    clsPtr = oPtr->classPtr;
    if (!isInstanceUnexport && !clsPtr) {
	Tcl_AppendResult(interp, "attempt to misuse API", NULL);

	return TCL_ERROR;
    }

    for (i=1 ; i<objc ; i++) {
	/*
	 * Unexporting is done by removing the PUBLIC_METHOD flag from the
	 * method record. If there is no such method in this object or class







>







1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
    oPtr = (Object *) TclOOGetDefineCmdContext(interp);
    if (oPtr == NULL) {
	return TCL_ERROR;
    }
    clsPtr = oPtr->classPtr;
    if (!isInstanceUnexport && !clsPtr) {
	Tcl_AppendResult(interp, "attempt to misuse API", NULL);
	Tcl_SetErrorCode(interp, "TCL", "OO", "MONKEY_BUSINESS", NULL);
	return TCL_ERROR;
    }

    for (i=1 ; i<objc ; i++) {
	/*
	 * Unexporting is done by removing the PUBLIC_METHOD flag from the
	 * method record. If there is no such method in this object or class
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
    int i;

    if (oPtr == NULL) {
	return TCL_ERROR;
    }
    if (!isInstanceVars && !oPtr->classPtr) {
	Tcl_AppendResult(interp, "attempt to misuse API", NULL);

	return TCL_ERROR;
    }

    for (i=1 ; i<objc ; i++) {
	const char *varName = Tcl_GetString(objv[i]);

	if (strstr(varName, "::") != NULL) {
	    Tcl_AppendResult(interp, "invalid declared variable name \"",
		    varName, "\": must not contain namespace separators",
		    NULL);

	    return TCL_ERROR;
	}
	if (Tcl_StringMatch(varName, "*(*)")) {
	    Tcl_AppendResult(interp, "invalid declared variable name \"",
		    varName, "\": must not refer to an array element", NULL);

	    return TCL_ERROR;
	}
    }
    for (i=1 ; i<objc ; i++) {
	Tcl_IncrRefCount(objv[i]);
    }








>










>





>







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
    int i;

    if (oPtr == NULL) {
	return TCL_ERROR;
    }
    if (!isInstanceVars && !oPtr->classPtr) {
	Tcl_AppendResult(interp, "attempt to misuse API", NULL);
	Tcl_SetErrorCode(interp, "TCL", "OO", "MONKEY_BUSINESS", NULL);
	return TCL_ERROR;
    }

    for (i=1 ; i<objc ; i++) {
	const char *varName = Tcl_GetString(objv[i]);

	if (strstr(varName, "::") != NULL) {
	    Tcl_AppendResult(interp, "invalid declared variable name \"",
		    varName, "\": must not contain namespace separators",
		    NULL);
	    Tcl_SetErrorCode(interp, "TCL", "OO", "BAD_DECLVAR", NULL);
	    return TCL_ERROR;
	}
	if (Tcl_StringMatch(varName, "*(*)")) {
	    Tcl_AppendResult(interp, "invalid declared variable name \"",
		    varName, "\": must not refer to an array element", NULL);
	    Tcl_SetErrorCode(interp, "TCL", "OO", "BAD_DECLVAR", NULL);
	    return TCL_ERROR;
	}
    }
    for (i=1 ; i<objc ; i++) {
	Tcl_IncrRefCount(objv[i]);
    }

Changes to generic/tclOOInfo.c.

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
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "tclInt.h"
#include "tclOOInt.h"

static inline Class *	GetClassFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr);

static Tcl_ObjCmdProc InfoObjectClassCmd;
static Tcl_ObjCmdProc InfoObjectDefnCmd;
static Tcl_ObjCmdProc InfoObjectFiltersCmd;
static Tcl_ObjCmdProc InfoObjectForwardCmd;
static Tcl_ObjCmdProc InfoObjectIsACmd;
static Tcl_ObjCmdProc InfoObjectMethodsCmd;
static Tcl_ObjCmdProc InfoObjectMethodTypeCmd;
static Tcl_ObjCmdProc InfoObjectMixinsCmd;
static Tcl_ObjCmdProc InfoObjectNsCmd;
static Tcl_ObjCmdProc InfoObjectVarsCmd;
static Tcl_ObjCmdProc InfoObjectVariablesCmd;

static Tcl_ObjCmdProc InfoClassConstrCmd;
static Tcl_ObjCmdProc InfoClassDefnCmd;
static Tcl_ObjCmdProc InfoClassDestrCmd;
static Tcl_ObjCmdProc InfoClassFiltersCmd;
static Tcl_ObjCmdProc InfoClassForwardCmd;
static Tcl_ObjCmdProc InfoClassInstancesCmd;
static Tcl_ObjCmdProc InfoClassMethodsCmd;
static Tcl_ObjCmdProc InfoClassMethodTypeCmd;
static Tcl_ObjCmdProc InfoClassMixinsCmd;
static Tcl_ObjCmdProc InfoClassSubsCmd;
static Tcl_ObjCmdProc InfoClassSupersCmd;
static Tcl_ObjCmdProc InfoClassVariablesCmd;

struct NameProcMap { const char *name; Tcl_ObjCmdProc *proc; };

/*
 * List of commands that are used to implement the [info object] subcommands.
 */

static const struct NameProcMap infoObjectCmds[] = {

    {"::oo::InfoObject::class",		InfoObjectClassCmd},
    {"::oo::InfoObject::definition",	InfoObjectDefnCmd},
    {"::oo::InfoObject::filters",	InfoObjectFiltersCmd},
    {"::oo::InfoObject::forward",	InfoObjectForwardCmd},
    {"::oo::InfoObject::isa",		InfoObjectIsACmd},
    {"::oo::InfoObject::methods",	InfoObjectMethodsCmd},
    {"::oo::InfoObject::methodtype",	InfoObjectMethodTypeCmd},
    {"::oo::InfoObject::mixins",	InfoObjectMixinsCmd},
    {"::oo::InfoObject::namespace",	InfoObjectNsCmd},
    {"::oo::InfoObject::variables",	InfoObjectVariablesCmd},
    {"::oo::InfoObject::vars",		InfoObjectVarsCmd},
    {NULL, NULL}
};

/*
 * List of commands that are used to implement the [info class] subcommands.
 */

static const struct NameProcMap infoClassCmds[] = {

    {"::oo::InfoClass::constructor",	InfoClassConstrCmd},
    {"::oo::InfoClass::definition",	InfoClassDefnCmd},
    {"::oo::InfoClass::destructor",	InfoClassDestrCmd},
    {"::oo::InfoClass::filters",	InfoClassFiltersCmd},
    {"::oo::InfoClass::forward",	InfoClassForwardCmd},
    {"::oo::InfoClass::instances",	InfoClassInstancesCmd},
    {"::oo::InfoClass::methods",	InfoClassMethodsCmd},







>











>




















>



















>







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
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "tclInt.h"
#include "tclOOInt.h"

static inline Class *	GetClassFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr);
static Tcl_ObjCmdProc InfoObjectCallCmd;
static Tcl_ObjCmdProc InfoObjectClassCmd;
static Tcl_ObjCmdProc InfoObjectDefnCmd;
static Tcl_ObjCmdProc InfoObjectFiltersCmd;
static Tcl_ObjCmdProc InfoObjectForwardCmd;
static Tcl_ObjCmdProc InfoObjectIsACmd;
static Tcl_ObjCmdProc InfoObjectMethodsCmd;
static Tcl_ObjCmdProc InfoObjectMethodTypeCmd;
static Tcl_ObjCmdProc InfoObjectMixinsCmd;
static Tcl_ObjCmdProc InfoObjectNsCmd;
static Tcl_ObjCmdProc InfoObjectVarsCmd;
static Tcl_ObjCmdProc InfoObjectVariablesCmd;
static Tcl_ObjCmdProc InfoClassCallCmd;
static Tcl_ObjCmdProc InfoClassConstrCmd;
static Tcl_ObjCmdProc InfoClassDefnCmd;
static Tcl_ObjCmdProc InfoClassDestrCmd;
static Tcl_ObjCmdProc InfoClassFiltersCmd;
static Tcl_ObjCmdProc InfoClassForwardCmd;
static Tcl_ObjCmdProc InfoClassInstancesCmd;
static Tcl_ObjCmdProc InfoClassMethodsCmd;
static Tcl_ObjCmdProc InfoClassMethodTypeCmd;
static Tcl_ObjCmdProc InfoClassMixinsCmd;
static Tcl_ObjCmdProc InfoClassSubsCmd;
static Tcl_ObjCmdProc InfoClassSupersCmd;
static Tcl_ObjCmdProc InfoClassVariablesCmd;

struct NameProcMap { const char *name; Tcl_ObjCmdProc *proc; };

/*
 * List of commands that are used to implement the [info object] subcommands.
 */

static const struct NameProcMap infoObjectCmds[] = {
    {"::oo::InfoObject::call",		InfoObjectCallCmd},
    {"::oo::InfoObject::class",		InfoObjectClassCmd},
    {"::oo::InfoObject::definition",	InfoObjectDefnCmd},
    {"::oo::InfoObject::filters",	InfoObjectFiltersCmd},
    {"::oo::InfoObject::forward",	InfoObjectForwardCmd},
    {"::oo::InfoObject::isa",		InfoObjectIsACmd},
    {"::oo::InfoObject::methods",	InfoObjectMethodsCmd},
    {"::oo::InfoObject::methodtype",	InfoObjectMethodTypeCmd},
    {"::oo::InfoObject::mixins",	InfoObjectMixinsCmd},
    {"::oo::InfoObject::namespace",	InfoObjectNsCmd},
    {"::oo::InfoObject::variables",	InfoObjectVariablesCmd},
    {"::oo::InfoObject::vars",		InfoObjectVarsCmd},
    {NULL, NULL}
};

/*
 * List of commands that are used to implement the [info class] subcommands.
 */

static const struct NameProcMap infoClassCmds[] = {
    {"::oo::InfoClass::call",		InfoClassCallCmd},
    {"::oo::InfoClass::constructor",	InfoClassConstrCmd},
    {"::oo::InfoClass::definition",	InfoClassDefnCmd},
    {"::oo::InfoClass::destructor",	InfoClassDestrCmd},
    {"::oo::InfoClass::filters",	InfoClassFiltersCmd},
    {"::oo::InfoClass::forward",	InfoClassForwardCmd},
    {"::oo::InfoClass::instances",	InfoClassInstancesCmd},
    {"::oo::InfoClass::methods",	InfoClassMethodsCmd},
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
    }

    if (objc == 2) {
	Tcl_SetObjResult(interp,
		TclOOObjectName(interp, oPtr->selfCls->thisPtr));
	return TCL_OK;
    } else {
	Object *o2Ptr;
	Class *mixinPtr;
	int i;

	o2Ptr = (Object *) Tcl_GetObjectFromObj(interp, objv[2]);
	if (o2Ptr == NULL) {
	    return TCL_ERROR;
	}
	if (o2Ptr->classPtr == NULL) {
	    Tcl_AppendResult(interp, "object \"", TclGetString(objv[2]),
		    "\" is not a class", NULL);
	    Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "CLASS",
		    TclGetString(objv[2]), NULL);
	    return TCL_ERROR;
	}

	FOREACH(mixinPtr, oPtr->mixins) {
	    if (TclOOIsReachable(o2Ptr->classPtr, mixinPtr)) {
		Tcl_SetObjResult(interp, Tcl_NewIntObj(1));
		return TCL_OK;
	    }
	}
	Tcl_SetObjResult(interp, Tcl_NewIntObj(
		TclOOIsReachable(o2Ptr->classPtr, oPtr->selfCls)));
	return TCL_OK;
    }
}

/*
 * ----------------------------------------------------------------------
 *







<
|


|
|
<
<
<
<
<
<
<




|





|







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
    }

    if (objc == 2) {
	Tcl_SetObjResult(interp,
		TclOOObjectName(interp, oPtr->selfCls->thisPtr));
	return TCL_OK;
    } else {

	Class *mixinPtr, *o2clsPtr;
	int i;

	o2clsPtr = GetClassFromObj(interp, objv[2]);
	if (o2clsPtr == NULL) {







	    return TCL_ERROR;
	}

	FOREACH(mixinPtr, oPtr->mixins) {
	    if (TclOOIsReachable(o2clsPtr, mixinPtr)) {
		Tcl_SetObjResult(interp, Tcl_NewIntObj(1));
		return TCL_OK;
	    }
	}
	Tcl_SetObjResult(interp, Tcl_NewIntObj(
		TclOOIsReachable(o2clsPtr, oPtr->selfCls)));
	return TCL_OK;
    }
}

/*
 * ----------------------------------------------------------------------
 *
492
493
494
495
496
497
498

499
500
501
502
503
504
505
	}
	o2Ptr = (Object *) Tcl_GetObjectFromObj(interp, objv[3]);
	if (o2Ptr == NULL) {
	    return TCL_ERROR;
	}
	if (o2Ptr->classPtr == NULL) {
	    Tcl_AppendResult(interp, "non-classes cannot be mixins", NULL);

	    return TCL_ERROR;
	} else {
	    Class *mixinPtr;

	    FOREACH(mixinPtr, oPtr->mixins) {
		if (mixinPtr == o2Ptr->classPtr) {
		    Tcl_SetObjResult(interp, Tcl_NewIntObj(1));







>







488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
	}
	o2Ptr = (Object *) Tcl_GetObjectFromObj(interp, objv[3]);
	if (o2Ptr == NULL) {
	    return TCL_ERROR;
	}
	if (o2Ptr->classPtr == NULL) {
	    Tcl_AppendResult(interp, "non-classes cannot be mixins", NULL);
	    Tcl_SetErrorCode(interp, "TCL", "OO", "NONCLASS", NULL);
	    return TCL_ERROR;
	} else {
	    Class *mixinPtr;

	    FOREACH(mixinPtr, oPtr->mixins) {
		if (mixinPtr == o2Ptr->classPtr) {
		    Tcl_SetObjResult(interp, Tcl_NewIntObj(1));
516
517
518
519
520
521
522

523
524
525
526
527
528
529
	}
	o2Ptr = (Object *) Tcl_GetObjectFromObj(interp, objv[3]);
	if (o2Ptr == NULL) {
	    return TCL_ERROR;
	}
	if (o2Ptr->classPtr == NULL) {
	    Tcl_AppendResult(interp, "non-classes cannot be types", NULL);

	    return TCL_ERROR;
	}
	if (TclOOIsReachable(o2Ptr->classPtr, oPtr->selfCls)) {
	    Tcl_SetObjResult(interp, Tcl_NewIntObj(1));
	} else {
	    Tcl_SetObjResult(interp, Tcl_NewIntObj(0));
	}







>







513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
	}
	o2Ptr = (Object *) Tcl_GetObjectFromObj(interp, objv[3]);
	if (o2Ptr == NULL) {
	    return TCL_ERROR;
	}
	if (o2Ptr->classPtr == NULL) {
	    Tcl_AppendResult(interp, "non-classes cannot be types", NULL);
	    Tcl_SetErrorCode(interp, "TCL", "OO", "NONCLASS", NULL);
	    return TCL_ERROR;
	}
	if (TclOOIsReachable(o2Ptr->classPtr, oPtr->selfCls)) {
	    Tcl_SetObjResult(interp, Tcl_NewIntObj(1));
	} else {
	    Tcl_SetObjResult(interp, Tcl_NewIntObj(0));
	}
878
879
880
881
882
883
884

885
886
887
888
889
890
891
    if (clsPtr->constructorPtr == NULL) {
	return TCL_OK;
    }
    procPtr = TclOOGetProcFromMethod(clsPtr->constructorPtr);
    if (procPtr == NULL) {
	Tcl_AppendResult(interp,
		"definition not available for this kind of method", NULL);

	return TCL_ERROR;
    }

    resultObjs[0] = Tcl_NewObj();
    for (localPtr=procPtr->firstLocalPtr; localPtr!=NULL;
	    localPtr=localPtr->nextPtr) {
	if (TclIsVarArgument(localPtr)) {







>







876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
    if (clsPtr->constructorPtr == NULL) {
	return TCL_OK;
    }
    procPtr = TclOOGetProcFromMethod(clsPtr->constructorPtr);
    if (procPtr == NULL) {
	Tcl_AppendResult(interp,
		"definition not available for this kind of method", NULL);
	Tcl_SetErrorCode(interp, "TCL", "OO", "METHOD_TYPE", NULL);
	return TCL_ERROR;
    }

    resultObjs[0] = Tcl_NewObj();
    for (localPtr=procPtr->firstLocalPtr; localPtr!=NULL;
	    localPtr=localPtr->nextPtr) {
	if (TclIsVarArgument(localPtr)) {
1005
1006
1007
1008
1009
1010
1011

1012
1013
1014
1015
1016
1017
1018
    if (clsPtr->destructorPtr == NULL) {
	return TCL_OK;
    }
    procPtr = TclOOGetProcFromMethod(clsPtr->destructorPtr);
    if (procPtr == NULL) {
	Tcl_AppendResult(interp,
		"definition not available for this kind of method", NULL);

	return TCL_ERROR;
    }

    Tcl_SetObjResult(interp, TclOOGetMethodBody(clsPtr->destructorPtr));
    return TCL_OK;
}








>







1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
    if (clsPtr->destructorPtr == NULL) {
	return TCL_OK;
    }
    procPtr = TclOOGetProcFromMethod(clsPtr->destructorPtr);
    if (procPtr == NULL) {
	Tcl_AppendResult(interp,
		"definition not available for this kind of method", NULL);
	Tcl_SetErrorCode(interp, "TCL", "OO", "METHOD_TYPE", NULL);
	return TCL_ERROR;
    }

    Tcl_SetObjResult(interp, TclOOGetMethodBody(clsPtr->destructorPtr));
    return TCL_OK;
}

1454
1455
1456
1457
1458
1459
1460
1461
1462























































































1463
1464
1465
1466
1467
1468
    resultObj = Tcl_NewObj();
    FOREACH(variableObj, clsPtr->variables) {
	Tcl_ListObjAppendElement(NULL, resultObj, variableObj);
    }
    Tcl_SetObjResult(interp, resultObj);
    return TCL_OK;
}

/*























































































 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78
 * End:
 */









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






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
    resultObj = Tcl_NewObj();
    FOREACH(variableObj, clsPtr->variables) {
	Tcl_ListObjAppendElement(NULL, resultObj, variableObj);
    }
    Tcl_SetObjResult(interp, resultObj);
    return TCL_OK;
}

/*
 * ----------------------------------------------------------------------
 *
 * InfoObjectCallCmd --
 *
 *	Implements [info object call $objName $methodName]
 *
 * ----------------------------------------------------------------------
 */

static int
InfoObjectCallCmd(
    ClientData clientData,
    Tcl_Interp *interp,
    int objc,
    Tcl_Obj *const objv[])
{
    Object *oPtr;
    CallContext *contextPtr;

    if (objc != 3) {
	Tcl_WrongNumArgs(interp, 1, objv, "objName methodName");
	return TCL_ERROR;
    }
    oPtr = (Object *) Tcl_GetObjectFromObj(interp, objv[1]);
    if (oPtr == NULL) {
	return TCL_ERROR;
    }

    /*
     * Get the call context and render its call chain.
     */

    contextPtr = TclOOGetCallContext(oPtr, objv[2], PUBLIC_METHOD, NULL);
    if (contextPtr == NULL) {
	Tcl_AppendResult(interp, "cannot construct any call chain", NULL);
	return TCL_ERROR;
    }
    Tcl_SetObjResult(interp,
	    TclOORenderCallChain(interp, contextPtr->callPtr));
    TclOODeleteContext(contextPtr);
    return TCL_OK;
}

/*
 * ----------------------------------------------------------------------
 *
 * InfoClassCallCmd --
 *
 *	Implements [info class call $clsName $methodName]
 *
 * ----------------------------------------------------------------------
 */

static int
InfoClassCallCmd(
    ClientData clientData,
    Tcl_Interp *interp,
    int objc,
    Tcl_Obj *const objv[])
{
    Class *clsPtr;
    CallChain *callPtr;

    if (objc != 3) {
	Tcl_WrongNumArgs(interp, 1, objv, "className methodName");
	return TCL_ERROR;
    }
    clsPtr = GetClassFromObj(interp, objv[1]);
    if (clsPtr == NULL) {
	return TCL_ERROR;
    }

    /*
     * Get an render the stereotypical call chain.
     */

    callPtr = TclOOGetStereotypeCallChain(clsPtr, objv[2], PUBLIC_METHOD);
    if (callPtr == NULL) {
	Tcl_AppendResult(interp, "cannot construct any call chain", NULL);
	return TCL_ERROR;
    }
    Tcl_SetObjResult(interp, TclOORenderCallChain(interp, callPtr));
    TclOODeleteChain(callPtr);
    return TCL_OK;
}

/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78
 * End:
 */

Changes to generic/tclOOInt.h.

460
461
462
463
464
465
466



467
468
469
470
471
472
473
			    Tcl_Interp *interp, int objc,
			    Tcl_Obj *const *objv);
MODULE_SCOPE int	TclOOCopyObjectCmd(ClientData clientData,
			    Tcl_Interp *interp, int objc,
			    Tcl_Obj *const *objv);
MODULE_SCOPE int	TclOONextObjCmd(ClientData clientData,
			    Tcl_Interp *interp, int objc,



			    Tcl_Obj *const *objv);
MODULE_SCOPE int	TclOOSelfObjCmd(ClientData clientData,
			    Tcl_Interp *interp, int objc,
			    Tcl_Obj *const *objv);

/*
 * Method implementations (in tclOOBasic.c).







>
>
>







460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
			    Tcl_Interp *interp, int objc,
			    Tcl_Obj *const *objv);
MODULE_SCOPE int	TclOOCopyObjectCmd(ClientData clientData,
			    Tcl_Interp *interp, int objc,
			    Tcl_Obj *const *objv);
MODULE_SCOPE int	TclOONextObjCmd(ClientData clientData,
			    Tcl_Interp *interp, int objc,
			    Tcl_Obj *const *objv);
MODULE_SCOPE int	TclOONextToObjCmd(ClientData clientData,
			    Tcl_Interp *interp, int objc,
			    Tcl_Obj *const *objv);
MODULE_SCOPE int	TclOOSelfObjCmd(ClientData clientData,
			    Tcl_Interp *interp, int objc,
			    Tcl_Obj *const *objv);

/*
 * Method implementations (in tclOOBasic.c).
514
515
516
517
518
519
520


521
522
523
524
525
526
527
MODULE_SCOPE void	TclOODeleteChain(CallChain *callPtr);
MODULE_SCOPE void	TclOODeleteChainCache(Tcl_HashTable *tablePtr);
MODULE_SCOPE void	TclOODeleteContext(CallContext *contextPtr);
MODULE_SCOPE void	TclOODelMethodRef(Method *method);
MODULE_SCOPE CallContext *TclOOGetCallContext(Object *oPtr,
			    Tcl_Obj *methodNameObj, int flags,
			    Tcl_Obj *cacheInThisObj);


MODULE_SCOPE Foundation	*TclOOGetFoundation(Tcl_Interp *interp);
MODULE_SCOPE Tcl_Obj *	TclOOGetFwdFromMethod(Method *mPtr);
MODULE_SCOPE Proc *	TclOOGetProcFromMethod(Method *mPtr);
MODULE_SCOPE Tcl_Obj *	TclOOGetMethodBody(Method *mPtr);
MODULE_SCOPE int	TclOOGetSortedClassMethodList(Class *clsPtr,
			    int flags, const char ***stringsPtr);
MODULE_SCOPE int	TclOOGetSortedMethodList(Object *oPtr, int flags,







>
>







517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
MODULE_SCOPE void	TclOODeleteChain(CallChain *callPtr);
MODULE_SCOPE void	TclOODeleteChainCache(Tcl_HashTable *tablePtr);
MODULE_SCOPE void	TclOODeleteContext(CallContext *contextPtr);
MODULE_SCOPE void	TclOODelMethodRef(Method *method);
MODULE_SCOPE CallContext *TclOOGetCallContext(Object *oPtr,
			    Tcl_Obj *methodNameObj, int flags,
			    Tcl_Obj *cacheInThisObj);
MODULE_SCOPE CallChain *TclOOGetStereotypeCallChain(Class *clsPtr,
			    Tcl_Obj *methodNameObj, int flags);
MODULE_SCOPE Foundation	*TclOOGetFoundation(Tcl_Interp *interp);
MODULE_SCOPE Tcl_Obj *	TclOOGetFwdFromMethod(Method *mPtr);
MODULE_SCOPE Proc *	TclOOGetProcFromMethod(Method *mPtr);
MODULE_SCOPE Tcl_Obj *	TclOOGetMethodBody(Method *mPtr);
MODULE_SCOPE int	TclOOGetSortedClassMethodList(Class *clsPtr,
			    int flags, const char ***stringsPtr);
MODULE_SCOPE int	TclOOGetSortedMethodList(Object *oPtr, int flags,
540
541
542
543
544
545
546


547
548
549
550
551
552
553
			    int objc, Tcl_Obj *const objv[]);
MODULE_SCOPE Tcl_Obj *	TclOOObjectName(Tcl_Interp *interp, Object *oPtr);
MODULE_SCOPE void	TclOORemoveFromInstances(Object *oPtr, Class *clsPtr);
MODULE_SCOPE void	TclOORemoveFromMixinSubs(Class *subPtr,
			    Class *mixinPtr);
MODULE_SCOPE void	TclOORemoveFromSubclasses(Class *subPtr,
			    Class *superPtr);


MODULE_SCOPE void	TclOOStashContext(Tcl_Obj *objPtr,
			    CallContext *contextPtr);
MODULE_SCOPE void	TclOOSetupVariableResolver(Tcl_Namespace *nsPtr);
MODULE_SCOPE int	TclOOUpcatchCmd(ClientData ignored,
			    Tcl_Interp *interp, int objc,
			    Tcl_Obj *const objv[]);








>
>







545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
			    int objc, Tcl_Obj *const objv[]);
MODULE_SCOPE Tcl_Obj *	TclOOObjectName(Tcl_Interp *interp, Object *oPtr);
MODULE_SCOPE void	TclOORemoveFromInstances(Object *oPtr, Class *clsPtr);
MODULE_SCOPE void	TclOORemoveFromMixinSubs(Class *subPtr,
			    Class *mixinPtr);
MODULE_SCOPE void	TclOORemoveFromSubclasses(Class *subPtr,
			    Class *superPtr);
MODULE_SCOPE Tcl_Obj *	TclOORenderCallChain(Tcl_Interp *interp,
			    CallChain *callPtr);
MODULE_SCOPE void	TclOOStashContext(Tcl_Obj *objPtr,
			    CallContext *contextPtr);
MODULE_SCOPE void	TclOOSetupVariableResolver(Tcl_Namespace *nsPtr);
MODULE_SCOPE int	TclOOUpcatchCmd(ClientData ignored,
			    Tcl_Interp *interp, int objc,
			    Tcl_Obj *const objv[]);


Changes to generic/tclOOIntDecls.h.

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
/*
 * This file is (mostly) automatically generated from tclOO.decls.
 */

#ifndef _TCLOOINTDECLS
#define _TCLOOINTDECLS

#undef TCL_STORAGE_CLASS
#ifdef BUILD_tcl
#   define TCL_STORAGE_CLASS DLLEXPORT
#else
#   ifdef USE_TCL_STUBS
#      define TCL_STORAGE_CLASS
#   else
#      define TCL_STORAGE_CLASS DLLIMPORT
#   endif
#endif

/*
 * WARNING: This file is automatically generated by the tools/genStubs.tcl
 * script.  Any modifications to the function declarations below should be made
 * in the generic/tclOO.decls script.
 */

/* !BEGIN!: Do not edit below this line. */

/*
 * Exported function declarations:
 */

/* 0 */
EXTERN Tcl_Object	TclOOGetDefineCmdContext(Tcl_Interp *interp);
/* 1 */
EXTERN Tcl_Method	TclOOMakeProcInstanceMethod(Tcl_Interp *interp,
				Object *oPtr, int flags, Tcl_Obj *nameObj,
				Tcl_Obj *argsObj, Tcl_Obj *bodyObj,
				const Tcl_MethodType *typePtr,
				ClientData clientData, Proc **procPtrPtr);
/* 2 */
EXTERN Tcl_Method	TclOOMakeProcMethod(Tcl_Interp *interp,
				Class *clsPtr, int flags, Tcl_Obj *nameObj,
				const char *namePtr, Tcl_Obj *argsObj,
				Tcl_Obj *bodyObj,
				const Tcl_MethodType *typePtr,
				ClientData clientData, Proc **procPtrPtr);
/* 3 */
EXTERN Method *		TclOONewProcInstanceMethod(Tcl_Interp *interp,
				Object *oPtr, int flags, Tcl_Obj *nameObj,
				Tcl_Obj *argsObj, Tcl_Obj *bodyObj,
				ProcedureMethod **pmPtrPtr);
/* 4 */
EXTERN Method *		TclOONewProcMethod(Tcl_Interp *interp, Class *clsPtr,
				int flags, Tcl_Obj *nameObj,
				Tcl_Obj *argsObj, Tcl_Obj *bodyObj,
				ProcedureMethod **pmPtrPtr);
/* 5 */
EXTERN int		TclOOObjectCmdCore(Object *oPtr, Tcl_Interp *interp,
				int objc, Tcl_Obj *const *objv,
				int publicOnly, Class *startCls);
/* 6 */
EXTERN int		TclOOIsReachable(Class *targetPtr, Class *startPtr);
/* 7 */
EXTERN Method *		TclOONewForwardMethod(Tcl_Interp *interp,
				Class *clsPtr, int isPublic,
				Tcl_Obj *nameObj, Tcl_Obj *prefixObj);
/* 8 */
EXTERN Method *		TclOONewForwardInstanceMethod(Tcl_Interp *interp,
				Object *oPtr, int isPublic, Tcl_Obj *nameObj,
				Tcl_Obj *prefixObj);
/* 9 */
EXTERN Tcl_Method	TclOONewProcInstanceMethodEx(Tcl_Interp *interp,
				Tcl_Object oPtr,
				TclOO_PreCallProc *preCallPtr,
				TclOO_PostCallProc *postCallPtr,
				ProcErrorProc *errProc,
				ClientData clientData, Tcl_Obj *nameObj,
				Tcl_Obj *argsObj, Tcl_Obj *bodyObj,
				int flags, void **internalTokenPtr);
/* 10 */
EXTERN Tcl_Method	TclOONewProcMethodEx(Tcl_Interp *interp,
				Tcl_Class clsPtr,
				TclOO_PreCallProc *preCallPtr,
				TclOO_PostCallProc *postCallPtr,
				ProcErrorProc *errProc,
				ClientData clientData, Tcl_Obj *nameObj,
				Tcl_Obj *argsObj, Tcl_Obj *bodyObj,
				int flags, void **internalTokenPtr);
/* 11 */
EXTERN int		TclOOInvokeObject(Tcl_Interp *interp,
				Tcl_Object object, Tcl_Class startCls,
				int publicPrivate, int objc,
				Tcl_Obj *const *objv);
/* 12 */
EXTERN void		TclOOObjectSetFilters(Object *oPtr, int numFilters,
				Tcl_Obj *const *filters);
/* 13 */
EXTERN void		TclOOClassSetFilters(Tcl_Interp *interp,
				Class *classPtr, int numFilters,
				Tcl_Obj *const *filters);
/* 14 */
EXTERN void		TclOOObjectSetMixins(Object *oPtr, int numMixins,
				Class *const *mixins);
/* 15 */
EXTERN void		TclOOClassSetMixins(Tcl_Interp *interp,
				Class *classPtr, int numMixins,
				Class *const *mixins);

typedef struct TclOOIntStubs {
    int magic;
    const struct TclOOIntStubHooks *hooks;








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







|

|





|






|




|




|



|

|



|



|








|








|




|


|



|


|







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
/*
 * This file is (mostly) automatically generated from tclOO.decls.
 */

#ifndef _TCLOOINTDECLS
#define _TCLOOINTDECLS


















/* !BEGIN!: Do not edit below this line. */

/*
 * Exported function declarations:
 */

/* 0 */
TCLOOAPI Tcl_Object	TclOOGetDefineCmdContext(Tcl_Interp *interp);
/* 1 */
TCLOOAPI Tcl_Method	TclOOMakeProcInstanceMethod(Tcl_Interp *interp,
				Object *oPtr, int flags, Tcl_Obj *nameObj,
				Tcl_Obj *argsObj, Tcl_Obj *bodyObj,
				const Tcl_MethodType *typePtr,
				ClientData clientData, Proc **procPtrPtr);
/* 2 */
TCLOOAPI Tcl_Method	TclOOMakeProcMethod(Tcl_Interp *interp,
				Class *clsPtr, int flags, Tcl_Obj *nameObj,
				const char *namePtr, Tcl_Obj *argsObj,
				Tcl_Obj *bodyObj,
				const Tcl_MethodType *typePtr,
				ClientData clientData, Proc **procPtrPtr);
/* 3 */
TCLOOAPI Method *	TclOONewProcInstanceMethod(Tcl_Interp *interp,
				Object *oPtr, int flags, Tcl_Obj *nameObj,
				Tcl_Obj *argsObj, Tcl_Obj *bodyObj,
				ProcedureMethod **pmPtrPtr);
/* 4 */
TCLOOAPI Method *	TclOONewProcMethod(Tcl_Interp *interp, Class *clsPtr,
				int flags, Tcl_Obj *nameObj,
				Tcl_Obj *argsObj, Tcl_Obj *bodyObj,
				ProcedureMethod **pmPtrPtr);
/* 5 */
TCLOOAPI int		TclOOObjectCmdCore(Object *oPtr, Tcl_Interp *interp,
				int objc, Tcl_Obj *const *objv,
				int publicOnly, Class *startCls);
/* 6 */
TCLOOAPI int		TclOOIsReachable(Class *targetPtr, Class *startPtr);
/* 7 */
TCLOOAPI Method *	TclOONewForwardMethod(Tcl_Interp *interp,
				Class *clsPtr, int isPublic,
				Tcl_Obj *nameObj, Tcl_Obj *prefixObj);
/* 8 */
TCLOOAPI Method *	TclOONewForwardInstanceMethod(Tcl_Interp *interp,
				Object *oPtr, int isPublic, Tcl_Obj *nameObj,
				Tcl_Obj *prefixObj);
/* 9 */
TCLOOAPI Tcl_Method	TclOONewProcInstanceMethodEx(Tcl_Interp *interp,
				Tcl_Object oPtr,
				TclOO_PreCallProc *preCallPtr,
				TclOO_PostCallProc *postCallPtr,
				ProcErrorProc *errProc,
				ClientData clientData, Tcl_Obj *nameObj,
				Tcl_Obj *argsObj, Tcl_Obj *bodyObj,
				int flags, void **internalTokenPtr);
/* 10 */
TCLOOAPI Tcl_Method	TclOONewProcMethodEx(Tcl_Interp *interp,
				Tcl_Class clsPtr,
				TclOO_PreCallProc *preCallPtr,
				TclOO_PostCallProc *postCallPtr,
				ProcErrorProc *errProc,
				ClientData clientData, Tcl_Obj *nameObj,
				Tcl_Obj *argsObj, Tcl_Obj *bodyObj,
				int flags, void **internalTokenPtr);
/* 11 */
TCLOOAPI int		TclOOInvokeObject(Tcl_Interp *interp,
				Tcl_Object object, Tcl_Class startCls,
				int publicPrivate, int objc,
				Tcl_Obj *const *objv);
/* 12 */
TCLOOAPI void		TclOOObjectSetFilters(Object *oPtr, int numFilters,
				Tcl_Obj *const *filters);
/* 13 */
TCLOOAPI void		TclOOClassSetFilters(Tcl_Interp *interp,
				Class *classPtr, int numFilters,
				Tcl_Obj *const *filters);
/* 14 */
TCLOOAPI void		TclOOObjectSetMixins(Object *oPtr, int numMixins,
				Class *const *mixins);
/* 15 */
TCLOOAPI void		TclOOClassSetMixins(Tcl_Interp *interp,
				Class *classPtr, int numMixins,
				Class *const *mixins);

typedef struct TclOOIntStubs {
    int magic;
    const struct TclOOIntStubHooks *hooks;

173
174
175
176
177
178
179
180
181
182
183
184
	(tclOOIntStubsPtr->tclOOObjectSetMixins) /* 14 */
#define TclOOClassSetMixins \
	(tclOOIntStubsPtr->tclOOClassSetMixins) /* 15 */

#endif /* defined(USE_TCLOO_STUBS) */

/* !END!: Do not edit above this line. */

#undef TCL_STORAGE_CLASS
#define TCL_STORAGE_CLASS DLLIMPORT

#endif /* _TCLOOINTDECLS */







<
<
<
<

156
157
158
159
160
161
162




163
	(tclOOIntStubsPtr->tclOOObjectSetMixins) /* 14 */
#define TclOOClassSetMixins \
	(tclOOIntStubsPtr->tclOOClassSetMixins) /* 15 */

#endif /* defined(USE_TCLOO_STUBS) */

/* !END!: Do not edit above this line. */




#endif /* _TCLOOINTDECLS */

Changes to generic/tclOOMethod.c.

1336
1337
1338
1339
1340
1341
1342

1343
1344
1345
1346
1347
1348
1349

    if (Tcl_ListObjLength(interp, prefixObj, &prefixLen) != TCL_OK) {
	return NULL;
    }
    if (prefixLen < 1) {
	Tcl_AppendResult(interp, "method forward prefix must be non-empty",
		NULL);

	return NULL;
    }

    fmPtr = ckalloc(sizeof(ForwardMethod));
    fmPtr->prefixObj = prefixObj;
    Tcl_ListObjIndex(interp, prefixObj, 0, &cmdObj);
    fmPtr->fullyQualified = (strncmp(TclGetString(cmdObj), "::", 2) == 0);







>







1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350

    if (Tcl_ListObjLength(interp, prefixObj, &prefixLen) != TCL_OK) {
	return NULL;
    }
    if (prefixLen < 1) {
	Tcl_AppendResult(interp, "method forward prefix must be non-empty",
		NULL);
	Tcl_SetErrorCode(interp, "TCL", "OO", "BAD_FORWARD", NULL);
	return NULL;
    }

    fmPtr = ckalloc(sizeof(ForwardMethod));
    fmPtr->prefixObj = prefixObj;
    Tcl_ListObjIndex(interp, prefixObj, 0, &cmdObj);
    fmPtr->fullyQualified = (strncmp(TclGetString(cmdObj), "::", 2) == 0);
1377
1378
1379
1380
1381
1382
1383

1384
1385
1386
1387
1388
1389
1390

    if (Tcl_ListObjLength(interp, prefixObj, &prefixLen) != TCL_OK) {
	return NULL;
    }
    if (prefixLen < 1) {
	Tcl_AppendResult(interp, "method forward prefix must be non-empty",
		NULL);

	return NULL;
    }

    fmPtr = ckalloc(sizeof(ForwardMethod));
    fmPtr->prefixObj = prefixObj;
    Tcl_ListObjIndex(interp, prefixObj, 0, &cmdObj);
    fmPtr->fullyQualified = (strncmp(TclGetString(cmdObj), "::", 2) == 0);







>







1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392

    if (Tcl_ListObjLength(interp, prefixObj, &prefixLen) != TCL_OK) {
	return NULL;
    }
    if (prefixLen < 1) {
	Tcl_AppendResult(interp, "method forward prefix must be non-empty",
		NULL);
	Tcl_SetErrorCode(interp, "TCL", "OO", "BAD_FORWARD", NULL);
	return NULL;
    }

    fmPtr = ckalloc(sizeof(ForwardMethod));
    fmPtr->prefixObj = prefixObj;
    Tcl_ListObjIndex(interp, prefixObj, 0, &cmdObj);
    fmPtr->fullyQualified = (strncmp(TclGetString(cmdObj), "::", 2) == 0);

Changes to generic/tclObj.c.

1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
    /*
     * This macro declares a variable, so must come here...
     */

    ObjInitDeletionContext(context);

    if (objPtr->refCount < -1) {
	Tcl_Panic("Reference count for %lx was negative", objPtr);
    }

    /*
     * Invalidate the string rep first so we can use the bytes value for our
     * pointer chain, and signal an obj deletion (as opposed to shimmering)
     * with 'length == -1'.
     */







|







1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
    /*
     * This macro declares a variable, so must come here...
     */

    ObjInitDeletionContext(context);

    if (objPtr->refCount < -1) {
	Tcl_Panic("Reference count for %p was negative", objPtr);
    }

    /*
     * Invalidate the string rep first so we can use the bytes value for our
     * pointer chain, and signal an obj deletion (as opposed to shimmering)
     * with 'length == -1'.
     */
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
		return TCL_OK;
	    }
	    goto tooLarge;
	}
#endif
	if (objPtr->typePtr == &tclDoubleType) {
	    if (interp != NULL) {
		Tcl_Obj *msg;

		TclNewLiteralStringObj(msg, "expected integer but got \"");
		Tcl_AppendObjToObj(msg, objPtr);
		Tcl_AppendToObj(msg, "\"", -1);
		Tcl_SetObjResult(interp, msg);
		Tcl_SetErrorCode(interp, "TCL", "VALUE", "INTEGER", NULL);
	    }
	    return TCL_ERROR;
	}
	if (objPtr->typePtr == &tclBignumType) {
	    /*
	     * Must check for those bignum values that can fit in a long, even







<
|
|
|
<
<







2759
2760
2761
2762
2763
2764
2765

2766
2767
2768


2769
2770
2771
2772
2773
2774
2775
		return TCL_OK;
	    }
	    goto tooLarge;
	}
#endif
	if (objPtr->typePtr == &tclDoubleType) {
	    if (interp != NULL) {

                Tcl_SetObjResult(interp, Tcl_ObjPrintf(
                        "expected integer but got \"%s\"",
                        Tcl_GetString(objPtr)));


		Tcl_SetErrorCode(interp, "TCL", "VALUE", "INTEGER", NULL);
	    }
	    return TCL_ERROR;
	}
	if (objPtr->typePtr == &tclBignumType) {
	    /*
	     * Must check for those bignum values that can fit in a long, even
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
#endif
	if (objPtr->typePtr == &tclIntType) {
	    *wideIntPtr = (Tcl_WideInt) objPtr->internalRep.longValue;
	    return TCL_OK;
	}
	if (objPtr->typePtr == &tclDoubleType) {
	    if (interp != NULL) {
		Tcl_Obj *msg;

		TclNewLiteralStringObj(msg, "expected integer but got \"");
		Tcl_AppendObjToObj(msg, objPtr);
		Tcl_AppendToObj(msg, "\"", -1);
		Tcl_SetObjResult(interp, msg);
		Tcl_SetErrorCode(interp, "TCL", "VALUE", "INTEGER", NULL);
	    }
	    return TCL_ERROR;
	}
	if (objPtr->typePtr == &tclBignumType) {
	    /*
	     * Must check for those bignum values that can fit in a







<
|
|
|
<
<







3060
3061
3062
3063
3064
3065
3066

3067
3068
3069


3070
3071
3072
3073
3074
3075
3076
#endif
	if (objPtr->typePtr == &tclIntType) {
	    *wideIntPtr = (Tcl_WideInt) objPtr->internalRep.longValue;
	    return TCL_OK;
	}
	if (objPtr->typePtr == &tclDoubleType) {
	    if (interp != NULL) {

                Tcl_SetObjResult(interp, Tcl_ObjPrintf(
                        "expected integer but got \"%s\"",
                        Tcl_GetString(objPtr)));


		Tcl_SetErrorCode(interp, "TCL", "VALUE", "INTEGER", NULL);
	    }
	    return TCL_ERROR;
	}
	if (objPtr->typePtr == &tclBignumType) {
	    /*
	     * Must check for those bignum values that can fit in a
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
	    TclBNInitBignumFromWideInt(bignumValue,
		    objPtr->internalRep.wideValue);
	    return TCL_OK;
	}
#endif
	if (objPtr->typePtr == &tclDoubleType) {
	    if (interp != NULL) {
		Tcl_Obj *msg;

		TclNewLiteralStringObj(msg, "expected integer but got \"");
		Tcl_AppendObjToObj(msg, objPtr);
		Tcl_AppendToObj(msg, "\"", -1);
		Tcl_SetObjResult(interp, msg);
		Tcl_SetErrorCode(interp, "TCL", "VALUE", "INTEGER", NULL);
	    }
	    return TCL_ERROR;
	}
    } while (TclParseNumber(interp, objPtr, "integer", NULL, -1, NULL,
	    TCL_PARSE_INTEGER_ONLY)==TCL_OK);
    return TCL_ERROR;







<
|
|
|
<
<







3391
3392
3393
3394
3395
3396
3397

3398
3399
3400


3401
3402
3403
3404
3405
3406
3407
	    TclBNInitBignumFromWideInt(bignumValue,
		    objPtr->internalRep.wideValue);
	    return TCL_OK;
	}
#endif
	if (objPtr->typePtr == &tclDoubleType) {
	    if (interp != NULL) {

                Tcl_SetObjResult(interp, Tcl_ObjPrintf(
                        "expected integer but got \"%s\"",
                        Tcl_GetString(objPtr)));


		Tcl_SetErrorCode(interp, "TCL", "VALUE", "INTEGER", NULL);
	    }
	    return TCL_ERROR;
	}
    } while (TclParseNumber(interp, objPtr, "integer", NULL, -1, NULL,
	    TCL_PARSE_INTEGER_ONLY)==TCL_OK);
    return TCL_ERROR;
3709
3710
3711
3712
3713
3714
3715

3716
3717
3718
3719
3720
3721
3722
3723
3724
3725
3726
3727
3728
3729
3730
3731
3732
3733
3734
3735
3736
3737
3738
3739
    /*
     * Check to make sure that the Tcl_Obj was allocated by the current
     * thread. Don't do this check when shutting down since thread local
     * storage can be finalized before the last Tcl_Obj is freed.
     */

    if (!TclInExit()) {

	Tcl_HashTable *tablePtr;
	Tcl_HashEntry *hPtr;
	ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);

	tablePtr = tsdPtr->objThreadMap;
	if (!tablePtr) {
	    Tcl_Panic("object table not initialized");
	}
	hPtr = Tcl_FindHashEntry(tablePtr, objPtr);
	if (!hPtr) {
	    Tcl_Panic("%s%s",
		    "Trying to incr ref count of "
		    "Tcl_Obj allocated in another thread");
	}
    }
# endif
#endif
    ++(objPtr)->refCount;
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_DbDecrRefCount --







>
|

<

<





|
|
<


|
|







3700
3701
3702
3703
3704
3705
3706
3707
3708
3709

3710

3711
3712
3713
3714
3715
3716
3717

3718
3719
3720
3721
3722
3723
3724
3725
3726
3727
3728
    /*
     * Check to make sure that the Tcl_Obj was allocated by the current
     * thread. Don't do this check when shutting down since thread local
     * storage can be finalized before the last Tcl_Obj is freed.
     */

    if (!TclInExit()) {
	ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
	Tcl_HashTable *tablePtr = tsdPtr->objThreadMap;
	Tcl_HashEntry *hPtr;



	if (!tablePtr) {
	    Tcl_Panic("object table not initialized");
	}
	hPtr = Tcl_FindHashEntry(tablePtr, objPtr);
	if (!hPtr) {
	    Tcl_Panic("Trying to %s of Tcl_Obj allocated in another thread",
                    "incr ref count");

	}
    }
# endif /* TCL_THREADS */
#endif /* TCL_MEM_DEBUG */
    ++(objPtr)->refCount;
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_DbDecrRefCount --
3774
3775
3776
3777
3778
3779
3780

3781
3782
3783
3784
3785
3786
3787
3788
3789
3790
3791
3792
3793
3794
3795
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805
3806
3807
3808
3809
3810
3811

3812
3813
3814
3815
3816
3817
3818
    /*
     * Check to make sure that the Tcl_Obj was allocated by the current
     * thread. Don't do this check when shutting down since thread local
     * storage can be finalized before the last Tcl_Obj is freed.
     */

    if (!TclInExit()) {

	Tcl_HashTable *tablePtr;
	Tcl_HashEntry *hPtr;
	ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);

	tablePtr = tsdPtr->objThreadMap;
	if (!tablePtr) {
	    Tcl_Panic("object table not initialized");
	}
	hPtr = Tcl_FindHashEntry(tablePtr, objPtr);
	if (!hPtr) {
	    Tcl_Panic("%s%s",
		    "Trying to decr ref count of "
		    "Tcl_Obj allocated in another thread");
	}

	/*
	 * If the Tcl_Obj is going to be deleted, remove the entry.
	 */

	if ((objPtr->refCount - 1) <= 0) {
	    ObjData *objData = Tcl_GetHashValue(hPtr);

	    if (objData != NULL) {
		ckfree(objData);
	    }

	    Tcl_DeleteHashEntry(hPtr);
	}
    }
# endif
#endif

    if (--(objPtr)->refCount <= 0) {
	TclFreeObj(objPtr);
    }
}

/*
 *----------------------------------------------------------------------







>
|

<

<





|
|
<
















|
|
>







3763
3764
3765
3766
3767
3768
3769
3770
3771
3772

3773

3774
3775
3776
3777
3778
3779
3780

3781
3782
3783
3784
3785
3786
3787
3788
3789
3790
3791
3792
3793
3794
3795
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805
3806
    /*
     * Check to make sure that the Tcl_Obj was allocated by the current
     * thread. Don't do this check when shutting down since thread local
     * storage can be finalized before the last Tcl_Obj is freed.
     */

    if (!TclInExit()) {
	ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
	Tcl_HashTable *tablePtr = tsdPtr->objThreadMap;
	Tcl_HashEntry *hPtr;



	if (!tablePtr) {
	    Tcl_Panic("object table not initialized");
	}
	hPtr = Tcl_FindHashEntry(tablePtr, objPtr);
	if (!hPtr) {
	    Tcl_Panic("Trying to %s of Tcl_Obj allocated in another thread",
                    "decr ref count");

	}

	/*
	 * If the Tcl_Obj is going to be deleted, remove the entry.
	 */

	if ((objPtr->refCount - 1) <= 0) {
	    ObjData *objData = Tcl_GetHashValue(hPtr);

	    if (objData != NULL) {
		ckfree(objData);
	    }

	    Tcl_DeleteHashEntry(hPtr);
	}
    }
# endif /* TCL_THREADS */
#endif /* TCL_MEM_DEBUG */

    if (--(objPtr)->refCount <= 0) {
	TclFreeObj(objPtr);
    }
}

/*
 *----------------------------------------------------------------------
3854
3855
3856
3857
3858
3859
3860

3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
    /*
     * Check to make sure that the Tcl_Obj was allocated by the current
     * thread. Don't do this check when shutting down since thread local
     * storage can be finalized before the last Tcl_Obj is freed.
     */

    if (!TclInExit()) {

	Tcl_HashTable *tablePtr;
	Tcl_HashEntry *hPtr;
	ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
	tablePtr = tsdPtr->objThreadMap;
	if (!tablePtr) {
	    Tcl_Panic("object table not initialized");
	}
	hPtr = Tcl_FindHashEntry(tablePtr, objPtr);
	if (!hPtr) {
	    Tcl_Panic("%s%s",
		    "Trying to check shared status of"
		    "Tcl_Obj allocated in another thread");
	}
    }
# endif
#endif

#ifdef TCL_COMPILE_STATS
    Tcl_MutexLock(&tclObjMutex);
    if ((objPtr)->refCount <= 1) {
	tclObjsShared[1]++;
    } else if ((objPtr)->refCount < TCL_MAX_SHARED_OBJ_STATS) {
	tclObjsShared[(objPtr)->refCount]++;
    } else {
	tclObjsShared[0]++;
    }
    Tcl_MutexUnlock(&tclObjMutex);
#endif

    return ((objPtr)->refCount > 1);
}

/*
 *----------------------------------------------------------------------
 *







>
|

|
<





|
|
<


|
|











|







3842
3843
3844
3845
3846
3847
3848
3849
3850
3851
3852

3853
3854
3855
3856
3857
3858
3859

3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
    /*
     * Check to make sure that the Tcl_Obj was allocated by the current
     * thread. Don't do this check when shutting down since thread local
     * storage can be finalized before the last Tcl_Obj is freed.
     */

    if (!TclInExit()) {
	ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
	Tcl_HashTable *tablePtr = tsdPtr->objThreadMap;
	Tcl_HashEntry *hPtr;


	if (!tablePtr) {
	    Tcl_Panic("object table not initialized");
	}
	hPtr = Tcl_FindHashEntry(tablePtr, objPtr);
	if (!hPtr) {
	    Tcl_Panic("Trying to %s of Tcl_Obj allocated in another thread",
                    "check shared status");

	}
    }
# endif /* TCL_THREADS */
#endif /* TCL_MEM_DEBUG */

#ifdef TCL_COMPILE_STATS
    Tcl_MutexLock(&tclObjMutex);
    if ((objPtr)->refCount <= 1) {
	tclObjsShared[1]++;
    } else if ((objPtr)->refCount < TCL_MAX_SHARED_OBJ_STATS) {
	tclObjsShared[(objPtr)->refCount]++;
    } else {
	tclObjsShared[0]++;
    }
    Tcl_MutexUnlock(&tclObjMutex);
#endif /* TCL_COMPILE_STATS */

    return ((objPtr)->refCount > 1);
}

/*
 *----------------------------------------------------------------------
 *
4374
4375
4376
4377
4378
4379
4380




4381
4382
4383
4384
4385
4386
4387
    register Tcl_Obj *objPtr)	/* The object to convert. */
{
    Interp *iPtr = (Interp *) interp;
    const char *name;
    register Command *cmdPtr;
    Namespace *currNsPtr;
    register ResolvedCmdName *resPtr;





    /*
     * Find the Command structure, if any, that describes the command called
     * "name". Build a ResolvedCmdName that holds a cached pointer to this
     * Command, and bump the reference count in the referenced Command
     * structure. A Command structure will not be deleted as long as it is
     * referenced from a CmdName object.







>
>
>
>







4361
4362
4363
4364
4365
4366
4367
4368
4369
4370
4371
4372
4373
4374
4375
4376
4377
4378
    register Tcl_Obj *objPtr)	/* The object to convert. */
{
    Interp *iPtr = (Interp *) interp;
    const char *name;
    register Command *cmdPtr;
    Namespace *currNsPtr;
    register ResolvedCmdName *resPtr;

    if (interp == NULL) {
	return TCL_ERROR;
    }

    /*
     * Find the Command structure, if any, that describes the command called
     * "name". Build a ResolvedCmdName that holds a cached pointer to this
     * Command, and bump the reference count in the referenced Command
     * structure. A Command structure will not be deleted as long as it is
     * referenced from a CmdName object.

Changes to generic/tclParse.c.

429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
		if (tokenPtr[i].type != TCL_TOKEN_TEXT) {
		    isLiteral = 0;
		    break;
		}
	    }

	    if (isLiteral) {
		int elemCount = 0, code = TCL_OK, nakedbs = 0;
		const char *nextElem, *listEnd, *elemStart;

		/*
		 * The word to be expanded is a literal, so determine the
		 * boundaries of the literal string to be treated as a list
		 * and expanded. That literal string starts at
		 * tokenPtr[1].start, and includes all bytes up to, but not







|







429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
		if (tokenPtr[i].type != TCL_TOKEN_TEXT) {
		    isLiteral = 0;
		    break;
		}
	    }

	    if (isLiteral) {
		int elemCount = 0, code = TCL_OK, literal = 1;
		const char *nextElem, *listEnd, *elemStart;

		/*
		 * The word to be expanded is a literal, so determine the
		 * boundaries of the literal string to be treated as a list
		 * and expanded. That literal string starts at
		 * tokenPtr[1].start, and includes all bytes up to, but not
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

		/*
		 * Step through the literal string, parsing and counting list
		 * elements.
		 */

		while (nextElem < listEnd) {
		    int size, brace;

		    code = TclFindElement(NULL, nextElem, listEnd - nextElem,
			    &elemStart, &nextElem, &size, &brace);
		    if (code != TCL_OK) {
			break;
		    }
		    if (!brace) {
			const char *s;

			for(s=elemStart;size>0;s++,size--) {
			    if ((*s)=='\\') {
				nakedbs = 1;
				break;
			    }
			}
		    }
		    if (elemStart < listEnd) {
			elemCount++;
		    }
		}

		if ((code != TCL_OK) || nakedbs) {
		    /*
		     * Some list element could not be parsed, or contained
		     * naked backslashes. This means the literal string was

		     * not in fact a valid nor canonical list. Defer the
		     * handling of this to compile/eval time, where code is
		     * already in place to report the "attempt to expand a
		     * non-list" error or expand lists that require
		     * substitution.
		     */

		    tokenPtr->type = TCL_TOKEN_EXPAND_WORD;
		} else if (elemCount == 0) {
		    /*







|


|
|

<
<
<
<
<
<
<
<
<
<






|

|
|
>
|
|
|







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

		/*
		 * Step through the literal string, parsing and counting list
		 * elements.
		 */

		while (nextElem < listEnd) {
		    int size;

		    code = TclFindElement(NULL, nextElem, listEnd - nextElem,
			    &elemStart, &nextElem, &size, &literal);
		    if ((code != TCL_OK) || !literal) {
			break;










		    }
		    if (elemStart < listEnd) {
			elemCount++;
		    }
		}

		if ((code != TCL_OK) || !literal) {
		    /*
		     * Some list element could not be parsed, or is not
		     * present as a literal substring of the script.  The
		     * compiler cannot handle list elements that get generated
		     * by a call to TclCopyAndCollapse(). Defer  the
		     * handling of  this to  compile/eval time, where  code is
		     * already  in place to  report the  "attempt to  expand a
		     * non-list" error or expand lists that require
		     * substitution.
		     */

		    tokenPtr->type = TCL_TOKEN_EXPAND_WORD;
		} else if (elemCount == 0) {
		    /*
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
		    parsePtr->numTokens = wordIndex;
		} else {
		    /*
		     * Recalculate the number of Tcl_Tokens needed to store
		     * tokens representing the expanded list.
		     */


		    int growthNeeded = wordIndex + 2*elemCount
			    - parsePtr->numTokens;

		    parsePtr->numWords += elemCount - 1;
		    if (growthNeeded > 0) {
			TclGrowParseTokenArray(parsePtr, growthNeeded);
			tokenPtr = &parsePtr->tokenPtr[wordIndex];
		    }
		    parsePtr->numTokens = wordIndex + 2*elemCount;

		    /*
		     * Generate a TCL_TOKEN_SIMPLE_WORD token sequence for
		     * each element of the literal list we are expanding in
		     * place. Take care with the start and size fields of each
		     * token so they point to the right literal characters in
		     * the original script to represent the right expanded
		     * word value.
		     */

		    nextElem = tokenPtr[1].start;
		    while (nextElem < listEnd) {
			int quoted, brace;
	
			tokenPtr->type = TCL_TOKEN_SIMPLE_WORD;
			tokenPtr->numComponents = 1;

			tokenPtr++;
			tokenPtr->type = TCL_TOKEN_TEXT;
			tokenPtr->numComponents = 0;
			TclFindElement(NULL, nextElem, listEnd - nextElem,
				&(tokenPtr->start), &nextElem,
				&(tokenPtr->size), &brace);


			quoted = brace || tokenPtr->start[-1] == '"';

			tokenPtr[-1].start = tokenPtr->start - quoted;
			tokenPtr[-1].size = tokenPtr->start + tokenPtr->size
				- tokenPtr[-1].start + quoted;

			tokenPtr++;
		    }
		}







>



















|

|









|

>
|
>







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
		    parsePtr->numTokens = wordIndex;
		} else {
		    /*
		     * Recalculate the number of Tcl_Tokens needed to store
		     * tokens representing the expanded list.
		     */

		    const char *listStart;
		    int growthNeeded = wordIndex + 2*elemCount
			    - parsePtr->numTokens;

		    parsePtr->numWords += elemCount - 1;
		    if (growthNeeded > 0) {
			TclGrowParseTokenArray(parsePtr, growthNeeded);
			tokenPtr = &parsePtr->tokenPtr[wordIndex];
		    }
		    parsePtr->numTokens = wordIndex + 2*elemCount;

		    /*
		     * Generate a TCL_TOKEN_SIMPLE_WORD token sequence for
		     * each element of the literal list we are expanding in
		     * place. Take care with the start and size fields of each
		     * token so they point to the right literal characters in
		     * the original script to represent the right expanded
		     * word value.
		     */

		    listStart = nextElem = tokenPtr[1].start;
		    while (nextElem < listEnd) {
			int quoted;
	
			tokenPtr->type = TCL_TOKEN_SIMPLE_WORD;
			tokenPtr->numComponents = 1;

			tokenPtr++;
			tokenPtr->type = TCL_TOKEN_TEXT;
			tokenPtr->numComponents = 0;
			TclFindElement(NULL, nextElem, listEnd - nextElem,
				&(tokenPtr->start), &nextElem,
				&(tokenPtr->size), NULL);

			quoted = (tokenPtr->start[-1] == '{'
				|| tokenPtr->start[-1] == '"')
				&& tokenPtr->start > listStart;
			tokenPtr[-1].start = tokenPtr->start - quoted;
			tokenPtr[-1].size = tokenPtr->start + tokenPtr->size
				- tokenPtr[-1].start + quoted;

			tokenPtr++;
		    }
		}
603
604
605
606
607
608
609
























610
611
612
613
614
615
616
    return TCL_OK;

  error:
    Tcl_FreeParse(parsePtr);
    parsePtr->commandSize = parsePtr->end - parsePtr->commandStart;
    return TCL_ERROR;
}

























/*
 *----------------------------------------------------------------------
 *
 * ParseWhiteSpace --
 *
 *	Scans up to numBytes bytes starting at src, consuming white space







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







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
    return TCL_OK;

  error:
    Tcl_FreeParse(parsePtr);
    parsePtr->commandSize = parsePtr->end - parsePtr->commandStart;
    return TCL_ERROR;
}

/*
 *----------------------------------------------------------------------
 *
 * TclIsSpaceProc --
 *
 *	Report whether byte is in the set of whitespace characters used by
 *	Tcl to separate words in scripts or elements in lists.
 *
 * Results:
 *	Returns 1, if byte is in the set, 0 otherwise.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

int
TclIsSpaceProc(
    char byte)
{
    return CHAR_TYPE(byte) & (TYPE_SPACE) || byte == '\n';
}

/*
 *----------------------------------------------------------------------
 *
 * ParseWhiteSpace --
 *
 *	Scans up to numBytes bytes starting at src, consuming white space
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
 *----------------------------------------------------------------------
 */

int
TclParseHex(
    const char *src,		/* First character to parse. */
    int numBytes,		/* Max number of byes to scan */
    Tcl_UniChar *resultPtr)	/* Points to storage provided by caller where
				 * the Tcl_UniChar resulting from the
				 * conversion is to be written. */
{
    Tcl_UniChar result = 0;
    register const char *p = src;

    while (numBytes--) {
	unsigned char digit = UCHAR(*p);

	if (!isxdigit(digit)) {
	    break;
	}

	p++;
	result <<= 4;

	if (digit >= 'a') {







|
|


|





|







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
 *----------------------------------------------------------------------
 */

int
TclParseHex(
    const char *src,		/* First character to parse. */
    int numBytes,		/* Max number of byes to scan */
    int *resultPtr)	/* Points to storage provided by caller where
				 * the character resulting from the
				 * conversion is to be written. */
{
    int result = 0;
    register const char *p = src;

    while (numBytes--) {
	unsigned char digit = UCHAR(*p);

	if (!isxdigit(digit) || (result > 0x10fff)) {
	    break;
	}

	p++;
	result <<= 4;

	if (digit >= 'a') {
786
787
788
789
790
791
792
793

794
795
796
797
798
799
800
				 * of bytes scanned should be written. */
    char *dst)			/* NULL, or points to buffer where the UTF-8
				 * encoding of the backslash sequence is to be
				 * written. At most TCL_UTF_MAX bytes will be
				 * written there. */
{
    register const char *p = src+1;
    Tcl_UniChar result;

    int count;
    char buf[TCL_UTF_MAX];

    if (numBytes == 0) {
	if (readPtr != NULL) {
	    *readPtr = 0;
	}







|
>







804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
				 * of bytes scanned should be written. */
    char *dst)			/* NULL, or points to buffer where the UTF-8
				 * encoding of the backslash sequence is to be
				 * written. At most TCL_UTF_MAX bytes will be
				 * written there. */
{
    register const char *p = src+1;
    Tcl_UniChar unichar;
    int result;
    int count;
    char buf[TCL_UTF_MAX];

    if (numBytes == 0) {
	if (readPtr != NULL) {
	    *readPtr = 0;
	}
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
    case 't':
	result = 0x9;
	break;
    case 'v':
	result = 0xb;
	break;
    case 'x':
	count += TclParseHex(p+1, numBytes-2, &result);
	if (count == 2) {
	    /*
	     * No hexadigits -> This is just "x".
	     */

	    result = 'x';
	} else {







|







862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
    case 't':
	result = 0x9;
	break;
    case 'v':
	result = 0xb;
	break;
    case 'x':
	count += TclParseHex(p+1, (numBytes > 3) ? 2 : numBytes-2, &result);
	if (count == 2) {
	    /*
	     * No hexadigits -> This is just "x".
	     */

	    result = 'x';
	} else {
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
	count += TclParseHex(p+1, (numBytes > 5) ? 4 : numBytes-2, &result);
	if (count == 2) {
	    /*
	     * No hexadigits -> This is just "u".
	     */
	    result = 'u';
	}









	break;
    case '\n':
	count--;
	do {
	    p++;
	    count++;
	} while ((count < numBytes) && ((*p == ' ') || (*p == '\t')));
	result = ' ';
	break;
    case 0:
	result = '\\';
	count = 1;
	break;
    default:
	/*
	 * Check for an octal number \oo?o?
	 */

	if (isdigit(UCHAR(*p)) && (UCHAR(*p) < '8')) {	/* INTL: digit */
	    result = UCHAR(*p - '0');
	    p++;
	    if ((numBytes == 2) || !isdigit(UCHAR(*p))	/* INTL: digit */
		    || (UCHAR(*p) >= '8')) {
		break;
	    }
	    count = 3;
	    result = UCHAR((result << 3) + (*p - '0'));
	    p++;
	    if ((numBytes == 3) || !isdigit(UCHAR(*p))	/* INTL: digit */
		    || (UCHAR(*p) >= '8')) {
		break;
	    }
	    count = 4;
	    result = UCHAR((result << 3) + (*p - '0'));
	    break;
	}

	/*
	 * We have to convert here in case the user has put a backslash in
	 * front of a multi-byte utf-8 character. While this means nothing
	 * special, we shouldn't break up a correct utf-8 character. [Bug
	 * #217987] test subst-3.2
	 */

	if (Tcl_UtfCharComplete(p, numBytes - 1)) {
	    count = Tcl_UtfToUniChar(p, &result) + 1;	/* +1 for '\' */
	} else {
	    char utfBytes[TCL_UTF_MAX];

	    memcpy(utfBytes, p, (size_t) (numBytes - 1));
	    utfBytes[numBytes - 1] = '\0';
	    count = Tcl_UtfToUniChar(utfBytes, &result) + 1;
	}

	break;
    }

  done:
    if (readPtr != NULL) {
	*readPtr = count;
    }
    return Tcl_UniCharToUtf((int) result, dst);
}

/*
 *----------------------------------------------------------------------
 *
 * ParseComment --
 *







>
>
>
>
>
>
>
>
>



















|






|


|















|





|

>







|







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
	count += TclParseHex(p+1, (numBytes > 5) ? 4 : numBytes-2, &result);
	if (count == 2) {
	    /*
	     * No hexadigits -> This is just "u".
	     */
	    result = 'u';
	}
	break;
    case 'U':
	count += TclParseHex(p+1, (numBytes > 9) ? 8 : numBytes-2, &result);
	if (count == 2) {
	    /*
	     * No hexadigits -> This is just "U".
	     */
	    result = 'U';
	}
	break;
    case '\n':
	count--;
	do {
	    p++;
	    count++;
	} while ((count < numBytes) && ((*p == ' ') || (*p == '\t')));
	result = ' ';
	break;
    case 0:
	result = '\\';
	count = 1;
	break;
    default:
	/*
	 * Check for an octal number \oo?o?
	 */

	if (isdigit(UCHAR(*p)) && (UCHAR(*p) < '8')) {	/* INTL: digit */
	    result = *p - '0';
	    p++;
	    if ((numBytes == 2) || !isdigit(UCHAR(*p))	/* INTL: digit */
		    || (UCHAR(*p) >= '8')) {
		break;
	    }
	    count = 3;
	    result = (result << 3) + (*p - '0');
	    p++;
	    if ((numBytes == 3) || !isdigit(UCHAR(*p))	/* INTL: digit */
		    || (UCHAR(*p) >= '8') || (result >= 0x20)) {
		break;
	    }
	    count = 4;
	    result = UCHAR((result << 3) + (*p - '0'));
	    break;
	}

	/*
	 * We have to convert here in case the user has put a backslash in
	 * front of a multi-byte utf-8 character. While this means nothing
	 * special, we shouldn't break up a correct utf-8 character. [Bug
	 * #217987] test subst-3.2
	 */

	if (Tcl_UtfCharComplete(p, numBytes - 1)) {
	    count = Tcl_UtfToUniChar(p, &unichar) + 1;	/* +1 for '\' */
	} else {
	    char utfBytes[TCL_UTF_MAX];

	    memcpy(utfBytes, p, (size_t) (numBytes - 1));
	    utfBytes[numBytes - 1] = '\0';
	    count = Tcl_UtfToUniChar(utfBytes, &unichar) + 1;
	}
	result = unichar;
	break;
    }

  done:
    if (readPtr != NULL) {
	*readPtr = count;
    }
    return Tcl_UniCharToUtf(result, dst);
}

/*
 *----------------------------------------------------------------------
 *
 * ParseComment --
 *
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
	    case '{':
		openBrace = 1;
		break;
	    case '\n':
		openBrace = 0;
		break;
	    case '#' :
		if (openBrace && isspace(UCHAR(src[-1]))) {
		    Tcl_AppendResult(parsePtr->interp,
			    ": possible unbalanced brace in comment", NULL);
		    goto error;
		}
		break;
	    }
	}







|







1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
	    case '{':
		openBrace = 1;
		break;
	    case '\n':
		openBrace = 0;
		break;
	    case '#' :
		if (openBrace && TclIsSpaceProc(src[-1])) {
		    Tcl_AppendResult(parsePtr->interp,
			    ": possible unbalanced brace in comment", NULL);
		    goto error;
		}
		break;
	    }
	}

Changes to generic/tclPathObj.c.

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
	    return TCL_OK;
	}

	if (pathPtr->bytes == NULL) {
	    UpdateStringOfFsPath(pathPtr);
	}
	FreeFsPathInternalRep(pathPtr);
	pathPtr->typePtr = NULL;
    }

    return Tcl_ConvertToType(interp, pathPtr, &tclFsPathType);

    /*
     * We used to have more complex code here:
     *
     * FsPath *fsPathPtr = PATHOBJ(pathPtr);
     * if (fsPathPtr->cwdPtr == NULL || PATHFLAGS(pathPtr) != 0) {
     *     return TCL_OK;
     * } else {
     *     if (TclFSCwdPointerEquals(&fsPathPtr->cwdPtr)) {
     *         return TCL_OK;
     *     } else {
     *         if (pathPtr->bytes == NULL) {
     *             UpdateStringOfFsPath(pathPtr);
     *         }
     *         FreeFsPathInternalRep(pathPtr);
     *         pathPtr->typePtr = NULL;
     *         return Tcl_ConvertToType(interp, pathPtr, &tclFsPathType);
     *     }
     * }
     *
     * But we no longer believe this is necessary.
     */
}







<


















<







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
	    return TCL_OK;
	}

	if (pathPtr->bytes == NULL) {
	    UpdateStringOfFsPath(pathPtr);
	}
	FreeFsPathInternalRep(pathPtr);

    }

    return Tcl_ConvertToType(interp, pathPtr, &tclFsPathType);

    /*
     * We used to have more complex code here:
     *
     * FsPath *fsPathPtr = PATHOBJ(pathPtr);
     * if (fsPathPtr->cwdPtr == NULL || PATHFLAGS(pathPtr) != 0) {
     *     return TCL_OK;
     * } else {
     *     if (TclFSCwdPointerEquals(&fsPathPtr->cwdPtr)) {
     *         return TCL_OK;
     *     } else {
     *         if (pathPtr->bytes == NULL) {
     *             UpdateStringOfFsPath(pathPtr);
     *         }
     *         FreeFsPathInternalRep(pathPtr);

     *         return Tcl_ConvertToType(interp, pathPtr, &tclFsPathType);
     *     }
     * }
     *
     * But we no longer believe this is necessary.
     */
}
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913

    if (fsPathPtr->cwdPtr != NULL) {
	if (!TclFSCwdPointerEquals(&fsPathPtr->cwdPtr)) {
	    if (pathPtr->bytes == NULL) {
		UpdateStringOfFsPath(pathPtr);
	    }
	    FreeFsPathInternalRep(pathPtr);
	    pathPtr->typePtr = NULL;
	    if (Tcl_ConvertToType(interp, pathPtr, &tclFsPathType) != TCL_OK) {
		return NULL;
	    }
	    fsPathPtr = PATHOBJ(pathPtr);
	} else if (fsPathPtr->normPathPtr == NULL) {
	    int cwdLen;
	    Tcl_Obj *copy;







<







1897
1898
1899
1900
1901
1902
1903

1904
1905
1906
1907
1908
1909
1910

    if (fsPathPtr->cwdPtr != NULL) {
	if (!TclFSCwdPointerEquals(&fsPathPtr->cwdPtr)) {
	    if (pathPtr->bytes == NULL) {
		UpdateStringOfFsPath(pathPtr);
	    }
	    FreeFsPathInternalRep(pathPtr);

	    if (Tcl_ConvertToType(interp, pathPtr, &tclFsPathType) != TCL_OK) {
		return NULL;
	    }
	    fsPathPtr = PATHOBJ(pathPtr);
	} else if (fsPathPtr->normPathPtr == NULL) {
	    int cwdLen;
	    Tcl_Obj *copy;
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
	 * We have to discard the stale representation and recalculate it.
	 */

	if (pathPtr->bytes == NULL) {
	    UpdateStringOfFsPath(pathPtr);
	}
	FreeFsPathInternalRep(pathPtr);
	pathPtr->typePtr = NULL;
	if (SetFsPathFromAny(NULL, pathPtr) != TCL_OK) {
	    return TCL_ERROR;
	}
	srcFsPathPtr = PATHOBJ(pathPtr);
    }

    /*







<







2207
2208
2209
2210
2211
2212
2213

2214
2215
2216
2217
2218
2219
2220
	 * We have to discard the stale representation and recalculate it.
	 */

	if (pathPtr->bytes == NULL) {
	    UpdateStringOfFsPath(pathPtr);
	}
	FreeFsPathInternalRep(pathPtr);

	if (SetFsPathFromAny(NULL, pathPtr) != TCL_OK) {
	    return TCL_ERROR;
	}
	srcFsPathPtr = PATHOBJ(pathPtr);
    }

    /*
2617
2618
2619
2620
2621
2622
2623
2624



2625
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
    Tcl_Obj *copyPtr)		/* Path obj with internal rep to set. */
{
    FsPath *srcFsPathPtr = PATHOBJ(srcPtr);
    FsPath *copyFsPathPtr = ckalloc(sizeof(FsPath));

    SETPATHOBJ(copyPtr, copyFsPathPtr);

    if (srcFsPathPtr->translatedPathPtr != NULL) {



	copyFsPathPtr->translatedPathPtr = srcFsPathPtr->translatedPathPtr;
	if (copyFsPathPtr->translatedPathPtr != copyPtr) {
	    Tcl_IncrRefCount(copyFsPathPtr->translatedPathPtr);
	}
    } else {
	copyFsPathPtr->translatedPathPtr = NULL;
    }

    if (srcFsPathPtr->normPathPtr != NULL) {



	copyFsPathPtr->normPathPtr = srcFsPathPtr->normPathPtr;
	if (copyFsPathPtr->normPathPtr != copyPtr) {
	    Tcl_IncrRefCount(copyFsPathPtr->normPathPtr);
	}
    } else {
	copyFsPathPtr->normPathPtr = NULL;
    }

    if (srcFsPathPtr->cwdPtr != NULL) {
	copyFsPathPtr->cwdPtr = srcFsPathPtr->cwdPtr;
	Tcl_IncrRefCount(copyFsPathPtr->cwdPtr);
    } else {
	copyFsPathPtr->cwdPtr = NULL;
    }

    copyFsPathPtr->flags = srcFsPathPtr->flags;

    if (srcFsPathPtr->fsRecPtr != NULL
	    && srcFsPathPtr->nativePathPtr != NULL) {
	Tcl_FSDupInternalRepProc *dupProc =







|
>
>
>

|


<
<


|
>
>
>

|


<
<


<
|
|
<
|







2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627


2628
2629
2630
2631
2632
2633
2634
2635
2636
2637


2638
2639

2640
2641

2642
2643
2644
2645
2646
2647
2648
2649
    Tcl_Obj *copyPtr)		/* Path obj with internal rep to set. */
{
    FsPath *srcFsPathPtr = PATHOBJ(srcPtr);
    FsPath *copyFsPathPtr = ckalloc(sizeof(FsPath));

    SETPATHOBJ(copyPtr, copyFsPathPtr);

    if (srcFsPathPtr->translatedPathPtr == srcPtr) {
	/* Cycle in src -> make cycle in copy. */
	copyFsPathPtr->translatedPathPtr = copyPtr;
    } else {
	copyFsPathPtr->translatedPathPtr = srcFsPathPtr->translatedPathPtr;
	if (copyFsPathPtr->translatedPathPtr != NULL) {
	    Tcl_IncrRefCount(copyFsPathPtr->translatedPathPtr);
	}


    }

    if (srcFsPathPtr->normPathPtr == srcPtr) {
	/* Cycle in src -> make cycle in copy. */
	copyFsPathPtr->normPathPtr = copyPtr;
    } else {
	copyFsPathPtr->normPathPtr = srcFsPathPtr->normPathPtr;
	if (copyFsPathPtr->normPathPtr != NULL) {
	    Tcl_IncrRefCount(copyFsPathPtr->normPathPtr);
	}


    }


    copyFsPathPtr->cwdPtr = srcFsPathPtr->cwdPtr;
    if (copyFsPathPtr->cwdPtr != NULL) {

	Tcl_IncrRefCount(copyFsPathPtr->cwdPtr);
    }

    copyFsPathPtr->flags = srcFsPathPtr->flags;

    if (srcFsPathPtr->fsRecPtr != NULL
	    && srcFsPathPtr->nativePathPtr != NULL) {
	Tcl_FSDupInternalRepProc *dupProc =

Changes to generic/tclPkg.c.

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
	DupBlock(availPtr->script, argv4, (unsigned) length + 1);
	break;
    }
    case PKG_NAMES:
	if (objc != 2) {
	    Tcl_WrongNumArgs(interp, 2, objv, NULL);
	    return TCL_ERROR;


	}

	tablePtr = &iPtr->packageTable;
	for (hPtr = Tcl_FirstHashEntry(tablePtr, &search); hPtr != NULL;
		hPtr = Tcl_NextHashEntry(&search)) {
	    pkgPtr = Tcl_GetHashValue(hPtr);
	    if ((pkgPtr->version != NULL) || (pkgPtr->availPtr != NULL)) {

		Tcl_AppendElement(interp, Tcl_GetHashKey(tablePtr, hPtr));
	    }


	}
	break;
    case PKG_PRESENT: {
	const char *name;

	if (objc < 3) {
	    goto require;
	}
	argv2 = TclGetString(objv[2]);
	if ((argv2[0] == '-') && (strcmp(argv2, "-exact") == 0)) {
	    if (objc != 5) {
		goto requireSyntax;







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




>







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
	DupBlock(availPtr->script, argv4, (unsigned) length + 1);
	break;
    }
    case PKG_NAMES:
	if (objc != 2) {
	    Tcl_WrongNumArgs(interp, 2, objv, NULL);
	    return TCL_ERROR;
	} else {
	    Tcl_Obj *resultObj;

	    resultObj = Tcl_NewObj();
	    tablePtr = &iPtr->packageTable;
	    for (hPtr = Tcl_FirstHashEntry(tablePtr, &search); hPtr != NULL;
		    hPtr = Tcl_NextHashEntry(&search)) {
		pkgPtr = Tcl_GetHashValue(hPtr);
		if ((pkgPtr->version != NULL) || (pkgPtr->availPtr != NULL)) {
		    Tcl_ListObjAppendElement(NULL,resultObj, Tcl_NewStringObj(
			    Tcl_GetHashKey(tablePtr, hPtr), -1));
		}
	    }
	    Tcl_SetObjResult(interp, resultObj);
	}
	break;
    case PKG_PRESENT: {
	const char *name;

	if (objc < 3) {
	    goto require;
	}
	argv2 = TclGetString(objv[2]);
	if ((argv2[0] == '-') && (strcmp(argv2, "-exact") == 0)) {
	    if (objc != 5) {
		goto requireSyntax;
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
	ckfree(iva);
	ckfree(ivb);
	break;
    case PKG_VERSIONS:
	if (objc != 3) {
	    Tcl_WrongNumArgs(interp, 2, objv, "package");
	    return TCL_ERROR;


	}
	argv2 = TclGetString(objv[2]);
	hPtr = Tcl_FindHashEntry(&iPtr->packageTable, argv2);
	if (hPtr != NULL) {
	    pkgPtr = Tcl_GetHashValue(hPtr);
	    for (availPtr = pkgPtr->availPtr; availPtr != NULL;
		    availPtr = availPtr->nextPtr) {

		Tcl_AppendElement(interp, availPtr->version);
	    }


	}
	break;
    case PKG_VSATISFIES: {
	char *argv2i = NULL;

	if (objc < 4) {
	    Tcl_WrongNumArgs(interp, 2, objv,
		    "version ?requirement ...?");
	    return TCL_ERROR;
	}

	argv2 = TclGetString(objv[2]);
	if (CheckVersionAndConvert(interp, argv2, &argv2i, NULL) != TCL_OK) {
	    return TCL_ERROR;
	} else if (CheckAllRequirements(interp, objc-3, objv+3) != TCL_OK) {







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






|
<







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
	ckfree(iva);
	ckfree(ivb);
	break;
    case PKG_VERSIONS:
	if (objc != 3) {
	    Tcl_WrongNumArgs(interp, 2, objv, "package");
	    return TCL_ERROR;
	} else {
	    Tcl_Obj *resultObj = Tcl_NewObj();

	    argv2 = TclGetString(objv[2]);
	    hPtr = Tcl_FindHashEntry(&iPtr->packageTable, argv2);
	    if (hPtr != NULL) {
		pkgPtr = Tcl_GetHashValue(hPtr);
		for (availPtr = pkgPtr->availPtr; availPtr != NULL;
			availPtr = availPtr->nextPtr) {
		    Tcl_ListObjAppendElement(NULL, resultObj,
			    Tcl_NewStringObj(availPtr->version, -1));
		}
	    }
	    Tcl_SetObjResult(interp, resultObj);
	}
	break;
    case PKG_VSATISFIES: {
	char *argv2i = NULL;

	if (objc < 4) {
	    Tcl_WrongNumArgs(interp, 2, objv, "version ?requirement ...?");

	    return TCL_ERROR;
	}

	argv2 = TclGetString(objv[2]);
	if (CheckVersionAndConvert(interp, argv2, &argv2i, NULL) != TCL_OK) {
	    return TCL_ERROR;
	} else if (CheckAllRequirements(interp, objc-3, objv+3) != TCL_OK) {

Changes to generic/tclPosixStr.c.

31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
 *----------------------------------------------------------------------
 */

const char *
Tcl_ErrnoId(void)
{
    switch (errno) {
#ifdef E2BIG
    case E2BIG: return "E2BIG";
#endif
#ifdef EACCES
    case EACCES: return "EACCES";
#endif
#ifdef EADDRINUSE
    case EADDRINUSE: return "EADDRINUSE";







|







31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
 *----------------------------------------------------------------------
 */

const char *
Tcl_ErrnoId(void)
{
    switch (errno) {
#if defined(E2BIG) && (!defined(EOVERFLOW) || (E2BIG != EOVERFLOW))
    case E2BIG: return "E2BIG";
#endif
#ifdef EACCES
    case EACCES: return "EACCES";
#endif
#ifdef EADDRINUSE
    case EADDRINUSE: return "EADDRINUSE";
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
#endif
#ifdef ELIBBAD
    case ELIBBAD: return "ELIBBAD";
#endif
#ifdef ELIBEXEC
    case ELIBEXEC: return "ELIBEXEC";
#endif
#ifdef ELIBMAX
    case ELIBMAX: return "ELIBMAX";
#endif
#ifdef ELIBSCN
    case ELIBSCN: return "ELIBSCN";
#endif
#ifdef ELNRNG
    case ELNRNG: return "ELNRNG";







|







199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
#endif
#ifdef ELIBBAD
    case ELIBBAD: return "ELIBBAD";
#endif
#ifdef ELIBEXEC
    case ELIBEXEC: return "ELIBEXEC";
#endif
#if defined(ELIBMAX) && (!defined(ECANCELED) || (ELIBMAX != ECANCELED))
    case ELIBMAX: return "ELIBMAX";
#endif
#ifdef ELIBSCN
    case ELIBSCN: return "ELIBSCN";
#endif
#ifdef ELNRNG
    case ELNRNG: return "ELNRNG";
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
 */

const char *
Tcl_ErrnoMsg(
     int err)			/* Error number (such as in errno variable). */
{
    switch (err) {
#ifdef E2BIG
    case E2BIG: return "argument list too long";
#endif
#ifdef EACCES
    case EACCES: return "permission denied";
#endif
#ifdef EADDRINUSE
    case EADDRINUSE: return "address already in use";







|







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

const char *
Tcl_ErrnoMsg(
     int err)			/* Error number (such as in errno variable). */
{
    switch (err) {
#if defined(E2BIG) && (!defined(EOVERFLOW) || (E2BIG != EOVERFLOW))
    case E2BIG: return "argument list too long";
#endif
#ifdef EACCES
    case EACCES: return "permission denied";
#endif
#ifdef EADDRINUSE
    case EADDRINUSE: return "address already in use";
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
#endif
#ifdef ELIBBAD
    case ELIBBAD: return "accessing a corrupted shared library";
#endif
#ifdef ELIBEXEC
    case ELIBEXEC: return "cannot exec a shared library directly";
#endif
#ifdef ELIBMAX
    case ELIBMAX: return
	    "attempting to link in more shared libraries than system limit";
#endif
#ifdef ELIBSCN
    case ELIBSCN: return ".lib section in a.out corrupted";
#endif
#ifdef ELNRNG







|







658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
#endif
#ifdef ELIBBAD
    case ELIBBAD: return "accessing a corrupted shared library";
#endif
#ifdef ELIBEXEC
    case ELIBEXEC: return "cannot exec a shared library directly";
#endif
#if defined(ELIBMAX) && (!defined(ECANCELED) || (ELIBMAX != ECANCELED))
    case ELIBMAX: return
	    "attempting to link in more shared libraries than system limit";
#endif
#ifdef ELIBSCN
    case ELIBSCN: return ".lib section in a.out corrupted";
#endif
#ifdef ELNRNG

Changes to generic/tclPreserve.c.

364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
				 * dereferencing it will give NULL. */
{
    HandleStruct *handlePtr;

    handlePtr = (HandleStruct *) handle;
#ifdef TCL_MEM_DEBUG
    if (handlePtr->refCount == 0x61616161) {
	Tcl_Panic("using previously disposed TclHandle %x", handlePtr);
    }
    if (handlePtr->ptr2 != handlePtr->ptr) {
	Tcl_Panic("someone has changed the block referenced by the handle %x\nfrom %x to %x",
		handlePtr, handlePtr->ptr2, handlePtr->ptr);
    }
#endif
    handlePtr->ptr = NULL;
    if (handlePtr->refCount == 0) {
	ckfree(handlePtr);
    }







|


|







364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
				 * dereferencing it will give NULL. */
{
    HandleStruct *handlePtr;

    handlePtr = (HandleStruct *) handle;
#ifdef TCL_MEM_DEBUG
    if (handlePtr->refCount == 0x61616161) {
	Tcl_Panic("using previously disposed TclHandle %p", handlePtr);
    }
    if (handlePtr->ptr2 != handlePtr->ptr) {
	Tcl_Panic("someone has changed the block referenced by the handle %p\nfrom %p to %p",
		handlePtr, handlePtr->ptr2, handlePtr->ptr);
    }
#endif
    handlePtr->ptr = NULL;
    if (handlePtr->refCount == 0) {
	ckfree(handlePtr);
    }
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
				 * referenced by this handle. */
{
    HandleStruct *handlePtr;

    handlePtr = (HandleStruct *) handle;
#ifdef TCL_MEM_DEBUG
    if (handlePtr->refCount == 0x61616161) {
	Tcl_Panic("using previously disposed TclHandle %x", handlePtr);
    }
    if ((handlePtr->ptr != NULL) && (handlePtr->ptr != handlePtr->ptr2)) {
	Tcl_Panic("someone has changed the block referenced by the handle %x\nfrom %x to %x",
		handlePtr, handlePtr->ptr2, handlePtr->ptr);
    }
#endif
    handlePtr->refCount++;

    return handle;
}







|


|







407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
				 * referenced by this handle. */
{
    HandleStruct *handlePtr;

    handlePtr = (HandleStruct *) handle;
#ifdef TCL_MEM_DEBUG
    if (handlePtr->refCount == 0x61616161) {
	Tcl_Panic("using previously disposed TclHandle %p", handlePtr);
    }
    if ((handlePtr->ptr != NULL) && (handlePtr->ptr != handlePtr->ptr2)) {
	Tcl_Panic("someone has changed the block referenced by the handle %p\nfrom %p to %p",
		handlePtr, handlePtr->ptr2, handlePtr->ptr);
    }
#endif
    handlePtr->refCount++;

    return handle;
}
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
				 * referenced by this handle. */
{
    HandleStruct *handlePtr;

    handlePtr = (HandleStruct *) handle;
#ifdef TCL_MEM_DEBUG
    if (handlePtr->refCount == 0x61616161) {
	Tcl_Panic("using previously disposed TclHandle %x", handlePtr);
    }
    if ((handlePtr->ptr != NULL) && (handlePtr->ptr != handlePtr->ptr2)) {
	Tcl_Panic("someone has changed the block referenced by the handle %x\nfrom %x to %x",
		handlePtr, handlePtr->ptr2, handlePtr->ptr);
    }
#endif
    handlePtr->refCount--;
    if ((handlePtr->refCount == 0) && (handlePtr->ptr == NULL)) {
	ckfree(handlePtr);
    }







|


|







448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
				 * referenced by this handle. */
{
    HandleStruct *handlePtr;

    handlePtr = (HandleStruct *) handle;
#ifdef TCL_MEM_DEBUG
    if (handlePtr->refCount == 0x61616161) {
	Tcl_Panic("using previously disposed TclHandle %p", handlePtr);
    }
    if ((handlePtr->ptr != NULL) && (handlePtr->ptr != handlePtr->ptr2)) {
	Tcl_Panic("someone has changed the block referenced by the handle %p\nfrom %p to %p",
		handlePtr, handlePtr->ptr2, handlePtr->ptr);
    }
#endif
    handlePtr->refCount--;
    if ((handlePtr->refCount == 0) && (handlePtr->ptr == NULL)) {
	ckfree(handlePtr);
    }

Changes to generic/tclProc.c.

1116
1117
1118
1119
1120
1121
1122


1123
1124
1125
1126
1127
1128
1129
    numArgs = framePtr->procPtr->numArgs;
    desiredObjs = TclStackAlloc(interp,
	    (int) sizeof(Tcl_Obj *) * (numArgs+1));

    if (framePtr->isProcCallFrame & FRAME_IS_LAMBDA) {
	desiredObjs[0] = Tcl_NewStringObj("lambdaExpr", -1);
    } else {


#ifdef AVOID_HACKS_FOR_ITCL
	desiredObjs[0] = framePtr->objv[skip-1];
#else
	desiredObjs[0] = Tcl_NewListObj(skip, framePtr->objv);
#endif /* AVOID_HACKS_FOR_ITCL */
    }
    Tcl_IncrRefCount(desiredObjs[0]);







>
>







1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
    numArgs = framePtr->procPtr->numArgs;
    desiredObjs = TclStackAlloc(interp,
	    (int) sizeof(Tcl_Obj *) * (numArgs+1));

    if (framePtr->isProcCallFrame & FRAME_IS_LAMBDA) {
	desiredObjs[0] = Tcl_NewStringObj("lambdaExpr", -1);
    } else {
	((Interp *) interp)->ensembleRewrite.numInsertedObjs -= skip - 1;

#ifdef AVOID_HACKS_FOR_ITCL
	desiredObjs[0] = framePtr->objv[skip-1];
#else
	desiredObjs[0] = Tcl_NewListObj(skip, framePtr->objv);
#endif /* AVOID_HACKS_FOR_ITCL */
    }
    Tcl_IncrRefCount(desiredObjs[0]);
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
		Tcl_SetErrorCode(interp, "TCL", "OPERATION", "PROC",
			"CROSSINTERPBYTECODE", NULL);
		return TCL_ERROR;
	    }
	    codePtr->compileEpoch = iPtr->compileEpoch;
	    codePtr->nsPtr = nsPtr;
	} else {
	    bodyPtr->typePtr->freeIntRepProc(bodyPtr);
	    bodyPtr->typePtr = NULL;
	}
    }

    if (bodyPtr->typePtr != &tclByteCodeType) {
	Tcl_HashEntry *hePtr;

#ifdef TCL_COMPILE_DEBUG







<
|







2004
2005
2006
2007
2008
2009
2010

2011
2012
2013
2014
2015
2016
2017
2018
		Tcl_SetErrorCode(interp, "TCL", "OPERATION", "PROC",
			"CROSSINTERPBYTECODE", NULL);
		return TCL_ERROR;
	    }
	    codePtr->compileEpoch = iPtr->compileEpoch;
	    codePtr->nsPtr = nsPtr;
	} else {

	    TclFreeIntRep(bodyPtr);
	}
    }

    if (bodyPtr->typePtr != &tclByteCodeType) {
	Tcl_HashEntry *hePtr;

#ifdef TCL_COMPILE_DEBUG
2060
2061
2062
2063
2064
2065
2066







2067
2068
2069
2070
2071
2072
2073
		procPtr->firstLocalPtr = NULL;
	    }
	    procPtr->lastLocalPtr = lastPtr;
	    while (clPtr) {
		CompiledLocal *toFree = clPtr;

		clPtr = clPtr->nextPtr;







		ckfree(toFree);
	    }
	    procPtr->numCompiledLocals = procPtr->numArgs;
	}

	TclPushStackFrame(interp, &framePtr, (Tcl_Namespace *) nsPtr,
		/* isProcCallFrame */ 0);







>
>
>
>
>
>
>







2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
		procPtr->firstLocalPtr = NULL;
	    }
	    procPtr->lastLocalPtr = lastPtr;
	    while (clPtr) {
		CompiledLocal *toFree = clPtr;

		clPtr = clPtr->nextPtr;
		if (toFree->resolveInfo) {
		    if (toFree->resolveInfo->deleteProc) {
			toFree->resolveInfo->deleteProc(toFree->resolveInfo);
		    } else {
			ckfree(toFree->resolveInfo);
		    }
		}
		ckfree(toFree);
	    }
	    procPtr->numCompiledLocals = procPtr->numArgs;
	}

	TclPushStackFrame(interp, &framePtr, (Tcl_Namespace *) nsPtr,
		/* isProcCallFrame */ 0);
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479




2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491


2492
2493
2494
2495
2496
2497
2498
static int
SetLambdaFromAny(
    Tcl_Interp *interp,		/* Used for error reporting if not NULL. */
    register Tcl_Obj *objPtr)	/* The object to convert. */
{
    Interp *iPtr = (Interp *) interp;
    const char *name;
    Tcl_Obj *argsPtr, *bodyPtr, *nsObjPtr, **objv, *errPtr;
    int objc, result;
    Proc *procPtr;





    /*
     * Convert objPtr to list type first; if it cannot be converted, or if its
     * length is not 2, then it cannot be converted to lambdaType.
     */

    result = TclListObjGetElements(interp, objPtr, &objc, &objv);
    if ((result != TCL_OK) || ((objc != 2) && (objc != 3))) {
	TclNewLiteralStringObj(errPtr, "can't interpret \"");
	Tcl_AppendObjToObj(errPtr, objPtr);
	Tcl_AppendToObj(errPtr, "\" as a lambda expression", -1);
	Tcl_SetObjResult(interp, errPtr);


	Tcl_SetErrorCode(interp, "TCL", "VALUE", "LAMBDA", NULL);
	return TCL_ERROR;
    }

    argsPtr = objv[0];
    bodyPtr = objv[1];








|


>
>
>
>






|

<
<
<
|
>
>







2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499



2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
static int
SetLambdaFromAny(
    Tcl_Interp *interp,		/* Used for error reporting if not NULL. */
    register Tcl_Obj *objPtr)	/* The object to convert. */
{
    Interp *iPtr = (Interp *) interp;
    const char *name;
    Tcl_Obj *argsPtr, *bodyPtr, *nsObjPtr, **objv;
    int objc, result;
    Proc *procPtr;

    if (interp == NULL) {
	return TCL_ERROR;
    }

    /*
     * Convert objPtr to list type first; if it cannot be converted, or if its
     * length is not 2, then it cannot be converted to lambdaType.
     */

    result = TclListObjGetElements(NULL, objPtr, &objc, &objv);
    if ((result != TCL_OK) || ((objc != 2) && (objc != 3))) {



	Tcl_SetObjResult(interp, Tcl_ObjPrintf(
		"can't interpret \"%s\" as a lambda expression",
		Tcl_GetString(objPtr)));
	Tcl_SetErrorCode(interp, "TCL", "VALUE", "LAMBDA", NULL);
	return TCL_ERROR;
    }

    argsPtr = objv[0];
    bodyPtr = objv[1];

2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641

    /*
     * Free the list internalrep of objPtr - this will free argsPtr, but
     * bodyPtr retains a reference from the Proc structure. Then finish the
     * conversion to lambdaType.
     */

    objPtr->typePtr->freeIntRepProc(objPtr);

    objPtr->internalRep.twoPtrValue.ptr1 = procPtr;
    objPtr->internalRep.twoPtrValue.ptr2 = nsObjPtr;
    objPtr->typePtr = &lambdaType;
    return TCL_OK;
}








|







2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652

    /*
     * Free the list internalrep of objPtr - this will free argsPtr, but
     * bodyPtr retains a reference from the Proc structure. Then finish the
     * conversion to lambdaType.
     */

    TclFreeIntRep(objPtr);

    objPtr->internalRep.twoPtrValue.ptr1 = procPtr;
    objPtr->internalRep.twoPtrValue.ptr2 = nsObjPtr;
    objPtr->typePtr = &lambdaType;
    return TCL_OK;
}


Changes to generic/tclResult.c.

985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
	    if (objResultPtr->bytes) {
		ckfree(objResultPtr->bytes);
	    }
	    objResultPtr->bytes = tclEmptyStringRep;
	    objResultPtr->length = 0;
	}
	TclFreeIntRep(objResultPtr);
	objResultPtr->typePtr = NULL;
    }
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_SetErrorCodeVA --







<







985
986
987
988
989
990
991

992
993
994
995
996
997
998
	    if (objResultPtr->bytes) {
		ckfree(objResultPtr->bytes);
	    }
	    objResultPtr->bytes = tclEmptyStringRep;
	    objResultPtr->length = 0;
	}
	TclFreeIntRep(objResultPtr);

    }
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_SetErrorCodeVA --
1590
1591
1592
1593
1594
1595
1596























1597
1598
1599
1600
1601
1602
1603
	Tcl_DictObjPut(NULL, options, keys[KEY_ERRORCODE], iPtr->errorCode);
    }
    if (iPtr->errorInfo) {
	Tcl_DictObjPut(NULL, options, keys[KEY_ERRORINFO], iPtr->errorInfo);
	Tcl_DictObjPut(NULL, options, keys[KEY_ERRORLINE],
		Tcl_NewIntObj(iPtr->errorLine));
    }























    return options;
}

/*
 *-------------------------------------------------------------------------
 *
 * Tcl_SetReturnOptions --







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







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
	Tcl_DictObjPut(NULL, options, keys[KEY_ERRORCODE], iPtr->errorCode);
    }
    if (iPtr->errorInfo) {
	Tcl_DictObjPut(NULL, options, keys[KEY_ERRORINFO], iPtr->errorInfo);
	Tcl_DictObjPut(NULL, options, keys[KEY_ERRORLINE],
		Tcl_NewIntObj(iPtr->errorLine));
    }
    return options;
}

/*
 *-------------------------------------------------------------------------
 *
 * TclNoErrorStack --
 *
 *	Removes the -errorstack entry from an options dict to avoid reference cycles
 *
 * Results:
 *	The (unshared) argument options dict, modified in -place.
 *
 *-------------------------------------------------------------------------
 */

Tcl_Obj *
TclNoErrorStack(Tcl_Interp *interp, Tcl_Obj *options)
{
    Tcl_Obj **keys = GetKeys();
    
    Tcl_DictObjRemove(interp, options, keys[KEY_ERRORSTACK]);

    return options;
}

/*
 *-------------------------------------------------------------------------
 *
 * Tcl_SetReturnOptions --

Changes to generic/tclScan.c.

997
998
999
1000
1001
1002
1003
1004





1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
	 */

	for (i = 0; i < totalVars; i++) {
	    if (objs[i] == NULL) {
		continue;
	    }
	    result++;
#warning Why make your own error message? Why?





	    if (Tcl_ObjSetVar2(interp, objv[i+3], NULL, objs[i], 0) == NULL) {
		Tcl_AppendResult(interp, "couldn't set variable \"",
			TclGetString(objv[i+3]), "\"", NULL);
		code = TCL_ERROR;
	    }
	    Tcl_DecrRefCount(objs[i]);
	}
    } else {
	/*
	 * Here no vars were specified, we want a list returned (inline scan)







|
>
>
>
>
>
|
<
|







997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010

1011
1012
1013
1014
1015
1016
1017
1018
	 */

	for (i = 0; i < totalVars; i++) {
	    if (objs[i] == NULL) {
		continue;
	    }
	    result++;

	    /*
	     * In case of multiple errors in setting variables, just report
	     * the first one.
	     */

	    if (Tcl_ObjSetVar2(interp, objv[i+3], NULL, objs[i],

		    (code == TCL_OK) ? TCL_LEAVE_ERR_MSG : 0) == NULL) {
		code = TCL_ERROR;
	    }
	    Tcl_DecrRefCount(objs[i]);
	}
    } else {
	/*
	 * Here no vars were specified, we want a list returned (inline scan)
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
	} else if (numVars) {
	    objPtr = Tcl_NewIntObj(result);
	}
	Tcl_SetObjResult(interp, objPtr);
    }
    return code;
}

/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78
 * End:
 */







|







1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
	} else if (numVars) {
	    objPtr = Tcl_NewIntObj(result);
	}
	Tcl_SetObjResult(interp, objPtr);
    }
    return code;
}

/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78
 * End:
 */

Changes to generic/tclStrToD.c.

245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
    10000,
    100000,
    1000000,
    10000000,
    100000000
};

static const Tcl_WideUInt wtens[] = {
    1, 10, 100, 1000, 10000, 100000, 1000000,
    (Tcl_WideUInt) 1000000*10, 		(Tcl_WideUInt) 1000000*100,
    (Tcl_WideUInt) 1000000*1000, 	(Tcl_WideUInt) 1000000*10000,
    (Tcl_WideUInt) 1000000*100000, 	(Tcl_WideUInt) 1000000*1000000,
    (Tcl_WideUInt) 1000000*1000000*10, 	(Tcl_WideUInt) 1000000*1000000*100,
    (Tcl_WideUInt) 1000000*1000000*1000,(Tcl_WideUInt) 1000000*1000000*10000
};

static const double bigtens[] = {
    1e016, 1e032, 1e064, 1e128, 1e256
};
#define N_BIGTENS 5

static const int log2pow5[27] = {
    01,  3,  5,  7, 10, 12, 14, 17, 19, 21,







<
<
<
<
<
<
<
<
<







245
246
247
248
249
250
251









252
253
254
255
256
257
258
    10000,
    100000,
    1000000,
    10000000,
    100000000
};










static const double bigtens[] = {
    1e016, 1e032, 1e064, 1e128, 1e256
};
#define N_BIGTENS 5

static const int log2pow5[27] = {
    01,  3,  5,  7, 10, 12, 14, 17, 19, 21,
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581

	case INITIAL:
	    /*
	     * Initial state. Acceptable characters are +, -, digits, period,
	     * I, N, and whitespace.
	     */

	    if (isspace(UCHAR(c))) {
		if (flags & TCL_PARSE_NO_WHITESPACE) {
		    goto endgame;
		}
		break;
	    } else if (c == '+') {
		state = SIGNUM;
		break;







|







558
559
560
561
562
563
564
565
566
567
568
569
570
571
572

	case INITIAL:
	    /*
	     * Initial state. Acceptable characters are +, -, digits, period,
	     * I, N, and whitespace.
	     */

	    if (TclIsSpaceProc(c)) {
		if (flags & TCL_PARSE_NO_WHITESPACE) {
		    goto endgame;
		}
		break;
	    } else if (c == '+') {
		state = SIGNUM;
		break;
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
	case sNANHEX:
	    if (c == ')') {
		state = sNANFINISH;
		break;
	    }
	    /* FALLTHROUGH */
	case sNANPAREN:
	    if (isspace(UCHAR(c))) {
		break;
	    }
	    if (numSigDigs < 13) {
		if (c >= '0' && c <= '9') {
		    d = c - '0';
		} else if (c >= 'a' && c <= 'f') {
		    d = 10 + c - 'a';
		} else if (c >= 'A' && c <= 'F') {
		    d = 10 + c - 'A';


		}

		significandWide = (significandWide << 4) + d;
		state = sNANHEX;
		break;
	    }
	    goto endgame;
	case sNANFINISH:
#endif







|









>
>

>







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
	case sNANHEX:
	    if (c == ')') {
		state = sNANFINISH;
		break;
	    }
	    /* FALLTHROUGH */
	case sNANPAREN:
	    if (TclIsSpaceProc(c)) {
		break;
	    }
	    if (numSigDigs < 13) {
		if (c >= '0' && c <= '9') {
		    d = c - '0';
		} else if (c >= 'a' && c <= 'f') {
		    d = 10 + c - 'a';
		} else if (c >= 'A' && c <= 'F') {
		    d = 10 + c - 'A';
		} else {
		    goto endgame;
		}
		numSigDigs++;
		significandWide = (significandWide << 4) + d;
		state = sNANHEX;
		break;
	    }
	    goto endgame;
	case sNANFINISH:
#endif
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
	p = acceptPoint;
	len = acceptLen;
	if (!(flags & TCL_PARSE_NO_WHITESPACE)) {
	    /*
	     * Accept trailing whitespace.
	     */

	    while (len != 0 && isspace(UCHAR(*p))) {
		p++;
		len--;
	    }
	}
	if (endPtrPtr == NULL) {
	    if ((len != 0) && ((numBytes > 0) || (*p != '\0'))) {
		status = TCL_ERROR;







|







1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
	p = acceptPoint;
	len = acceptLen;
	if (!(flags & TCL_PARSE_NO_WHITESPACE)) {
	    /*
	     * Accept trailing whitespace.
	     */

	    while (len != 0 && TclIsSpaceProc(*p)) {
		p++;
		len--;
	    }
	}
	if (endPtrPtr == NULL) {
	    if ((len != 0) && ((numBytes > 0) || (*p != '\0'))) {
		status = TCL_ERROR;
1380
1381
1382
1383
1384
1385
1386
1387

1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398

    /*
     * Format an error message when an invalid number is encountered.
     */

    if (status != TCL_OK) {
	if (interp != NULL) {
	    Tcl_Obj *msg;


	    TclNewLiteralStringObj(msg, "expected ");
	    Tcl_AppendToObj(msg, expected, -1);
	    Tcl_AppendToObj(msg, " but got \"", -1);
	    Tcl_AppendLimitedToObj(msg, bytes, numBytes, 50, "");
	    Tcl_AppendToObj(msg, "\"", -1);
	    if (state == BAD_OCTAL) {
		Tcl_AppendToObj(msg, " (looks like invalid octal number)", -1);
	    }
	    Tcl_SetObjResult(interp, msg);
	    Tcl_SetErrorCode(interp, "TCL", "VALUE", "NUMBER", NULL);







|
>

<
<
<







1374
1375
1376
1377
1378
1379
1380
1381
1382
1383



1384
1385
1386
1387
1388
1389
1390

    /*
     * Format an error message when an invalid number is encountered.
     */

    if (status != TCL_OK) {
	if (interp != NULL) {
	    Tcl_Obj *msg = Tcl_ObjPrintf("expected %s but got \"",
		    expected);




	    Tcl_AppendLimitedToObj(msg, bytes, numBytes, 50, "");
	    Tcl_AppendToObj(msg, "\"", -1);
	    if (state == BAD_OCTAL) {
		Tcl_AppendToObj(msg, " (looks like invalid octal number)", -1);
	    }
	    Tcl_SetObjResult(interp, msg);
	    Tcl_SetErrorCode(interp, "TCL", "VALUE", "NUMBER", NULL);
3816
3817
3818
3819
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829
3830
     * Endgame - store the location of the decimal point and the end of the
     * string.
     */

    if (m2plus > m2minus) {
	mp_clear(&mplus);
    }
    mp_clear_multi(&b, &mminus, &temp, NULL);
    *s = '\0';
    *decpt = k;
    if (endPtr) {
	*endPtr = s;
    }
    return retval;
}







|







3808
3809
3810
3811
3812
3813
3814
3815
3816
3817
3818
3819
3820
3821
3822
     * Endgame - store the location of the decimal point and the end of the
     * string.
     */

    if (m2plus > m2minus) {
	mp_clear(&mplus);
    }
    mp_clear_multi(&b, &mminus, &temp, &dig, &S, NULL);
    *s = '\0';
    *decpt = k;
    if (endPtr) {
	*endPtr = s;
    }
    return retval;
}
3873
3874
3875
3876
3877
3878
3879

3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
    int i, j;

    /*
     * b = bw * 2**b2 * 5**b5
     * S = 2**s2 * 5*s5
     */


    TclBNInitBignumFromWideUInt(&b, bw);
    mp_mul_2d(&b, b2, &b);
    mp_init_set_int(&S, 1);
    MulPow5(&S, s5, &S); mp_mul_2d(&S, s2, &S);

    /*
     * Handle the case where we guess the position of the decimal point wrong.
     */

    if (mp_cmp_mag(&b, &S) == MP_LT) {
	mp_mul_d(&b, 10, &b);
	ilim =ilim1;
	--k;
    }
    mp_init(&temp);

    /*
     * Convert the leading digit.
     */

    mp_init(&dig);
    i = 0;
    mp_div(&b, &S, &dig, &b);
    if (dig.used > 1 || dig.dp[0] >= 10) {
	Tcl_Panic("wrong digit!");
    }
    digit = dig.dp[0];








>














<





<







3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886

3887
3888
3889
3890
3891

3892
3893
3894
3895
3896
3897
3898
    int i, j;

    /*
     * b = bw * 2**b2 * 5**b5
     * S = 2**s2 * 5*s5
     */

    mp_init_multi(&temp, &dig, NULL);
    TclBNInitBignumFromWideUInt(&b, bw);
    mp_mul_2d(&b, b2, &b);
    mp_init_set_int(&S, 1);
    MulPow5(&S, s5, &S); mp_mul_2d(&S, s2, &S);

    /*
     * Handle the case where we guess the position of the decimal point wrong.
     */

    if (mp_cmp_mag(&b, &S) == MP_LT) {
	mp_mul_d(&b, 10, &b);
	ilim =ilim1;
	--k;
    }


    /*
     * Convert the leading digit.
     */


    i = 0;
    mp_div(&b, &S, &dig, &b);
    if (dig.used > 1 || dig.dp[0] >= 10) {
	Tcl_Panic("wrong digit!");
    }
    digit = dig.dp[0];

3981
3982
3983
3984
3985
3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
    ++s;

    /*
     * Endgame - store the location of the decimal point and the end of the
     * string.
     */

    mp_clear_multi(&b, &temp, NULL);
    *s = '\0';
    *decpt = k;
    if (endPtr) {
	*endPtr = s;
    }
    return retval;
}







|







3972
3973
3974
3975
3976
3977
3978
3979
3980
3981
3982
3983
3984
3985
3986
    ++s;

    /*
     * Endgame - store the location of the decimal point and the end of the
     * string.
     */

    mp_clear_multi(&b, &S, &temp, &dig, NULL);
    *s = '\0';
    *decpt = k;
    if (endPtr) {
	*endPtr = s;
    }
    return retval;
}
4478
4479
4480
4481
4482
4483
4484



4485
4486
4487
4488
4489
4490
4491
{
    int i;

    ckfree(pow10_wide);
    for (i=0; i<9; ++i) {
	mp_clear(pow5 + i);
    }



}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_InitBignumFromDouble --
 *







>
>
>







4469
4470
4471
4472
4473
4474
4475
4476
4477
4478
4479
4480
4481
4482
4483
4484
4485
{
    int i;

    ckfree(pow10_wide);
    for (i=0; i<9; ++i) {
	mp_clear(pow5 + i);
    }
    for (i=0; i < 5; ++i) {
	mp_clear(pow5_13 + i);
    }
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_InitBignumFromDouble --
 *
4559
4560
4561
4562
4563
4564
4565
4566
4567
4568

4569
4570
4571

4572
4573
4574
4575
4576
4577
4578
4579
4580
4581
4582
4583











4584
4585


4586
4587







4588



4589




4590



4591


4592



4593


4594
4595
4596
4597
4598
4599
4600
 */

double
TclBignumToDouble(
    const mp_int *a)			/* Integer to convert. */
{
    mp_int b;
    int bits, shift, i;
    double r;


    /*
     * Determine how many bits we need, and extract that many from the input.
     * Round to nearest unit in the last place.

     */

    bits = mp_count_bits(a);
    if (bits > DBL_MAX_EXP*log2FLT_RADIX) {
	errno = ERANGE;
	if (a->sign == MP_ZPOS) {
	    return HUGE_VAL;
	} else {
	    return -HUGE_VAL;
	}
    }
    shift = mantBits + 1 - bits;











    mp_init(&b);
    if (shift > 0) {


	mp_mul_2d(a, shift, &b);
    } else if (shift < 0) {







	mp_div_2d(a, -shift, &b, NULL);



    } else {




	mp_copy(a, &b);



    }


    mp_add_d(&b, 1, &b);



    mp_div_2d(&b, 1, &b, NULL);



    /*
     * Accumulate the result, one mp_digit at a time.
     */

    r = 0.0;
    for (i=b.used-1 ; i>=0 ; --i) {







|


>

|
<
>











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

|
>
>


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







4553
4554
4555
4556
4557
4558
4559
4560
4561
4562
4563
4564
4565

4566
4567
4568
4569
4570
4571
4572
4573
4574
4575
4576
4577
4578
4579
4580
4581
4582
4583
4584
4585
4586
4587
4588
4589
4590
4591
4592
4593
4594
4595
4596
4597
4598
4599
4600
4601
4602
4603
4604
4605
4606
4607
4608
4609
4610
4611
4612
4613
4614
4615
4616
4617
4618
4619
4620
4621
4622
4623
4624
4625
4626
4627
4628
4629
4630
4631
4632
 */

double
TclBignumToDouble(
    const mp_int *a)			/* Integer to convert. */
{
    mp_int b;
    int bits, shift, i, lsb;
    double r;


    /*
     * We need a 'mantBits'-bit significand.  Determine what shift will 

     * give us that.
     */

    bits = mp_count_bits(a);
    if (bits > DBL_MAX_EXP*log2FLT_RADIX) {
	errno = ERANGE;
	if (a->sign == MP_ZPOS) {
	    return HUGE_VAL;
	} else {
	    return -HUGE_VAL;
	}
    }
    shift = mantBits - bits;

    /* 
     * If shift > 0, shift the significand left by the requisite number of
     * bits.  If shift == 0, the significand is already exactly 'mantBits'
     * in length.  If shift < 0, we will need to shift the significand right
     * by the requisite number of bits, and round it. If the '1-shift'
     * least significant bits are 0, but the 'shift'th bit is nonzero,
     * then the significand lies exactly between two values and must be
     * 'rounded to even'.
     */

    mp_init(&b);
    if (shift == 0) {
	mp_copy(a, &b);
    } else if (shift > 0) {
	mp_mul_2d(a, shift, &b);
    } else if (shift < 0) {
	lsb = mp_cnt_lsb(a);
	if (lsb == -1-shift) {

	    /*
	     * Round to even
	     */

	    mp_div_2d(a, -shift, &b, NULL);
	    if (mp_isodd(&b)) {
		if (b.sign == MP_ZPOS) {
		    mp_add_d(&b, 1, &b);
		} else {
		    mp_sub_d(&b, 1, &b);
		}
	    }
	} else {

	    /*
	     * Ordinary rounding
	     */

	    mp_div_2d(a, -1-shift, &b, NULL);
	    if (b.sign == MP_ZPOS) {
		mp_add_d(&b, 1, &b);
	    } else {
		mp_sub_d(&b, 1, &b);
	    }
	    mp_div_2d(&b, 1, &b, NULL);
	}
    }

    /*
     * Accumulate the result, one mp_digit at a time.
     */

    r = 0.0;
    for (i=b.used-1 ; i>=0 ; --i) {

Changes to generic/tclStringObj.c.

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
#define STRING_SIZE(numChars) \
	(sizeof(String) + ((numChars) * sizeof(Tcl_UniChar)))
#define stringCheckLimits(numChars) \
    if ((numChars) < 0 || (numChars) > STRING_MAXCHARS) { \
	Tcl_Panic("max length for a Tcl unicode value (%d chars) exceeded", \
		STRING_MAXCHARS); \
    }


#define stringAlloc(numChars) \
	(String *) ckalloc((unsigned) STRING_SIZE(numChars) )
#define stringRealloc(ptr, numChars) \
    (String *) ckrealloc((ptr), (unsigned) STRING_SIZE(numChars) )
#define stringAttemptRealloc(ptr, numChars) \
    (String *) attemptckrealloc((ptr), (unsigned) STRING_SIZE(numChars) )
#define GET_STRING(objPtr) \
	((String *) (objPtr)->internalRep.otherValuePtr)
#define SET_STRING(objPtr, stringPtr) \
	((objPtr)->internalRep.otherValuePtr = (void *) (stringPtr))

/*
 * TCL STRING GROWTH ALGORITHM
 *
 * When growing strings (during an append, for example), the following growth
 * algorithm is used:
 *
 *   Attempt to allocate 2 * (originalLength + appendLength)
 *   On failure:
 *	attempt to allocate originalLength + 2*appendLength +
 *			TCL_GROWTH_MIN_ALLOC
 *
 * This algorithm allows very good performance, as it rapidly increases the
 * memory allocated for a given string, which minimizes the number of
 * reallocations that must be performed. However, using only the doubling
 * algorithm can lead to a significant waste of memory. In particular, it may
 * fail even when there is sufficient memory available to complete the append
 * request (but there is not 2*totalLength memory available). So when the
 * doubling fails (because there is not enough memory available), the
 * algorithm requests a smaller amount of memory, which is still enough to
 * cover the request, but which hopefully will be less than the total
 * available memory.
 *
 * The addition of TCL_GROWTH_MIN_ALLOC allows for efficient handling of very
 * small appends. Without this extra slush factor, a sequence of several small
 * appends would cause several memory allocations. As long as
 * TCL_GROWTH_MIN_ALLOC is a reasonable size, we can avoid that behavior.
 *
 * The growth algorithm can be tuned by adjusting the following parameters:
 *
 * TCL_GROWTH_MIN_ALLOC		Additional space, in bytes, to allocate when
 *				the double allocation has failed. Default is
 *				1024 (1 kilobyte).
 */

#ifndef TCL_GROWTH_MIN_ALLOC
#define TCL_GROWTH_MIN_ALLOC	1024
#endif

static void
GrowStringBuffer(
    Tcl_Obj *objPtr,
    int needed,
    int flag)







>
>



















|
<












|


|



|

|


|
|







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
#define STRING_SIZE(numChars) \
	(sizeof(String) + ((numChars) * sizeof(Tcl_UniChar)))
#define stringCheckLimits(numChars) \
    if ((numChars) < 0 || (numChars) > STRING_MAXCHARS) { \
	Tcl_Panic("max length for a Tcl unicode value (%d chars) exceeded", \
		STRING_MAXCHARS); \
    }
#define stringAttemptAlloc(numChars) \
	(String *) attemptckalloc((unsigned) STRING_SIZE(numChars) )
#define stringAlloc(numChars) \
	(String *) ckalloc((unsigned) STRING_SIZE(numChars) )
#define stringRealloc(ptr, numChars) \
    (String *) ckrealloc((ptr), (unsigned) STRING_SIZE(numChars) )
#define stringAttemptRealloc(ptr, numChars) \
    (String *) attemptckrealloc((ptr), (unsigned) STRING_SIZE(numChars) )
#define GET_STRING(objPtr) \
	((String *) (objPtr)->internalRep.otherValuePtr)
#define SET_STRING(objPtr, stringPtr) \
	((objPtr)->internalRep.otherValuePtr = (void *) (stringPtr))

/*
 * TCL STRING GROWTH ALGORITHM
 *
 * When growing strings (during an append, for example), the following growth
 * algorithm is used:
 *
 *   Attempt to allocate 2 * (originalLength + appendLength)
 *   On failure:
 *	attempt to allocate originalLength + 2*appendLength + TCL_MIN_GROWTH

 *
 * This algorithm allows very good performance, as it rapidly increases the
 * memory allocated for a given string, which minimizes the number of
 * reallocations that must be performed. However, using only the doubling
 * algorithm can lead to a significant waste of memory. In particular, it may
 * fail even when there is sufficient memory available to complete the append
 * request (but there is not 2*totalLength memory available). So when the
 * doubling fails (because there is not enough memory available), the
 * algorithm requests a smaller amount of memory, which is still enough to
 * cover the request, but which hopefully will be less than the total
 * available memory.
 *
 * The addition of TCL_MIN_GROWTH allows for efficient handling of very
 * small appends. Without this extra slush factor, a sequence of several small
 * appends would cause several memory allocations. As long as
 * TCL_MIN_GROWTH is a reasonable size, we can avoid that behavior.
 *
 * The growth algorithm can be tuned by adjusting the following parameters:
 *
 * TCL_MIN_GROWTH		Additional space, in bytes, to allocate when
 *				the double allocation has failed. Default is
 *				1024 (1 kilobyte).  See tclInt.h.
 */

#ifndef TCL_MIN_UNICHAR_GROWTH
#define TCL_MIN_UNICHAR_GROWTH	TCL_MIN_GROWTH/sizeof(Tcl_UniChar)
#endif

static void
GrowStringBuffer(
    Tcl_Obj *objPtr,
    int needed,
    int flag)
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
	if (ptr == NULL) {
	    /*
	     * Take care computing the amount of modest growth to avoid
	     * overflow into invalid argument values for attempt.
	     */

	    unsigned int limit = INT_MAX - needed;
	    unsigned int extra = needed - objPtr->length + TCL_GROWTH_MIN_ALLOC;
	    int growth = (int) ((extra > limit) ? limit : extra);

	    attempt = needed + growth;
	    ptr = attemptckrealloc(objPtr->bytes, attempt + 1);
	}
    }
    if (ptr == NULL) {







|







209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
	if (ptr == NULL) {
	    /*
	     * Take care computing the amount of modest growth to avoid
	     * overflow into invalid argument values for attempt.
	     */

	    unsigned int limit = INT_MAX - needed;
	    unsigned int extra = needed - objPtr->length + TCL_MIN_GROWTH;
	    int growth = (int) ((extra > limit) ? limit : extra);

	    attempt = needed + growth;
	    ptr = attemptckrealloc(objPtr->bytes, attempt + 1);
	}
    }
    if (ptr == NULL) {
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
	    /*
	     * Take care computing the amount of modest growth to avoid
	     * overflow into invalid argument values for attempt.
	     */

	    unsigned int limit = STRING_MAXCHARS - needed;
	    unsigned int extra = needed - stringPtr->numChars
		    + TCL_GROWTH_MIN_ALLOC/sizeof(Tcl_UniChar);
	    int growth = (int) ((extra > limit) ? limit : extra);

	    attempt = needed + growth;
	    ptr = stringAttemptRealloc(stringPtr, attempt);
	}
    }
    if (ptr == NULL) {







|







260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
	    /*
	     * Take care computing the amount of modest growth to avoid
	     * overflow into invalid argument values for attempt.
	     */

	    unsigned int limit = STRING_MAXCHARS - needed;
	    unsigned int extra = needed - stringPtr->numChars
		    + TCL_MIN_UNICHAR_GROWTH;
	    int growth = (int) ((extra > limit) ? limit : extra);

	    attempt = needed + growth;
	    ptr = stringAttemptRealloc(stringPtr, attempt);
	}
    }
    if (ptr == NULL) {
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
    }

    /*
     * Set the type to NULL and free any internal rep for the old type.
     */

    TclFreeIntRep(objPtr);
    objPtr->typePtr = NULL;

    /*
     * Free any old string rep, then set the string rep to a copy of the
     * length bytes starting at "bytes".
     */

    TclInvalidateStringRep(objPtr);







<







754
755
756
757
758
759
760

761
762
763
764
765
766
767
    }

    /*
     * Set the type to NULL and free any internal rep for the old type.
     */

    TclFreeIntRep(objPtr);


    /*
     * Free any old string rep, then set the string rep to a copy of the
     * length bytes starting at "bytes".
     */

    TclInvalidateStringRep(objPtr);
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
    stringPtr->numChars = -1;
    stringPtr->hasUnicode = 0;

    memcpy(objPtr->bytes + oldLength, bytes, numBytes);
    objPtr->bytes[newLength] = 0;
    objPtr->length = newLength;
}


/*
 *----------------------------------------------------------------------
 *
 * Tcl_AppendStringsToObjVA --
 *
 *	This function appends one or more null-terminated strings to an







<







1605
1606
1607
1608
1609
1610
1611

1612
1613
1614
1615
1616
1617
1618
    stringPtr->numChars = -1;
    stringPtr->hasUnicode = 0;

    memcpy(objPtr->bytes + oldLength, bytes, numBytes);
    objPtr->bytes[newLength] = 0;
    objPtr->length = newLength;
}


/*
 *----------------------------------------------------------------------
 *
 * Tcl_AppendStringsToObjVA --
 *
 *	This function appends one or more null-terminated strings to an
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
Tcl_AppendFormatToObj(
    Tcl_Interp *interp,
    Tcl_Obj *appendObj,
    const char *format,
    int objc,
    Tcl_Obj *const objv[])
{
    const char *span = format, *msg;
    int numBytes = 0, objIndex = 0, gotXpg = 0, gotSequential = 0;
    int originalLength, limit;
    static const char *mixedXPG =
	    "cannot mix \"%\" and \"%n$\" conversion specifiers";
    static const char *const badIndex[2] = {
	"not enough arguments for all format specifiers",
	"\"%n$\" argument index out of range"







|







1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
Tcl_AppendFormatToObj(
    Tcl_Interp *interp,
    Tcl_Obj *appendObj,
    const char *format,
    int objc,
    Tcl_Obj *const objv[])
{
    const char *span = format, *msg, *errCode;
    int numBytes = 0, objIndex = 0, gotXpg = 0, gotSequential = 0;
    int originalLength, limit;
    static const char *mixedXPG =
	    "cannot mix \"%\" and \"%n$\" conversion specifiers";
    static const char *const badIndex[2] = {
	"not enough arguments for all format specifiers",
	"\"%n$\" argument index out of range"
1740
1741
1742
1743
1744
1745
1746

1747
1748
1749
1750
1751
1752
1753
	if (ch != '%') {
	    numBytes += step;
	    continue;
	}
	if (numBytes) {
	    if (numBytes > limit) {
		msg = overflow;

		goto errorMsg;
	    }
	    Tcl_AppendToObj(appendObj, span, numBytes);
	    limit -= numBytes;
	    numBytes = 0;
	}








>







1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
	if (ch != '%') {
	    numBytes += step;
	    continue;
	}
	if (numBytes) {
	    if (numBytes > limit) {
		msg = overflow;
		errCode = "OVERFLOW";
		goto errorMsg;
	    }
	    Tcl_AppendToObj(appendObj, span, numBytes);
	    limit -= numBytes;
	    numBytes = 0;
	}

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
		format = end + 1;
		step = Tcl_UtfToUniChar(format, &ch);
	    }
	}
	if (newXpg) {
	    if (gotSequential) {
		msg = mixedXPG;

		goto errorMsg;
	    }
	    gotXpg = 1;
	} else {
	    if (gotXpg) {
		msg = mixedXPG;

		goto errorMsg;
	    }
	    gotSequential = 1;
	}
	if ((objIndex < 0) || (objIndex >= objc)) {
	    msg = badIndex[gotXpg];

	    goto errorMsg;
	}

	/*
	 * Step 2. Set of flags.
	 */








>






>






>







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
		format = end + 1;
		step = Tcl_UtfToUniChar(format, &ch);
	    }
	}
	if (newXpg) {
	    if (gotSequential) {
		msg = mixedXPG;
		errCode = "MIXEDSPECTYPES";
		goto errorMsg;
	    }
	    gotXpg = 1;
	} else {
	    if (gotXpg) {
		msg = mixedXPG;
		errCode = "MIXEDSPECTYPES";
		goto errorMsg;
	    }
	    gotSequential = 1;
	}
	if ((objIndex < 0) || (objIndex >= objc)) {
	    msg = badIndex[gotXpg];
	    errCode = gotXpg ? "INDEXRANGE" : "FIELDVARMISMATCH";
	    goto errorMsg;
	}

	/*
	 * Step 2. Set of flags.
	 */

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
	if (isdigit(UCHAR(ch))) {
	    width = strtoul(format, &end, 10);
	    format = end;
	    step = Tcl_UtfToUniChar(format, &ch);
	} else if (ch == '*') {
	    if (objIndex >= objc - 1) {
		msg = badIndex[gotXpg];

		goto errorMsg;
	    }
	    if (TclGetIntFromObj(interp, objv[objIndex], &width) != TCL_OK) {
		goto error;
	    }
	    if (width < 0) {
		width = -width;
		gotMinus = 1;
	    }
	    objIndex++;
	    format += step;
	    step = Tcl_UtfToUniChar(format, &ch);
	}
	if (width > limit) {
	    msg = overflow;

	    goto errorMsg;
	}

	/*
	 * Step 4. Precision.
	 */

	gotPrecision = precision = 0;
	if (ch == '.') {
	    gotPrecision = 1;
	    format += step;
	    step = Tcl_UtfToUniChar(format, &ch);
	}
	if (isdigit(UCHAR(ch))) {
	    precision = strtoul(format, &end, 10);
	    format = end;
	    step = Tcl_UtfToUniChar(format, &ch);
	} else if (ch == '*') {
	    if (objIndex >= objc - 1) {
		msg = badIndex[gotXpg];

		goto errorMsg;
	    }
	    if (TclGetIntFromObj(interp, objv[objIndex], &precision)
		    != TCL_OK) {
		goto error;
	    }








>















>




















>







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
	if (isdigit(UCHAR(ch))) {
	    width = strtoul(format, &end, 10);
	    format = end;
	    step = Tcl_UtfToUniChar(format, &ch);
	} else if (ch == '*') {
	    if (objIndex >= objc - 1) {
		msg = badIndex[gotXpg];
		errCode = gotXpg ? "INDEXRANGE" : "FIELDVARMISMATCH";
		goto errorMsg;
	    }
	    if (TclGetIntFromObj(interp, objv[objIndex], &width) != TCL_OK) {
		goto error;
	    }
	    if (width < 0) {
		width = -width;
		gotMinus = 1;
	    }
	    objIndex++;
	    format += step;
	    step = Tcl_UtfToUniChar(format, &ch);
	}
	if (width > limit) {
	    msg = overflow;
	    errCode = "OVERFLOW";
	    goto errorMsg;
	}

	/*
	 * Step 4. Precision.
	 */

	gotPrecision = precision = 0;
	if (ch == '.') {
	    gotPrecision = 1;
	    format += step;
	    step = Tcl_UtfToUniChar(format, &ch);
	}
	if (isdigit(UCHAR(ch))) {
	    precision = strtoul(format, &end, 10);
	    format = end;
	    step = Tcl_UtfToUniChar(format, &ch);
	} else if (ch == '*') {
	    if (objIndex >= objc - 1) {
		msg = badIndex[gotXpg];
		errCode = gotXpg ? "INDEXRANGE" : "FIELDVARMISMATCH";
		goto errorMsg;
	    }
	    if (TclGetIntFromObj(interp, objv[objIndex], &precision)
		    != TCL_OK) {
		goto error;
	    }

1930
1931
1932
1933
1934
1935
1936

1937
1938
1939
1940
1941
1942
1943
	numChars = -1;
	if (ch == 'i') {
	    ch = 'd';
	}
	switch (ch) {
	case '\0':
	    msg = "format string ended in middle of field specifier";

	    goto errorMsg;
	case 's':
	    if (gotPrecision) {
		numChars = Tcl_GetCharLength(segment);
		if (precision < numChars) {
		    segment = Tcl_GetRange(segment, 0, precision - 1);
		    numChars = precision;







>







1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
	numChars = -1;
	if (ch == 'i') {
	    ch = 'd';
	}
	switch (ch) {
	case '\0':
	    msg = "format string ended in middle of field specifier";
	    errCode = "INCOMPLETE";
	    goto errorMsg;
	case 's':
	    if (gotPrecision) {
		numChars = Tcl_GetCharLength(segment);
		if (precision < numChars) {
		    segment = Tcl_GetRange(segment, 0, precision - 1);
		    numChars = precision;
1959
1960
1961
1962
1963
1964
1965

1966
1967
1968
1969
1970
1971
1972
	    allocSegment = 1;
	    break;
	}

	case 'u':
	    if (useBig) {
		msg = "unsigned bignum format is invalid";

		goto errorMsg;
	    }
	case 'd':
	case 'o':
	case 'x':
	case 'X':
	case 'b': {







>







1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
	    allocSegment = 1;
	    break;
	}

	case 'u':
	    if (useBig) {
		msg = "unsigned bignum format is invalid";
		errCode = "BADUNSIGNED";
		goto errorMsg;
	    }
	case 'd':
	case 'o':
	case 'x':
	case 'X':
	case 'b': {
2106
2107
2108
2109
2110
2111
2112

2113
2114
2115
2116
2117
2118
2119
		    while (length < width) {
			Tcl_AppendToObj(segment, "0", 1);
			length++;
		    }
		}
		if (toAppend > segmentLimit) {
		    msg = overflow;

		    goto errorMsg;
		}
		Tcl_AppendToObj(segment, bytes, toAppend);
		Tcl_DecrRefCount(pure);
		break;
	    }








>







2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
		    while (length < width) {
			Tcl_AppendToObj(segment, "0", 1);
			length++;
		    }
		}
		if (toAppend > segmentLimit) {
		    msg = overflow;
		    errCode = "OVERFLOW";
		    goto errorMsg;
		}
		Tcl_AppendToObj(segment, bytes, toAppend);
		Tcl_DecrRefCount(pure);
		break;
	    }

2161
2162
2163
2164
2165
2166
2167

2168
2169
2170
2171
2172
2173
2174
			    (((Tcl_WideInt) big.used * DIGIT_BIT) / numBits);
		    while ((mask & big.dp[big.used-1]) == 0) {
			numDigits--;
			mask >>= numBits;
		    }
		    if (numDigits > INT_MAX) {
			msg = overflow;

			goto errorMsg;
		    }
		} else if (!useBig) {
		    unsigned long ul = (unsigned long) l;

		    bits = (Tcl_WideUInt) ul;
		    while (ul) {







>







2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
			    (((Tcl_WideInt) big.used * DIGIT_BIT) / numBits);
		    while ((mask & big.dp[big.used-1]) == 0) {
			numDigits--;
			mask >>= numBits;
		    }
		    if (numDigits > INT_MAX) {
			msg = overflow;
			errCode = "OVERFLOW";
			goto errorMsg;
		    }
		} else if (!useBig) {
		    unsigned long ul = (unsigned long) l;

		    bits = (Tcl_WideUInt) ul;
		    while (ul) {
2228
2229
2230
2231
2232
2233
2234

2235
2236
2237
2238
2239
2240
2241
		    while (length < width) {
			Tcl_AppendToObj(segment, "0", 1);
			length++;
		    }
		}
		if (toAppend > segmentLimit) {
		    msg = overflow;

		    goto errorMsg;
		}
		Tcl_AppendObjToObj(segment, pure);
		Tcl_DecrRefCount(pure);
		break;
	    }








>







2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
		    while (length < width) {
			Tcl_AppendToObj(segment, "0", 1);
			length++;
		    }
		}
		if (toAppend > segmentLimit) {
		    msg = overflow;
		    errCode = "OVERFLOW";
		    goto errorMsg;
		}
		Tcl_AppendObjToObj(segment, pure);
		Tcl_DecrRefCount(pure);
		break;
	    }

2281
2282
2283
2284
2285
2286
2287

2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303

2304
2305
2306
2307
2308

2309
2310
2311
2312
2313
2314
2315
2316

2317
2318
2319
2320
2321
2322
2323
		} 
	    }
	    if (gotPrecision) {
		*p++ = '.';
		p += sprintf(p, "%d", precision);
		if (precision > INT_MAX - length) {
		    msg = overflow;

		    goto errorMsg;
		}
		length += precision;
	    }

	    /*
	     * Don't pass length modifiers!
	     */

	    *p++ = (char) ch;
	    *p = '\0';

	    segment = Tcl_NewObj();
	    allocSegment = 1;
	    if (!Tcl_AttemptSetObjLength(segment, length)) {
		msg = overflow;

		goto errorMsg;
	    }
	    bytes = TclGetString(segment);
	    if (!Tcl_AttemptSetObjLength(segment, sprintf(bytes, spec, d))) {
		msg = overflow;

		goto errorMsg;
	    }
	    break;
	}
	default:
	    if (interp != NULL) {
		Tcl_SetObjResult(interp,
			Tcl_ObjPrintf("bad field specifier \"%c\"", ch));

	    }
	    goto error;
	}

	switch (ch) {
	case 'E':
	case 'G':







>
















>





>








>







2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
		} 
	    }
	    if (gotPrecision) {
		*p++ = '.';
		p += sprintf(p, "%d", precision);
		if (precision > INT_MAX - length) {
		    msg = overflow;
		    errCode = "OVERFLOW";
		    goto errorMsg;
		}
		length += precision;
	    }

	    /*
	     * Don't pass length modifiers!
	     */

	    *p++ = (char) ch;
	    *p = '\0';

	    segment = Tcl_NewObj();
	    allocSegment = 1;
	    if (!Tcl_AttemptSetObjLength(segment, length)) {
		msg = overflow;
		errCode = "OVERFLOW";
		goto errorMsg;
	    }
	    bytes = TclGetString(segment);
	    if (!Tcl_AttemptSetObjLength(segment, sprintf(bytes, spec, d))) {
		msg = overflow;
		errCode = "OVERFLOW";
		goto errorMsg;
	    }
	    break;
	}
	default:
	    if (interp != NULL) {
		Tcl_SetObjResult(interp,
			Tcl_ObjPrintf("bad field specifier \"%c\"", ch));
		Tcl_SetErrorCode(interp, "TCL", "FORMAT", "BADTYPE", NULL);
	    }
	    goto error;
	}

	switch (ch) {
	case 'E':
	case 'G':
2341
2342
2343
2344
2345
2346
2347

2348
2349
2350
2351
2352
2353
2354

	Tcl_GetStringFromObj(segment, &segmentNumBytes);
	if (segmentNumBytes > limit) {
	    if (allocSegment) {
		Tcl_DecrRefCount(segment);
	    }
	    msg = overflow;

	    goto errorMsg;
	}
	Tcl_AppendObjToObj(appendObj, segment);
	limit -= segmentNumBytes;
	if (allocSegment) {
	    Tcl_DecrRefCount(segment);
	}







>







2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370

	Tcl_GetStringFromObj(segment, &segmentNumBytes);
	if (segmentNumBytes > limit) {
	    if (allocSegment) {
		Tcl_DecrRefCount(segment);
	    }
	    msg = overflow;
	    errCode = "OVERFLOW";
	    goto errorMsg;
	}
	Tcl_AppendObjToObj(appendObj, segment);
	limit -= segmentNumBytes;
	if (allocSegment) {
	    Tcl_DecrRefCount(segment);
	}
2363
2364
2365
2366
2367
2368
2369

2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381

2382
2383
2384
2385
2386
2387
2388
	}

	objIndex += gotSequential;
    }
    if (numBytes) {
	if (numBytes > limit) {
	    msg = overflow;

	    goto errorMsg;
	}
	Tcl_AppendToObj(appendObj, span, numBytes);
	limit -= numBytes;
	numBytes = 0;
    }

    return TCL_OK;

  errorMsg:
    if (interp != NULL) {
	Tcl_SetObjResult(interp, Tcl_NewStringObj(msg, -1));

    }
  error:
    Tcl_SetObjLength(appendObj, originalLength);
    return TCL_ERROR;
}

/*







>












>







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
	}

	objIndex += gotSequential;
    }
    if (numBytes) {
	if (numBytes > limit) {
	    msg = overflow;
	    errCode = "OVERFLOW";
	    goto errorMsg;
	}
	Tcl_AppendToObj(appendObj, span, numBytes);
	limit -= numBytes;
	numBytes = 0;
    }

    return TCL_OK;

  errorMsg:
    if (interp != NULL) {
	Tcl_SetObjResult(interp, Tcl_NewStringObj(msg, -1));
	Tcl_SetErrorCode(interp, "TCL", "FORMAT", errCode, NULL);
    }
  error:
    Tcl_SetObjLength(appendObj, originalLength);
    return TCL_ERROR;
}

/*
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
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
 *	argument with modifications done in place.
 *
 * Side effects:
 *	May allocate a new Tcl_Obj.
 *
 *---------------------------------------------------------------------------
 */























Tcl_Obj *
TclStringObjReverse(
    Tcl_Obj *objPtr)
{
    String *stringPtr;
    char *src = NULL, *dest = NULL;
    Tcl_UniChar *usrc = NULL, *udest = NULL;
    Tcl_Obj *resultPtr = NULL;











    SetStringFromAny(NULL, objPtr);
    stringPtr = GET_STRING(objPtr);

    if (stringPtr->hasUnicode == 0) {
	if (stringPtr->numChars == -1) {
	    TclNumUtfChars(stringPtr->numChars, objPtr->bytes, objPtr->length);
	}
	if (stringPtr->numChars <= 1) {
	    return objPtr;
	}
	if (stringPtr->numChars == objPtr->length) {
	    /*
	     * All one-byte chars. Reverse in objPtr->bytes.
	     */

	    if (Tcl_IsShared(objPtr)) {
		resultPtr = Tcl_NewObj();
		Tcl_SetObjLength(resultPtr, objPtr->length);
		dest = TclGetString(resultPtr);
		src = objPtr->bytes + objPtr->length - 1;
		while (src >= objPtr->bytes) {
		    *dest++ = *src--;
		}
		return resultPtr;
	    }

	    /*
	     * Unshared. Reverse objPtr->bytes in place.
	     */

	    dest = objPtr->bytes;
	    src = dest + objPtr->length - 1;
	    while (dest < src) {
		char tmp = *src;

		*src-- = *dest;
		*dest++ = tmp;
	    }
	    return objPtr;
	}
	FillUnicodeRep(objPtr);
	stringPtr = GET_STRING(objPtr);
    }
    if (stringPtr->numChars <= 1) {
	return objPtr;
    }

    /*
     * Reverse the Unicode rep.
     */

    if (Tcl_IsShared(objPtr)) {
	Tcl_UniChar ch = 0;

	/*
	 * Create a non-empty, pure unicode value, so we can coax
	 * Tcl_SetObjLength into growing the unicode rep buffer.
	 */


	resultPtr = Tcl_NewUnicodeObj(&ch, 1);
	Tcl_SetObjLength(resultPtr, stringPtr->numChars);
	udest = Tcl_GetUnicode(resultPtr);
	usrc = stringPtr->unicode + stringPtr->numChars - 1;




	while (usrc >= stringPtr->unicode) {


	    *udest++ = *usrc--;
	}


	return resultPtr;




    }







    /*
     * Unshared. Reverse objPtr->bytes in place.
     */







    udest = stringPtr->unicode;

    usrc = udest + stringPtr->numChars - 1;
    while (udest < usrc) {






	Tcl_UniChar tmp = *usrc;







	*usrc-- = *udest;
	*udest++ = tmp;

    }



    TclInvalidateStringRep(objPtr);
    stringPtr->allocated = 0;
    return objPtr;
}

/*
 *---------------------------------------------------------------------------
 *
 * FillUnicodeRep --







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






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




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

|
|
|
|

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







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
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
 *	argument with modifications done in place.
 *
 * Side effects:
 *	May allocate a new Tcl_Obj.
 *
 *---------------------------------------------------------------------------
 */

static void
ReverseBytes(
    unsigned char *to,		/* Copy bytes into here... */
    unsigned char *from,	/* ...from here... */
    int count)		/* Until this many are copied, */
				/* reversing as you go. */
{
    unsigned char *src = from + count;
    if (to == from) {
	/* Reversing in place */
	while (--src > to) {
	    unsigned char c = *src;
	    *src = *to;
	    *to++ = c;
	}
    }  else {
	while (--src >= from) {
	    *to++ = *src;
	}
    }
}

Tcl_Obj *
TclStringObjReverse(
    Tcl_Obj *objPtr)
{
    String *stringPtr;

    Tcl_UniChar ch;

    if (TclIsPureByteArray(objPtr)) {
	int numBytes;
	unsigned char *from = Tcl_GetByteArrayFromObj(objPtr, &numBytes);

	if (Tcl_IsShared(objPtr)) {
	    objPtr = Tcl_NewByteArrayObj(NULL, numBytes);
	}
	ReverseBytes(Tcl_GetByteArrayFromObj(objPtr, NULL), from, numBytes);
	return objPtr;
    }

    SetStringFromAny(NULL, objPtr);
    stringPtr = GET_STRING(objPtr);

    if (stringPtr->hasUnicode) {










	Tcl_UniChar *from = Tcl_GetUnicode(objPtr);




























	Tcl_UniChar *src = from + stringPtr->numChars;







	if (Tcl_IsShared(objPtr)) {
	    Tcl_UniChar *to;

	    /*
	     * Create a non-empty, pure unicode value, so we can coax
	     * Tcl_SetObjLength into growing the unicode rep buffer.
	     */

	    ch = 0;
	    objPtr = Tcl_NewUnicodeObj(&ch, 1);
	    Tcl_SetObjLength(objPtr, stringPtr->numChars);
	    to = Tcl_GetUnicode(objPtr);
	    while (--src >= from) {
		*to++ = *src;
	    }
	} else {
	    /* Reversing in place */
	    while (--src > from) {
		ch = *src;
		*src = *from;
		*from++ = ch;
	    }
	}
    }

    if (objPtr->bytes) {
	int numChars = stringPtr->numChars;
	int numBytes = objPtr->length;
	char *to, *from = objPtr->bytes;

	if (Tcl_IsShared(objPtr)) {
	    objPtr = Tcl_NewObj();
	    Tcl_SetObjLength(objPtr, numBytes);
	}
	to = objPtr->bytes;

	if (numChars < numBytes) {
	    /*


	     * Either numChars == -1 and we don't know how many chars are
	     * represented by objPtr->bytes and we need Pass 1 just in case,
	     * or numChars >= 0 and we know we have fewer chars than bytes,
	     * so we know there's a multibyte character needing Pass 1.
	     *
	     * Pass 1. Reverse the bytes of each multi-byte character.
	     */
	    int charCount = 0;
	    int bytesLeft = numBytes;

	    while (bytesLeft) {
		/*
		 * NOTE: We know that the from buffer is NUL-terminated.
		 * It's part of the contract for objPtr->bytes values.
		 * Thus, we can skip calling Tcl_UtfCharComplete() here.
		 */
		int bytesInChar = Tcl_UtfToUniChar(from, &ch);

		ReverseBytes((unsigned char *)to, (unsigned char *)from,
			bytesInChar);
		to += bytesInChar;
		from += bytesInChar;
		bytesLeft -= bytesInChar;
		charCount++;
	    }

	    from = to = objPtr->bytes;
	    stringPtr->numChars = charCount;
	}
	/* Pass 2. Reverse all the bytes. */
	ReverseBytes((unsigned char *)to, (unsigned char *)from, numBytes);
    }


    return objPtr;
}

/*
 *---------------------------------------------------------------------------
 *
 * FillUnicodeRep --
2835
2836
2837
2838
2839
2840
2841



2842

2843
2844
2845
2846
2847
2848
2849
	int copyMaxChars;

	if (srcStringPtr->maxChars / 2 >= srcStringPtr->numChars) {
	    copyMaxChars = 2 * srcStringPtr->numChars;
	} else {
	    copyMaxChars = srcStringPtr->maxChars;
	}



	copyStringPtr = stringAlloc(copyMaxChars);

	copyStringPtr->maxChars = copyMaxChars;
	memcpy(copyStringPtr->unicode, srcStringPtr->unicode,
		srcStringPtr->numChars * sizeof(Tcl_UniChar));
	copyStringPtr->unicode[srcStringPtr->numChars] = 0;
    } else {
	copyStringPtr = stringAlloc(0);
	copyStringPtr->maxChars = 0;







>
>
>
|
>







2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
	int copyMaxChars;

	if (srcStringPtr->maxChars / 2 >= srcStringPtr->numChars) {
	    copyMaxChars = 2 * srcStringPtr->numChars;
	} else {
	    copyMaxChars = srcStringPtr->maxChars;
	}
	copyStringPtr = stringAttemptAlloc(copyMaxChars);
	if (copyStringPtr == NULL) {
	    copyMaxChars = srcStringPtr->numChars;
	    copyStringPtr = stringAlloc(copyMaxChars);
	}
	copyStringPtr->maxChars = copyMaxChars;
	memcpy(copyStringPtr->unicode, srcStringPtr->unicode,
		srcStringPtr->numChars * sizeof(Tcl_UniChar));
	copyStringPtr->unicode[srcStringPtr->numChars] = 0;
    } else {
	copyStringPtr = stringAlloc(0);
	copyStringPtr->maxChars = 0;

Changes to generic/tclStubInit.c.

460
461
462
463
464
465
466

467
468
469
470
471
472
473
    TclBN_mp_toom_sqr, /* 56 */
    TclBN_s_mp_add, /* 57 */
    TclBN_s_mp_mul_digs, /* 58 */
    TclBN_s_mp_sqr, /* 59 */
    TclBN_s_mp_sub, /* 60 */
    TclBN_mp_init_set_int, /* 61 */
    TclBN_mp_set_int, /* 62 */

};

static const TclStubHooks tclStubHooks = {
    &tclPlatStubs,
    &tclIntStubs,
    &tclIntPlatStubs
};







>







460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
    TclBN_mp_toom_sqr, /* 56 */
    TclBN_s_mp_add, /* 57 */
    TclBN_s_mp_mul_digs, /* 58 */
    TclBN_s_mp_sqr, /* 59 */
    TclBN_s_mp_sub, /* 60 */
    TclBN_mp_init_set_int, /* 61 */
    TclBN_mp_set_int, /* 62 */
    TclBN_mp_cnt_lsb, /* 63 */
};

static const TclStubHooks tclStubHooks = {
    &tclPlatStubs,
    &tclIntStubs,
    &tclIntPlatStubs
};

Changes to generic/tclTest.c.

70
71
72
73
74
75
76


77
78
79
80
81
82
83
    int id;			/* Identifier for this handler. */
    Tcl_AsyncHandler handler;	/* Tcl's token for the handler. */
    char *command;		/* Command to invoke when the handler is
				 * invoked. */
    struct TestAsyncHandler *nextPtr;
				/* Next is list of handlers. */
} TestAsyncHandler;



static TestAsyncHandler *firstHandler = NULL;

/*
 * The dynamic string below is used by the "testdstring" command to test the
 * dynamic string facilities.
 */







>
>







70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
    int id;			/* Identifier for this handler. */
    Tcl_AsyncHandler handler;	/* Tcl's token for the handler. */
    char *command;		/* Command to invoke when the handler is
				 * invoked. */
    struct TestAsyncHandler *nextPtr;
				/* Next is list of handlers. */
} TestAsyncHandler;

TCL_DECLARE_MUTEX(asyncTestMutex);

static TestAsyncHandler *firstHandler = NULL;

/*
 * The dynamic string below is used by the "testdstring" command to test the
 * dynamic string facilities.
 */
305
306
307
308
309
310
311


312
313
314
315
316
317
318
static int		TestexitmainloopCmd(ClientData dummy,
			    Tcl_Interp *interp, int argc, const char **argv);
static int		TestpanicCmd(ClientData dummy,
			    Tcl_Interp *interp, int argc, const char **argv);
static int		TestfinexitObjCmd(ClientData dummy,
			    Tcl_Interp *interp, int objc,
			    Tcl_Obj *const objv[]);


static int		TestparserObjCmd(ClientData dummy,
			    Tcl_Interp *interp, int objc,
			    Tcl_Obj *const objv[]);
static int		TestparsevarObjCmd(ClientData dummy,
			    Tcl_Interp *interp, int objc,
			    Tcl_Obj *const objv[]);
static int		TestparsevarnameObjCmd(ClientData dummy,







>
>







307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
static int		TestexitmainloopCmd(ClientData dummy,
			    Tcl_Interp *interp, int argc, const char **argv);
static int		TestpanicCmd(ClientData dummy,
			    Tcl_Interp *interp, int argc, const char **argv);
static int		TestfinexitObjCmd(ClientData dummy,
			    Tcl_Interp *interp, int objc,
			    Tcl_Obj *const objv[]);
static int              TestparseargsCmd(ClientData dummy, Tcl_Interp *interp,
                            int objc, Tcl_Obj *const objv[]);
static int		TestparserObjCmd(ClientData dummy,
			    Tcl_Interp *interp, int objc,
			    Tcl_Obj *const objv[]);
static int		TestparsevarObjCmd(ClientData dummy,
			    Tcl_Interp *interp, int objc,
			    Tcl_Obj *const objv[]);
static int		TestparsevarnameObjCmd(ClientData dummy,
618
619
620
621
622
623
624

625
626
627
628
629
630
631
    Tcl_CreateCommand(interp, "testinterpdelete", TestinterpdeleteCmd,
	    NULL, NULL);
    Tcl_CreateCommand(interp, "testlink", TestlinkCmd, NULL, NULL);
    Tcl_CreateObjCommand(interp, "testlocale", TestlocaleCmd, NULL,
	    NULL);
    Tcl_CreateCommand(interp, "testpanic", TestpanicCmd, NULL, NULL);
    Tcl_CreateObjCommand(interp, "testfinexit", TestfinexitObjCmd, NULL, NULL);

    Tcl_CreateObjCommand(interp, "testparser", TestparserObjCmd,
	    NULL, NULL);
    Tcl_CreateObjCommand(interp, "testparsevar", TestparsevarObjCmd,
	    NULL, NULL);
    Tcl_CreateObjCommand(interp, "testparsevarname", TestparsevarnameObjCmd,
	    NULL, NULL);
    Tcl_CreateObjCommand(interp, "testregexp", TestregexpObjCmd,







>







622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
    Tcl_CreateCommand(interp, "testinterpdelete", TestinterpdeleteCmd,
	    NULL, NULL);
    Tcl_CreateCommand(interp, "testlink", TestlinkCmd, NULL, NULL);
    Tcl_CreateObjCommand(interp, "testlocale", TestlocaleCmd, NULL,
	    NULL);
    Tcl_CreateCommand(interp, "testpanic", TestpanicCmd, NULL, NULL);
    Tcl_CreateObjCommand(interp, "testfinexit", TestfinexitObjCmd, NULL, NULL);
    Tcl_CreateObjCommand(interp, "testparseargs", TestparseargsCmd,NULL,NULL);
    Tcl_CreateObjCommand(interp, "testparser", TestparserObjCmd,
	    NULL, NULL);
    Tcl_CreateObjCommand(interp, "testparsevar", TestparsevarObjCmd,
	    NULL, NULL);
    Tcl_CreateObjCommand(interp, "testparsevarname", TestparsevarnameObjCmd,
	    NULL, NULL);
    Tcl_CreateObjCommand(interp, "testregexp", TestregexpObjCmd,
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
	return TCL_ERROR;
    }
    if (strcmp(argv[1], "create") == 0) {
	if (argc != 3) {
	    goto wrongNumArgs;
	}
	asyncPtr = ckalloc(sizeof(TestAsyncHandler));



	asyncPtr->id = nextId;
	nextId++;
	asyncPtr->handler = Tcl_AsyncCreate(AsyncHandlerProc,
		(ClientData) asyncPtr);
	asyncPtr->command = ckalloc(strlen(argv[2]) + 1);
	strcpy(asyncPtr->command, argv[2]);
	asyncPtr->nextPtr = firstHandler;
	firstHandler = asyncPtr;

	Tcl_SetObjResult(interp, Tcl_NewIntObj(asyncPtr->id));
    } else if (strcmp(argv[1], "delete") == 0) {
	if (argc == 2) {

	    while (firstHandler != NULL) {
		asyncPtr = firstHandler;
		firstHandler = asyncPtr->nextPtr;
		Tcl_AsyncDelete(asyncPtr->handler);
		ckfree(asyncPtr->command);
		ckfree(asyncPtr);
	    }

	    return TCL_OK;
	}
	if (argc != 3) {
	    goto wrongNumArgs;
	}
	if (Tcl_GetInt(interp, argv[2], &id) != TCL_OK) {
	    return TCL_ERROR;
	}

	for (prevPtr = NULL, asyncPtr = firstHandler; asyncPtr != NULL;
		prevPtr = asyncPtr, asyncPtr = asyncPtr->nextPtr) {
	    if (asyncPtr->id != id) {
		continue;
	    }
	    if (prevPtr == NULL) {
		firstHandler = asyncPtr->nextPtr;
	    } else {
		prevPtr->nextPtr = asyncPtr->nextPtr;
	    }
	    Tcl_AsyncDelete(asyncPtr->handler);
	    ckfree(asyncPtr->command);
	    ckfree(asyncPtr);
	    break;
	}

    } else if (strcmp(argv[1], "mark") == 0) {
	if (argc != 5) {
	    goto wrongNumArgs;
	}
	if ((Tcl_GetInt(interp, argv[2], &id) != TCL_OK)
		|| (Tcl_GetInt(interp, argv[4], &code) != TCL_OK)) {
	    return TCL_ERROR;







>
>
>



<
<
|


>



>







>








>















>







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
	return TCL_ERROR;
    }
    if (strcmp(argv[1], "create") == 0) {
	if (argc != 3) {
	    goto wrongNumArgs;
	}
	asyncPtr = ckalloc(sizeof(TestAsyncHandler));
	asyncPtr->command = ckalloc(strlen(argv[2]) + 1);
	strcpy(asyncPtr->command, argv[2]);
        Tcl_MutexLock(&asyncTestMutex);
	asyncPtr->id = nextId;
	nextId++;
	asyncPtr->handler = Tcl_AsyncCreate(AsyncHandlerProc,


                                            INT2PTR(asyncPtr->id));
	asyncPtr->nextPtr = firstHandler;
	firstHandler = asyncPtr;
        Tcl_MutexUnlock(&asyncTestMutex);
	Tcl_SetObjResult(interp, Tcl_NewIntObj(asyncPtr->id));
    } else if (strcmp(argv[1], "delete") == 0) {
	if (argc == 2) {
            Tcl_MutexLock(&asyncTestMutex);
	    while (firstHandler != NULL) {
		asyncPtr = firstHandler;
		firstHandler = asyncPtr->nextPtr;
		Tcl_AsyncDelete(asyncPtr->handler);
		ckfree(asyncPtr->command);
		ckfree(asyncPtr);
	    }
            Tcl_MutexUnlock(&asyncTestMutex);
	    return TCL_OK;
	}
	if (argc != 3) {
	    goto wrongNumArgs;
	}
	if (Tcl_GetInt(interp, argv[2], &id) != TCL_OK) {
	    return TCL_ERROR;
	}
        Tcl_MutexLock(&asyncTestMutex);
	for (prevPtr = NULL, asyncPtr = firstHandler; asyncPtr != NULL;
		prevPtr = asyncPtr, asyncPtr = asyncPtr->nextPtr) {
	    if (asyncPtr->id != id) {
		continue;
	    }
	    if (prevPtr == NULL) {
		firstHandler = asyncPtr->nextPtr;
	    } else {
		prevPtr->nextPtr = asyncPtr->nextPtr;
	    }
	    Tcl_AsyncDelete(asyncPtr->handler);
	    ckfree(asyncPtr->command);
	    ckfree(asyncPtr);
	    break;
	}
        Tcl_MutexUnlock(&asyncTestMutex);
    } else if (strcmp(argv[1], "mark") == 0) {
	if (argc != 5) {
	    goto wrongNumArgs;
	}
	if ((Tcl_GetInt(interp, argv[2], &id) != TCL_OK)
		|| (Tcl_GetInt(interp, argv[4], &code) != TCL_OK)) {
	    return TCL_ERROR;
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
	    return TCL_ERROR;
	}
	for (asyncPtr = firstHandler; asyncPtr != NULL;
		asyncPtr = asyncPtr->nextPtr) {
	    if (asyncPtr->id == id) {
		Tcl_ThreadId threadID;
		if (Tcl_CreateThread(&threadID, AsyncThreadProc,
			(ClientData) asyncPtr, TCL_THREAD_STACK_DEFAULT,
			TCL_THREAD_NOFLAGS) != TCL_OK) {
		    Tcl_SetResult(interp, "can't create thread", TCL_STATIC);
		    return TCL_ERROR;
		}
		break;
	    }
	}







|







869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
	    return TCL_ERROR;
	}
	for (asyncPtr = firstHandler; asyncPtr != NULL;
		asyncPtr = asyncPtr->nextPtr) {
	    if (asyncPtr->id == id) {
		Tcl_ThreadId threadID;
		if (Tcl_CreateThread(&threadID, AsyncThreadProc,
			INT2PTR(id), TCL_THREAD_STACK_DEFAULT,
			TCL_THREAD_NOFLAGS) != TCL_OK) {
		    Tcl_SetResult(interp, "can't create thread", TCL_STATIC);
		    return TCL_ERROR;
		}
		break;
	    }
	}
882
883
884
885
886
887
888
889

890
891
892
893
894

895
896












897
898
899
900
901
902
903
#endif
    }
    return TCL_OK;
}

static int
AsyncHandlerProc(
    ClientData clientData,	/* Pointer to TestAsyncHandler structure. */

    Tcl_Interp *interp,		/* Interpreter in which command was
				 * executed, or NULL. */
    int code)			/* Current return code from command. */
{
    TestAsyncHandler *asyncPtr = (TestAsyncHandler *) clientData;

    const char *listArgv[4], *cmd;
    char string[TCL_INTEGER_SPACE];













    TclFormatInt(string, code);
    listArgv[0] = asyncPtr->command;
    listArgv[1] = Tcl_GetString(Tcl_GetObjResult(interp));
    listArgv[2] = string;
    listArgv[3] = NULL;
    cmd = Tcl_Merge(3, listArgv);







|
>




|
>


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







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
#endif
    }
    return TCL_OK;
}

static int
AsyncHandlerProc(
    ClientData clientData,	/* If of TestAsyncHandler structure. 
                                 * in global list. */
    Tcl_Interp *interp,		/* Interpreter in which command was
				 * executed, or NULL. */
    int code)			/* Current return code from command. */
{
    TestAsyncHandler *asyncPtr;
    int id = PTR2INT(clientData);
    const char *listArgv[4], *cmd;
    char string[TCL_INTEGER_SPACE];

    Tcl_MutexLock(&asyncTestMutex);
    for (asyncPtr = firstHandler; asyncPtr != NULL;
         asyncPtr = asyncPtr->nextPtr) {
        if (asyncPtr->id == id) break;
    }
    Tcl_MutexUnlock(&asyncTestMutex);

    if (!asyncPtr) {
        /* Woops - this one was deleted between the AsyncMark and now */
        return TCL_OK;
    }

    TclFormatInt(string, code);
    listArgv[0] = asyncPtr->command;
    listArgv[1] = Tcl_GetString(Tcl_GetObjResult(interp));
    listArgv[2] = string;
    listArgv[3] = NULL;
    cmd = Tcl_Merge(3, listArgv);
928
929
930
931
932
933
934
935
936
937
938


939




940




941
942
943
944
945
946
947
 *
 *----------------------------------------------------------------------
 */

#ifdef TCL_THREADS
static Tcl_ThreadCreateType
AsyncThreadProc(
    ClientData clientData)	/* Parameter is a pointer to a
				 * TestAsyncHandler, defined above. */
{
    TestAsyncHandler *asyncPtr = clientData;


    Tcl_Sleep(1);




    Tcl_AsyncMark(asyncPtr->handler);




    Tcl_ExitThread(TCL_OK);
    TCL_THREAD_CREATE_RETURN;
}
#endif

/*
 *----------------------------------------------------------------------







|


|
>
>

>
>
>
>
|
>
>
>
>







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
 *
 *----------------------------------------------------------------------
 */

#ifdef TCL_THREADS
static Tcl_ThreadCreateType
AsyncThreadProc(
    ClientData clientData)	/* Parameter is the id of a
				 * TestAsyncHandler, defined above. */
{
    TestAsyncHandler *asyncPtr;
    int id = PTR2INT(clientData);

    Tcl_Sleep(1);
    Tcl_MutexLock(&asyncTestMutex);
    for (asyncPtr = firstHandler; asyncPtr != NULL;
         asyncPtr = asyncPtr->nextPtr) {
        if (asyncPtr->id == id) {
            Tcl_AsyncMark(asyncPtr->handler);
            break;
        }
    }
    Tcl_MutexUnlock(&asyncTestMutex);
    Tcl_ExitThread(TCL_OK);
    TCL_THREAD_CREATE_RETURN;
}
#endif

/*
 *----------------------------------------------------------------------
3935
3936
3937
3938
3939
3940
3941
3942
3943
3944
3945
3946
3947
3948
3949
3950
3951
3952
	    } else if (ii > info.nsubs) {
		newPtr = Tcl_NewObj();
	    } else {
		newPtr = Tcl_GetRange(objPtr, info.matches[ii].start,
			info.matches[ii].end - 1);
	    }
	}
	valuePtr = Tcl_ObjSetVar2(interp, varPtr, NULL, newPtr, 0);
	if (valuePtr == NULL) {
	    Tcl_AppendResult(interp, "couldn't set variable \"",
		    Tcl_GetString(varPtr), "\"", NULL);
	    return TCL_ERROR;
	}
    }

    /*
     * Set the interpreter's object result to an integer object w/ value 1.
     */







|

<
<







3970
3971
3972
3973
3974
3975
3976
3977
3978


3979
3980
3981
3982
3983
3984
3985
	    } else if (ii > info.nsubs) {
		newPtr = Tcl_NewObj();
	    } else {
		newPtr = Tcl_GetRange(objPtr, info.matches[ii].start,
			info.matches[ii].end - 1);
	    }
	}
	valuePtr = Tcl_ObjSetVar2(interp, varPtr, NULL, newPtr, TCL_LEAVE_ERR_MSG);
	if (valuePtr == NULL) {


	    return TCL_ERROR;
	}
    }

    /*
     * Set the interpreter's object result to an integer object w/ value 1.
     */
7046
7047
7048
7049
7050
7051
7052











































7053
7054
7055
7056
7057
7058


7059
7060
    Tcl_DecrRefCount(tmpPtr);

    if (result == TCL_OK) {
	Tcl_ResetResult(interp);
    }
    return result;
}












































/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78


 * End:
 */







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






>
>


7079
7080
7081
7082
7083
7084
7085
7086
7087
7088
7089
7090
7091
7092
7093
7094
7095
7096
7097
7098
7099
7100
7101
7102
7103
7104
7105
7106
7107
7108
7109
7110
7111
7112
7113
7114
7115
7116
7117
7118
7119
7120
7121
7122
7123
7124
7125
7126
7127
7128
7129
7130
7131
7132
7133
7134
7135
7136
7137
7138
    Tcl_DecrRefCount(tmpPtr);

    if (result == TCL_OK) {
	Tcl_ResetResult(interp);
    }
    return result;
}

/*
 *----------------------------------------------------------------------
 *
 * TestparseargsCmd --
 *
 *	This procedure implements the "testparseargs" command. It is used to
 *	test that Tcl_ParseArgsObjv does indeed return the right number of
 *	arguments. In other words, that [Bug 3413857] was fixed properly.
 *
 * Results:
 *	A standard Tcl result.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

static int
TestparseargsCmd(
    ClientData dummy,		/* Not used. */
    Tcl_Interp *interp,		/* Current interpreter. */
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Arguments. */
{
    int count = objc, foo = 0;
    Tcl_Obj **remObjv, *result[3];
    Tcl_ArgvInfo argTable[] = {
        {TCL_ARGV_CONSTANT, "-bool", INT2PTR(1), &foo, "booltest", NULL},
        TCL_ARGV_AUTO_REST, TCL_ARGV_AUTO_HELP, TCL_ARGV_TABLE_END
    };

    if (Tcl_ParseArgsObjv(interp, argTable, &count, objv, &remObjv)!=TCL_OK) {
        return TCL_ERROR;
    }
    result[0] = Tcl_NewIntObj(foo);
    result[1] = Tcl_NewIntObj(count);
    result[2] = Tcl_NewListObj(count, remObjv);
    Tcl_SetObjResult(interp, Tcl_NewListObj(3, result));
    ckfree(remObjv);
    return TCL_OK;
}

/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78
 * tab-width: 8
 * indent-tabs-mode: nil
 * End:
 */

Changes to generic/tclTestObj.c.

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

#ifndef USE_TCL_STUBS
#   define USE_TCL_STUBS
#endif
#include "tclInt.h"
#include "tommath.h"

/*
 * An array of Tcl_Obj pointers used in the commands that operate on or get
 * the values of Tcl object-valued variables. varPtr[i] is the i-th variable's
 * Tcl_Obj *.
 */

#define NUMBER_OF_OBJECT_VARS 20
static Tcl_Obj *varPtr[NUMBER_OF_OBJECT_VARS];

/*
 * Forward declarations for functions defined later in this file:
 */

static int		CheckIfVarUnset(Tcl_Interp *interp, int varIndex);
static int		GetVariableIndex(Tcl_Interp *interp,
			    const char *string, int *indexPtr);
static void		SetVarToObj(int varIndex, Tcl_Obj *objPtr);
static int		TestbignumobjCmd(ClientData dummy, Tcl_Interp *interp,
			    int objc, Tcl_Obj *const objv[]);
static int		TestbooleanobjCmd(ClientData dummy,
			    Tcl_Interp *interp, int objc,
			    Tcl_Obj *const objv[]);
static int		TestdoubleobjCmd(ClientData dummy, Tcl_Interp *interp,
			    int objc, Tcl_Obj *const objv[]);







<
<
<
<
<
<
<
<





|


|







16
17
18
19
20
21
22








23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

#ifndef USE_TCL_STUBS
#   define USE_TCL_STUBS
#endif
#include "tclInt.h"
#include "tommath.h"










/*
 * Forward declarations for functions defined later in this file:
 */

static int		CheckIfVarUnset(Tcl_Interp *interp, Tcl_Obj **varPtr, int varIndex);
static int		GetVariableIndex(Tcl_Interp *interp,
			    const char *string, int *indexPtr);
static void		SetVarToObj(Tcl_Obj **varPtr, int varIndex, Tcl_Obj *objPtr);
static int		TestbignumobjCmd(ClientData dummy, Tcl_Interp *interp,
			    int objc, Tcl_Obj *const objv[]);
static int		TestbooleanobjCmd(ClientData dummy,
			    Tcl_Interp *interp, int objc,
			    Tcl_Obj *const objv[]);
static int		TestdoubleobjCmd(ClientData dummy, Tcl_Interp *interp,
			    int objc, Tcl_Obj *const objv[]);
57
58
59
60
61
62
63





















64
65
66
67
68
69
70

typedef struct TestString {
    int numChars;
    int allocated;
    int maxChars;
    Tcl_UniChar unicode[2];
} TestString;






















/*
 *----------------------------------------------------------------------
 *
 * TclObjTest_Init --
 *
 *	This function creates additional commands that are used to test the







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







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

typedef struct TestString {
    int numChars;
    int allocated;
    int maxChars;
    Tcl_UniChar unicode[2];
} TestString;

#define VARPTR_KEY "TCLOBJTEST_VARPTR"
#define NUMBER_OF_OBJECT_VARS 20

static void VarPtrDeleteProc(ClientData clientData, Tcl_Interp *interp)
{
    register int i;
    Tcl_Obj **varPtr = (Tcl_Obj **) clientData;
    for (i = 0;  i < NUMBER_OF_OBJECT_VARS;  i++) {
	if (varPtr[i]) Tcl_DecrRefCount(varPtr[i]);
    }
    Tcl_DeleteAssocData(interp, VARPTR_KEY);
    ckfree(varPtr);
}

static Tcl_Obj **GetVarPtr(Tcl_Interp *interp)
{
    Tcl_InterpDeleteProc *proc;

    return (Tcl_Obj **) Tcl_GetAssocData(interp, VARPTR_KEY, &proc);
}

/*
 *----------------------------------------------------------------------
 *
 * TclObjTest_Init --
 *
 *	This function creates additional commands that are used to test the
81
82
83
84
85
86
87






88





89
90
91
92
93
94
95
 */

int
TclObjTest_Init(
    Tcl_Interp *interp)
{
    register int i;












    for (i = 0;  i < NUMBER_OF_OBJECT_VARS;  i++) {
	varPtr[i] = NULL;
    }

    Tcl_CreateObjCommand(interp, "testbignumobj", TestbignumobjCmd,
	    NULL, NULL);
    Tcl_CreateObjCommand(interp, "testbooleanobj", TestbooleanobjCmd,







>
>
>
>
>
>

>
>
>
>
>







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
 */

int
TclObjTest_Init(
    Tcl_Interp *interp)
{
    register int i;
    /*
     * An array of Tcl_Obj pointers used in the commands that operate on or get
     * the values of Tcl object-valued variables. varPtr[i] is the i-th variable's
     * Tcl_Obj *.
     */
    Tcl_Obj **varPtr;

    varPtr = (Tcl_Obj **) ckalloc(NUMBER_OF_OBJECT_VARS *sizeof(varPtr[0]));
    if (!varPtr) {
	return TCL_ERROR;
    }
    Tcl_SetAssocData(interp, VARPTR_KEY, VarPtrDeleteProc, varPtr);
    for (i = 0;  i < NUMBER_OF_OBJECT_VARS;  i++) {
	varPtr[i] = NULL;
    }

    Tcl_CreateObjCommand(interp, "testbignumobj", TestbignumobjCmd,
	    NULL, NULL);
    Tcl_CreateObjCommand(interp, "testbooleanobj", TestbooleanobjCmd,
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
    };
    enum options {
	BIGNUM_SET, BIGNUM_GET,	BIGNUM_MULT10,	BIGNUM_DIV10
    };
    int index, varIndex;
    const char *string;
    mp_int bignumValue, newValue;


    if (objc < 3) {
	Tcl_WrongNumArgs(interp, 1, objv, "option ?arg ...?");
	return TCL_ERROR;
    }
    if (Tcl_GetIndexFromObj(interp, objv[1], subcmds, "option", 0,
	    &index) != TCL_OK) {
	return TCL_ERROR;
    }
    string = Tcl_GetString(objv[2]);
    if (GetVariableIndex(interp, string, &varIndex) != TCL_OK) {
	return TCL_ERROR;
    }


    switch (index) {
    case BIGNUM_SET:
	if (objc != 4) {
	    Tcl_WrongNumArgs(interp, 2, objv, "var value");
	    return TCL_ERROR;
	}







>













>







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
    };
    enum options {
	BIGNUM_SET, BIGNUM_GET,	BIGNUM_MULT10,	BIGNUM_DIV10
    };
    int index, varIndex;
    const char *string;
    mp_int bignumValue, newValue;
    Tcl_Obj **varPtr;

    if (objc < 3) {
	Tcl_WrongNumArgs(interp, 1, objv, "option ?arg ...?");
	return TCL_ERROR;
    }
    if (Tcl_GetIndexFromObj(interp, objv[1], subcmds, "option", 0,
	    &index) != TCL_OK) {
	return TCL_ERROR;
    }
    string = Tcl_GetString(objv[2]);
    if (GetVariableIndex(interp, string, &varIndex) != TCL_OK) {
	return TCL_ERROR;
    }
    varPtr = GetVarPtr(interp);

    switch (index) {
    case BIGNUM_SET:
	if (objc != 4) {
	    Tcl_WrongNumArgs(interp, 2, objv, "var value");
	    return TCL_ERROR;
	}
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
	 * we must create a new object to modify/set and decrement the old
	 * formerly-shared object's ref count. This is "copy on write".
	 */

	if ((varPtr[varIndex] != NULL) && !Tcl_IsShared(varPtr[varIndex])) {
	    Tcl_SetBignumObj(varPtr[varIndex], &bignumValue);
	} else {
	    SetVarToObj(varIndex, Tcl_NewBignumObj(&bignumValue));
	}
	break;

    case BIGNUM_GET:
	if (objc != 3) {
	    Tcl_WrongNumArgs(interp, 2, objv, "varIndex");
	    return TCL_ERROR;
	}
	if (CheckIfVarUnset(interp, varIndex)) {
	    return TCL_ERROR;
	}
	break;

    case BIGNUM_MULT10:
	if (objc != 3) {
	    Tcl_WrongNumArgs(interp, 2, objv, "varIndex");
	    return TCL_ERROR;
	}
	if (CheckIfVarUnset(interp, varIndex)) {
	    return TCL_ERROR;
	}
	if (Tcl_GetBignumFromObj(interp, varPtr[varIndex],
		&bignumValue) != TCL_OK) {
	    return TCL_ERROR;
	}
	if (mp_init(&newValue) != MP_OKAY
		|| (mp_mul_d(&bignumValue, 10, &newValue) != MP_OKAY)) {
	    mp_clear(&bignumValue);
	    mp_clear(&newValue);
	    Tcl_SetObjResult(interp,
		    Tcl_NewStringObj("error in mp_mul_d", -1));
	    return TCL_ERROR;
	}
	mp_clear(&bignumValue);
	if (!Tcl_IsShared(varPtr[varIndex])) {
	    Tcl_SetBignumObj(varPtr[varIndex], &newValue);
	} else {
	    SetVarToObj(varIndex, Tcl_NewBignumObj(&newValue));
	}
	break;

    case BIGNUM_DIV10:
	if (objc != 3) {
	    Tcl_WrongNumArgs(interp, 2, objv, "varIndex");
	    return TCL_ERROR;
	}
	if (CheckIfVarUnset(interp, varIndex)) {
	    return TCL_ERROR;
	}
	if (Tcl_GetBignumFromObj(interp, varPtr[varIndex],
		&bignumValue) != TCL_OK) {
	    return TCL_ERROR;
	}
	if (mp_init(&newValue) != MP_OKAY
		|| (mp_div_d(&bignumValue, 10, &newValue, NULL) != MP_OKAY)) {
	    mp_clear(&bignumValue);
	    mp_clear(&newValue);
	    Tcl_SetObjResult(interp,
		    Tcl_NewStringObj("error in mp_div_d", -1));
	    return TCL_ERROR;
	}
	mp_clear(&bignumValue);
	if (!Tcl_IsShared(varPtr[varIndex])) {
	    Tcl_SetBignumObj(varPtr[varIndex], &newValue);
	} else {
	    SetVarToObj(varIndex, Tcl_NewBignumObj(&newValue));
	}
    }

    Tcl_SetObjResult(interp, varPtr[varIndex]);
    return TCL_OK;
}








|








|









|


















|








|


















|







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
	 * we must create a new object to modify/set and decrement the old
	 * formerly-shared object's ref count. This is "copy on write".
	 */

	if ((varPtr[varIndex] != NULL) && !Tcl_IsShared(varPtr[varIndex])) {
	    Tcl_SetBignumObj(varPtr[varIndex], &bignumValue);
	} else {
	    SetVarToObj(varPtr, varIndex, Tcl_NewBignumObj(&bignumValue));
	}
	break;

    case BIGNUM_GET:
	if (objc != 3) {
	    Tcl_WrongNumArgs(interp, 2, objv, "varIndex");
	    return TCL_ERROR;
	}
	if (CheckIfVarUnset(interp, varPtr,varIndex)) {
	    return TCL_ERROR;
	}
	break;

    case BIGNUM_MULT10:
	if (objc != 3) {
	    Tcl_WrongNumArgs(interp, 2, objv, "varIndex");
	    return TCL_ERROR;
	}
	if (CheckIfVarUnset(interp, varPtr,varIndex)) {
	    return TCL_ERROR;
	}
	if (Tcl_GetBignumFromObj(interp, varPtr[varIndex],
		&bignumValue) != TCL_OK) {
	    return TCL_ERROR;
	}
	if (mp_init(&newValue) != MP_OKAY
		|| (mp_mul_d(&bignumValue, 10, &newValue) != MP_OKAY)) {
	    mp_clear(&bignumValue);
	    mp_clear(&newValue);
	    Tcl_SetObjResult(interp,
		    Tcl_NewStringObj("error in mp_mul_d", -1));
	    return TCL_ERROR;
	}
	mp_clear(&bignumValue);
	if (!Tcl_IsShared(varPtr[varIndex])) {
	    Tcl_SetBignumObj(varPtr[varIndex], &newValue);
	} else {
	    SetVarToObj(varPtr, varIndex, Tcl_NewBignumObj(&newValue));
	}
	break;

    case BIGNUM_DIV10:
	if (objc != 3) {
	    Tcl_WrongNumArgs(interp, 2, objv, "varIndex");
	    return TCL_ERROR;
	}
	if (CheckIfVarUnset(interp, varPtr,varIndex)) {
	    return TCL_ERROR;
	}
	if (Tcl_GetBignumFromObj(interp, varPtr[varIndex],
		&bignumValue) != TCL_OK) {
	    return TCL_ERROR;
	}
	if (mp_init(&newValue) != MP_OKAY
		|| (mp_div_d(&bignumValue, 10, &newValue, NULL) != MP_OKAY)) {
	    mp_clear(&bignumValue);
	    mp_clear(&newValue);
	    Tcl_SetObjResult(interp,
		    Tcl_NewStringObj("error in mp_div_d", -1));
	    return TCL_ERROR;
	}
	mp_clear(&bignumValue);
	if (!Tcl_IsShared(varPtr[varIndex])) {
	    Tcl_SetBignumObj(varPtr[varIndex], &newValue);
	} else {
	    SetVarToObj(varPtr, varIndex, Tcl_NewBignumObj(&newValue));
	}
    }

    Tcl_SetObjResult(interp, varPtr[varIndex]);
    return TCL_OK;
}

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
    ClientData clientData,	/* Not used. */
    Tcl_Interp *interp,		/* Current interpreter. */
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    int varIndex, boolValue;
    const char *index, *subCmd;


    if (objc < 3) {
	wrongNumArgs:
	Tcl_WrongNumArgs(interp, 1, objv, "option arg ?arg ...?");
	return TCL_ERROR;
    }

    index = Tcl_GetString(objv[2]);
    if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
	return TCL_ERROR;
    }



    subCmd = Tcl_GetString(objv[1]);
    if (strcmp(subCmd, "set") == 0) {
	if (objc != 4) {
	    goto wrongNumArgs;
	}
	if (Tcl_GetBooleanFromObj(interp, objv[3], &boolValue) != TCL_OK) {







>











>
>







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
    ClientData clientData,	/* Not used. */
    Tcl_Interp *interp,		/* Current interpreter. */
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    int varIndex, boolValue;
    const char *index, *subCmd;
    Tcl_Obj **varPtr;

    if (objc < 3) {
	wrongNumArgs:
	Tcl_WrongNumArgs(interp, 1, objv, "option arg ?arg ...?");
	return TCL_ERROR;
    }

    index = Tcl_GetString(objv[2]);
    if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
	return TCL_ERROR;
    }

    varPtr = GetVarPtr(interp);

    subCmd = Tcl_GetString(objv[1]);
    if (strcmp(subCmd, "set") == 0) {
	if (objc != 4) {
	    goto wrongNumArgs;
	}
	if (Tcl_GetBooleanFromObj(interp, objv[3], &boolValue) != TCL_OK) {
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
	 * we must create a new object to modify/set and decrement the old
	 * formerly-shared object's ref count. This is "copy on write".
	 */

	if ((varPtr[varIndex] != NULL) && !Tcl_IsShared(varPtr[varIndex])) {
	    Tcl_SetBooleanObj(varPtr[varIndex], boolValue);
	} else {
	    SetVarToObj(varIndex, Tcl_NewBooleanObj(boolValue));
	}
	Tcl_SetObjResult(interp, varPtr[varIndex]);
    } else if (strcmp(subCmd, "get") == 0) {
	if (objc != 3) {
	    goto wrongNumArgs;
	}
	if (CheckIfVarUnset(interp, varIndex)) {
	    return TCL_ERROR;
	}
	Tcl_SetObjResult(interp, varPtr[varIndex]);
    } else if (strcmp(subCmd, "not") == 0) {
	if (objc != 3) {
	    goto wrongNumArgs;
	}
	if (CheckIfVarUnset(interp, varIndex)) {
	    return TCL_ERROR;
	}
	if (Tcl_GetBooleanFromObj(interp, varPtr[varIndex],
				  &boolValue) != TCL_OK) {
	    return TCL_ERROR;
	}
	if (!Tcl_IsShared(varPtr[varIndex])) {
	    Tcl_SetBooleanObj(varPtr[varIndex], !boolValue);
	} else {
	    SetVarToObj(varIndex, Tcl_NewBooleanObj(!boolValue));
	}
	Tcl_SetObjResult(interp, varPtr[varIndex]);
    } else {
	Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
		"bad option \"", Tcl_GetString(objv[1]),
		"\": must be set, get, or not", NULL);
	return TCL_ERROR;







|






|







|









|







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
	 * we must create a new object to modify/set and decrement the old
	 * formerly-shared object's ref count. This is "copy on write".
	 */

	if ((varPtr[varIndex] != NULL) && !Tcl_IsShared(varPtr[varIndex])) {
	    Tcl_SetBooleanObj(varPtr[varIndex], boolValue);
	} else {
	    SetVarToObj(varPtr, varIndex, Tcl_NewBooleanObj(boolValue));
	}
	Tcl_SetObjResult(interp, varPtr[varIndex]);
    } else if (strcmp(subCmd, "get") == 0) {
	if (objc != 3) {
	    goto wrongNumArgs;
	}
	if (CheckIfVarUnset(interp, varPtr,varIndex)) {
	    return TCL_ERROR;
	}
	Tcl_SetObjResult(interp, varPtr[varIndex]);
    } else if (strcmp(subCmd, "not") == 0) {
	if (objc != 3) {
	    goto wrongNumArgs;
	}
	if (CheckIfVarUnset(interp, varPtr,varIndex)) {
	    return TCL_ERROR;
	}
	if (Tcl_GetBooleanFromObj(interp, varPtr[varIndex],
				  &boolValue) != TCL_OK) {
	    return TCL_ERROR;
	}
	if (!Tcl_IsShared(varPtr[varIndex])) {
	    Tcl_SetBooleanObj(varPtr[varIndex], !boolValue);
	} else {
	    SetVarToObj(varPtr, varIndex, Tcl_NewBooleanObj(!boolValue));
	}
	Tcl_SetObjResult(interp, varPtr[varIndex]);
    } else {
	Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
		"bad option \"", Tcl_GetString(objv[1]),
		"\": must be set, get, or not", NULL);
	return TCL_ERROR;
381
382
383
384
385
386
387

388
389
390
391
392
393


394
395
396
397
398
399
400
    Tcl_Interp *interp,		/* Current interpreter. */
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    int varIndex;
    double doubleValue;
    const char *index, *subCmd, *string;


    if (objc < 3) {
	wrongNumArgs:
	Tcl_WrongNumArgs(interp, 1, objv, "option arg ?arg ...?");
	return TCL_ERROR;
    }



    index = Tcl_GetString(objv[2]);
    if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
	return TCL_ERROR;
    }

    subCmd = Tcl_GetString(objv[1]);







>






>
>







410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
    Tcl_Interp *interp,		/* Current interpreter. */
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    int varIndex;
    double doubleValue;
    const char *index, *subCmd, *string;
    Tcl_Obj **varPtr;

    if (objc < 3) {
	wrongNumArgs:
	Tcl_WrongNumArgs(interp, 1, objv, "option arg ?arg ...?");
	return TCL_ERROR;
    }

    varPtr = GetVarPtr(interp);

    index = Tcl_GetString(objv[2]);
    if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
	return TCL_ERROR;
    }

    subCmd = Tcl_GetString(objv[1]);
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
	 * must create a new object to modify/set and decrement the old
	 * formerly-shared object's ref count. This is "copy on write".
	 */

	if ((varPtr[varIndex] != NULL) && !Tcl_IsShared(varPtr[varIndex])) {
	    Tcl_SetDoubleObj(varPtr[varIndex], doubleValue);
	} else {
	    SetVarToObj(varIndex, Tcl_NewDoubleObj(doubleValue));
	}
	Tcl_SetObjResult(interp, varPtr[varIndex]);
    } else if (strcmp(subCmd, "get") == 0) {
	if (objc != 3) {
	    goto wrongNumArgs;
	}
	if (CheckIfVarUnset(interp, varIndex)) {
	    return TCL_ERROR;
	}
	Tcl_SetObjResult(interp, varPtr[varIndex]);
    } else if (strcmp(subCmd, "mult10") == 0) {
	if (objc != 3) {
	    goto wrongNumArgs;
	}
	if (CheckIfVarUnset(interp, varIndex)) {
	    return TCL_ERROR;
	}
	if (Tcl_GetDoubleFromObj(interp, varPtr[varIndex],
				 &doubleValue) != TCL_OK) {
	    return TCL_ERROR;
	}
	if (!Tcl_IsShared(varPtr[varIndex])) {
	    Tcl_SetDoubleObj(varPtr[varIndex], doubleValue * 10.0);
	} else {
	    SetVarToObj(varIndex, Tcl_NewDoubleObj(doubleValue * 10.0));
	}
	Tcl_SetObjResult(interp, varPtr[varIndex]);
    } else if (strcmp(subCmd, "div10") == 0) {
	if (objc != 3) {
	    goto wrongNumArgs;
	}
	if (CheckIfVarUnset(interp, varIndex)) {
	    return TCL_ERROR;
	}
	if (Tcl_GetDoubleFromObj(interp, varPtr[varIndex],
		&doubleValue) != TCL_OK) {
	    return TCL_ERROR;
	}
	if (!Tcl_IsShared(varPtr[varIndex])) {
	    Tcl_SetDoubleObj(varPtr[varIndex], doubleValue / 10.0);
	} else {
	    SetVarToObj(varIndex, Tcl_NewDoubleObj(doubleValue / 10.0));
	}
	Tcl_SetObjResult(interp, varPtr[varIndex]);
    } else {
	Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
		"bad option \"", Tcl_GetString(objv[1]),
		"\": must be set, get, mult10, or div10", NULL);
	return TCL_ERROR;







|






|







|









|






|









|







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
	 * must create a new object to modify/set and decrement the old
	 * formerly-shared object's ref count. This is "copy on write".
	 */

	if ((varPtr[varIndex] != NULL) && !Tcl_IsShared(varPtr[varIndex])) {
	    Tcl_SetDoubleObj(varPtr[varIndex], doubleValue);
	} else {
	    SetVarToObj(varPtr, varIndex, Tcl_NewDoubleObj(doubleValue));
	}
	Tcl_SetObjResult(interp, varPtr[varIndex]);
    } else if (strcmp(subCmd, "get") == 0) {
	if (objc != 3) {
	    goto wrongNumArgs;
	}
	if (CheckIfVarUnset(interp, varPtr,varIndex)) {
	    return TCL_ERROR;
	}
	Tcl_SetObjResult(interp, varPtr[varIndex]);
    } else if (strcmp(subCmd, "mult10") == 0) {
	if (objc != 3) {
	    goto wrongNumArgs;
	}
	if (CheckIfVarUnset(interp, varPtr,varIndex)) {
	    return TCL_ERROR;
	}
	if (Tcl_GetDoubleFromObj(interp, varPtr[varIndex],
				 &doubleValue) != TCL_OK) {
	    return TCL_ERROR;
	}
	if (!Tcl_IsShared(varPtr[varIndex])) {
	    Tcl_SetDoubleObj(varPtr[varIndex], doubleValue * 10.0);
	} else {
	    SetVarToObj(varPtr, varIndex, Tcl_NewDoubleObj(doubleValue * 10.0));
	}
	Tcl_SetObjResult(interp, varPtr[varIndex]);
    } else if (strcmp(subCmd, "div10") == 0) {
	if (objc != 3) {
	    goto wrongNumArgs;
	}
	if (CheckIfVarUnset(interp, varPtr,varIndex)) {
	    return TCL_ERROR;
	}
	if (Tcl_GetDoubleFromObj(interp, varPtr[varIndex],
		&doubleValue) != TCL_OK) {
	    return TCL_ERROR;
	}
	if (!Tcl_IsShared(varPtr[varIndex])) {
	    Tcl_SetDoubleObj(varPtr[varIndex], doubleValue / 10.0);
	} else {
	    SetVarToObj(varPtr, varIndex, Tcl_NewDoubleObj(doubleValue / 10.0));
	}
	Tcl_SetObjResult(interp, varPtr[varIndex]);
    } else {
	Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
		"bad option \"", Tcl_GetString(objv[1]),
		"\": must be set, get, mult10, or div10", NULL);
	return TCL_ERROR;
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
     * object, clear out the object's cached state.
     */

    if (objv[3]->typePtr != NULL
	    && !strcmp("index", objv[3]->typePtr->name)) {
	indexRep = objv[3]->internalRep.otherValuePtr;
	if (indexRep->tablePtr == (void *) argv) {
	    objv[3]->typePtr->freeIntRepProc(objv[3]);
	    objv[3]->typePtr = NULL;
	}
    }

    result = Tcl_GetIndexFromObj((setError? interp : NULL), objv[3],
	    argv, "token", (allowAbbrev? 0 : TCL_EXACT), &index);
    ckfree(argv);
    if (result == TCL_OK) {







<
|







590
591
592
593
594
595
596

597
598
599
600
601
602
603
604
     * object, clear out the object's cached state.
     */

    if (objv[3]->typePtr != NULL
	    && !strcmp("index", objv[3]->typePtr->name)) {
	indexRep = objv[3]->internalRep.otherValuePtr;
	if (indexRep->tablePtr == (void *) argv) {

	    TclFreeIntRep(objv[3]);
	}
    }

    result = Tcl_GetIndexFromObj((setError? interp : NULL), objv[3],
	    argv, "token", (allowAbbrev? 0 : TCL_EXACT), &index);
    ckfree(argv);
    if (result == TCL_OK) {
600
601
602
603
604
605
606

607
608
609
610
611
612
613

614
615
616
617
618
619
620
    Tcl_Interp *interp,		/* Current interpreter. */
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    int intValue, varIndex, i;
    long longValue;
    const char *index, *subCmd, *string;


    if (objc < 3) {
	wrongNumArgs:
	Tcl_WrongNumArgs(interp, 1, objv, "option arg ?arg ...?");
	return TCL_ERROR;
    }


    index = Tcl_GetString(objv[2]);
    if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
	return TCL_ERROR;
    }

    subCmd = Tcl_GetString(objv[1]);
    if (strcmp(subCmd, "set") == 0) {







>







>







631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
    Tcl_Interp *interp,		/* Current interpreter. */
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    int intValue, varIndex, i;
    long longValue;
    const char *index, *subCmd, *string;
    Tcl_Obj **varPtr;

    if (objc < 3) {
	wrongNumArgs:
	Tcl_WrongNumArgs(interp, 1, objv, "option arg ?arg ...?");
	return TCL_ERROR;
    }

    varPtr = GetVarPtr(interp);
    index = Tcl_GetString(objv[2]);
    if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
	return TCL_ERROR;
    }

    subCmd = Tcl_GetString(objv[1]);
    if (strcmp(subCmd, "set") == 0) {
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
	 * must create a new object to modify/set and decrement the old
	 * formerly-shared object's ref count. This is "copy on write".
	 */

	if ((varPtr[varIndex] != NULL) && !Tcl_IsShared(varPtr[varIndex])) {
	    Tcl_SetIntObj(varPtr[varIndex], intValue);
	} else {
	    SetVarToObj(varIndex, Tcl_NewIntObj(intValue));
	}
	Tcl_SetObjResult(interp, varPtr[varIndex]);
    } else if (strcmp(subCmd, "set2") == 0) { /* doesn't set result */
	if (objc != 4) {
	    goto wrongNumArgs;
	}
	string = Tcl_GetString(objv[3]);
	if (Tcl_GetInt(interp, string, &i) != TCL_OK) {
	    return TCL_ERROR;
	}
	intValue = i;
	if ((varPtr[varIndex] != NULL) && !Tcl_IsShared(varPtr[varIndex])) {
	    Tcl_SetIntObj(varPtr[varIndex], intValue);
	} else {
	    SetVarToObj(varIndex, Tcl_NewIntObj(intValue));
	}
    } else if (strcmp(subCmd, "setlong") == 0) {
	if (objc != 4) {
	    goto wrongNumArgs;
	}
	string = Tcl_GetString(objv[3]);
	if (Tcl_GetInt(interp, string, &i) != TCL_OK) {
	    return TCL_ERROR;
	}
	intValue = i;
	if ((varPtr[varIndex] != NULL) && !Tcl_IsShared(varPtr[varIndex])) {
	    Tcl_SetLongObj(varPtr[varIndex], intValue);
	} else {
	    SetVarToObj(varIndex, Tcl_NewLongObj(intValue));
	}
	Tcl_SetObjResult(interp, varPtr[varIndex]);
    } else if (strcmp(subCmd, "setmaxlong") == 0) {
	long maxLong = LONG_MAX;
	if (objc != 3) {
	    goto wrongNumArgs;
	}
	if ((varPtr[varIndex] != NULL) && !Tcl_IsShared(varPtr[varIndex])) {
	    Tcl_SetLongObj(varPtr[varIndex], maxLong);
	} else {
	    SetVarToObj(varIndex, Tcl_NewLongObj(maxLong));
	}
    } else if (strcmp(subCmd, "ismaxlong") == 0) {
	if (objc != 3) {
	    goto wrongNumArgs;
	}
	if (CheckIfVarUnset(interp, varIndex)) {
	    return TCL_ERROR;
	}
	if (Tcl_GetLongFromObj(interp, varPtr[varIndex], &longValue) != TCL_OK) {
	    return TCL_ERROR;
	}
	Tcl_AppendToObj(Tcl_GetObjResult(interp),
		((longValue == LONG_MAX)? "1" : "0"), -1);
    } else if (strcmp(subCmd, "get") == 0) {
	if (objc != 3) {
	    goto wrongNumArgs;
	}
	if (CheckIfVarUnset(interp, varIndex)) {
	    return TCL_ERROR;
	}
	Tcl_SetObjResult(interp, varPtr[varIndex]);
    } else if (strcmp(subCmd, "get2") == 0) {
	if (objc != 3) {
	    goto wrongNumArgs;
	}
	if (CheckIfVarUnset(interp, varIndex)) {
	    return TCL_ERROR;
	}
	string = Tcl_GetString(varPtr[varIndex]);
	Tcl_AppendToObj(Tcl_GetObjResult(interp), string, -1);
    } else if (strcmp(subCmd, "inttoobigtest") == 0) {
	/*
	 * If long ints have more bits than ints on this platform, verify that







|














|













|










|





|











|







|







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
	 * must create a new object to modify/set and decrement the old
	 * formerly-shared object's ref count. This is "copy on write".
	 */

	if ((varPtr[varIndex] != NULL) && !Tcl_IsShared(varPtr[varIndex])) {
	    Tcl_SetIntObj(varPtr[varIndex], intValue);
	} else {
	    SetVarToObj(varPtr, varIndex, Tcl_NewIntObj(intValue));
	}
	Tcl_SetObjResult(interp, varPtr[varIndex]);
    } else if (strcmp(subCmd, "set2") == 0) { /* doesn't set result */
	if (objc != 4) {
	    goto wrongNumArgs;
	}
	string = Tcl_GetString(objv[3]);
	if (Tcl_GetInt(interp, string, &i) != TCL_OK) {
	    return TCL_ERROR;
	}
	intValue = i;
	if ((varPtr[varIndex] != NULL) && !Tcl_IsShared(varPtr[varIndex])) {
	    Tcl_SetIntObj(varPtr[varIndex], intValue);
	} else {
	    SetVarToObj(varPtr, varIndex, Tcl_NewIntObj(intValue));
	}
    } else if (strcmp(subCmd, "setlong") == 0) {
	if (objc != 4) {
	    goto wrongNumArgs;
	}
	string = Tcl_GetString(objv[3]);
	if (Tcl_GetInt(interp, string, &i) != TCL_OK) {
	    return TCL_ERROR;
	}
	intValue = i;
	if ((varPtr[varIndex] != NULL) && !Tcl_IsShared(varPtr[varIndex])) {
	    Tcl_SetLongObj(varPtr[varIndex], intValue);
	} else {
	    SetVarToObj(varPtr, varIndex, Tcl_NewLongObj(intValue));
	}
	Tcl_SetObjResult(interp, varPtr[varIndex]);
    } else if (strcmp(subCmd, "setmaxlong") == 0) {
	long maxLong = LONG_MAX;
	if (objc != 3) {
	    goto wrongNumArgs;
	}
	if ((varPtr[varIndex] != NULL) && !Tcl_IsShared(varPtr[varIndex])) {
	    Tcl_SetLongObj(varPtr[varIndex], maxLong);
	} else {
	    SetVarToObj(varPtr, varIndex, Tcl_NewLongObj(maxLong));
	}
    } else if (strcmp(subCmd, "ismaxlong") == 0) {
	if (objc != 3) {
	    goto wrongNumArgs;
	}
	if (CheckIfVarUnset(interp, varPtr,varIndex)) {
	    return TCL_ERROR;
	}
	if (Tcl_GetLongFromObj(interp, varPtr[varIndex], &longValue) != TCL_OK) {
	    return TCL_ERROR;
	}
	Tcl_AppendToObj(Tcl_GetObjResult(interp),
		((longValue == LONG_MAX)? "1" : "0"), -1);
    } else if (strcmp(subCmd, "get") == 0) {
	if (objc != 3) {
	    goto wrongNumArgs;
	}
	if (CheckIfVarUnset(interp, varPtr,varIndex)) {
	    return TCL_ERROR;
	}
	Tcl_SetObjResult(interp, varPtr[varIndex]);
    } else if (strcmp(subCmd, "get2") == 0) {
	if (objc != 3) {
	    goto wrongNumArgs;
	}
	if (CheckIfVarUnset(interp, varPtr,varIndex)) {
	    return TCL_ERROR;
	}
	string = Tcl_GetString(varPtr[varIndex]);
	Tcl_AppendToObj(Tcl_GetObjResult(interp), string, -1);
    } else if (strcmp(subCmd, "inttoobigtest") == 0) {
	/*
	 * If long ints have more bits than ints on this platform, verify that
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
	}
#if (INT_MAX == LONG_MAX)   /* int is same size as long int */
	Tcl_AppendToObj(Tcl_GetObjResult(interp), "1", -1);
#else
	if ((varPtr[varIndex] != NULL) && !Tcl_IsShared(varPtr[varIndex])) {
	    Tcl_SetLongObj(varPtr[varIndex], LONG_MAX);
	} else {
	    SetVarToObj(varIndex, Tcl_NewLongObj(LONG_MAX));
	}
	if (Tcl_GetIntFromObj(interp, varPtr[varIndex], &i) != TCL_OK) {
	    Tcl_ResetResult(interp);
	    Tcl_AppendToObj(Tcl_GetObjResult(interp), "1", -1);
	    return TCL_OK;
	}
	Tcl_AppendToObj(Tcl_GetObjResult(interp), "0", -1);
#endif
    } else if (strcmp(subCmd, "mult10") == 0) {
	if (objc != 3) {
	    goto wrongNumArgs;
	}
	if (CheckIfVarUnset(interp, varIndex)) {
	    return TCL_ERROR;
	}
	if (Tcl_GetIntFromObj(interp, varPtr[varIndex],
		&intValue) != TCL_OK) {
	    return TCL_ERROR;
	}
	if (!Tcl_IsShared(varPtr[varIndex])) {
	    Tcl_SetIntObj(varPtr[varIndex], intValue * 10);
	} else {
	    SetVarToObj(varIndex, Tcl_NewIntObj(intValue * 10));
	}
	Tcl_SetObjResult(interp, varPtr[varIndex]);
    } else if (strcmp(subCmd, "div10") == 0) {
	if (objc != 3) {
	    goto wrongNumArgs;
	}
	if (CheckIfVarUnset(interp, varIndex)) {
	    return TCL_ERROR;
	}
	if (Tcl_GetIntFromObj(interp, varPtr[varIndex],
		&intValue) != TCL_OK) {
	    return TCL_ERROR;
	}
	if (!Tcl_IsShared(varPtr[varIndex])) {
	    Tcl_SetIntObj(varPtr[varIndex], intValue / 10);
	} else {
	    SetVarToObj(varIndex, Tcl_NewIntObj(intValue / 10));
	}
	Tcl_SetObjResult(interp, varPtr[varIndex]);
    } else {
	Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
		"bad option \"", Tcl_GetString(objv[1]),
		"\": must be set, get, get2, mult10, or div10", NULL);
	return TCL_ERROR;







|












|









|






|









|







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
	}
#if (INT_MAX == LONG_MAX)   /* int is same size as long int */
	Tcl_AppendToObj(Tcl_GetObjResult(interp), "1", -1);
#else
	if ((varPtr[varIndex] != NULL) && !Tcl_IsShared(varPtr[varIndex])) {
	    Tcl_SetLongObj(varPtr[varIndex], LONG_MAX);
	} else {
	    SetVarToObj(varPtr, varIndex, Tcl_NewLongObj(LONG_MAX));
	}
	if (Tcl_GetIntFromObj(interp, varPtr[varIndex], &i) != TCL_OK) {
	    Tcl_ResetResult(interp);
	    Tcl_AppendToObj(Tcl_GetObjResult(interp), "1", -1);
	    return TCL_OK;
	}
	Tcl_AppendToObj(Tcl_GetObjResult(interp), "0", -1);
#endif
    } else if (strcmp(subCmd, "mult10") == 0) {
	if (objc != 3) {
	    goto wrongNumArgs;
	}
	if (CheckIfVarUnset(interp, varPtr,varIndex)) {
	    return TCL_ERROR;
	}
	if (Tcl_GetIntFromObj(interp, varPtr[varIndex],
		&intValue) != TCL_OK) {
	    return TCL_ERROR;
	}
	if (!Tcl_IsShared(varPtr[varIndex])) {
	    Tcl_SetIntObj(varPtr[varIndex], intValue * 10);
	} else {
	    SetVarToObj(varPtr, varIndex, Tcl_NewIntObj(intValue * 10));
	}
	Tcl_SetObjResult(interp, varPtr[varIndex]);
    } else if (strcmp(subCmd, "div10") == 0) {
	if (objc != 3) {
	    goto wrongNumArgs;
	}
	if (CheckIfVarUnset(interp, varPtr,varIndex)) {
	    return TCL_ERROR;
	}
	if (Tcl_GetIntFromObj(interp, varPtr[varIndex],
		&intValue) != TCL_OK) {
	    return TCL_ERROR;
	}
	if (!Tcl_IsShared(varPtr[varIndex])) {
	    Tcl_SetIntObj(varPtr[varIndex], intValue / 10);
	} else {
	    SetVarToObj(varPtr, varIndex, Tcl_NewIntObj(intValue / 10));
	}
	Tcl_SetObjResult(interp, varPtr[varIndex]);
    } else {
	Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
		"bad option \"", Tcl_GetString(objv[1]),
		"\": must be set, get, get2, mult10, or div10", NULL);
	return TCL_ERROR;
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
    };

    const char* index;		/* Argument giving the variable number */
    int varIndex;		/* Variable number converted to binary */
    int cmdIndex;		/* Ordinal number of the subcommand */
    int first;			/* First index in the list */
    int count;			/* Count of elements in a list */


    if (objc < 3) {
	Tcl_WrongNumArgs(interp, 1, objv, "option arg ?arg...?");
	return TCL_ERROR;
    }

    index = Tcl_GetString(objv[2]);
    if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
	return TCL_ERROR;
    }
    if (Tcl_GetIndexFromObj(interp, objv[1], subcommands, "command",
			    0, &cmdIndex) != TCL_OK) {
	return TCL_ERROR;
    }
    switch(cmdIndex) {
    case LISTOBJ_SET:
	if ((varPtr[varIndex] != NULL) && !Tcl_IsShared(varPtr[varIndex])) {
	    Tcl_SetListObj(varPtr[varIndex], objc-3, objv+3);
	} else {
	    SetVarToObj(varIndex, Tcl_NewListObj(objc-3, objv+3));
	}
	Tcl_SetObjResult(interp, varPtr[varIndex]);
	break;

    case LISTOBJ_GET:
	if (objc != 3) {
	    Tcl_WrongNumArgs(interp, 2, objv, "varIndex");
	    return TCL_ERROR;
	}
	if (CheckIfVarUnset(interp, varIndex)) {
	    return TCL_ERROR;
	}
	Tcl_SetObjResult(interp, varPtr[varIndex]);
	break;

    case LISTOBJ_REPLACE:
	if (objc < 5) {
	    Tcl_WrongNumArgs(interp, 2, objv,
			     "varIndex start count ?element...?");
	    return TCL_ERROR;
	}
	if (Tcl_GetIntFromObj(interp, objv[3], &first) != TCL_OK
	    || Tcl_GetIntFromObj(interp, objv[4], &count) != TCL_OK) {
	    return TCL_ERROR;
	}
	if (Tcl_IsShared(varPtr[varIndex])) {
	    SetVarToObj(varIndex, Tcl_DuplicateObj(varPtr[varIndex]));
	}
	Tcl_ResetResult(interp);
	return Tcl_ListObjReplace(interp, varPtr[varIndex], first, count,
				  objc-5, objv+5);
    }
    return TCL_OK;
}







>





>













|









|
















|







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
    };

    const char* index;		/* Argument giving the variable number */
    int varIndex;		/* Variable number converted to binary */
    int cmdIndex;		/* Ordinal number of the subcommand */
    int first;			/* First index in the list */
    int count;			/* Count of elements in a list */
    Tcl_Obj **varPtr;

    if (objc < 3) {
	Tcl_WrongNumArgs(interp, 1, objv, "option arg ?arg...?");
	return TCL_ERROR;
    }
    varPtr = GetVarPtr(interp);
    index = Tcl_GetString(objv[2]);
    if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
	return TCL_ERROR;
    }
    if (Tcl_GetIndexFromObj(interp, objv[1], subcommands, "command",
			    0, &cmdIndex) != TCL_OK) {
	return TCL_ERROR;
    }
    switch(cmdIndex) {
    case LISTOBJ_SET:
	if ((varPtr[varIndex] != NULL) && !Tcl_IsShared(varPtr[varIndex])) {
	    Tcl_SetListObj(varPtr[varIndex], objc-3, objv+3);
	} else {
	    SetVarToObj(varPtr, varIndex, Tcl_NewListObj(objc-3, objv+3));
	}
	Tcl_SetObjResult(interp, varPtr[varIndex]);
	break;

    case LISTOBJ_GET:
	if (objc != 3) {
	    Tcl_WrongNumArgs(interp, 2, objv, "varIndex");
	    return TCL_ERROR;
	}
	if (CheckIfVarUnset(interp, varPtr,varIndex)) {
	    return TCL_ERROR;
	}
	Tcl_SetObjResult(interp, varPtr[varIndex]);
	break;

    case LISTOBJ_REPLACE:
	if (objc < 5) {
	    Tcl_WrongNumArgs(interp, 2, objv,
			     "varIndex start count ?element...?");
	    return TCL_ERROR;
	}
	if (Tcl_GetIntFromObj(interp, objv[3], &first) != TCL_OK
	    || Tcl_GetIntFromObj(interp, objv[4], &count) != TCL_OK) {
	    return TCL_ERROR;
	}
	if (Tcl_IsShared(varPtr[varIndex])) {
	    SetVarToObj(varPtr, varIndex, Tcl_DuplicateObj(varPtr[varIndex]));
	}
	Tcl_ResetResult(interp);
	return Tcl_ListObjReplace(interp, varPtr[varIndex], first, count,
				  objc-5, objv+5);
    }
    return TCL_OK;
}
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
    Tcl_Interp *interp,		/* Current interpreter. */
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    int varIndex, destIndex, i;
    const char *index, *subCmd, *string;
    const Tcl_ObjType *targetType;


    if (objc < 2) {
	wrongNumArgs:
	Tcl_WrongNumArgs(interp, 1, objv, "option arg ?arg ...?");
	return TCL_ERROR;
    }


    subCmd = Tcl_GetString(objv[1]);
    if (strcmp(subCmd, "assign") == 0) {
	if (objc != 4) {
	    goto wrongNumArgs;
	}
	index = Tcl_GetString(objv[2]);
	if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
	    return TCL_ERROR;
	}
	if (CheckIfVarUnset(interp, varIndex)) {
	    return TCL_ERROR;
	}
	string = Tcl_GetString(objv[3]);
	if (GetVariableIndex(interp, string, &destIndex) != TCL_OK) {
	    return TCL_ERROR;
	}
	SetVarToObj(destIndex, varPtr[varIndex]);
	Tcl_SetObjResult(interp, varPtr[destIndex]);
    } else if (strcmp(subCmd, "convert") == 0) {
	const char *typeName;

	if (objc != 4) {
	    goto wrongNumArgs;
	}
	index = Tcl_GetString(objv[2]);
	if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
	    return TCL_ERROR;
	}
	if (CheckIfVarUnset(interp, varIndex)) {
	    return TCL_ERROR;
	}
	typeName = Tcl_GetString(objv[3]);
	if ((targetType = Tcl_GetObjType(typeName)) == NULL) {
	    Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
		    "no type ", typeName, " found", NULL);
	    return TCL_ERROR;







>







>









|






|











|







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
    Tcl_Interp *interp,		/* Current interpreter. */
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    int varIndex, destIndex, i;
    const char *index, *subCmd, *string;
    const Tcl_ObjType *targetType;
    Tcl_Obj **varPtr;

    if (objc < 2) {
	wrongNumArgs:
	Tcl_WrongNumArgs(interp, 1, objv, "option arg ?arg ...?");
	return TCL_ERROR;
    }

    varPtr = GetVarPtr(interp);
    subCmd = Tcl_GetString(objv[1]);
    if (strcmp(subCmd, "assign") == 0) {
	if (objc != 4) {
	    goto wrongNumArgs;
	}
	index = Tcl_GetString(objv[2]);
	if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
	    return TCL_ERROR;
	}
	if (CheckIfVarUnset(interp, varPtr,varIndex)) {
	    return TCL_ERROR;
	}
	string = Tcl_GetString(objv[3]);
	if (GetVariableIndex(interp, string, &destIndex) != TCL_OK) {
	    return TCL_ERROR;
	}
	SetVarToObj(varPtr, destIndex, varPtr[varIndex]);
	Tcl_SetObjResult(interp, varPtr[destIndex]);
    } else if (strcmp(subCmd, "convert") == 0) {
	const char *typeName;

	if (objc != 4) {
	    goto wrongNumArgs;
	}
	index = Tcl_GetString(objv[2]);
	if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
	    return TCL_ERROR;
	}
	if (CheckIfVarUnset(interp, varPtr,varIndex)) {
	    return TCL_ERROR;
	}
	typeName = Tcl_GetString(objv[3]);
	if ((targetType = Tcl_GetObjType(typeName)) == NULL) {
	    Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
		    "no type ", typeName, " found", NULL);
	    return TCL_ERROR;
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
	if (objc != 4) {
	    goto wrongNumArgs;
	}
	index = Tcl_GetString(objv[2]);
	if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
	    return TCL_ERROR;
	}
	if (CheckIfVarUnset(interp, varIndex)) {
	    return TCL_ERROR;
	}
	string = Tcl_GetString(objv[3]);
	if (GetVariableIndex(interp, string, &destIndex) != TCL_OK) {
	    return TCL_ERROR;
	}
	SetVarToObj(destIndex, Tcl_DuplicateObj(varPtr[varIndex]));
	Tcl_SetObjResult(interp, varPtr[destIndex]);
    } else if (strcmp(subCmd, "freeallvars") == 0) {
	if (objc != 2) {
	    goto wrongNumArgs;
	}
	for (i = 0;  i < NUMBER_OF_OBJECT_VARS;  i++) {
	    if (varPtr[i] != NULL) {
		Tcl_DecrRefCount(varPtr[i]);
		varPtr[i] = NULL;
	    }
	}
    } else if (strcmp(subCmd, "invalidateStringRep") == 0) {
	if (objc != 3) {
	    goto wrongNumArgs;
	}
	index = Tcl_GetString(objv[2]);
	if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
	    return TCL_ERROR;
	}
	if (CheckIfVarUnset(interp, varIndex)) {
	    return TCL_ERROR;
	}
	Tcl_InvalidateStringRep(varPtr[varIndex]);
	Tcl_SetObjResult(interp, varPtr[varIndex]);
    } else if (strcmp(subCmd, "newobj") == 0) {
	if (objc != 3) {
	    goto wrongNumArgs;
	}
	index = Tcl_GetString(objv[2]);
	if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
	    return TCL_ERROR;
	}
	SetVarToObj(varIndex, Tcl_NewObj());
	Tcl_SetObjResult(interp, varPtr[varIndex]);
    } else if (strcmp(subCmd, "objtype") == 0) {
	const char *typeName;

	/*
	 * Return an object containing the name of the argument's type of
	 * internal rep. If none exists, return "none".







|






|



















|












|







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
	if (objc != 4) {
	    goto wrongNumArgs;
	}
	index = Tcl_GetString(objv[2]);
	if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
	    return TCL_ERROR;
	}
	if (CheckIfVarUnset(interp, varPtr,varIndex)) {
	    return TCL_ERROR;
	}
	string = Tcl_GetString(objv[3]);
	if (GetVariableIndex(interp, string, &destIndex) != TCL_OK) {
	    return TCL_ERROR;
	}
	SetVarToObj(varPtr, destIndex, Tcl_DuplicateObj(varPtr[varIndex]));
	Tcl_SetObjResult(interp, varPtr[destIndex]);
    } else if (strcmp(subCmd, "freeallvars") == 0) {
	if (objc != 2) {
	    goto wrongNumArgs;
	}
	for (i = 0;  i < NUMBER_OF_OBJECT_VARS;  i++) {
	    if (varPtr[i] != NULL) {
		Tcl_DecrRefCount(varPtr[i]);
		varPtr[i] = NULL;
	    }
	}
    } else if (strcmp(subCmd, "invalidateStringRep") == 0) {
	if (objc != 3) {
	    goto wrongNumArgs;
	}
	index = Tcl_GetString(objv[2]);
	if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
	    return TCL_ERROR;
	}
	if (CheckIfVarUnset(interp, varPtr,varIndex)) {
	    return TCL_ERROR;
	}
	Tcl_InvalidateStringRep(varPtr[varIndex]);
	Tcl_SetObjResult(interp, varPtr[varIndex]);
    } else if (strcmp(subCmd, "newobj") == 0) {
	if (objc != 3) {
	    goto wrongNumArgs;
	}
	index = Tcl_GetString(objv[2]);
	if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
	    return TCL_ERROR;
	}
	SetVarToObj(varPtr, varIndex, Tcl_NewObj());
	Tcl_SetObjResult(interp, varPtr[varIndex]);
    } else if (strcmp(subCmd, "objtype") == 0) {
	const char *typeName;

	/*
	 * Return an object containing the name of the argument's type of
	 * internal rep. If none exists, return "none".
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
	if (objc != 3) {
	    goto wrongNumArgs;
	}
	index = Tcl_GetString(objv[2]);
	if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
	    return TCL_ERROR;
	}
	if (CheckIfVarUnset(interp, varIndex)) {
	    return TCL_ERROR;
	}
	Tcl_SetObjResult(interp, Tcl_NewIntObj(varPtr[varIndex]->refCount));
    } else if (strcmp(subCmd, "type") == 0) {
	if (objc != 3) {
	    goto wrongNumArgs;
	}
	index = Tcl_GetString(objv[2]);
	if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
	    return TCL_ERROR;
	}
	if (CheckIfVarUnset(interp, varIndex)) {
	    return TCL_ERROR;
	}
	if (varPtr[varIndex]->typePtr == NULL) { /* a string! */
	    Tcl_AppendToObj(Tcl_GetObjResult(interp), "string", -1);
	} else {
	    Tcl_AppendToObj(Tcl_GetObjResult(interp),
		    varPtr[varIndex]->typePtr->name, -1);







|











|







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
	if (objc != 3) {
	    goto wrongNumArgs;
	}
	index = Tcl_GetString(objv[2]);
	if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
	    return TCL_ERROR;
	}
	if (CheckIfVarUnset(interp, varPtr,varIndex)) {
	    return TCL_ERROR;
	}
	Tcl_SetObjResult(interp, Tcl_NewIntObj(varPtr[varIndex]->refCount));
    } else if (strcmp(subCmd, "type") == 0) {
	if (objc != 3) {
	    goto wrongNumArgs;
	}
	index = Tcl_GetString(objv[2]);
	if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
	    return TCL_ERROR;
	}
	if (CheckIfVarUnset(interp, varPtr,varIndex)) {
	    return TCL_ERROR;
	}
	if (varPtr[varIndex]->typePtr == NULL) { /* a string! */
	    Tcl_AppendToObj(Tcl_GetObjResult(interp), "string", -1);
	} else {
	    Tcl_AppendToObj(Tcl_GetObjResult(interp),
		    varPtr[varIndex]->typePtr->name, -1);
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
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    Tcl_UniChar *unicode;
    int varIndex, option, i, length;
#define MAX_STRINGS 11
    const char *index, *string, *strings[MAX_STRINGS+1];
    TestString *strPtr;

    static const char *const options[] = {
	"append", "appendstrings", "get", "get2", "length", "length2",
	"set", "set2", "setlength", "maxchars", "getunicode",
	"appendself", "appendself2", NULL
    };

    if (objc < 3) {
	wrongNumArgs:
	Tcl_WrongNumArgs(interp, 1, objv, "option arg ?arg ...?");
	return TCL_ERROR;
    }


    index = Tcl_GetString(objv[2]);
    if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
	return TCL_ERROR;
    }

    if (Tcl_GetIndexFromObj(interp, objv[1], options, "option", 0, &option)
	    != TCL_OK) {
	return TCL_ERROR;
    }
    switch (option) {
	case 0:				/* append */
	    if (objc != 5) {
		goto wrongNumArgs;
	    }
	    if (Tcl_GetIntFromObj(interp, objv[4], &length) != TCL_OK) {
		return TCL_ERROR;
	    }
	    if (varPtr[varIndex] == NULL) {
		SetVarToObj(varIndex, Tcl_NewObj());
	    }

	    /*
	     * If the object bound to variable "varIndex" is shared, we must
	     * "copy on write" and append to a copy of the object.
	     */

	    if (Tcl_IsShared(varPtr[varIndex])) {
		SetVarToObj(varIndex, Tcl_DuplicateObj(varPtr[varIndex]));
	    }
	    string = Tcl_GetString(objv[3]);
	    Tcl_AppendToObj(varPtr[varIndex], string, length);
	    Tcl_SetObjResult(interp, varPtr[varIndex]);
	    break;
	case 1:				/* appendstrings */
	    if (objc > (MAX_STRINGS+3)) {
		goto wrongNumArgs;
	    }
	    if (varPtr[varIndex] == NULL) {
		SetVarToObj(varIndex, Tcl_NewObj());
	    }

	    /*
	     * If the object bound to variable "varIndex" is shared, we must
	     * "copy on write" and append to a copy of the object.
	     */

	    if (Tcl_IsShared(varPtr[varIndex])) {
		SetVarToObj(varIndex, Tcl_DuplicateObj(varPtr[varIndex]));
	    }
	    for (i = 3;  i < objc;  i++) {
		strings[i-3] = Tcl_GetString(objv[i]);
	    }
	    for ( ; i < 12 + 3; i++) {
		strings[i - 3] = NULL;
	    }
	    Tcl_AppendStringsToObj(varPtr[varIndex], strings[0], strings[1],
		    strings[2], strings[3], strings[4], strings[5],
		    strings[6], strings[7], strings[8], strings[9],
		    strings[10], strings[11]);
	    Tcl_SetObjResult(interp, varPtr[varIndex]);
	    break;
	case 2:				/* get */
	    if (objc != 3) {
		goto wrongNumArgs;
	    }
	    if (CheckIfVarUnset(interp, varIndex)) {
		return TCL_ERROR;
	    }
	    Tcl_SetObjResult(interp, varPtr[varIndex]);
	    break;
	case 3:				/* get2 */
	    if (objc != 3) {
		goto wrongNumArgs;
	    }
	    if (CheckIfVarUnset(interp, varIndex)) {
		return TCL_ERROR;
	    }
	    string = Tcl_GetString(varPtr[varIndex]);
	    Tcl_AppendToObj(Tcl_GetObjResult(interp), string, -1);
	    break;
	case 4:				/* length */
	    if (objc != 3) {







>












>


















|








|










|








|

















|








|







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
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    Tcl_UniChar *unicode;
    int varIndex, option, i, length;
#define MAX_STRINGS 11
    const char *index, *string, *strings[MAX_STRINGS+1];
    TestString *strPtr;
    Tcl_Obj **varPtr;
    static const char *const options[] = {
	"append", "appendstrings", "get", "get2", "length", "length2",
	"set", "set2", "setlength", "maxchars", "getunicode",
	"appendself", "appendself2", NULL
    };

    if (objc < 3) {
	wrongNumArgs:
	Tcl_WrongNumArgs(interp, 1, objv, "option arg ?arg ...?");
	return TCL_ERROR;
    }

    varPtr = GetVarPtr(interp);
    index = Tcl_GetString(objv[2]);
    if (GetVariableIndex(interp, index, &varIndex) != TCL_OK) {
	return TCL_ERROR;
    }

    if (Tcl_GetIndexFromObj(interp, objv[1], options, "option", 0, &option)
	    != TCL_OK) {
	return TCL_ERROR;
    }
    switch (option) {
	case 0:				/* append */
	    if (objc != 5) {
		goto wrongNumArgs;
	    }
	    if (Tcl_GetIntFromObj(interp, objv[4], &length) != TCL_OK) {
		return TCL_ERROR;
	    }
	    if (varPtr[varIndex] == NULL) {
		SetVarToObj(varPtr, varIndex, Tcl_NewObj());
	    }

	    /*
	     * If the object bound to variable "varIndex" is shared, we must
	     * "copy on write" and append to a copy of the object.
	     */

	    if (Tcl_IsShared(varPtr[varIndex])) {
		SetVarToObj(varPtr, varIndex, Tcl_DuplicateObj(varPtr[varIndex]));
	    }
	    string = Tcl_GetString(objv[3]);
	    Tcl_AppendToObj(varPtr[varIndex], string, length);
	    Tcl_SetObjResult(interp, varPtr[varIndex]);
	    break;
	case 1:				/* appendstrings */
	    if (objc > (MAX_STRINGS+3)) {
		goto wrongNumArgs;
	    }
	    if (varPtr[varIndex] == NULL) {
		SetVarToObj(varPtr, varIndex, Tcl_NewObj());
	    }

	    /*
	     * If the object bound to variable "varIndex" is shared, we must
	     * "copy on write" and append to a copy of the object.
	     */

	    if (Tcl_IsShared(varPtr[varIndex])) {
		SetVarToObj(varPtr, varIndex, Tcl_DuplicateObj(varPtr[varIndex]));
	    }
	    for (i = 3;  i < objc;  i++) {
		strings[i-3] = Tcl_GetString(objv[i]);
	    }
	    for ( ; i < 12 + 3; i++) {
		strings[i - 3] = NULL;
	    }
	    Tcl_AppendStringsToObj(varPtr[varIndex], strings[0], strings[1],
		    strings[2], strings[3], strings[4], strings[5],
		    strings[6], strings[7], strings[8], strings[9],
		    strings[10], strings[11]);
	    Tcl_SetObjResult(interp, varPtr[varIndex]);
	    break;
	case 2:				/* get */
	    if (objc != 3) {
		goto wrongNumArgs;
	    }
	    if (CheckIfVarUnset(interp, varPtr,varIndex)) {
		return TCL_ERROR;
	    }
	    Tcl_SetObjResult(interp, varPtr[varIndex]);
	    break;
	case 3:				/* get2 */
	    if (objc != 3) {
		goto wrongNumArgs;
	    }
	    if (CheckIfVarUnset(interp, varPtr, varIndex)) {
		return TCL_ERROR;
	    }
	    string = Tcl_GetString(varPtr[varIndex]);
	    Tcl_AppendToObj(Tcl_GetObjResult(interp), string, -1);
	    break;
	case 4:				/* length */
	    if (objc != 3) {
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
	     */

	    string = Tcl_GetStringFromObj(objv[3], &length);
	    if ((varPtr[varIndex] != NULL)
		    && !Tcl_IsShared(varPtr[varIndex])) {
		Tcl_SetStringObj(varPtr[varIndex], string, length);
	    } else {
		SetVarToObj(varIndex, Tcl_NewStringObj(string, length));
	    }
	    Tcl_SetObjResult(interp, varPtr[varIndex]);
	    break;
	case 7:				/* set2 */
	    if (objc != 4) {
		goto wrongNumArgs;
	    }
	    SetVarToObj(varIndex, objv[3]);
	    break;
	case 8:				/* setlength */
	    if (objc != 4) {
		goto wrongNumArgs;
	    }
	    if (Tcl_GetIntFromObj(interp, objv[3], &length) != TCL_OK) {
		return TCL_ERROR;







|







|







1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
	     */

	    string = Tcl_GetStringFromObj(objv[3], &length);
	    if ((varPtr[varIndex] != NULL)
		    && !Tcl_IsShared(varPtr[varIndex])) {
		Tcl_SetStringObj(varPtr[varIndex], string, length);
	    } else {
		SetVarToObj(varPtr, varIndex, Tcl_NewStringObj(string, length));
	    }
	    Tcl_SetObjResult(interp, varPtr[varIndex]);
	    break;
	case 7:				/* set2 */
	    if (objc != 4) {
		goto wrongNumArgs;
	    }
	    SetVarToObj(varPtr, varIndex, objv[3]);
	    break;
	case 8:				/* setlength */
	    if (objc != 4) {
		goto wrongNumArgs;
	    }
	    if (Tcl_GetIntFromObj(interp, objv[3], &length) != TCL_OK) {
		return TCL_ERROR;
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
	    Tcl_GetUnicodeFromObj(varPtr[varIndex], NULL);
	    break;
	case 11:			/* appendself */
	    if (objc != 4) {
		goto wrongNumArgs;
	    }
	    if (varPtr[varIndex] == NULL) {
		SetVarToObj(varIndex, Tcl_NewObj());
	    }

	    /*
	     * If the object bound to variable "varIndex" is shared, we must
	     * "copy on write" and append to a copy of the object.
	     */

	    if (Tcl_IsShared(varPtr[varIndex])) {
		SetVarToObj(varIndex, Tcl_DuplicateObj(varPtr[varIndex]));
	    }

	    string = Tcl_GetStringFromObj(varPtr[varIndex], &length);

	    if (Tcl_GetIntFromObj(interp, objv[3], &i) != TCL_OK) {
		return TCL_ERROR;
	    }







|








|







1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
	    Tcl_GetUnicodeFromObj(varPtr[varIndex], NULL);
	    break;
	case 11:			/* appendself */
	    if (objc != 4) {
		goto wrongNumArgs;
	    }
	    if (varPtr[varIndex] == NULL) {
		SetVarToObj(varPtr, varIndex, Tcl_NewObj());
	    }

	    /*
	     * If the object bound to variable "varIndex" is shared, we must
	     * "copy on write" and append to a copy of the object.
	     */

	    if (Tcl_IsShared(varPtr[varIndex])) {
		SetVarToObj(varPtr, varIndex, Tcl_DuplicateObj(varPtr[varIndex]));
	    }

	    string = Tcl_GetStringFromObj(varPtr[varIndex], &length);

	    if (Tcl_GetIntFromObj(interp, objv[3], &i) != TCL_OK) {
		return TCL_ERROR;
	    }
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
	    Tcl_SetObjResult(interp, varPtr[varIndex]);
	    break;
	case 12:			/* appendself2 */
	    if (objc != 4) {
		goto wrongNumArgs;
	    }
	    if (varPtr[varIndex] == NULL) {
		SetVarToObj(varIndex, Tcl_NewObj());
	    }

	    /*
	     * If the object bound to variable "varIndex" is shared, we must
	     * "copy on write" and append to a copy of the object.
	     */

	    if (Tcl_IsShared(varPtr[varIndex])) {
		SetVarToObj(varIndex, Tcl_DuplicateObj(varPtr[varIndex]));
	    }

	    unicode = Tcl_GetUnicodeFromObj(varPtr[varIndex], &length);

	    if (Tcl_GetIntFromObj(interp, objv[3], &i) != TCL_OK) {
		return TCL_ERROR;
	    }







|








|







1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
	    Tcl_SetObjResult(interp, varPtr[varIndex]);
	    break;
	case 12:			/* appendself2 */
	    if (objc != 4) {
		goto wrongNumArgs;
	    }
	    if (varPtr[varIndex] == NULL) {
		SetVarToObj(varPtr, varIndex, Tcl_NewObj());
	    }

	    /*
	     * If the object bound to variable "varIndex" is shared, we must
	     * "copy on write" and append to a copy of the object.
	     */

	    if (Tcl_IsShared(varPtr[varIndex])) {
		SetVarToObj(varPtr, varIndex, Tcl_DuplicateObj(varPtr[varIndex]));
	    }

	    unicode = Tcl_GetUnicodeFromObj(varPtr[varIndex], &length);

	    if (Tcl_GetIntFromObj(interp, objv[3], &i) != TCL_OK) {
		return TCL_ERROR;
	    }
1351
1352
1353
1354
1355
1356
1357

1358
1359
1360
1361
1362
1363
1364
 *	incremented (also if not NULL).
 *
 *----------------------------------------------------------------------
 */

static void
SetVarToObj(

    int varIndex,		/* Designates the assignment variable. */
    Tcl_Obj *objPtr)		/* Points to object to assign to var. */
{
    if (varPtr[varIndex] != NULL) {
	Tcl_DecrRefCount(varPtr[varIndex]);
    }
    varPtr[varIndex] = objPtr;







>







1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
 *	incremented (also if not NULL).
 *
 *----------------------------------------------------------------------
 */

static void
SetVarToObj(
    Tcl_Obj **varPtr,
    int varIndex,		/* Designates the assignment variable. */
    Tcl_Obj *objPtr)		/* Points to object to assign to var. */
{
    if (varPtr[varIndex] != NULL) {
	Tcl_DecrRefCount(varPtr[varIndex]);
    }
    varPtr[varIndex] = objPtr;
1423
1424
1425
1426
1427
1428
1429

1430
1431
1432
1433
1434
1435
1436
 *
 *----------------------------------------------------------------------
 */

static int
CheckIfVarUnset(
    Tcl_Interp *interp,		/* Interpreter for error reporting. */

    int varIndex)		/* Index of the test variable to check. */
{
    if (varPtr[varIndex] == NULL) {
	char buf[32 + TCL_INTEGER_SPACE];

	sprintf(buf, "variable %d is unset (NULL)", varIndex);
	Tcl_ResetResult(interp);







>







1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
 *
 *----------------------------------------------------------------------
 */

static int
CheckIfVarUnset(
    Tcl_Interp *interp,		/* Interpreter for error reporting. */
    Tcl_Obj ** varPtr,
    int varIndex)		/* Index of the test variable to check. */
{
    if (varPtr[varIndex] == NULL) {
	char buf[32 + TCL_INTEGER_SPACE];

	sprintf(buf, "variable %d is unset (NULL)", varIndex);
	Tcl_ResetResult(interp);

generic/tclThreadAlloc.c became a regular file.

Changes to generic/tclThreadTest.c.

42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
static Tcl_ThreadDataKey dataKey;

/*
 * This list is used to list all threads that have interpreters. This is
 * protected by threadMutex.
 */

static ThreadSpecificData *threadList;

/*
 * The following bit-values are legal for the "flags" field of the
 * ThreadSpecificData structure.
 */

#define TP_Dying		0x001 /* This thread is being canceled */







|







42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
static Tcl_ThreadDataKey dataKey;

/*
 * This list is used to list all threads that have interpreters. This is
 * protected by threadMutex.
 */

static ThreadSpecificData *threadList = NULL;

/*
 * The following bit-values are legal for the "flags" field of the
 * ThreadSpecificData structure.
 */

#define TP_Dying		0x001 /* This thread is being canceled */
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
	ThreadErrorProc(tsdPtr->interp);
    }

    /*
     * Clean up.
     */

    ListRemove(tsdPtr);
    Tcl_Release(tsdPtr->interp);
    Tcl_DeleteInterp(tsdPtr->interp);
    Tcl_ExitThread(result);

    TCL_THREAD_CREATE_RETURN;
}

/*
 *------------------------------------------------------------------------







|

|







619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
	ThreadErrorProc(tsdPtr->interp);
    }

    /*
     * Clean up.
     */

    Tcl_DeleteInterp(tsdPtr->interp);
    Tcl_Release(tsdPtr->interp);
    ListRemove(tsdPtr);
    Tcl_ExitThread(result);

    TCL_THREAD_CREATE_RETURN;
}

/*
 *------------------------------------------------------------------------
740
741
742
743
744
745
746

747
748
749
750
751
752
753
    } else {
	threadList = tsdPtr->nextPtr;
    }
    if (tsdPtr->nextPtr) {
	tsdPtr->nextPtr->prevPtr = tsdPtr->prevPtr;
    }
    tsdPtr->nextPtr = tsdPtr->prevPtr = 0;

    Tcl_MutexUnlock(&threadMutex);
}

/*
 *------------------------------------------------------------------------
 *
 * ThreadList --







>







740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
    } else {
	threadList = tsdPtr->nextPtr;
    }
    if (tsdPtr->nextPtr) {
	tsdPtr->nextPtr->prevPtr = tsdPtr->prevPtr;
    }
    tsdPtr->nextPtr = tsdPtr->prevPtr = 0;
    tsdPtr->interp = NULL;
    Tcl_MutexUnlock(&threadMutex);
}

/*
 *------------------------------------------------------------------------
 *
 * ThreadList --
1144
1145
1146
1147
1148
1149
1150





1151
1152
1153
1154
1155
1156
1157
static void
ThreadExitProc(
    ClientData clientData)
{
    char *threadEvalScript = clientData;
    ThreadEventResult *resultPtr, *nextPtr;
    Tcl_ThreadId self = Tcl_GetCurrentThread();






    Tcl_MutexLock(&threadMutex);

    if (threadEvalScript) {
	ckfree(threadEvalScript);
	threadEvalScript = NULL;
    }







>
>
>
>
>







1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
static void
ThreadExitProc(
    ClientData clientData)
{
    char *threadEvalScript = clientData;
    ThreadEventResult *resultPtr, *nextPtr;
    Tcl_ThreadId self = Tcl_GetCurrentThread();
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);

    if (tsdPtr->interp != NULL) {
	ListRemove(tsdPtr);
    }

    Tcl_MutexLock(&threadMutex);

    if (threadEvalScript) {
	ckfree(threadEvalScript);
	threadEvalScript = NULL;
    }

Changes to generic/tclTimer.c.

789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
{
    Tcl_WideInt ms = 0;		/* Number of milliseconds to wait */
    Tcl_Time wakeup;
    AfterInfo *afterPtr;
    AfterAssocData *assocPtr;
    int length;
    int index;
    char buf[16 + TCL_INTEGER_SPACE];
    static const char *const afterSubCmds[] = {
	"cancel", "idle", "info", NULL
    };
    enum afterSubCmds {AFTER_CANCEL, AFTER_IDLE, AFTER_INFO};
    ThreadSpecificData *tsdPtr = InitTimer();

    if (objc < 2) {







<







789
790
791
792
793
794
795

796
797
798
799
800
801
802
{
    Tcl_WideInt ms = 0;		/* Number of milliseconds to wait */
    Tcl_Time wakeup;
    AfterInfo *afterPtr;
    AfterAssocData *assocPtr;
    int length;
    int index;

    static const char *const afterSubCmds[] = {
	"cancel", "idle", "info", NULL
    };
    enum afterSubCmds {AFTER_CANCEL, AFTER_IDLE, AFTER_INFO};
    ThreadSpecificData *tsdPtr = InitTimer();

    if (objc < 2) {
827
828
829
830
831
832
833


834
835
836


837
838
839
840
841
842
843
	    || objv[1]->typePtr == &tclWideIntType
#endif
	    || objv[1]->typePtr == &tclBignumType
	    || (Tcl_GetIndexFromObj(NULL, objv[1], afterSubCmds, "", 0,
		    &index) != TCL_OK)) {
	index = -1;
	if (Tcl_GetWideIntFromObj(NULL, objv[1], &ms) != TCL_OK) {


	    Tcl_AppendResult(interp, "bad argument \"",
		    Tcl_GetString(objv[1]),
		    "\": must be cancel, idle, info, or an integer", NULL);


	    return TCL_ERROR;
	}
    }

    /*
     * At this point, either index = -1 and ms contains the number of ms
     * to wait, or else index is the index of a subcommand.







>
>
|
<

>
>







826
827
828
829
830
831
832
833
834
835

836
837
838
839
840
841
842
843
844
845
	    || objv[1]->typePtr == &tclWideIntType
#endif
	    || objv[1]->typePtr == &tclBignumType
	    || (Tcl_GetIndexFromObj(NULL, objv[1], afterSubCmds, "", 0,
		    &index) != TCL_OK)) {
	index = -1;
	if (Tcl_GetWideIntFromObj(NULL, objv[1], &ms) != TCL_OK) {
            const char *arg = Tcl_GetString(objv[1]);

	    Tcl_AppendResult(interp, "bad argument \"", arg,

		    "\": must be cancel, idle, info, or an integer", NULL);
            Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "INDEX", "argument",
                    arg, NULL);
	    return TCL_ERROR;
	}
    }

    /*
     * At this point, either index = -1 and ms contains the number of ms
     * to wait, or else index is the index of a subcommand.
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
	tsdPtr->afterId += 1;
	afterPtr->token = NULL;
	afterPtr->nextPtr = assocPtr->firstAfterPtr;
	assocPtr->firstAfterPtr = afterPtr;
	Tcl_DoWhenIdle(AfterProc, afterPtr);
	Tcl_SetObjResult(interp, Tcl_ObjPrintf("after#%d", afterPtr->id));
	break;
    case AFTER_INFO: {

	Tcl_Obj *resultListPtr;

	if (objc == 2) {
	    for (afterPtr = assocPtr->firstAfterPtr; afterPtr != NULL;
		    afterPtr = afterPtr->nextPtr) {
		if (assocPtr->interp == interp) {

		    sprintf(buf, "after#%d", afterPtr->id);
		    Tcl_AppendElement(interp, buf);
		}
	    }

	    return TCL_OK;
	}
	if (objc != 3) {
	    Tcl_WrongNumArgs(interp, 2, objv, "?id?");
	    return TCL_ERROR;
	}
	afterPtr = GetAfterEvent(assocPtr, objv[2]);
	if (afterPtr == NULL) {


	    Tcl_AppendResult(interp, "event \"", TclGetString(objv[2]),
		    "\" doesn't exist", NULL);

	    return TCL_ERROR;
	}
	resultListPtr = Tcl_NewObj();

	Tcl_ListObjAppendElement(interp, resultListPtr, afterPtr->commandPtr);

	Tcl_ListObjAppendElement(interp, resultListPtr, Tcl_NewStringObj(
		(afterPtr->token == NULL) ? "idle" : "timer", -1));
	Tcl_SetObjResult(interp, resultListPtr);
	break;
    }

    default:
	Tcl_Panic("Tcl_AfterObjCmd: bad subcommand index to afterSubCmds");
    }
    return TCL_OK;
}

/*







|
>
|

<



>
|
<


>








>
>
|
|
>

|
|
>
|
>
|
|
|
<
|
>







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
	tsdPtr->afterId += 1;
	afterPtr->token = NULL;
	afterPtr->nextPtr = assocPtr->firstAfterPtr;
	assocPtr->firstAfterPtr = afterPtr;
	Tcl_DoWhenIdle(AfterProc, afterPtr);
	Tcl_SetObjResult(interp, Tcl_ObjPrintf("after#%d", afterPtr->id));
	break;
    case AFTER_INFO:
	if (objc == 2) {
            Tcl_Obj *resultObj = Tcl_NewObj();


	    for (afterPtr = assocPtr->firstAfterPtr; afterPtr != NULL;
		    afterPtr = afterPtr->nextPtr) {
		if (assocPtr->interp == interp) {
                    Tcl_ListObjAppendElement(NULL, resultObj, Tcl_ObjPrintf(
                            "after#%d", afterPtr->id));

		}
	    }
            Tcl_SetObjResult(interp, resultObj);
	    return TCL_OK;
	}
	if (objc != 3) {
	    Tcl_WrongNumArgs(interp, 2, objv, "?id?");
	    return TCL_ERROR;
	}
	afterPtr = GetAfterEvent(assocPtr, objv[2]);
	if (afterPtr == NULL) {
            const char *eventStr = TclGetString(objv[2]);

	    Tcl_AppendResult(interp, "event \"", eventStr, "\" doesn't exist",
                    NULL);
            Tcl_SetErrorCode(interp, "TCL","LOOKUP","EVENT", eventStr, NULL);
	    return TCL_ERROR;
	} else {
            Tcl_Obj *resultListPtr = Tcl_NewObj();

            Tcl_ListObjAppendElement(interp, resultListPtr,
                    afterPtr->commandPtr);
            Tcl_ListObjAppendElement(interp, resultListPtr, Tcl_NewStringObj(
		    (afterPtr->token == NULL) ? "idle" : "timer", -1));
            Tcl_SetObjResult(interp, resultListPtr);

        }
	break;
    default:
	Tcl_Panic("Tcl_AfterObjCmd: bad subcommand index to afterSubCmds");
    }
    return TCL_OK;
}

/*

Changes to generic/tclTomMath.decls.

214
215
216
217
218
219
220



}
declare 61 {
    int TclBN_mp_init_set_int(mp_int* a, unsigned long i)
}
declare 62 {
    int TclBN_mp_set_int(mp_int* a, unsigned long i)
}










>
>
>
214
215
216
217
218
219
220
221
222
223
}
declare 61 {
    int TclBN_mp_init_set_int(mp_int* a, unsigned long i)
}
declare 62 {
    int TclBN_mp_set_int(mp_int* a, unsigned long i)
}
declare 63 {
    int TclBN_mp_cnt_lsb(const mp_int* a)
}

Changes to generic/tclTomMathDecls.h.

59
60
61
62
63
64
65

66
67
68
69
70
71
72
#define mp_and TclBN_mp_and
#define mp_clamp TclBN_mp_clamp
#define mp_clear TclBN_mp_clear
#define mp_clear_multi TclBN_mp_clear_multi
#define mp_cmp TclBN_mp_cmp
#define mp_cmp_d TclBN_mp_cmp_d
#define mp_cmp_mag TclBN_mp_cmp_mag

#define mp_copy TclBN_mp_copy
#define mp_count_bits TclBN_mp_count_bits
#define mp_div TclBN_mp_div
#define mp_div_2 TclBN_mp_div_2
#define mp_div_2d TclBN_mp_div_2d
#define mp_div_3 TclBN_mp_div_3
#define mp_div_d TclBN_mp_div_d







>







59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#define mp_and TclBN_mp_and
#define mp_clamp TclBN_mp_clamp
#define mp_clear TclBN_mp_clear
#define mp_clear_multi TclBN_mp_clear_multi
#define mp_cmp TclBN_mp_cmp
#define mp_cmp_d TclBN_mp_cmp_d
#define mp_cmp_mag TclBN_mp_cmp_mag
#define mp_cnt_lsb TclBN_mp_cnt_lsb
#define mp_copy TclBN_mp_copy
#define mp_count_bits TclBN_mp_count_bits
#define mp_div TclBN_mp_div
#define mp_div_2 TclBN_mp_div_2
#define mp_div_2d TclBN_mp_div_2d
#define mp_div_3 TclBN_mp_div_3
#define mp_div_d TclBN_mp_div_d
268
269
270
271
272
273
274


275
276
277
278
279
280
281
EXTERN int		TclBN_s_mp_sqr(mp_int *a, mp_int *b);
/* 60 */
EXTERN int		TclBN_s_mp_sub(mp_int *a, mp_int *b, mp_int *c);
/* 61 */
EXTERN int		TclBN_mp_init_set_int(mp_int*a, unsigned long i);
/* 62 */
EXTERN int		TclBN_mp_set_int(mp_int*a, unsigned long i);



typedef struct TclTomMathStubs {
    int magic;
    const struct TclTomMathStubHooks *hooks;

    int (*tclBN_epoch) (void); /* 0 */
    int (*tclBN_revision) (void); /* 1 */







>
>







269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
EXTERN int		TclBN_s_mp_sqr(mp_int *a, mp_int *b);
/* 60 */
EXTERN int		TclBN_s_mp_sub(mp_int *a, mp_int *b, mp_int *c);
/* 61 */
EXTERN int		TclBN_mp_init_set_int(mp_int*a, unsigned long i);
/* 62 */
EXTERN int		TclBN_mp_set_int(mp_int*a, unsigned long i);
/* 63 */
EXTERN int		TclBN_mp_cnt_lsb(const mp_int*a);

typedef struct TclTomMathStubs {
    int magic;
    const struct TclTomMathStubHooks *hooks;

    int (*tclBN_epoch) (void); /* 0 */
    int (*tclBN_revision) (void); /* 1 */
336
337
338
339
340
341
342

343
344
345
346
347
348
349
    int (*tclBN_mp_toom_sqr) (mp_int *a, mp_int *b); /* 56 */
    int (*tclBN_s_mp_add) (mp_int *a, mp_int *b, mp_int *c); /* 57 */
    int (*tclBN_s_mp_mul_digs) (mp_int *a, mp_int *b, mp_int *c, int digs); /* 58 */
    int (*tclBN_s_mp_sqr) (mp_int *a, mp_int *b); /* 59 */
    int (*tclBN_s_mp_sub) (mp_int *a, mp_int *b, mp_int *c); /* 60 */
    int (*tclBN_mp_init_set_int) (mp_int*a, unsigned long i); /* 61 */
    int (*tclBN_mp_set_int) (mp_int*a, unsigned long i); /* 62 */

} TclTomMathStubs;

#ifdef __cplusplus
extern "C" {
#endif
extern const TclTomMathStubs *tclTomMathStubsPtr;
#ifdef __cplusplus







>







339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
    int (*tclBN_mp_toom_sqr) (mp_int *a, mp_int *b); /* 56 */
    int (*tclBN_s_mp_add) (mp_int *a, mp_int *b, mp_int *c); /* 57 */
    int (*tclBN_s_mp_mul_digs) (mp_int *a, mp_int *b, mp_int *c, int digs); /* 58 */
    int (*tclBN_s_mp_sqr) (mp_int *a, mp_int *b); /* 59 */
    int (*tclBN_s_mp_sub) (mp_int *a, mp_int *b, mp_int *c); /* 60 */
    int (*tclBN_mp_init_set_int) (mp_int*a, unsigned long i); /* 61 */
    int (*tclBN_mp_set_int) (mp_int*a, unsigned long i); /* 62 */
    int (*tclBN_mp_cnt_lsb) (const mp_int*a); /* 63 */
} TclTomMathStubs;

#ifdef __cplusplus
extern "C" {
#endif
extern const TclTomMathStubs *tclTomMathStubsPtr;
#ifdef __cplusplus
478
479
480
481
482
483
484


485
486
487
488
489
490
491
492
493
	(tclTomMathStubsPtr->tclBN_s_mp_sqr) /* 59 */
#define TclBN_s_mp_sub \
	(tclTomMathStubsPtr->tclBN_s_mp_sub) /* 60 */
#define TclBN_mp_init_set_int \
	(tclTomMathStubsPtr->tclBN_mp_init_set_int) /* 61 */
#define TclBN_mp_set_int \
	(tclTomMathStubsPtr->tclBN_mp_set_int) /* 62 */



#endif /* defined(USE_TCL_STUBS) */

/* !END!: Do not edit above this line. */

#undef TCL_STORAGE_CLASS
#define TCL_STORAGE_CLASS DLLIMPORT

#endif /* _TCLINTDECLS */







>
>









482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
	(tclTomMathStubsPtr->tclBN_s_mp_sqr) /* 59 */
#define TclBN_s_mp_sub \
	(tclTomMathStubsPtr->tclBN_s_mp_sub) /* 60 */
#define TclBN_mp_init_set_int \
	(tclTomMathStubsPtr->tclBN_mp_init_set_int) /* 61 */
#define TclBN_mp_set_int \
	(tclTomMathStubsPtr->tclBN_mp_set_int) /* 62 */
#define TclBN_mp_cnt_lsb \
	(tclTomMathStubsPtr->tclBN_mp_cnt_lsb) /* 63 */

#endif /* defined(USE_TCL_STUBS) */

/* !END!: Do not edit above this line. */

#undef TCL_STORAGE_CLASS
#define TCL_STORAGE_CLASS DLLIMPORT

#endif /* _TCLINTDECLS */

Changes to generic/tclTrace.c.

364
365
366
367
368
369
370

371
372
373
374
375
376
377
#endif /* TCL_REMOVE_OBSOLETE_TRACES */
    }
    return TCL_OK;

  badVarOps:
    Tcl_AppendResult(interp, "bad operations \"", flagOps,
	    "\": should be one or more of rwua", NULL);

    return TCL_ERROR;
}

/*
 *----------------------------------------------------------------------
 *
 * TraceExecutionObjCmd --







>







364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
#endif /* TCL_REMOVE_OBSOLETE_TRACES */
    }
    return TCL_OK;

  badVarOps:
    Tcl_AppendResult(interp, "bad operations \"", flagOps,
	    "\": should be one or more of rwua", NULL);
    Tcl_SetErrorCode(interp, "TCL", "OPERATION", "TRACE", "BADOPS", NULL);
    return TCL_ERROR;
}

/*
 *----------------------------------------------------------------------
 *
 * TraceExecutionObjCmd --
432
433
434
435
436
437
438


439
440
441
442
443
444
445
	if (result != TCL_OK) {
	    return result;
	}
	if (listLen == 0) {
	    Tcl_SetResult(interp, "bad operation list \"\": must be "
		    "one or more of enter, leave, enterstep, or leavestep",
		    TCL_STATIC);


	    return TCL_ERROR;
	}
	for (i = 0; i < listLen; i++) {
	    if (Tcl_GetIndexFromObj(interp, elemPtrs[i], opStrings,
		    "operation", TCL_EXACT, &index) != TCL_OK) {
		return TCL_ERROR;
	    }







>
>







433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
	if (result != TCL_OK) {
	    return result;
	}
	if (listLen == 0) {
	    Tcl_SetResult(interp, "bad operation list \"\": must be "
		    "one or more of enter, leave, enterstep, or leavestep",
		    TCL_STATIC);
	    Tcl_SetErrorCode(interp, "TCL", "OPERATION", "TRACE", "NOOPS",
		    NULL);
	    return TCL_ERROR;
	}
	for (i = 0; i < listLen; i++) {
	    if (Tcl_GetIndexFromObj(interp, elemPtrs[i], opStrings,
		    "operation", TCL_EXACT, &index) != TCL_OK) {
		return TCL_ERROR;
	    }
672
673
674
675
676
677
678


679
680
681
682
683
684
685
	result = Tcl_ListObjGetElements(interp, objv[4], &listLen, &elemPtrs);
	if (result != TCL_OK) {
	    return result;
	}
	if (listLen == 0) {
	    Tcl_SetResult(interp, "bad operation list \"\": must be "
		    "one or more of delete or rename", TCL_STATIC);


	    return TCL_ERROR;
	}

	for (i = 0; i < listLen; i++) {
	    if (Tcl_GetIndexFromObj(interp, elemPtrs[i], opStrings,
		    "operation", TCL_EXACT, &index) != TCL_OK) {
		return TCL_ERROR;







>
>







675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
	result = Tcl_ListObjGetElements(interp, objv[4], &listLen, &elemPtrs);
	if (result != TCL_OK) {
	    return result;
	}
	if (listLen == 0) {
	    Tcl_SetResult(interp, "bad operation list \"\": must be "
		    "one or more of delete or rename", TCL_STATIC);
	    Tcl_SetErrorCode(interp, "TCL", "OPERATION", "TRACE", "NOOPS",
		    NULL);
	    return TCL_ERROR;
	}

	for (i = 0; i < listLen; i++) {
	    if (Tcl_GetIndexFromObj(interp, elemPtrs[i], opStrings,
		    "operation", TCL_EXACT, &index) != TCL_OK) {
		return TCL_ERROR;
868
869
870
871
872
873
874


875
876
877
878
879
880
881
	result = Tcl_ListObjGetElements(interp, objv[4], &listLen, &elemPtrs);
	if (result != TCL_OK) {
	    return result;
	}
	if (listLen == 0) {
	    Tcl_SetResult(interp, "bad operation list \"\": must be "
		    "one or more of array, read, unset, or write", TCL_STATIC);


	    return TCL_ERROR;
	}
	for (i = 0; i < listLen ; i++) {
	    if (Tcl_GetIndexFromObj(interp, elemPtrs[i], opStrings,
		    "operation", TCL_EXACT, &index) != TCL_OK) {
		return TCL_ERROR;
	    }







>
>







873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
	result = Tcl_ListObjGetElements(interp, objv[4], &listLen, &elemPtrs);
	if (result != TCL_OK) {
	    return result;
	}
	if (listLen == 0) {
	    Tcl_SetResult(interp, "bad operation list \"\": must be "
		    "one or more of array, read, unset, or write", TCL_STATIC);
	    Tcl_SetErrorCode(interp, "TCL", "OPERATION", "TRACE", "NOOPS",
		    NULL);
	    return TCL_ERROR;
	}
	for (i = 0; i < listLen ; i++) {
	    if (Tcl_GetIndexFromObj(interp, elemPtrs[i], opStrings,
		    "operation", TCL_EXACT, &index) != TCL_OK) {
		return TCL_ERROR;
	    }
2017
2018
2019
2020
2021
2022
2023

2024
2025
2026
2027
2028
2029
2030
	    code = Tcl_EvalEx(interp, Tcl_DStringValue(&cmd),
		    Tcl_DStringLength(&cmd), 0);
	    if (rewind) {
		((Interp *)interp)->execEnvPtr->rewind = rewind;
	    }
	    if (code != TCL_OK) {		/* copy error msg to result */
		Tcl_Obj *errMsgObj = Tcl_GetObjResult(interp);

		Tcl_IncrRefCount(errMsgObj);
		result = (char *) errMsgObj;
	    }
	    Tcl_DStringFree(&cmd);
	}
    }
    if (destroy && result != NULL) {







>







2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
	    code = Tcl_EvalEx(interp, Tcl_DStringValue(&cmd),
		    Tcl_DStringLength(&cmd), 0);
	    if (rewind) {
		((Interp *)interp)->execEnvPtr->rewind = rewind;
	    }
	    if (code != TCL_OK) {		/* copy error msg to result */
		Tcl_Obj *errMsgObj = Tcl_GetObjResult(interp);

		Tcl_IncrRefCount(errMsgObj);
		result = (char *) errMsgObj;
	    }
	    Tcl_DStringFree(&cmd);
	}
    }
    if (destroy && result != NULL) {
2871
2872
2873
2874
2875
2876
2877










2878
2879
2880
2881
2882
2883
2884
	allFlags |= tracePtr->flags;
    }

    /*
     * The code below makes it possible to delete traces while traces are
     * active: it makes sure that the deleted trace won't be processed by
     * TclCallVarTraces.










     */

    for (activePtr = iPtr->activeVarTracePtr;  activePtr != NULL;
	    activePtr = activePtr->nextPtr) {
	if (activePtr->nextTracePtr == tracePtr) {
	    activePtr->nextTracePtr = tracePtr->nextPtr;
	}







>
>
>
>
>
>
>
>
>
>







2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
	allFlags |= tracePtr->flags;
    }

    /*
     * The code below makes it possible to delete traces while traces are
     * active: it makes sure that the deleted trace won't be processed by
     * TclCallVarTraces.
     *
     * Caveat (Bug 3062331): When an unset trace handler on a variable
     * tries to delete a different unset trace handler on the same variable,
     * the results may be surprising.  When variable unset traces fire, the
     * traced variable is already gone.  So the TclLookupVar() call above
     * will not find that variable, and not finding it will never reach here
     * to perform the deletion.  This means callers of Tcl_UntraceVar*()
     * attempting to delete unset traces from within the handler of another
     * unset trace have to account for the possibility that their call to
     * Tcl_UntraceVar*() is a no-op.
     */

    for (activePtr = iPtr->activeVarTracePtr;  activePtr != NULL;
	    activePtr = activePtr->nextPtr) {
	if (activePtr->nextTracePtr == tracePtr) {
	    activePtr->nextTracePtr = tracePtr->nextPtr;
	}

Changes to generic/tclUniData.c.

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
 * Bits 5-7	Case delta type: 000 = identity
 *				 010 = add delta for lower
 *				 011 = add delta for lower, add 1 for title
 *				 100 = subtract delta for title/upper
 *				 101 = sub delta for upper, sub 1 for title
 *				 110 = sub delta for upper, add delta for lower
 *
 * Bits 8-21	Reserved for future use.
 *
 * Bits 22-31	Case delta: delta for case conversions.  This should be the
 *			    highest field so we can easily sign extend.
 */

static const int groups[] = {
    0, 15, 12, 25, 27, 21, 22, 26, 20, 9, 134217793, 28, 19, 134217858,
    29, 2, 23, 16, 11, 1178599554, 24, -507510654, 4194369, 4194434,
    -834666431, 973078658, -507510719, 1258291330, -817889150, 880803905,
    864026689, 859832385, 331350081, 847249473, 851443777, 868220993,
    -406847358, 884998209, 876609601, -683671422, 893386817, -545259390,
    897581121, 914358337, 910164033, 918552641, 5, -234880894, 8388705,
    4194467, 8388770, 331350146, -406847423, -234880959, -545259455,
    -1967128511, -683671487, -1979711423, 1883242626, -817889215,
    289407041, 297795649, 2017460354, 2030043266, 2021654658, 880803970,
    864026754, 859832450, 847249538, 851443842, 868221058, -1241513854,
    876609666, 884998274, -2109734782, -2134900606, 893386882, 897581186,
    -2042625918, 914358402, 289407106, 910164098, 297795714, 918552706,
    4, 6, -352321402, 159383617, 155189313, 268435521, 264241217,
    159383682, 155189378, 130023554, 268435586, 264241282, 33554497,
    260046978, 239075458, 1, 197132418, 226492546, 33554562, 360710274,
    335544450, -29359998, -251658175, 402653314, -29360063, 335544385,
    7, 62914625, 62914690, 201326657, 201326722, 8, 402653249, 10,
    2130706562, 1182793858, 247464066, -1874853823, -33554302, -33554367,
    -310378366, -360710014, -419430270, -536870782, -469761918, -528482174,
    -33554365, -37748606, -310378431, -37748669, 155189378, -360710079,

    -419430335, -469761983, -536870847, -528482239, 13, 14, -1463812031,
    -801111999, -293601215, 117440577, 117440642, 67108938, 67109002,
    109051997, 109052061, -2109734847, 1182793793, -2042625983, -1967128446,
    -1979711358, 2030043201, -2134900671, 2017460289, 2021654593,
    1883242561, 402653314, 2130706497, -1241513919, 18, 17


};

/*
 * The following constants are used to determine the category of a
 * Unicode character.
 */








|

|




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







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
 * Bits 5-7	Case delta type: 000 = identity
 *				 010 = add delta for lower
 *				 011 = add delta for lower, add 1 for title
 *				 100 = subtract delta for title/upper
 *				 101 = sub delta for upper, sub 1 for title
 *				 110 = sub delta for upper, add delta for lower
 *
 * Bits 8-14	Reserved for future use.
 *
 * Bits 15-31	Case delta: delta for case conversions.  This should be the
 *			    highest field so we can easily sign extend.
 */

static const int groups[] = {
    0, 15, 12, 25, 27, 21, 22, 26, 20, 9, 1048641, 28, 19, 1048706,
    29, 2, 23, 16, 11, -24346494, 24, -3964798, 32833, 32898, -6520767,
    7602306, -3964863, 9830530, -6389630, 6881345, 6750273, 6717505,
    2588737, 6619201, 6651969, 6783041, -3178366, 6914113, 6848577,
    -5341054, 6979649, -4259710, 7012417, 7143489, 7110721, 7176257,
    5, -1834878, 65633, 32931, 65698, 2588802, -3178431, -1834943,
    -4259775, 353730625, -5341119, 353632321, -354385790, -6389695,
    2261057, 2326593, -353337214, -353238910, -353304446, 6881410,
    6750338, 6717570, 6619266, 6652034, 6783106, -1385430910, 6848642,
    6914178, -352026494, -352223102, 6979714, 7012482, -351502206,
    7143554, 2261122, 7110786, 2326658, 7176322, 4, 6, -2752378, 1245249,
    1212481, 2097217, 2064449, 1245314, 1212546, 1015938, 2097282,
    2064514, 262209, 2031746, 1867906, 1, 1540226, 1769602, 262274,
    2818178, 2621570, -229246, -1966015, 3145858, -229311, 2621505,
    7, 491585, 491650, 1572929, 1572994, 8, 238026817, 10, -1157758846,
    -124977022, 1933442, -249528255, -262014, -262079, -2424702, -2817918,


    -3276670, -4194174, -3669886, -4128638, -262077, -294782, -2424767,

    -294845, 236093570, -2817983, -3276735, -3669951, -4194239, -4128703,
    13, 14, -246316991, -274694079, -270729151, 917569, 917634, 524362,

    524426, 852061, 852125, -352026559, -124977087, -351502271, 353730690,


    353632386, -353238975, -352223167, -353337279, -353304511, -354385855,
    238026882, -1157758911, -1385430975, 18, 17
};

/*
 * The following constants are used to determine the category of a
 * Unicode character.
 */

817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
 * The following macros extract the fields of the character info.  The
 * GetDelta() macro is complicated because we can't rely on the C compiler
 * to do sign extension on right shifts.
 */

#define GetCaseType(info) (((info) & 0xE0) >> 5)
#define GetCategory(info) ((info) & 0x1F)
#define GetDelta(info) (((info) > 0) ? ((info) >> 22) : (~(~((info)) >> 22)))

/*
 * This macro extracts the information about a character from the
 * Unicode character tables.
 */

#define GetUniCharInfo(ch) (groups[groupMap[(pageMap[(((int)(ch)) & 0xffff) >> OFFSET_BITS] << OFFSET_BITS) | ((ch) & ((1 << OFFSET_BITS)-1))]])








|








814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
 * The following macros extract the fields of the character info.  The
 * GetDelta() macro is complicated because we can't rely on the C compiler
 * to do sign extension on right shifts.
 */

#define GetCaseType(info) (((info) & 0xE0) >> 5)
#define GetCategory(info) ((info) & 0x1F)
#define GetDelta(info) (((info) > 0) ? ((info) >> 15) : (~(~((info)) >> 15)))

/*
 * This macro extracts the information about a character from the
 * Unicode character tables.
 */

#define GetUniCharInfo(ch) (groups[groupMap[(pageMap[(((int)(ch)) & 0xffff) >> OFFSET_BITS] << OFFSET_BITS) | ((ch) & ((1 << OFFSET_BITS)-1))]])

Changes to generic/tclUtf.c.

1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537

    /*
     * If the character is within the first 127 characters, just use the
     * standard C function, otherwise consult the Unicode table.
     */

    if (ch < 0x80) {
	return isspace(UCHAR(ch)); /* INTL: ISO space */
    } else {
	category = (GetUniCharInfo(ch) & UNICODE_CATEGORY_MASK);
	return ((SPACE_BITS >> category) & 1);
    }
}

/*







|







1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537

    /*
     * If the character is within the first 127 characters, just use the
     * standard C function, otherwise consult the Unicode table.
     */

    if (ch < 0x80) {
	return TclIsSpaceProc((char)ch);
    } else {
	category = (GetUniCharInfo(ch) & UNICODE_CATEGORY_MASK);
	return ((SPACE_BITS >> category) & 1);
    }
}

/*

Changes to generic/tclUtil.c.

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
 */

static ProcessGlobalValue executableName = {
    0, 0, NULL, NULL, NULL, NULL, NULL
};

/*
 * The following values are used in the flags returned by Tcl_ScanElement and
 * used by Tcl_ConvertElement. The values TCL_DONT_USE_BRACES and
 * TCL_DONT_QUOTE_HASH are defined in tcl.h; make sure neither value overlaps
 * with any of the values below.
 *






 * TCL_DONT_USE_BRACES -	1 means the string mustn't be enclosed in
 *				braces (e.g. it contains unmatched braces, or
 *				ends in a backslash character, or user just
 *				doesn't want braces); handle all special
 *				characters by adding backslashes.
 * USE_BRACES -			1 means the string contains a special
 *				character that can be handled simply by
 *				enclosing the entire argument in braces.
 * BRACES_UNMATCHED -		1 means that braces aren't properly matched in
 *				the argument.
 * TCL_DONT_QUOTE_HASH -	1 means the caller insists that a leading hash
 *				character ('#') should *not* be quoted. This
 *				is appropriate when the caller can guarantee
 *				the element is not the first element of a
 *				list, so [eval] cannot mis-parse the element
 *				as a comment.






































 */

#define USE_BRACES		2
#define BRACES_UNMATCHED	4





/*
 * The following key is used by Tcl_PrintDouble and TclPrecTraceProc to
 * access the precision to be used for double formatting.
 */

static Tcl_ThreadDataKey precisionKey;







|
|
|
<

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






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


|
|
>
>
>
>







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
 */

static ProcessGlobalValue executableName = {
    0, 0, NULL, NULL, NULL, NULL, NULL
};

/*
 * The following values are used in the flags arguments of Tcl*Scan*Element and
 * Tcl*Convert*Element. The values TCL_DONT_USE_BRACES and TCL_DONT_QUOTE_HASH
 * are defined in tcl.h, like so:

 *
#define TCL_DONT_USE_BRACES     1
#define TCL_DONT_QUOTE_HASH     8
 *
 * Those are public flag bits which callers of the public routines
 * Tcl_Convert*Element() can use to indicate:
 *
 * TCL_DONT_USE_BRACES -	1 means the caller is insisting that brace



 *				quoting not be used when converting the list




 *				element.
 * TCL_DONT_QUOTE_HASH -	1 means the caller insists that a leading hash
 *				character ('#') should *not* be quoted. This
 *				is appropriate when the caller can guarantee
 *				the element is not the first element of a
 *				list, so [eval] cannot mis-parse the element
 *				as a comment.
 *
 * The remaining values which can be carried by the flags of these routines
 * are for internal use only.  Make sure they do not overlap with the public
 * values above.
 *
 * The Tcl*Scan*Element() routines make a determination which of 4 modes of
 * conversion is most appropriate for Tcl*Convert*Element() to perform, and
 * sets two bits of the flags value to indicate the mode selected.
 *
 * CONVERT_NONE		The element needs no quoting.  Its literal string
 *			is suitable as is.
 * CONVERT_BRACE	The conversion should be enclosing the literal string
 *			in braces.
 * CONVERT_ESCAPE	The conversion should be using backslashes to escape
 *			any characters in the string that require it.
 * CONVERT_MASK		A mask value used to extract the conversion mode from
 *			the flags argument.
 *			Also indicates a strange conversion mode where all
 *			special characters are escaped with backslashes 
 *			*except for braces*.  This is a strange and unnecessary
 *			case, but it's part of the historical way in which
 *			lists have been formatted in Tcl.  To experiment with
 *			removing this case, set the value of COMPAT to 0.
 *
 * One last flag value is used only by callers of TclScanElement().  The flag
 * value produced by a call to Tcl*Scan*Element() will never leave this bit
 * set.
 *
 * CONVERT_ANY		The caller of TclScanElement() declares it can make
 *			no promise about what public flags will be passed to
 *			the matching call of TclConvertElement().  As such,
 *			TclScanElement() has to determine the worst case
 *			destination buffer length over all possibilities, and
 *			in other cases this means an overestimate of the
 *			required size.
 *
 * For more details, see the comments on the Tcl*Scan*Element and 
 * Tcl*Convert*Element routines.
 */

#define COMPAT 1
#define CONVERT_NONE	0
#define CONVERT_BRACE	2
#define CONVERT_ESCAPE	4
#define CONVERT_MASK	(CONVERT_BRACE | CONVERT_ESCAPE)
#define CONVERT_ANY	16

/*
 * The following key is used by Tcl_PrintDouble and TclPrecTraceProc to
 * access the precision to be used for double formatting.
 */

static Tcl_ThreadDataKey precisionKey;
80
81
82
83
84
85
86















































































































































































































































































































87
88
89
90
91
92
93
const Tcl_ObjType tclEndOffsetType = {
    "end-offset",			/* name */
    NULL,				/* freeIntRepProc */
    NULL,				/* dupIntRepProc */
    UpdateStringOfEndOffset,		/* updateStringProc */
    SetEndOffsetFromAny
};
















































































































































































































































































































/*
 *----------------------------------------------------------------------
 *
 * TclFindElement --
 *
 *	Given a pointer into a Tcl list, locate the first (or next) element in







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







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
const Tcl_ObjType tclEndOffsetType = {
    "end-offset",			/* name */
    NULL,				/* freeIntRepProc */
    NULL,				/* dupIntRepProc */
    UpdateStringOfEndOffset,		/* updateStringProc */
    SetEndOffsetFromAny
};

/*
 *	*	STRING REPRESENTATION OF LISTS	*	*	*
 *
 * The next several routines implement the conversions of strings to and
 * from Tcl lists.  To understand their operation, the rules of parsing
 * and generating the string representation of lists must be known.  Here
 * we describe them in one place.
 *
 * A list is made up of zero or more elements.  Any string is a list if
 * it is made up of alternating substrings of element-separating ASCII
 * whitespace and properly formatted elements.
 *
 * The ASCII characters which can make up the whitespace between list
 * elements are:
 *
 *	\u0009	\t	TAB
 *	\u000A	\n	NEWLINE
 *	\u000B	\v	VERTICAL TAB
 *	\u000C	\f	FORM FEED
 * 	\u000D	\r	CARRIAGE RETURN
 *	\u0020		SPACE
 *
 * NOTE: differences between this and other places where Tcl defines a role
 * for "whitespace".
 *
 *	* Unlike command parsing, here NEWLINE is just another whitespace
 *	  character; its role as a command terminator in a script has no
 *	  importance here.
 *
 *	* Unlike command parsing, the BACKSLASH NEWLINE sequence is not
 *	  considered to be a whitespace character.
 *
 *	* Other Unicode whitespace characters (recognized by
 *	  [string is space] or Tcl_UniCharIsSpace()) do not play any role
 *	  as element separators in Tcl lists.
 *
 *	* The NUL byte ought not appear, as it is not in strings properly
 *	  encoded for Tcl, but if it is present, it is not treated as
 *	  separating whitespace, or a string terminator.  It is just
 *	  another character in a list element.
 *
 * The interpretaton of a formatted substring as a list element follows
 * rules similar to the parsing of the words of a command in a Tcl script.
 * Backslash substitution plays a key role, and is defined exactly as it is
 * in command parsing.  The same routine, TclParseBackslash() is used in both
 * command parsing and list parsing.  
 *
 * NOTE:  This means that if and when backslash substitution rules ever
 * change for command parsing, the interpretation of strings as lists also
 * changes.
 * 
 * Backslash substitution replaces an "escape sequence" of one or more
 * characters starting with
 *		\u005c	\	BACKSLASH
 * with a single character.  The one character escape sequent case happens
 * only when BACKSLASH is the last character in the string.  In all other
 * cases, the escape sequence is at least two characters long.
 *
 * The formatted substrings are interpreted as element values according to
 * the following cases:
 *
 * * If the first character of a formatted substring is
 *		\u007b	{	OPEN BRACE
 *   then the end of the substring is the matching 
 *		\u007d	}	CLOSE BRACE
 *   character, where matching is determined by counting nesting levels,
 *   and not including any brace characters that are contained within a
 *   backslash escape sequence in the nesting count.  Having found the
 *   matching brace, all characters between the braces are the string
 *   value of the element.  If no matching close brace is found before the
 *   end of the string, the string is not a Tcl list.  If the character
 *   following the close brace is not an element separating whitespace
 *   character, or the end of the string, then the string is not a Tcl list.
 *
 *   NOTE: this differs from a brace-quoted word in the parsing of a
 *   Tcl command only in its treatment of the backslash-newline sequence.
 *   In a list element, the literal characters in the backslash-newline
 *   sequence become part of the element value.  In a script word,
 *   conversion to a single SPACE character is done.
 *
 *   NOTE: Most list element values can be represented by a formatted
 *   substring using brace quoting.  The exceptions are any element value
 *   that includes an unbalanced brace not in a backslash escape sequence,
 *   and any value that ends with a backslash not itself in a backslash
 *   escape sequence.
 * 
 * * If the first character of a formatted substring is
 *		\u0022	"	QUOTE
 *   then the end of the substring is the next QUOTE character, not counting
 *   any QUOTE characters that are contained within a backslash escape
 *   sequence.  If no next QUOTE is found before the end of the string, the
 *   string is not a Tcl list.  If the character following the closing QUOTE
 *   is not an element separating whitespace character, or the end of the
 *   string, then the string is not a Tcl list.  Having found the limits
 *   of the substring, the element value is produced by performing backslash
 *   substitution on the character sequence between the open and close QUOTEs.
 *
 *   NOTE: Any element value can be represented by this style of formatting,
 *   given suitable choice of backslash escape sequences.
 *
 * * All other formatted substrings are terminated by the next element
 *   separating whitespace character in the string.  Having found the limits
 *   of the substring, the element value is produced by performing backslash
 *   substitution on it.
 *
 *   NOTE:  Any element value can be represented by this style of formatting,
 *   given suitable choice of backslash escape sequences, with one exception.
 *   The empty string cannot be represented as a list element without the use
 *   of either braces or quotes to delimit it.
 *
 * This collection of parsing rules is implemented in the routine
 * TclFindElement().
 *
 * In order to produce lists that can be parsed by these rules, we need
 * the ability to distinguish between characters that are part of a list
 * element value from characters providing syntax that define the structure
 * of the list.  This means that our code that generates lists must at a
 * minimum be able to produce escape sequences for the 10 characters
 * identified above that have significance to a list parser.
 *
 *	*	*	CANONICAL LISTS	*	*	*	*	*	
 *
 * In addition to the basic rules for parsing strings into Tcl lists, there
 * are additional properties to be met by the set of list values that are
 * generated by Tcl.  Such list values are often said to be in "canonical
 * form":
 *
 * * When any canonical list is evaluated as a Tcl script, it is a script
 *   of either zero commands (an empty list) or exactly one command.  The
 *   command word is exactly the first element of the list, and each argument
 *   word is exactly one of the following elements of the list.  This means
 *   that any characters that have special meaning during script evaluation
 *   need special treatment when canonical lists are produced:
 *
 *	* Whitespace between elements may not include NEWLINE.
 *	* The command terminating character,
 *		\u003b	;	SEMICOLON
 *	  must be BRACEd, QUOTEd, or escaped so that it does not terminate
 * 	  the command prematurely.
 *	* Any of the characters that begin substitutions in scripts,
 *		\u0024	$	DOLLAR
 *		\u005b	[	OPEN BRACKET
 *		\u005c	\	BACKSLASH
 *	  need to be BRACEd or escaped.
 *	* In any list where the first character of the first element is
 *		\u0023	#	HASH
 *	  that HASH character must be BRACEd, QUOTEd, or escaped so that it
 *	  does not convert the command into a comment.
 *	* Any list element that contains the character sequence
 *	  BACKSLASH NEWLINE cannot be formatted with BRACEs.  The
 *	  BACKSLASH character must be represented by an escape
 *	  sequence, and unless QUOTEs are used, the NEWLINE must
 *	  be as well.
 *
 * * It is also guaranteed that one can use a canonical list as a building
 *   block of a larger script within command substitution, as in this example:
 *	set script "puts \[[list $cmd $arg]]"; eval $script
 *   To support this usage, any appearance of the character
 *		\u005d	]	CLOSE BRACKET
 *   in a list element must be BRACEd, QUOTEd, or escaped.
 *
 * * Finally it is guaranteed that enclosing a canonical list in braces
 *   produces a new value that is also a canonical list.  This new list has
 *   length 1, and its only element is the original canonical list.  This
 *   same guarantee also makes it possible to construct scripts where an
 *   argument word is given a list value by enclosing the canonical form
 *   of that list in braces:
 *	set script "puts {[list $one $two $three]}"; eval $script
 *   This sort of coding was once fairly common, though it's become more
 *   idiomatic to see the following instead:
 *	set script [list puts [list $one $two $three]]; eval $script
 *   In order to support this guarantee, every canonical list must have 
 *   balance when counting those braces that are not in escape sequences.
 *
 * Within these constraints, the canonical list generation routines
 * TclScanElement() and TclConvertElement() attempt to generate the string
 * for any list that is easiest to read.  When an element value is itself
 * acceptable as the formatted substring, it is usually used (CONVERT_NONE).
 * When some quoting or escaping is required, use of BRACEs (CONVERT_BRACE)
 * is usually preferred over the use of escape sequences (CONVERT_ESCAPE).
 * There are some exceptions to both of these preferences for reasons of
 * code simplicity, efficiency, and continuation of historical habits.
 * Canonical lists never use the QUOTE formatting to delimit their elements
 * because that form of quoting does not nest, which makes construction of
 * nested lists far too much trouble.  Canonical lists always use only a
 * single SPACE character for element-separating whitespace.
 *
 *	*	*	FUTURE CONSIDERATIONS	*	*	*
 *
 * When a list element requires quoting or escaping due to a CLOSE BRACKET
 * character or an internal QUOTE character, a strange formatting mode is
 * recommended.  For example, if the value "a{b]c}d" is converted by the
 * usual modes:
 *
 *	CONVERT_BRACE:	a{b]c}d		=> {a{b]c}d}
 *	CONVERT_ESCAPE:	a{b]c}d		=> a\{b\]c\}d
 *
 * we get perfectly usable formatted list elements.  However, this is not
 * what Tcl releases have been producing.  Instead, we have:
 *
 *	CONVERT_MASK:	a{b]c}d		=> a{b\]c}d
 *
 * where the CLOSE BRACKET is escaped, but the BRACEs are not.  The same
 * effect can be seen replacing ] with " in this example.  There does not
 * appear to be any functional or aesthetic purpose for this strange
 * additional mode.  The sole purpose I can see for preserving it is to
 * keep generating the same formatted lists programmers have become accustomed
 * to, and perhaps written tests to expect.  That is, compatibility only.
 * The additional code complexity required to support this mode is significant.
 * The lines of code supporting it are delimited in the routines below with
 * #if COMPAT directives.  This makes it easy to experiment with eliminating
 * this formatting mode simply with "#define COMPAT 0" above.  I believe
 * this is worth considering.
 * 
 * Another consideration is the treatment of QUOTE characters in list elements.
 * TclConvertElement() must have the ability to produce the escape sequence
 * \" so that when a list element begins with a QUOTE we do not confuse
 * that first character with a QUOTE used as list syntax to define list
 * structure.  However, that is the only place where QUOTE characters need
 * quoting.  In this way, handling QUOTE could really be much more like
 * the way we handle HASH which also needs quoting and escaping only in
 * particular situations.  Following up this could increase the set of
 * list elements that can use the CONVERT_NONE formatting mode.
 *
 * More speculative is that the demands of canonical list form require brace
 * balance for the list as a whole, while the current implementation achieves
 * this by establishing brace balance for every element.
 *
 * Finally, a reminder that the rules for parsing and formatting lists are
 * closely tied together with the rules for parsing and evaluating scripts,
 * and will need to evolve in sync.
 */

/*
 *----------------------------------------------------------------------
 *
 * TclMaxListLength --
 *
 *	Given 'bytes' pointing to 'numBytes' bytes, scan through them and
 *	count the number of whitespace runs that could be list element
 *	separators.  If 'numBytes' is -1, scan to the terminating '\0'.
 *	Not a full list parser.  Typically used to get a quick and dirty
 *	overestimate of length size in order to allocate space for an
 *	actual list parser to operate with.
 *
 * Results:
 *	Returns the largest number of list elements that could possibly
 *	be in this string, interpreted as a Tcl list.  If 'endPtr' is not
 *	NULL, writes a pointer to the end of the string scanned there.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

int
TclMaxListLength(
    const char *bytes,
    int numBytes,
    const char **endPtr)
{
    int count = 0;

    if ((numBytes == 0) || ((numBytes == -1) && (*bytes == '\0'))) {
	/* Empty string case - quick exit */
	goto done;
    }

    /* No list element before leading white space */
    count += 1 - TclIsSpaceProc(*bytes); 

    /* Count white space runs as potential element separators */
    while (numBytes) {
	if ((numBytes == -1) && (*bytes == '\0')) {
	    break;
	}
	if (TclIsSpaceProc(*bytes)) {
	    /* Space run started; bump count */
	    count++;
	    do {
		bytes++;
		numBytes -= (numBytes != -1);
	    } while (numBytes && TclIsSpaceProc(*bytes));
	    if ((numBytes == 0) || ((numBytes == -1) && (*bytes == '\0'))) {
		break;
	    }
	    /* (*bytes) is non-space; return to counting state */
	}
	bytes++;
	numBytes -= (numBytes != -1);
    }

    /* No list element following trailing white space */
    count -= TclIsSpaceProc(bytes[-1]); 

    done:
    if (endPtr) {
	*endPtr = bytes;
    }
    return count;
}

/*
 *----------------------------------------------------------------------
 *
 * TclFindElement --
 *
 *	Given a pointer into a Tcl list, locate the first (or next) element in
101
102
103
104
105
106
107
108
109
110
111
112
113




114

115
116
117
118
119
120
121
 *
 *	If TCL_OK is returned, then *elementPtr will be set to point to the
 *	first element of list, and *nextPtr will be set to point to the
 *	character just after any white space following the last character
 *	that's part of the element. If this is the last argument in the list,
 *	then *nextPtr will point just after the last character in the list
 *	(i.e., at the character at list+listLength). If sizePtr is non-NULL,
 *	*sizePtr is filled in with the number of characters in the element. If
 *	the element is in braces, then *elementPtr will point to the character
 *	after the opening brace and *sizePtr will not include either of the
 *	braces. If there isn't an element in the list, *sizePtr will be zero,
 *	and both *elementPtr and *termPtr will point just after the last
 *	character in the list. Note: this function does NOT collapse backslash




 *	sequences.

 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */








|



|
|
>
>
>
>
|
>







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
 *
 *	If TCL_OK is returned, then *elementPtr will be set to point to the
 *	first element of list, and *nextPtr will be set to point to the
 *	character just after any white space following the last character
 *	that's part of the element. If this is the last argument in the list,
 *	then *nextPtr will point just after the last character in the list
 *	(i.e., at the character at list+listLength). If sizePtr is non-NULL,
 *	*sizePtr is filled in with the number of bytes in the element. If
 *	the element is in braces, then *elementPtr will point to the character
 *	after the opening brace and *sizePtr will not include either of the
 *	braces. If there isn't an element in the list, *sizePtr will be zero,
 *	and both *elementPtr and *nextPtr will point just after the last
 *	character in the list. If literalPtr is non-NULL, *literalPtr is set
 *	to a boolean value indicating whether the substring returned as
 *	the values of **elementPtr and *sizePtr is the literal value of
 *	a list element.  If not, a call to TclCopyAndCollapse() is needed
 *	to produce the actual value of the list element.  Note: this function
 *	does NOT collapse backslash sequences, but uses *literalPtr to tell
 * 	callers when it is required for them to do so.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

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 char **elementPtr,	/* Where to put address of first significant
				 * character in first element of list. */
    const char **nextPtr,	/* Fill in with location of character just
				 * after all white space following end of
				 * argument (next arg or end of list). */
    int *sizePtr,		/* If non-zero, fill in with size of
				 * element. */
    int *bracePtr)		/* If non-zero, fill in with non-zero/zero to
				 * indicate that arg was/wasn't in braces. */




{
    const char *p = list;
    const char *elemStart;	/* Points to first byte of first element. */
    const char *limit;		/* Points just after list's last byte. */
    int openBraces = 0;		/* Brace nesting level during parse. */
    int inQuotes = 0;
    int size = 0;		/* lint. */
    int numChars;

    const char *p2;

    /*
     * Skim off leading white space and check for an opening brace or quote.
     * We treat embedded NULLs in the list as bytes belonging to a list
     * element.
     */

    limit = (list + listLength);
    while ((p < limit) && (isspace(UCHAR(*p)))) { /* INTL: ISO space. */
	p++;
    }
    if (p == limit) {		/* no element found */
	elemStart = limit;
	goto done;
    }

    if (*p == '{') {
	openBraces = 1;
	p++;
    } else if (*p == '"') {
	inQuotes = 1;
	p++;
    }
    elemStart = p;
    if (bracePtr != 0) {
	*bracePtr = openBraces;
    }

    /*
     * Find element's end (a space, close brace, or the end of the string).
     */

    while (p < limit) {
	switch (*p) {







|
|
>
>
>
>








>









|















<
<
<







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
    const char **elementPtr,	/* Where to put address of first significant
				 * character in first element of list. */
    const char **nextPtr,	/* Fill in with location of character just
				 * after all white space following end of
				 * argument (next arg or end of list). */
    int *sizePtr,		/* If non-zero, fill in with size of
				 * element. */
    int *literalPtr)		/* If non-zero, fill in with non-zero/zero to
				 * indicate that the substring of *sizePtr
				 * bytes starting at **elementPtr is/is not
				 * the literal list element and therefore
				 * does not/does require a call to 
				 * TclCopyAndCollapse() by the caller. */
{
    const char *p = list;
    const char *elemStart;	/* Points to first byte of first element. */
    const char *limit;		/* Points just after list's last byte. */
    int openBraces = 0;		/* Brace nesting level during parse. */
    int inQuotes = 0;
    int size = 0;		/* lint. */
    int numChars;
    int literal = 1;
    const char *p2;

    /*
     * Skim off leading white space and check for an opening brace or quote.
     * We treat embedded NULLs in the list as bytes belonging to a list
     * element.
     */

    limit = (list + listLength);
    while ((p < limit) && (TclIsSpaceProc(*p))) {
	p++;
    }
    if (p == limit) {		/* no element found */
	elemStart = limit;
	goto done;
    }

    if (*p == '{') {
	openBraces = 1;
	p++;
    } else if (*p == '"') {
	inQuotes = 1;
	p++;
    }
    elemStart = p;




    /*
     * Find element's end (a space, close brace, or the end of the string).
     */

    while (p < limit) {
	switch (*p) {
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

	case '}':
	    if (openBraces > 1) {
		openBraces--;
	    } else if (openBraces == 1) {
		size = (p - elemStart);
		p++;
		if ((p >= limit)
			|| isspace(UCHAR(*p))) {	/* INTL: ISO space. */
		    goto done;
		}

		/*
		 * Garbage after the closing brace; return an error.
		 */

		if (interp != NULL) {
		    p2 = p;
		    while ((p2 < limit)
			    && (!isspace(UCHAR(*p2)))	/* INTL: ISO space. */
			    && (p2 < p+20)) {
			p2++;
		    }
		    Tcl_SetObjResult(interp, Tcl_ObjPrintf(
			    "list element in braces followed by \"%.*s\" "
			    "instead of space", (int) (p2-p), p));
		    Tcl_SetErrorCode(interp, "TCL", "VALUE", "LIST", "JUNK",
			    NULL);
		}
		return TCL_ERROR;
	    }
	    break;

	    /*
	     * Backslash: skip over everything up to the end of the backslash
	     * sequence.
	     */

	case '\\':









	    TclParseBackslash(p, limit - p, &numChars, NULL);
	    p += (numChars - 1);
	    break;

	    /*
	     * Space: ignore if element is in braces or quotes; otherwise
	     * terminate element.







|
<









|
<



















>
>
>
>
>
>
>
>
>







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

	case '}':
	    if (openBraces > 1) {
		openBraces--;
	    } else if (openBraces == 1) {
		size = (p - elemStart);
		p++;
		if ((p >= limit) || TclIsSpaceProc(*p)) {

		    goto done;
		}

		/*
		 * Garbage after the closing brace; return an error.
		 */

		if (interp != NULL) {
		    p2 = p;
		    while ((p2 < limit) && (!TclIsSpaceProc(*p2))

			    && (p2 < p+20)) {
			p2++;
		    }
		    Tcl_SetObjResult(interp, Tcl_ObjPrintf(
			    "list element in braces followed by \"%.*s\" "
			    "instead of space", (int) (p2-p), p));
		    Tcl_SetErrorCode(interp, "TCL", "VALUE", "LIST", "JUNK",
			    NULL);
		}
		return TCL_ERROR;
	    }
	    break;

	    /*
	     * Backslash: skip over everything up to the end of the backslash
	     * sequence.
	     */

	case '\\':
	    if (openBraces == 0) {
		/*
		 * A backslash sequence not within a brace quoted element
		 * means the value of the element is different from the
		 * substring we are parsing.  A call to TclCopyAndCollapse()
		 * is needed to produce the element value.  Inform the caller.
		 */
		literal = 0;
	    }
	    TclParseBackslash(p, limit - p, &numChars, NULL);
	    p += (numChars - 1);
	    break;

	    /*
	     * Space: ignore if element is in braces or quotes; otherwise
	     * terminate element.
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
	     * Double-quote: if element is in quotes then terminate it.
	     */

	case '"':
	    if (inQuotes) {
		size = (p - elemStart);
		p++;
		if ((p >= limit)
			|| isspace(UCHAR(*p))) {	/* INTL: ISO space */
		    goto done;
		}

		/*
		 * Garbage after the closing quote; return an error.
		 */

		if (interp != NULL) {
		    p2 = p;
		    while ((p2 < limit)
			    && (!isspace(UCHAR(*p2)))	/* INTL: ISO space */
			    && (p2 < p+20)) {
			p2++;
		    }
		    Tcl_SetObjResult(interp, Tcl_ObjPrintf(
			    "list element in quotes followed by \"%.*s\" "
			    "instead of space", (int) (p2-p), p));
		    Tcl_SetErrorCode(interp, "TCL", "VALUE", "LIST", "JUNK",







|
<









|
<







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
	     * Double-quote: if element is in quotes then terminate it.
	     */

	case '"':
	    if (inQuotes) {
		size = (p - elemStart);
		p++;
		if ((p >= limit) || TclIsSpaceProc(*p)) {

		    goto done;
		}

		/*
		 * Garbage after the closing quote; return an error.
		 */

		if (interp != NULL) {
		    p2 = p;
		    while ((p2 < limit) && (!TclIsSpaceProc(*p2))

			    && (p2 < p+20)) {
			p2++;
		    }
		    Tcl_SetObjResult(interp, Tcl_ObjPrintf(
			    "list element in quotes followed by \"%.*s\" "
			    "instead of space", (int) (p2-p), p));
		    Tcl_SetErrorCode(interp, "TCL", "VALUE", "LIST", "JUNK",
314
315
316
317
318
319
320
321
322
323
324
325
326
327



328
329
330
331
332
333
334
	    }
	    return TCL_ERROR;
	}
	size = (p - elemStart);
    }

  done:
    while ((p < limit) && (isspace(UCHAR(*p)))) { /* INTL: ISO space. */
	p++;
    }
    *elementPtr = elemStart;
    *nextPtr = p;
    if (sizePtr != 0) {
	*sizePtr = size;



    }
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *







|






>
>
>







669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
	    }
	    return TCL_ERROR;
	}
	size = (p - elemStart);
    }

  done:
    while ((p < limit) && (TclIsSpaceProc(*p))) {
	p++;
    }
    *elementPtr = elemStart;
    *nextPtr = p;
    if (sizePtr != 0) {
	*sizePtr = size;
    }
    if (literalPtr != 0) {
	*literalPtr = literal;
    }
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
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
				 * NULL, no error message is left. */
    const char *list,		/* Pointer to string with list structure. */
    int *argcPtr,		/* Pointer to location to fill in with the
				 * number of elements in the list. */
    const char ***argvPtr)	/* Pointer to place to store pointer to array
				 * of pointers to list elements. */
{
    const char **argv, *l, *element;
    char *p;
    int length, size, i, result, elSize, brace;

    /*
     * Figure out how much space to allocate. There must be enough space for
     * both the array of pointers and also for a copy of the list. To estimate
     * the number of pointers needed, count the number of space characters in
     * the list.
     */

    for (size = 2, l = list; *l != 0; l++) {
	if (isspace(UCHAR(*l))) {			/* INTL: ISO space. */
	    size++;

	    /*
	     * Consecutive space can only count as a single list delimiter.

	     */

	    while (1) {
		char next = *(l + 1);

		if (next == '\0') {
		    break;
		}
		l++;
		if (isspace(UCHAR(next))) {		/* INTL: ISO space. */
		    continue;
		}
		break;
	    }
	}
    }
    length = l - list;
    argv = ckalloc((size * sizeof(char *)) + length + 1);

    for (i = 0, p = ((char *) argv) + size*sizeof(char *);
	    *list != 0;  i++) {
	const char *prevList = list;


	result = TclFindElement(interp, list, length, &element, &list,
		&elSize, &brace);
	length -= (list - prevList);
	if (result != TCL_OK) {
	    ckfree(argv);
	    return result;
	}
	if (*element == 0) {
	    break;
	}
	if (i >= size) {
	    ckfree(argv);
	    if (interp != NULL) {
		Tcl_SetResult(interp, "internal error in Tcl_SplitList",
			TCL_STATIC);


	    }
	    return TCL_ERROR;
	}
	argv[i] = p;
	if (brace) {
	    memcpy(p, element, (size_t) elSize);
	    p += elSize;
	    *p = 0;
	    p++;
	} else {
	    TclCopyAndCollapse(elSize, element, p);
	    p += elSize+1;
	}
    }

    argv[i] = NULL;
    *argvPtr = argv;
    *argcPtr = i;
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_ScanElement --
 *
 *	This function is a companion function to Tcl_ConvertElement. It scans
 *	a string to see what needs to be done to it (e.g. add backslashes or
 *	enclosing braces) to make the string into a valid Tcl list element.
 *
 * Results:
 *	The return value is an overestimate of the number of characters that
 *	will be needed by Tcl_ConvertElement to produce a valid list element
 *	from string. The word at *flagPtr is filled in with a value needed by
 *	Tcl_ConvertElement when doing the actual conversion.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

int
Tcl_ScanElement(
    register const char *string,/* String to convert to list element. */
    register int *flagPtr)	/* Where to store information to guide
				 * Tcl_ConvertCountedElement. */
{
    return Tcl_ScanCountedElement(string, -1, flagPtr);
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_ScanCountedElement --
 *
 *	This function is a companion function to Tcl_ConvertCountedElement. It
 *	scans a string to see what needs to be done to it (e.g. add
 *	backslashes or enclosing braces) to make the string into a valid Tcl
 *	list element. If length is -1, then the string is scanned up to the
 *	first null byte.
 *
 * Results:
 *	The return value is an overestimate of the number of characters that
 *	will be needed by Tcl_ConvertCountedElement to produce a valid list
 *	element from string. The word at *flagPtr is filled in with a value
 *	needed by Tcl_ConvertCountedElement when doing the actual conversion.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

int
Tcl_ScanCountedElement(
    const char *string,		/* String to convert to Tcl list element. */
    int length,			/* Number of bytes in string, or -1. */












































    int *flagPtr)		/* Where to store information to guide
				 * Tcl_ConvertElement. */
{
    int flags, nestingLevel;
    register const char *p, *lastChar;

    /*

     * This function and Tcl_ConvertElement together do two things:

     *
     * 1. They produce a proper list, one that will yield back the argument
     *	  strings when evaluated or when disassembled with Tcl_SplitList. This
     *	  is the most important thing.
     *
     * 2. They try to produce legible output, which means minimizing the use
     *	  of backslashes (using braces instead). However, there are some
     *	  situations where backslashes must be used (e.g. an element like
     *	  "{abc": the leading brace will have to be backslashed. For each
     *	  element, one of three things must be done:
     *
     *	  (a) Use the element as-is (it doesn't contain any special
     *	      characters). This is the most desirable option.
     *
     *	  (b) Enclose the element in braces, but leave the contents alone.
     *	      This happens if the element contains embedded space, or if it
     *	      contains characters with special interpretation ($, [, ;, or \),
     *	      or if it starts with a brace or double-quote, or if there are no
     *	      characters in the element.
     *
     *	  (c) Don't enclose the element in braces, but add backslashes to
     *	      prevent special interpretation of special characters. This is a
     *	      last resort used when the argument would normally fall under
     *	      case (b) but contains unmatched braces. It also occurs if the
     *	      last character of the argument is a backslash or if the element
     *	      contains a backslash followed by newline.
     *
     * The function figures out how many bytes will be needed to store the
     * result (actually, it overestimates). It also collects information about

     * the element in the form of a flags word.



     *



     * Note: list elements produced by this function and
     * Tcl_ConvertCountedElement must have the property that they can be
     * enclosing in curly braces to make sub-lists. This means, for example,
     * that we must not leave unmatched curly braces in the resulting list
     * element. This property is necessary in order for functions like
     * Tcl_DStringStartSublist to work.
     */

    nestingLevel = 0;
    flags = 0;
    if (string == NULL) {
	string = "";

    }
    if (length == -1) {
	length = strlen(string);
    }
    lastChar = string + length;
    p = string;
    if ((p == lastChar) || (*p == '{') || (*p == '"')) {
	flags |= USE_BRACES;
    }
    for (; p < lastChar; p++) {
	switch (*p) {
	case '{':




	    nestingLevel++;
	    break;
	case '}':




	    nestingLevel--;
	    if (nestingLevel < 0) {
		flags |= TCL_DONT_USE_BRACES|BRACES_UNMATCHED;


	    }
	    break;










	case '[':
	case '$':
	case ';':
	case ' ':
	case '\f':
	case '\n':
	case '\r':
	case '\t':
	case '\v':
	    flags |= USE_BRACES;




	    break;
	case '\\':






	    if ((p+1 == lastChar) || (p[1] == '\n')) {
		flags = TCL_DONT_USE_BRACES | BRACES_UNMATCHED;


	    } else {


		int size;

		TclParseBackslash(p, lastChar - p, &size, NULL);





		p += size-1;

		flags |= USE_BRACES;





	    }

	    break;
	}


    }


    if (nestingLevel != 0) {



	flags = TCL_DONT_USE_BRACES | BRACES_UNMATCHED;


    }










    *flagPtr = flags;



    /*




















     * Allow enough space to backslash every character plus leave two spaces











     * for braces.
     */
























    return 2*(p-string) + 2;












}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_ConvertElement --
 *







|

|


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

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

>



>


|













>
>




|





|
<



















|

|










|



|










|
|


|

|










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



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

<
<
|
|
<
<
<
<
<


>
>
>
>



>
>
>
>


<
>
>


>
>
>
>
>
>
>
>
>
>









|
>
>
>
>


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

>


>
>

>
>

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







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
				 * NULL, no error message is left. */
    const char *list,		/* Pointer to string with list structure. */
    int *argcPtr,		/* Pointer to location to fill in with the
				 * number of elements in the list. */
    const char ***argvPtr)	/* Pointer to place to store pointer to array
				 * of pointers to list elements. */
{
    const char **argv, *end, *element;
    char *p;
    int length, size, i, result, elSize;

    /*
     * Allocate enough space to work in. A (const char *) for each
     * (possible) list element plus one more for terminating NULL,



     * plus as many bytes as in the original string value, plus one



     * more for a terminating '\0'.  Space used to hold element separating

     * white space in the original string gets re-purposed to hold '\0'
     * characters in the argv array.
     */



    size = TclMaxListLength(list, -1, &end) + 1;











    length = end - list;
    argv = ckalloc((size * sizeof(char *)) + length + 1);

    for (i = 0, p = ((char *) argv) + size*sizeof(char *);
	    *list != 0;  i++) {
	const char *prevList = list;
	int literal;

	result = TclFindElement(interp, list, length, &element, &list,
		&elSize, &literal);
	length -= (list - prevList);
	if (result != TCL_OK) {
	    ckfree(argv);
	    return result;
	}
	if (*element == 0) {
	    break;
	}
	if (i >= size) {
	    ckfree(argv);
	    if (interp != NULL) {
		Tcl_SetResult(interp, "internal error in Tcl_SplitList",
			TCL_STATIC);
		Tcl_SetErrorCode(interp, "TCL", "INTERNAL", "Tcl_SplitList",
			NULL);
	    }
	    return TCL_ERROR;
	}
	argv[i] = p;
	if (literal) {
	    memcpy(p, element, (size_t) elSize);
	    p += elSize;
	    *p = 0;
	    p++;
	} else {
	    p += 1 + TclCopyAndCollapse(elSize, element, p);

	}
    }

    argv[i] = NULL;
    *argvPtr = argv;
    *argcPtr = i;
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_ScanElement --
 *
 *	This function is a companion function to Tcl_ConvertElement. It scans
 *	a string to see what needs to be done to it (e.g. add backslashes or
 *	enclosing braces) to make the string into a valid Tcl list element.
 *
 * Results:
 *	The return value is an overestimate of the number of bytes that
 *	will be needed by Tcl_ConvertElement to produce a valid list element
 *	from src. The word at *flagPtr is filled in with a value needed by
 *	Tcl_ConvertElement when doing the actual conversion.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

int
Tcl_ScanElement(
    register const char *src,	/* String to convert to list element. */
    register int *flagPtr)	/* Where to store information to guide
				 * Tcl_ConvertCountedElement. */
{
    return Tcl_ScanCountedElement(src, -1, flagPtr);
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_ScanCountedElement --
 *
 *	This function is a companion function to Tcl_ConvertCountedElement. It
 *	scans a string to see what needs to be done to it (e.g. add
 *	backslashes or enclosing braces) to make the string into a valid Tcl
 *	list element. If length is -1, then the string is scanned from src up
 *	to the first null byte.
 *
 * Results:
 *	The return value is an overestimate of the number of bytes that
 *	will be needed by Tcl_ConvertCountedElement to produce a valid list
 *	element from src. The word at *flagPtr is filled in with a value
 *	needed by Tcl_ConvertCountedElement when doing the actual conversion.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

int
Tcl_ScanCountedElement(
    const char *src,		/* String to convert to Tcl list element. */
    int length,			/* Number of bytes in src, or -1. */
    int *flagPtr)		/* Where to store information to guide
				 * Tcl_ConvertElement. */
{
    int flags = CONVERT_ANY;
    int numBytes = TclScanElement(src, length, &flags);

    *flagPtr = flags;
    return numBytes;
}

/*
 *----------------------------------------------------------------------
 *
 * TclScanElement --
 *
 *	This function is a companion function to TclConvertElement. It
 *	scans a string to see what needs to be done to it (e.g. add
 *	backslashes or enclosing braces) to make the string into a valid Tcl
 *	list element. If length is -1, then the string is scanned from src up
 *	to the first null byte.  A NULL value for src is treated as an
 *	empty string.  The incoming value of *flagPtr is a report from the
 *	caller what additional flags it will pass to TclConvertElement().
 *
 * Results:
 *	The recommended formatting mode for the element is determined and
 *	a value is written to *flagPtr indicating that recommendation.  This
 *	recommendation is combined with the incoming flag values in *flagPtr
 *	set by the caller to determine how many bytes will be needed by
 *	TclConvertElement() in which to write the formatted element following
 *	the recommendation modified by the flag values.  This number of bytes
 *	is the return value of the routine.  In some situations it may be
 *	an overestimate, but so long as the caller passes the same flags
 *	to TclConvertElement(), it will be large enough.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

int
TclScanElement(
    const char *src,		/* String to convert to Tcl list element. */
    int length,			/* Number of bytes in src, or -1. */
    int *flagPtr)		/* Where to store information to guide
				 * Tcl_ConvertElement. */
{

    const char *p = src;
    int nestingLevel = 0;	/* Brace nesting count */

    int forbidNone = 0;		/* Do not permit CONVERT_NONE mode. Something
				   needs protection or escape. */
    int requireEscape = 0;	/* Force use of CONVERT_ESCAPE mode.  For some
				 * reason bare or brace-quoted form fails. */
    int extra = 0;		/* Count of number of extra bytes needed for
				 * formatted element, assuming we use escape
				 * sequences in formatting. */
    int bytesNeeded;		/* Buffer length computed to complete the
				 * element formatting in the selected mode. */
#if COMPAT
    int preferEscape = 0;	/* Use preferences to track whether to use */
    int preferBrace = 0;	/* CONVERT_MASK mode. */
    int braceCount = 0;		/* Count of all braces '{' '}' seen. */








#endif







    


    if ((p == NULL) || (length == 0) || ((*p == '\0') && (length == -1))) {
	/* Empty string element must be brace quoted. */
	*flagPtr = CONVERT_BRACE;
	return 2;
    }

    if ((*p == '{') || (*p == '"')) {
	/*
	 * Must escape or protect so leading character of value is not
	 * misinterpreted as list element delimiting syntax.





	 */
	forbidNone = 1;


#if COMPAT
	preferBrace = 1;
#endif
    }



    while (length) {





	switch (*p) {
	case '{':
#if COMPAT
	    braceCount++;
#endif
	    extra++;				/* Escape '{' => '\{' */
	    nestingLevel++;
	    break;
	case '}':
#if COMPAT
	    braceCount++;
#endif
	    extra++;				/* Escape '}' => '\}' */
	    nestingLevel--;
	    if (nestingLevel < 0) {

		/* Unbalanced braces!  Cannot format with brace quoting. */
		requireEscape = 1;
	    }
	    break;
	case ']':
	case '"':
#if COMPAT
	    forbidNone = 1;
	    extra++;		/* Escapes all just prepend a backslash */
	    preferEscape = 1;
	    break;
#else
	    /* FLOW THROUGH */
#endif
	case '[':
	case '$':
	case ';':
	case ' ':
	case '\f':
	case '\n':
	case '\r':
	case '\t':
	case '\v':
	    forbidNone = 1;
	    extra++;		/* Escape sequences all one byte longer. */
#if COMPAT
	    preferBrace = 1;
#endif
	    break;
	case '\\':
	    extra++;				/* Escape '\' => '\\' */
	    if ((length == 1) || ((length == -1) && (p[1] == '\0'))) {
		/* Final backslash. Cannot format with brace quoting. */
		requireEscape = 1;		
		break;
	    }
	    if (p[1] == '\n') {

		extra++;	/* Escape newline => '\n', one byte longer */
		/* Backslash newline sequence.  Brace quoting not permitted. */
		requireEscape = 1;
		length -= (length > 0);
		p++;
		break;
	    }

	    if ((p[1] == '{') || (p[1] == '}') || (p[1] == '\\')) {
		extra++;	/* Escape sequences all one byte longer. */
		length -= (length > 0);
		p++;
	    }
	    forbidNone = 1;
#if COMPAT
	    preferBrace = 1;
#endif
	    break;
	case '\0':
	    if (length == -1) {
		goto endOfString;
	    }
	    /* TODO: Panic on improper encoding? */
	    break;
	}
	length -= (length > 0);
	p++;
    }

    endOfString:
    if (nestingLevel != 0) {
	/* Unbalanced braces!  Cannot format with brace quoting. */
	requireEscape = 1;
    }

    /* We need at least as many bytes as are in the element value... */
    bytesNeeded = p - src;

    if (requireEscape) {
	/*
	 * We must use escape sequences.  Add all the extra bytes needed
	 * to have room to create them.
	 */
	bytesNeeded += extra;
	/* Make room to escape leading #, if needed. */
	if ((*src == '#') && !(*flagPtr & TCL_DONT_QUOTE_HASH)) {
	    bytesNeeded++;
	}
	*flagPtr = CONVERT_ESCAPE;
	goto overflowCheck;
    }
    if (*flagPtr & CONVERT_ANY) {
	/*
	 * The caller has not let us know what flags it will pass to
	 * TclConvertElement() so compute the max size we might need for
	 * any possible choice.  Normally the formatting using escape
	 * sequences is the longer one, and a minimum "extra" value of 2
	 * makes sure we don't request too small a buffer in those edge
	 * cases where that's not true.
	 */
	if (extra < 2) {
	    extra = 2;
	}
	*flagPtr &= ~CONVERT_ANY;
	*flagPtr |= TCL_DONT_USE_BRACES;
    }
    if (forbidNone) {
	/* We must request some form of quoting of escaping... */
#if COMPAT
	if (preferEscape && !preferBrace) {
	    /*
	     * If we are quoting solely due to ] or internal " characters
	     * use the CONVERT_MASK mode where we escape all special 
	     * characters except for braces.  "extra" counted space needed
	     * to escape braces too, so substract "braceCount" to get our
	     * actual needs.
	     */
	    bytesNeeded += (extra - braceCount);
	    /* Make room to escape leading #, if needed. */
	    if ((*src == '#') && !(*flagPtr & TCL_DONT_QUOTE_HASH)) {
		bytesNeeded++;
	    }
	    /*
	     * If the caller reports it will direct TclConvertElement() to
	     * use full escapes on the element, add back the bytes needed to
	     * escape the braces.
	     */
	    if (*flagPtr & TCL_DONT_USE_BRACES) {
		bytesNeeded += braceCount;
	    }
	    *flagPtr = CONVERT_MASK;
	    goto overflowCheck;
	}
#endif
	if (*flagPtr & TCL_DONT_USE_BRACES) {
	    /*
	     * If the caller reports it will direct TclConvertElement() to
	     * use escapes, add the extra bytes needed to have room for them.
	     */
	    bytesNeeded += extra;
	    /* Make room to escape leading #, if needed. */
	    if ((*src == '#') && !(*flagPtr & TCL_DONT_QUOTE_HASH)) {
		bytesNeeded++;
	    }
	} else {
	    /* Add 2 bytes for room for the enclosing braces. */
	    bytesNeeded += 2;
	}
	*flagPtr = CONVERT_BRACE;
	goto overflowCheck;
    }

    /* So far, no need to quote or escape anything. */
    if ((*src == '#') && !(*flagPtr & TCL_DONT_QUOTE_HASH)) {
	/* If we need to quote a leading #, make room to enclose in braces. */
	bytesNeeded += 2;
    }
    *flagPtr = CONVERT_NONE;

    overflowCheck:
    if (bytesNeeded < 0) {
	Tcl_Panic("TclScanElement: string length overflow");
    }
    return bytesNeeded;
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_ConvertElement --
 *
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
int
Tcl_ConvertCountedElement(
    register const char *src,	/* Source information for list element. */
    int length,			/* Number of bytes in src, or -1. */
    char *dst,			/* Place to put list-ified element. */
    int flags)			/* Flags produced by Tcl_ScanElement. */
{
    register char *p = dst;
    register const char *lastChar;



    /*


     * See the comment block at the beginning of the Tcl_ScanElement code for





     * details of how this works.









     */



    if (src && length == -1) {





	length = strlen(src);



    }


    if ((src == NULL) || (length == 0)) {
	p[0] = '{';
	p[1] = '}';
	p[2] = 0;
	return 2;
    }
    lastChar = src + length;

    if ((*src == '#') && !(flags & TCL_DONT_QUOTE_HASH)) {
	flags |= USE_BRACES;
    }
    if ((flags & USE_BRACES) && !(flags & TCL_DONT_USE_BRACES)) {
	*p = '{';
	p++;
	for (; src != lastChar; src++, p++) {
	    *p = *src;
	}
	*p = '}';
	p++;
    } else {
	if (*src == '{') {
	    /*
	     * Can't have a leading brace unless the whole element is enclosed
	     * in braces. Add a backslash before the brace. Furthermore, this
	     * may destroy the balance between open and close braces, so set
	     * BRACES_UNMATCHED.
	     */

	    p[0] = '\\';
	    p[1] = '{';
	    p += 2;
	    src++;
	    flags |= BRACES_UNMATCHED;
	} else if ((*src == '#') && !(flags & TCL_DONT_QUOTE_HASH)) {
	    /*
	     * Leading '#' could be seen by [eval] as the start of a comment,
	     * if on the first element of a list, so quote it.
	     */

	    p[0] = '\\';
	    p[1] = '#';
	    p += 2;
	    src++;



	}

	for (; src != lastChar; src++) {




































	    switch (*src) {
	    case ']':
	    case '[':
	    case '$':
	    case ';':
	    case ' ':
	    case '\\':
	    case '"':
		*p = '\\';
		p++;
		break;
	    case '{':
	    case '}':
		/*
		 * It may not seem necessary to backslash braces, but it is.
		 * The reason for this is that the resulting list element may
		 * actually be an element of a sub-list enclosed in braces
		 * (e.g. if Tcl_DStringStartSublist has been invoked), so
		 * there may be a brace mismatch if the braces aren't
		 * backslashed.
		 */

		if (flags & BRACES_UNMATCHED) {
		    *p = '\\';
		    p++;

		}

		break;
	    case '\f':
		*p = '\\';
		p++;
		*p = 'f';
		p++;
		continue;
	    case '\n':
		*p = '\\';
		p++;
		*p = 'n';
		p++;
		continue;
	    case '\r':
		*p = '\\';
		p++;
		*p = 'r';
		p++;
		continue;
	    case '\t':
		*p = '\\';
		p++;
		*p = 't';
		p++;
		continue;
	    case '\v':
		*p = '\\';
		p++;
		*p = 'v';
		p++;
		continue;



	    }









	    *p = *src;
	    p++;
	}
    }
    *p = '\0';
    return p-dst;
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_Merge --
 *







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

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

>
>
|
|
<
|
|

|
>

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




>
>
>

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

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







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
int
Tcl_ConvertCountedElement(
    register const char *src,	/* Source information for list element. */
    int length,			/* Number of bytes in src, or -1. */
    char *dst,			/* Place to put list-ified element. */
    int flags)			/* Flags produced by Tcl_ScanElement. */
{
    int numBytes = TclConvertElement(src, length, dst, flags);
    dst[numBytes] = '\0';
    return numBytes;
}

/*
 *----------------------------------------------------------------------
 *
 * TclConvertElement --
 *
 *	This is a companion function to TclScanElement. Given the
 *	information produced by TclScanElement, this function converts
 *	a string to a list element equal to that string.
 *
 * Results:
 *	Information is copied to *dst in the form of a list element identical
 *	to src (i.e. if Tcl_SplitList is applied to dst it will produce a
 *	string identical to src). The return value is a count of the number of
 *	characters copied (not including the terminating NULL character).
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

int TclConvertElement(
    register const char *src,	/* Source information for list element. */
    int length,			/* Number of bytes in src, or -1. */
    char *dst,			/* Place to put list-ified element. */
    int flags)			/* Flags produced by Tcl_ScanElement. */
{
    int conversion = flags & CONVERT_MASK;
    char *p = dst;

    /* Let the caller demand we use escape sequences rather than braces. */
    if ((flags & TCL_DONT_USE_BRACES) && (conversion & CONVERT_BRACE)) {
	conversion = CONVERT_ESCAPE;
    }

    /* No matter what the caller demands, empty string must be braced! */
    if ((src == NULL) || (length == 0) || ((*src == '\0') && (length == -1))) {
	src = tclEmptyStringRep;

	length = 0;
	conversion = CONVERT_BRACE;
    }

    /* Escape leading hash as needed and requested. */
    if ((*src == '#') && !(flags & TCL_DONT_QUOTE_HASH)) {


















	if (conversion == CONVERT_ESCAPE) {











	    p[0] = '\\';
	    p[1] = '#';
	    p += 2;
	    src++;
	    length -= (length > 0);
	} else {
	    conversion = CONVERT_BRACE;
	}
    }

    /* No escape or quoting needed.  Copy the literal string value. */
    if (conversion == CONVERT_NONE) {
	if (length == -1) {
	    /* TODO: INT_MAX overflow? */
	    while (*src) {
		*p++ = *src++;
	    }
	    return p - dst;
	} else {
	    memcpy(dst, src, length);
	    return length;
	}
    }

    /* Formatted string is original string enclosed in braces. */
    if (conversion == CONVERT_BRACE) {
	*p = '{';
	p++;
	if (length == -1) {
	    /* TODO: INT_MAX overflow? */
	    while (*src) {
		*p++ = *src++;
	    }
	} else {
	    memcpy(p, src, length);
	    p += length;
	}
	*p = '}';
	p++;
	return p - dst;
    }

    /* conversion == CONVERT_ESCAPE or CONVERT_MASK */

    /* Formatted string is original string converted to escape sequences. */
    for ( ; length; src++, length -= (length > 0)) {
	switch (*src) {
	case ']':
	case '[':
	case '$':
	case ';':
	case ' ':
	case '\\':
	case '"':
	    *p = '\\';
	    p++;
	    break;
	case '{':
	case '}':





#if COMPAT


	    if (conversion == CONVERT_ESCAPE) {
#endif
		*p = '\\';
		p++;
#if COMPAT
	    }
#endif
	    break;
	case '\f':
	    *p = '\\';
	    p++;
	    *p = 'f';
	    p++;
	    continue;
	case '\n':
	    *p = '\\';
	    p++;
	    *p = 'n';
	    p++;
	    continue;
	case '\r':
	    *p = '\\';
	    p++;
	    *p = 'r';
	    p++;
	    continue;
	case '\t':
	    *p = '\\';
	    p++;
	    *p = 't';
	    p++;
	    continue;
	case '\v':
	    *p = '\\';
	    p++;
	    *p = 'v';
	    p++;
	    continue;
	case '\0':
	    if (length == -1) {
		return p - dst;
	    }
	    /* 
	     * If we reach this point, there's an embedded NULL in the
	     * string range being processed, which should not happen when
	     * the encoding rules for Tcl strings are properly followed.
	     * If the day ever comes when we stop tolerating such things,
	     * this is where to put the Tcl_Panic().
	     */
	    break;
	}
	*p = *src;
	p++;
    }


    return p - dst;
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_Merge --
 *
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

char *
Tcl_Merge(
    int argc,			/* How many strings to merge. */
    const char *const *argv)	/* Array of string values. */
{
#   define LOCAL_SIZE 20
    int localFlags[LOCAL_SIZE], *flagPtr;
    int numChars;
    char *result;

    char *dst;





    int i;




    /*
     * Pass 1: estimate space, gather flags.
     */

    if (argc <= LOCAL_SIZE) {
	flagPtr = localFlags;














    } else {
	flagPtr = ckalloc(argc * sizeof(int));
    }
    numChars = 1;
    for (i = 0; i < argc; i++) {

	numChars += Tcl_ScanElement(argv[i], &flagPtr[i]) + 1;


    }






    /*
     * Pass two: copy into the result area.
     */

    result = ckalloc(numChars);
    dst = result;
    for (i = 0; i < argc; i++) {
	numChars = Tcl_ConvertElement(argv[i], dst,
		flagPtr[i] | (i==0 ? 0 : TCL_DONT_QUOTE_HASH));
	dst += numChars;
	*dst = ' ';
	dst++;
    }
    if (dst == result) {
	*dst = 0;
    } else {
	dst[-1] = 0;
    }

    if (flagPtr != localFlags) {
	ckfree(flagPtr);
    }
    return result;
}








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







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



<

>
|
>
>
|
>
>
>
>
>





|


<
|
|



<
<
<
|
<







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

char *
Tcl_Merge(
    int argc,			/* How many strings to merge. */
    const char *const *argv)	/* Array of string values. */
{
#   define LOCAL_SIZE 20
    int localFlags[LOCAL_SIZE], *flagPtr = NULL;
    int i, bytesNeeded = 0;
    char *result, *dst;
    const int maxFlags = UINT_MAX / sizeof(int);

    if (argc == 0) {
	/*
	 * Handle empty list case first, so logic of the general case
	 * can be simpler.
	 */
	result = ckalloc(1);
	result[0] = '\0';
	return result;
    }

    /*
     * Pass 1: estimate space, gather flags.
     */

    if (argc <= LOCAL_SIZE) {
	flagPtr = localFlags;
    } else if (argc > maxFlags) {
	/*
	 * We cannot allocate a large enough flag array to format this
	 * list in one pass.  We could imagine converting this routine
	 * to a multi-pass implementation, but for sizeof(int) == 4, 
	 * the limit is a max of 2^30 list elements and since each element
	 * is at least one byte formatted, and requires one byte space
	 * between it and the next one, that a minimum space requirement
	 * of 2^31 bytes, which is already INT_MAX. If we tried to format
	 * a list of > maxFlags elements, we're just going to overflow
	 * the size limits on the formatted string anyway, so just issue
	 * that same panic early.
	 */
	Tcl_Panic("max size for a Tcl value (%d bytes) exceeded", INT_MAX);
    } else {
	flagPtr = ckalloc(argc * sizeof(int));
    }

    for (i = 0; i < argc; i++) {
	flagPtr[i] = ( i ? TCL_DONT_QUOTE_HASH : 0 );
	bytesNeeded += TclScanElement(argv[i], -1, &flagPtr[i]);
	if (bytesNeeded < 0) {
	    Tcl_Panic("max size for a Tcl value (%d bytes) exceeded", INT_MAX);
	}
    }
    if (bytesNeeded > INT_MAX - argc + 1) {
	Tcl_Panic("max size for a Tcl value (%d bytes) exceeded", INT_MAX);
    }
    bytesNeeded += argc;

    /*
     * Pass two: copy into the result area.
     */

    result = ckalloc(bytesNeeded);
    dst = result;
    for (i = 0; i < argc; i++) {

	flagPtr[i] |= ( i ? TCL_DONT_QUOTE_HASH : 0 );
	dst += TclConvertElement(argv[i], -1, dst, flagPtr[i]);
	*dst = ' ';
	dst++;
    }



    dst[-1] = 0;


    if (flagPtr != localFlags) {
	ckfree(flagPtr);
    }
    return result;
}

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
    TclUtfToUniChar(buf, &ch);
    return (char) ch;
}

/*
 *----------------------------------------------------------------------
 *







































































































































 * Tcl_Concat --
 *
 *	Concatenate a set of strings into a single large string.
 *
 * Results:
 *	The return value is dynamically-allocated string containing a
 *	concatenation of all the strings in argv, with spaces between the
 *	original argv elements.
 *
 * Side effects:
 *	Memory is allocated for the result; the caller is responsible for
 *	freeing the memory.
 *
 *----------------------------------------------------------------------
 */





char *
Tcl_Concat(
    int argc,			/* Number of strings to concatenate. */
    const char *const *argv)	/* Array of strings to concatenate. */
{
    int totalSize, i;
    char *p;
    char *result;

    for (totalSize = 1, i = 0; i < argc; i++) {
	totalSize += strlen(argv[i]) + 1;
    }
    result = ckalloc(totalSize);
    if (argc == 0) {

	*result = '\0';
	return result;
    }
    for (p = result, i = 0; i < argc; i++) {
	const char *element;


	int length;





	/*
	 * Clip white space off the front and back of the string to generate a
	 * neater result, and ignore any empty elements.


	 */









	element = argv[i];

	while (isspace(UCHAR(*element))) { /* INTL: ISO space. */


	    element++;

	}




	for (length = strlen(element);
		(length > 0)
		&& (isspace(UCHAR(element[length-1]))) /* INTL: ISO space. */
		&& ((length < 2) || (element[length-2] != '\\'));
		length--) {
	    /* Null loop body. */
	}

	if (length == 0) {
	    continue;
	}
	memcpy(p, element, (size_t) length);
	p += length;


	*p = ' ';
	p++;
    }
    if (p != result) {
	p[-1] = 0;

    } else {
	*p = 0;
    }

    return result;
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_ConcatObj --







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
















>
>
>
>





|
<
|

<
<
<
|

>
|


|
<
>
>
|
>
>
|
>
>

<
<
>
>

>
|
>
>
>
>
>
>
>

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


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

>







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
    TclUtfToUniChar(buf, &ch);
    return (char) ch;
}

/*
 *----------------------------------------------------------------------
 *
 * TclTrimRight --
 *	Takes two counted strings in the Tcl encoding which must both be
 *	null terminated.  Conceptually trims from the right side of the
 *	first string all characters found in the second string.
 *
 * Results:
 *	The number of bytes to be removed from the end of the string.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

int
TclTrimRight(
    const char *bytes,	/* String to be trimmed... */
    int numBytes,	/* ...and its length in bytes */
    const char *trim,	/* String of trim characters... */
    int numTrim)	/* ...and its length in bytes */
{
    const char *p = bytes + numBytes;
    int pInc;

    if ((bytes[numBytes] != '\0') || (trim[numTrim] != '\0')) {
	Tcl_Panic("TclTrimRight works only on null-terminated strings");
    }

    /* Empty strings -> nothing to do */
    if ((numBytes == 0) || (numTrim == 0)) {
	return 0;
    }

    /* Outer loop: iterate over string to be trimmed */
    do {
	Tcl_UniChar ch1;
	const char *q = trim;
	int bytesLeft = numTrim;

	p = Tcl_UtfPrev(p, bytes);
 	pInc = TclUtfToUniChar(p, &ch1);

	/* Inner loop: scan trim string for match to current character */
	do {
	    Tcl_UniChar ch2;
	    int qInc = TclUtfToUniChar(q, &ch2);

	    if (ch1 == ch2) {
		break;
	    }

	    q += qInc;
	    bytesLeft -= qInc;
	} while (bytesLeft);

	if (bytesLeft == 0) {
	    /* No match; trim task done; *p is last non-trimmed char */
	    p += pInc;
	    break;
	}
    } while (p > bytes);

    return numBytes - (p - bytes);
}

/*
 *----------------------------------------------------------------------
 *
 * TclTrimLeft --
 *	Takes two counted strings in the Tcl encoding which must both be
 *	null terminated.  Conceptually trims from the left side of the
 *	first string all characters found in the second string.
 *
 * Results:
 *	The number of bytes to be removed from the start of the string.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

int
TclTrimLeft(
    const char *bytes,	/* String to be trimmed... */
    int numBytes,	/* ...and its length in bytes */
    const char *trim,	/* String of trim characters... */
    int numTrim)	/* ...and its length in bytes */
{
    const char *p = bytes;

    if ((bytes[numBytes] != '\0') || (trim[numTrim] != '\0')) {
	Tcl_Panic("TclTrimLeft works only on null-terminated strings");
    }

    /* Empty strings -> nothing to do */
    if ((numBytes == 0) || (numTrim == 0)) {
	return 0;
    }

    /* Outer loop: iterate over string to be trimmed */
    do {
	Tcl_UniChar ch1;
	int pInc = TclUtfToUniChar(p, &ch1);
	const char *q = trim;
	int bytesLeft = numTrim;

	/* Inner loop: scan trim string for match to current character */
	do {
	    Tcl_UniChar ch2;
	    int qInc = TclUtfToUniChar(q, &ch2);

	    if (ch1 == ch2) {
		break;
	    }

	    q += qInc;
	    bytesLeft -= qInc;
	} while (bytesLeft);

	if (bytesLeft == 0) {
	    /* No match; trim task done; *p is first non-trimmed char */
	    break;
	}

	p += pInc;
	numBytes -= pInc;
    } while (numBytes);

    return p - bytes;
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_Concat --
 *
 *	Concatenate a set of strings into a single large string.
 *
 * Results:
 *	The return value is dynamically-allocated string containing a
 *	concatenation of all the strings in argv, with spaces between the
 *	original argv elements.
 *
 * Side effects:
 *	Memory is allocated for the result; the caller is responsible for
 *	freeing the memory.
 *
 *----------------------------------------------------------------------
 */

/* The whitespace characters trimmed during [concat] operations */
#define CONCAT_WS " \f\v\r\t\n"
#define CONCAT_WS_SIZE (int) (sizeof(CONCAT_WS "") - 1)

char *
Tcl_Concat(
    int argc,			/* Number of strings to concatenate. */
    const char *const *argv)	/* Array of strings to concatenate. */
{
    int i, needSpace = 0, bytesNeeded = 0;

    char *result, *p;




    /* Dispose of the empty result corner case first to simplify later code */
    if (argc == 0) {
	result = (char *) ckalloc(1);
	result[0] = '\0';
	return result;
    }


    /* First allocate the result buffer at the size required */
    for (i = 0;  i < argc;  i++) {
	bytesNeeded += strlen(argv[i]);
	if (bytesNeeded < 0) {
	    Tcl_Panic("Tcl_Concat: max size of Tcl value exceeded");
	}
    }
    if (bytesNeeded + argc - 1 < 0) {
	/*


	 * Panic test could be tighter, but not going to bother for 
	 * this legacy routine.
	 */
	Tcl_Panic("Tcl_Concat: max size of Tcl value exceeded");
    }
    /* All element bytes + (argc - 1) spaces + 1 terminating NULL */
    result = (char *) ckalloc((unsigned) (bytesNeeded + argc));

    for (p = result, i = 0;  i < argc;  i++) {
	int trim, elemLength;
	const char *element;
	
	element = argv[i];
	elemLength = strlen(argv[i]);

	/* Trim away the leading whitespace */
	trim = TclTrimLeft(element, elemLength, CONCAT_WS, CONCAT_WS_SIZE);
	element += trim;
	elemLength -= trim;

	/*
	 * Trim away the trailing whitespace.  Do not permit trimming
	 * to expose a final backslash character.
	 */


	trim = TclTrimRight(element, elemLength, CONCAT_WS, CONCAT_WS_SIZE);
	trim -= trim && (element[elemLength - trim - 1] == '\\');
	elemLength -= trim;


	/* If we're left with empty element after trimming, do nothing */
	if (elemLength == 0) {
	    continue;
	}


	/* Append to the result with space if needed */
	if (needSpace) {
	    *p++ = ' ';

	}


	memcpy(p, element, (size_t) elemLength);
	p += elemLength;
	needSpace = 1;
    }
    *p = '\0';
    return result;
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_ConcatObj --
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
 */

Tcl_Obj *
Tcl_ConcatObj(
    int objc,			/* Number of objects to concatenate. */
    Tcl_Obj *const objv[])	/* Array of objects to concatenate. */
{
    int allocSize, finalSize, length, elemLength, i;
    char *p;
    const char *element;
    char *concatStr;
    Tcl_Obj *objPtr, *resPtr;

    /*
     * Check first to see if all the items are of list type or empty. If so,
     * we will concat them together as lists, and return a list object. This
     * is only valid when the lists have no current string representation,
     * since we don't know what the original type was. An original string rep
     * may have lost some whitespace info when converted which could be
     * important.
     */

    for (i = 0;  i < objc;  i++) {
	List *listRepPtr;

	objPtr = objv[i];
	if (objPtr->typePtr != &tclListType) {
	    TclGetString(objPtr);
	    if (objPtr->length) {
		break;
	    } else {
		continue;
	    }
	}
	listRepPtr = objPtr->internalRep.twoPtrValue.ptr1;
	if (objPtr->bytes != NULL && !listRepPtr->canonicalFlag) {

	    break;
	}
    }
    if (i == objc) {
	Tcl_Obj **listv;
	int listc;

	resPtr = NULL;
	for (i = 0;  i < objc;  i++) {
	    /*
	     * Tcl_ListObjAppendList could be used here, but this saves us a
	     * bit of type checking (since we've already done it). Use of
	     * INT_MAX tells us to always put the new stuff on the end. It
	     * will be set right in Tcl_ListObjReplace.
	     * Note that all objs at this point are either lists or have an
	     * empty string rep.
	     */

	    objPtr = objv[i];
	    if (objPtr->bytes && !objPtr->length) {
		continue;
	    }
	    TclListObjGetElements(NULL, objPtr, &listc, &listv);
	    if (listc) {
		if (resPtr) {
		    Tcl_ListObjReplace(NULL, resPtr, INT_MAX, 0, listc, listv);
		} else {
		    resPtr = TclListObjCopy(NULL, objPtr);
		}
	    }
	}
	if (!resPtr) {
	    resPtr = Tcl_NewObj();
	}
	return resPtr;
    }

    /*
     * Something cannot be determined to be safe, so build the concatenation
     * the slow way, using the string representations.
     */

    allocSize = 0;
    for (i = 0;  i < objc;  i++) {
	objPtr = objv[i];
	element = TclGetStringFromObj(objPtr, &length);
	if ((element != NULL) && (length > 0)) {
	    allocSize += (length + 1);
	}
    }
    if (allocSize == 0) {
	allocSize = 1;		/* enough for the NULL byte at end */

    }

    /*
     * Allocate storage for the concatenated result. Note that allocSize is
     * one more than the total number of characters, and so includes room for

     * the terminating NULL byte.

     */

    concatStr = ckalloc(allocSize);

    /*
     * Now concatenate the elements. Clip white space off the front and back
     * to generate a neater result, and ignore any empty elements. Also put a
     * null byte at the end.
     */


    finalSize = 0;
    if (objc == 0) {
	*concatStr = '\0';
    } else {
	p = concatStr;
	for (i = 0;  i < objc;  i++) {

	    objPtr = objv[i];
	    element = TclGetStringFromObj(objPtr, &elemLength);
	    while ((elemLength > 0) && (UCHAR(*element) < 127)
		    && isspace(UCHAR(*element))) { /* INTL: ISO C space. */

		element++;
		elemLength--;
	    }

	    /*
	     * Trim trailing white space. But, be careful not to trim a space
	     * character if it is preceded by a backslash: in this case it
	     * could be significant.
	     */

	    while ((elemLength > 0) && (UCHAR(element[elemLength-1]) < 127)
		    && isspace(UCHAR(element[elemLength-1]))
						/* INTL: ISO C space. */
		    && ((elemLength < 2) || (element[elemLength-2] != '\\'))) {
		elemLength--;
	    }

	    if (elemLength == 0) {
		continue;	/* nothing left of this element */
	    }
	    memcpy(p, element, (size_t) elemLength);
	    p += elemLength;
	    *p = ' ';
	    p++;
	    finalSize += (elemLength + 1);
	}

	if (p != concatStr) {
	    p[-1] = 0;
	    finalSize -= 1;	/* we overwrote the final ' ' */
	} else {
	    *p = 0;

	}


    }

    TclNewObj(objPtr);
    objPtr->bytes = concatStr;
    objPtr->length = finalSize;
    return objPtr;
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_StringMatch --
 *







|
<

<





|
<
<
<



|


|
<
<
<
<
|
|
<
<
|
>




<
<
<


<
<
<
<
<
<
<
<
<

|


<
<
|
|
|
|
<













|

<
|
<
|
<
<
|
<
>
|
|

<
<
>
|
>

|
<
|
<
<
<
<
<
>

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

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

>
>

<
<
<
<
|







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
 */

Tcl_Obj *
Tcl_ConcatObj(
    int objc,			/* Number of objects to concatenate. */
    Tcl_Obj *const objv[])	/* Array of objects to concatenate. */
{
    int i, elemLength, needSpace = 0, bytesNeeded = 0;

    const char *element;

    Tcl_Obj *objPtr, *resPtr;

    /*
     * Check first to see if all the items are of list type or empty. If so,
     * we will concat them together as lists, and return a list object. This
     * is only valid when the lists are in canonical form.



     */

    for (i = 0;  i < objc;  i++) {
	int length;

	objPtr = objv[i];
	if (TclListObjIsCanonical(objPtr)) {




	    continue;
	}


	Tcl_GetStringFromObj(objPtr, &length);
	if (length > 0) {
	    break;
	}
    }
    if (i == objc) {



	resPtr = NULL;
	for (i = 0;  i < objc;  i++) {









	    objPtr = objv[i];
	    if (objPtr->bytes && objPtr->length == 0) {
		continue;
	    }


	    if (resPtr) {
		Tcl_ListObjAppendList(NULL, resPtr, objPtr);
	    } else {
		resPtr = TclListObjCopy(NULL, objPtr);

	    }
	}
	if (!resPtr) {
	    resPtr = Tcl_NewObj();
	}
	return resPtr;
    }

    /*
     * Something cannot be determined to be safe, so build the concatenation
     * the slow way, using the string representations.
     */

    /* First try to pre-allocate the size required */
    for (i = 0;  i < objc;  i++) {

	element = TclGetStringFromObj(objv[i], &elemLength);

	bytesNeeded += elemLength;


	if (bytesNeeded < 0) {

	    break;
	}
    }
    /*


     * Does not matter if this fails, will simply try later to build up
     * the string with each Append reallocating as needed with the usual
     * string append algorithm.  When that fails it will report the error.
     */
    TclNewObj(resPtr);

    Tcl_AttemptSetObjLength(resPtr, bytesNeeded + objc - 1);





    Tcl_SetObjLength(resPtr, 0);






    for (i = 0;  i < objc;  i++) {
	int trim;
	
	element = TclGetStringFromObj(objv[i], &elemLength);

	/* Trim away the leading whitespace */
	trim = TclTrimLeft(element, elemLength, CONCAT_WS, CONCAT_WS_SIZE);
	element += trim;
	elemLength -= trim;


	/*
	 * Trim away the trailing whitespace.  Do not permit trimming
	 * to expose a final backslash character.

	 */

	trim = TclTrimRight(element, elemLength, CONCAT_WS, CONCAT_WS_SIZE);
	trim -= trim && (element[elemLength - trim - 1] == '\\');


	elemLength -= trim;

	/* If we're left with empty element after trimming, do nothing */
	if (elemLength == 0) {
	    continue;
	}






	/* Append to the result with space if needed */
	if (needSpace) {




	    Tcl_AppendToObj(resPtr, " ", 1);
	}
	Tcl_AppendToObj(resPtr, element, elemLength);
	needSpace = 1;
    }




    return resPtr;
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_StringMatch --
 *
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

char *
Tcl_DStringAppendElement(
    Tcl_DString *dsPtr,		/* Structure describing dynamic string. */
    const char *element)	/* String to append. Must be
				 * null-terminated. */
{
    int newSize, flags, strSize;
    char *dst;

    strSize = ((element== NULL) ? 0 : strlen(element));
    newSize = Tcl_ScanCountedElement(element, strSize, &flags)

	+ dsPtr->length + 1;


    /*
     * Allocate a larger buffer for the string if the current one isn't large
     * enough. Allocate extra space in the new buffer so that there will be
     * room to grow before we have to allocate again. SPECIAL NOTE: must use
     * memcpy, not strcpy, to copy the string to a larger buffer, since there
     * may be embedded NULLs in the string in some cases.
     */

    if (newSize >= dsPtr->spaceAvl) {
	dsPtr->spaceAvl = newSize * 2;
	if (dsPtr->string == dsPtr->staticSpace) {
	    char *newString = ckalloc(dsPtr->spaceAvl);

	    memcpy(newString, dsPtr->string, (size_t) dsPtr->length);
	    dsPtr->string = newString;
	} else {
	    dsPtr->string = ckrealloc(dsPtr->string, dsPtr->spaceAvl);
	}

    }

    /*
     * Convert the new string to a list element and copy it into the buffer at
     * the end, with a space, if needed.
     */

    dst = dsPtr->string + dsPtr->length;
    if (TclNeedSpace(dsPtr->string, dst)) {
	*dst = ' ';
	dst++;
	dsPtr->length++;

	/*
	 * If we need a space to separate this element from preceding stuff,
	 * then this element will not lead a list, and need not have it's
	 * leading '#' quoted.
	 */

	flags |= TCL_DONT_QUOTE_HASH;
    }
    dsPtr->length += Tcl_ConvertCountedElement(element, strSize, dst, flags);

    return dsPtr->string;
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_DStringSetLength --







<
|
|
<
<
>
|
>



















>







<
|












|
>







2452
2453
2454
2455
2456
2457
2458

2459
2460


2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490

2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512

char *
Tcl_DStringAppendElement(
    Tcl_DString *dsPtr,		/* Structure describing dynamic string. */
    const char *element)	/* String to append. Must be
				 * null-terminated. */
{

    char *dst = dsPtr->string + dsPtr->length;
    int needSpace = TclNeedSpace(dsPtr->string, dst);


    int flags = needSpace ? TCL_DONT_QUOTE_HASH : 0;
    int newSize = dsPtr->length + needSpace
	    + TclScanElement(element, -1, &flags);

    /*
     * Allocate a larger buffer for the string if the current one isn't large
     * enough. Allocate extra space in the new buffer so that there will be
     * room to grow before we have to allocate again. SPECIAL NOTE: must use
     * memcpy, not strcpy, to copy the string to a larger buffer, since there
     * may be embedded NULLs in the string in some cases.
     */

    if (newSize >= dsPtr->spaceAvl) {
	dsPtr->spaceAvl = newSize * 2;
	if (dsPtr->string == dsPtr->staticSpace) {
	    char *newString = ckalloc(dsPtr->spaceAvl);

	    memcpy(newString, dsPtr->string, (size_t) dsPtr->length);
	    dsPtr->string = newString;
	} else {
	    dsPtr->string = ckrealloc(dsPtr->string, dsPtr->spaceAvl);
	}
	dst = dsPtr->string + dsPtr->length;
    }

    /*
     * Convert the new string to a list element and copy it into the buffer at
     * the end, with a space, if needed.
     */


    if (needSpace) {
	*dst = ' ';
	dst++;
	dsPtr->length++;

	/*
	 * If we need a space to separate this element from preceding stuff,
	 * then this element will not lead a list, and need not have it's
	 * leading '#' quoted.
	 */

	flags |= TCL_DONT_QUOTE_HASH;
    }
    dsPtr->length += TclConvertElement(element, -1, dst, flags);
    dsPtr->string[dsPtr->length] = '\0';
    return dsPtr->string;
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_DStringSetLength --
2481
2482
2483
2484
2485
2486
2487

2488
2489
2490
2491
2492
2493
2494
2495

    /*
     * Check whether "n" is the maximum negative value. This is
     * -2^(m-1) for an m-bit word, and has no positive equivalent;
     * negating it produces the same value.
     */


    if (n == -n) {
	return sprintf(buffer, "%ld", n);
    }

    /*
     * Generate the characters of the result backwards in the buffer.
     */








>
|







3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167

    /*
     * Check whether "n" is the maximum negative value. This is
     * -2^(m-1) for an m-bit word, and has no positive equivalent;
     * negating it produces the same value.
     */

    intVal = -n;			/* [Bug 3390638] Workaround for*/
    if (n == -n || intVal == n) {	/* broken compiler optimizers. */
	return sprintf(buffer, "%ld", n);
    }

    /*
     * Generate the characters of the result backwards in the buffer.
     */

2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602

    bytes = TclGetStringFromObj(objPtr, &length);

    /*
     * Leading whitespace is acceptable in an index.
     */

    while (length && isspace(UCHAR(*bytes))) {		/* INTL: ISO space. */
	bytes++;
	length--;
    }

    if (TclParseNumber(NULL, NULL, NULL, bytes, length, (const char **)&opPtr,
	    TCL_PARSE_INTEGER_ONLY | TCL_PARSE_NO_WHITESPACE) == TCL_OK) {
	int code, first, second;
	char savedOp = *opPtr;

	if ((savedOp != '+') && (savedOp != '-')) {
	    goto parseError;
	}
	if (isspace(UCHAR(opPtr[1]))) {
	    goto parseError;
	}
	*opPtr = '\0';
	code = Tcl_GetInt(interp, bytes, &first);
	*opPtr = savedOp;
	if (code == TCL_ERROR) {
	    goto parseError;







|












|







3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274

    bytes = TclGetStringFromObj(objPtr, &length);

    /*
     * Leading whitespace is acceptable in an index.
     */

    while (length && TclIsSpaceProc(*bytes)) {
	bytes++;
	length--;
    }

    if (TclParseNumber(NULL, NULL, NULL, bytes, length, (const char **)&opPtr,
	    TCL_PARSE_INTEGER_ONLY | TCL_PARSE_NO_WHITESPACE) == TCL_OK) {
	int code, first, second;
	char savedOp = *opPtr;

	if ((savedOp != '+') && (savedOp != '-')) {
	    goto parseError;
	}
	if (TclIsSpaceProc(opPtr[1])) {
	    goto parseError;
	}
	*opPtr = '\0';
	code = Tcl_GetInt(interp, bytes, &first);
	*opPtr = savedOp;
	if (code == TCL_ERROR) {
	    goto parseError;
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
	offset = 0;
    } else if ((length > 4) && ((bytes[3] == '-') || (bytes[3] == '+'))) {
	/*
	 * This is our limited string expression evaluator. Pass everything
	 * after "end-" to Tcl_GetInt, then reverse for offset.
	 */

	if (isspace(UCHAR(bytes[4]))) {
	    goto badIndexFormat;
	}
	if (Tcl_GetInt(interp, bytes+4, &offset) != TCL_OK) {
	    return TCL_ERROR;
	}
	if (bytes[3] == '-') {
	    offset = -offset;







|







3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
	offset = 0;
    } else if ((length > 4) && ((bytes[3] == '-') || (bytes[3] == '+'))) {
	/*
	 * This is our limited string expression evaluator. Pass everything
	 * after "end-" to Tcl_GetInt, then reverse for offset.
	 */

	if (TclIsSpaceProc(bytes[4])) {
	    goto badIndexFormat;
	}
	if (Tcl_GetInt(interp, bytes+4, &offset) != TCL_OK) {
	    return TCL_ERROR;
	}
	if (bytes[3] == '-') {
	    offset = -offset;
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
    register const char *p = value;

    /*
     * A frequent mistake is invalid octal values due to an unwanted leading
     * zero. Try to generate a meaningful error message.
     */

    while (isspace(UCHAR(*p))) {	/* INTL: ISO space. */
	p++;
    }
    if (*p == '+' || *p == '-') {
	p++;
    }
    if (*p == '0') {
	if ((p[1] == 'o') || p[1] == 'O') {
	    p += 2;
	}
	while (isdigit(UCHAR(*p))) {	/* INTL: digit. */
	    p++;
	}
	while (isspace(UCHAR(*p))) {	/* INTL: ISO space. */
	    p++;
	}
	if (*p == '\0') {
	    /*
	     * Reached end of string.
	     */








|












|







3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
    register const char *p = value;

    /*
     * A frequent mistake is invalid octal values due to an unwanted leading
     * zero. Try to generate a meaningful error message.
     */

    while (TclIsSpaceProc(*p)) {
	p++;
    }
    if (*p == '+' || *p == '-') {
	p++;
    }
    if (*p == '0') {
	if ((p[1] == 'o') || p[1] == 'O') {
	    p += 2;
	}
	while (isdigit(UCHAR(*p))) {	/* INTL: digit. */
	    p++;
	}
	while (TclIsSpaceProc(*p)) {
	    p++;
	}
	if (*p == '\0') {
	    /*
	     * Reached end of string.
	     */

3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
    const char *reStr,
    int reStrLen,
    Tcl_DString *dsPtr,
    int *exactPtr)
{
    int anchorLeft, anchorRight, lastIsStar, numStars;
    char *dsStr, *dsStrStart;
    const char *msg, *p, *strEnd;

    strEnd = reStr + reStrLen;
    Tcl_DStringInit(dsPtr);

    /*
     * "***=xxx" == "*xxx*", watch for glob-sensitive chars.
     */







|







3938
3939
3940
3941
3942
3943
3944
3945
3946
3947
3948
3949
3950
3951
3952
    const char *reStr,
    int reStrLen,
    Tcl_DString *dsPtr,
    int *exactPtr)
{
    int anchorLeft, anchorRight, lastIsStar, numStars;
    char *dsStr, *dsStrStart;
    const char *msg, *p, *strEnd, *code;

    strEnd = reStr + reStrLen;
    Tcl_DStringInit(dsPtr);

    /*
     * "***=xxx" == "*xxx*", watch for glob-sensitive chars.
     */
3320
3321
3322
3323
3324
3325
3326

3327
3328
3329
3330
3331
3332
3333
     * possible. Do not alter the start of str so we can free it correctly.
     *
     * Keep track of the last char being an unescaped star to prevent multiple
     * instances.  Simpler than checking that the last star may be escaped.
     */

    msg = NULL;

    p = reStr;
    anchorRight = 0;
    lastIsStar = 0;
    numStars = 0;

    if (*p == '^') {
	anchorLeft = 1;







>







3992
3993
3994
3995
3996
3997
3998
3999
4000
4001
4002
4003
4004
4005
4006
     * possible. Do not alter the start of str so we can free it correctly.
     *
     * Keep track of the last char being an unescaped star to prevent multiple
     * instances.  Simpler than checking that the last star may be escaped.
     */

    msg = NULL;
    code = NULL;
    p = reStr;
    anchorRight = 0;
    lastIsStar = 0;
    numStars = 0;

    if (*p == '^') {
	anchorLeft = 1;
3376
3377
3378
3379
3380
3381
3382

3383
3384
3385
3386
3387
3388
3389
		/* fall through */
	    case '{': case '}': case '(': case ')': case '+':
	    case '.': case '|': case '^': case '$':
		*dsStr++ = *p;
		break;
	    default:
		msg = "invalid escape sequence";

		goto invalidGlob;
	    }
	    break;
	case '.':
	    anchorLeft = 0; /* prevent exact match */
	    if (p+1 < strEnd) {
		if (p[1] == '*') {







>







4049
4050
4051
4052
4053
4054
4055
4056
4057
4058
4059
4060
4061
4062
4063
		/* fall through */
	    case '{': case '}': case '(': case ')': case '+':
	    case '.': case '|': case '^': case '$':
		*dsStr++ = *p;
		break;
	    default:
		msg = "invalid escape sequence";
		code = "BADESCAPE";
		goto invalidGlob;
	    }
	    break;
	case '.':
	    anchorLeft = 0; /* prevent exact match */
	    if (p+1 < strEnd) {
		if (p[1] == '*') {
3404
3405
3406
3407
3408
3409
3410

3411
3412
3413
3414
3415
3416
3417

3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432

3433
3434
3435
3436
3437
3438
3439
		}
	    }
	    *dsStr++ = '?';
	    break;
	case '$':
	    if (p+1 != strEnd) {
		msg = "$ not anchor";

		goto invalidGlob;
	    }
	    anchorRight = 1;
	    break;
	case '*': case '+': case '?': case '|': case '^':
	case '{': case '}': case '(': case ')': case '[': case ']':
	    msg = "unhandled RE special char";

	    goto invalidGlob;
	    break;
	default:
	    *dsStr++ = *p;
	    break;
	}
	lastIsStar = 0;
    }
    if (numStars > 1) {
	/*
	 * Heuristic: if >1 non-anchoring *, the risk is large that glob
	 * matching is slower than the RE engine, so report invalid.
	 */

	msg = "excessive recursive glob backtrack potential";

	goto invalidGlob;
    }

    if (!anchorRight && !lastIsStar) {
	*dsStr++ = '*';
    }
    Tcl_DStringSetLength(dsPtr, dsStr - dsStrStart);







>







>

<













>







4078
4079
4080
4081
4082
4083
4084
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094

4095
4096
4097
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
4108
4109
4110
4111
4112
4113
4114
4115
		}
	    }
	    *dsStr++ = '?';
	    break;
	case '$':
	    if (p+1 != strEnd) {
		msg = "$ not anchor";
		code = "NONANCHOR";
		goto invalidGlob;
	    }
	    anchorRight = 1;
	    break;
	case '*': case '+': case '?': case '|': case '^':
	case '{': case '}': case '(': case ')': case '[': case ']':
	    msg = "unhandled RE special char";
	    code = "UNHANDLED";
	    goto invalidGlob;

	default:
	    *dsStr++ = *p;
	    break;
	}
	lastIsStar = 0;
    }
    if (numStars > 1) {
	/*
	 * Heuristic: if >1 non-anchoring *, the risk is large that glob
	 * matching is slower than the RE engine, so report invalid.
	 */

	msg = "excessive recursive glob backtrack potential";
	code = "OVERCOMPLEX";
	goto invalidGlob;
    }

    if (!anchorRight && !lastIsStar) {
	*dsStr++ = '*';
    }
    Tcl_DStringSetLength(dsPtr, dsStr - dsStrStart);
3454
3455
3456
3457
3458
3459
3460

3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
#if 0
    fprintf(stderr, "INPUT RE '%.*s' NO OUTPUT GLOB %s (%c)\n",
	    reStrLen, reStr, msg, *p);
    fflush(stderr);
#endif
    if (interp != NULL) {
	Tcl_AppendResult(interp, msg, NULL);

    }
    Tcl_DStringFree(dsPtr);
    return TCL_ERROR;
}

/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78
 * End:
 */







>












4130
4131
4132
4133
4134
4135
4136
4137
4138
4139
4140
4141
4142
4143
4144
4145
4146
4147
4148
4149
#if 0
    fprintf(stderr, "INPUT RE '%.*s' NO OUTPUT GLOB %s (%c)\n",
	    reStrLen, reStr, msg, *p);
    fflush(stderr);
#endif
    if (interp != NULL) {
	Tcl_AppendResult(interp, msg, NULL);
	Tcl_SetErrorCode(interp, "TCL", "RE2GLOB", code, NULL);
    }
    Tcl_DStringFree(dsPtr);
    return TCL_ERROR;
}

/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78
 * End:
 */

Changes to generic/tclVar.c.

699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
  doneParsing:
    /*
     * part1Ptr is not an array element; look it up, and convert it to one of
     * the cached types if possible.
     */

    TclFreeIntRep(part1Ptr);
    part1Ptr->typePtr = NULL;

    varPtr = TclLookupSimpleVar(interp, part1Ptr, flags, createPart1,
	    &errMsg, &index);
    if (varPtr == NULL) {
	if ((errMsg != NULL) && (flags & TCL_LEAVE_ERR_MSG)) {
	    TclObjVarErrMsg(interp, part1Ptr, part2Ptr, msg, errMsg, -1);
	    Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "VARNAME",







<







699
700
701
702
703
704
705

706
707
708
709
710
711
712
  doneParsing:
    /*
     * part1Ptr is not an array element; look it up, and convert it to one of
     * the cached types if possible.
     */

    TclFreeIntRep(part1Ptr);


    varPtr = TclLookupSimpleVar(interp, part1Ptr, flags, createPart1,
	    &errMsg, &index);
    if (varPtr == NULL) {
	if ((errMsg != NULL) && (flags & TCL_LEAVE_ERR_MSG)) {
	    TclObjVarErrMsg(interp, part1Ptr, part2Ptr, msg, errMsg, -1);
	    Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "VARNAME",
1823
1824
1825
1826
1827
1828
1829

1830
1831
1832
1833
1834
1835
1836
    int index)			/* Index of local var where part1 is to be
				 * found. */
{
    Interp *iPtr = (Interp *) interp;
    Tcl_Obj *oldValuePtr;
    Tcl_Obj *resultPtr = NULL;
    int result;


    /*
     * If the variable is in a hashtable and its hPtr field is NULL, then we
     * may have an upvar to an array element where the array was deleted or an
     * upvar to a namespace variable whose namespace was deleted. Generate an
     * error (allowing the variable to be reset would screw up our storage
     * allocation and is meaningless anyway).







>







1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
    int index)			/* Index of local var where part1 is to be
				 * found. */
{
    Interp *iPtr = (Interp *) interp;
    Tcl_Obj *oldValuePtr;
    Tcl_Obj *resultPtr = NULL;
    int result;
    int cleanupOnEarlyError = (newValuePtr->refCount == 0);

    /*
     * If the variable is in a hashtable and its hPtr field is NULL, then we
     * may have an upvar to an array element where the array was deleted or an
     * upvar to a namespace variable whose namespace was deleted. Generate an
     * error (allowing the variable to be reset would screw up our storage
     * allocation and is meaningless anyway).
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
    }
    if (TclIsVarUndefined(varPtr)) {
	TclCleanupVar(varPtr, arrayPtr);
    }
    return resultPtr;

  earlyError:
    if (newValuePtr->refCount == 0) {
	Tcl_DecrRefCount(newValuePtr);
    }
    goto cleanup;
}

/*
 *----------------------------------------------------------------------







|







1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
    }
    if (TclIsVarUndefined(varPtr)) {
	TclCleanupVar(varPtr, arrayPtr);
    }
    return resultPtr;

  earlyError:
    if (cleanupOnEarlyError) {
	Tcl_DecrRefCount(newValuePtr);
    }
    goto cleanup;
}

/*
 *----------------------------------------------------------------------
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
     * Try to avoid keeping the Var struct allocated due to a tclNsVarNameType
     * keeping a reference. This removes some additional exteriorisations of
     * [Bug 736729], but may be a good thing independently of the bug.
     */

    if (part1Ptr->typePtr == &tclNsVarNameType) {
	TclFreeIntRep(part1Ptr);
	part1Ptr->typePtr = NULL;
    }
#endif

    /*
     * Finally, if the variable is truly not in use then free up its Var
     * structure and remove it from its hash table, if any. The ref count of
     * its value object, if any, was decremented above.







<







2357
2358
2359
2360
2361
2362
2363

2364
2365
2366
2367
2368
2369
2370
     * Try to avoid keeping the Var struct allocated due to a tclNsVarNameType
     * keeping a reference. This removes some additional exteriorisations of
     * [Bug 736729], but may be a good thing independently of the bug.
     */

    if (part1Ptr->typePtr == &tclNsVarNameType) {
	TclFreeIntRep(part1Ptr);

    }
#endif

    /*
     * Finally, if the variable is truly not in use then free up its Var
     * structure and remove it from its hash table, if any. The ref count of
     * its value object, if any, was decremented above.
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679

2680
2681
2682
2683
2684
2685
2686
	if (varPtr == NULL) {
	    return TCL_ERROR;
	}
	for (i=2 ; i<objc ; i++) {
	    /*
	     * Note that we do not need to increase the refCount of the Var
	     * pointers: should a trace delete the variable, the return value
	     * of TclPtrSetVar will be NULL, and we will not access the
	     * variable again.
	     */

	    varValuePtr = TclPtrSetVar(interp, varPtr, arrayPtr, objv[1],
		    NULL, objv[i], TCL_APPEND_VALUE|TCL_LEAVE_ERR_MSG, -1);
	    if (varValuePtr == NULL) {

		return TCL_ERROR;
	    }
	}
    }
    Tcl_SetObjResult(interp, varValuePtr);
    return TCL_OK;
}







|
|




|
>







2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
	if (varPtr == NULL) {
	    return TCL_ERROR;
	}
	for (i=2 ; i<objc ; i++) {
	    /*
	     * Note that we do not need to increase the refCount of the Var
	     * pointers: should a trace delete the variable, the return value
	     * of TclPtrSetVar will be NULL or emptyObjPtr, and we will not
	     * access the variable again.
	     */

	    varValuePtr = TclPtrSetVar(interp, varPtr, arrayPtr, objv[1],
		    NULL, objv[i], TCL_APPEND_VALUE|TCL_LEAVE_ERR_MSG, -1);
	    if ((varValuePtr == NULL) ||
		    (varValuePtr == ((Interp *) interp)->emptyObjPtr)) {
		return TCL_ERROR;
	    }
	}
    }
    Tcl_SetObjResult(interp, varValuePtr);
    return TCL_OK;
}
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094


3095
3096
3097
3098
3099
3100
3101
     * Make a new array search with a free name.
     */

    searchPtr = ckalloc(sizeof(ArraySearch));
    hPtr = Tcl_CreateHashEntry(&iPtr->varSearches, varPtr, &isNew);
    if (isNew) {
	searchPtr->id = 1;
	Tcl_AppendResult(interp, "s-1-", varName, NULL);
	varPtr->flags |= VAR_SEARCH_ACTIVE;
	searchPtr->nextPtr = NULL;
    } else {
	char string[TCL_INTEGER_SPACE];

	searchPtr->id = ((ArraySearch *) Tcl_GetHashValue(hPtr))->id + 1;
	TclFormatInt(string, searchPtr->id);
	Tcl_AppendResult(interp, "s-", string, "-", varName, NULL);
	searchPtr->nextPtr = Tcl_GetHashValue(hPtr);
    }
    searchPtr->varPtr = varPtr;
    searchPtr->nextEntry = VarHashFirstEntry(varPtr->value.tablePtr,
	    &searchPtr->search);
    Tcl_SetHashValue(hPtr, searchPtr);


    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * ArrayAnyMoreCmd --







<



<
<

<
<






>
>







3073
3074
3075
3076
3077
3078
3079

3080
3081
3082


3083


3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
     * Make a new array search with a free name.
     */

    searchPtr = ckalloc(sizeof(ArraySearch));
    hPtr = Tcl_CreateHashEntry(&iPtr->varSearches, varPtr, &isNew);
    if (isNew) {
	searchPtr->id = 1;

	varPtr->flags |= VAR_SEARCH_ACTIVE;
	searchPtr->nextPtr = NULL;
    } else {


	searchPtr->id = ((ArraySearch *) Tcl_GetHashValue(hPtr))->id + 1;


	searchPtr->nextPtr = Tcl_GetHashValue(hPtr);
    }
    searchPtr->varPtr = varPtr;
    searchPtr->nextEntry = VarHashFirstEntry(varPtr->value.tablePtr,
	    &searchPtr->search);
    Tcl_SetHashValue(hPtr, searchPtr);
    Tcl_SetObjResult(interp,
	    Tcl_ObjPrintf("s-%d-%s", searchPtr->id, varName));
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * ArrayAnyMoreCmd --

Changes to generic/tclZlib.c.

572
573
574
575
576
577
578

579
580
581
582
583
584
585
	Tcl_DStringAppend(&cmdname, "::tcl::zlib::streamcmd_", -1);
	Tcl_DStringAppend(&cmdname, Tcl_GetString(Tcl_GetObjResult(interp)),
		-1);
	if (Tcl_GetCommandInfo(interp, Tcl_DStringValue(&cmdname),
		&cmdinfo) == 1) {
	    Tcl_SetResult(interp,
		    "BUG: Stream command name already exists", TCL_STATIC);

	    Tcl_DStringFree(&cmdname);
	    goto error;
	}
	Tcl_ResetResult(interp);

	/*
	 * Create the command.







>







572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
	Tcl_DStringAppend(&cmdname, "::tcl::zlib::streamcmd_", -1);
	Tcl_DStringAppend(&cmdname, Tcl_GetString(Tcl_GetObjResult(interp)),
		-1);
	if (Tcl_GetCommandInfo(interp, Tcl_DStringValue(&cmdname),
		&cmdinfo) == 1) {
	    Tcl_SetResult(interp,
		    "BUG: Stream command name already exists", TCL_STATIC);
	    Tcl_SetErrorCode(interp, "TCL", "BUG", "EXISTING_CMD", NULL);
	    Tcl_DStringFree(&cmdname);
	    goto error;
	}
	Tcl_ResetResult(interp);

	/*
	 * Create the command.
894
895
896
897
898
899
900

901
902
903
904
905
906
907
    int e, size, outSize;
    Tcl_Obj *obj;

    if (zshPtr->streamEnd) {
	if (zshPtr->interp) {
	    Tcl_SetResult(zshPtr->interp,
		    "already past compressed stream end", TCL_STATIC);

	}
	return TCL_ERROR;
    }

    if (zshPtr->mode == TCL_ZLIB_STREAM_DEFLATE) {
	zshPtr->stream.next_in = Tcl_GetByteArrayFromObj(data, &size);
	zshPtr->stream.avail_in = size;







>







895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
    int e, size, outSize;
    Tcl_Obj *obj;

    if (zshPtr->streamEnd) {
	if (zshPtr->interp) {
	    Tcl_SetResult(zshPtr->interp,
		    "already past compressed stream end", TCL_STATIC);
	    Tcl_SetErrorCode(zshPtr->interp, "TCL", "ZIP", "CLOSED", NULL);
	}
	return TCL_ERROR;
    }

    if (zshPtr->mode == TCL_ZLIB_STREAM_DEFLATE) {
	zshPtr->stream.next_in = Tcl_GetByteArrayFromObj(data, &size);
	zshPtr->stream.avail_in = size;
1079
1080
1081
1082
1083
1084
1085


1086
1087
1088
1089
1090
1091
1092
	     */

	    if (zshPtr->stream.avail_in > 0) {
		if (zshPtr->interp) {
		    Tcl_SetResult(zshPtr->interp,
			"Unexpected zlib internal state during decompression",
			TCL_STATIC);


		}
		Tcl_SetByteArrayLength(data, existing);
		return TCL_ERROR;
	    }

	    if (zshPtr->currentInput) {
		Tcl_DecrRefCount(zshPtr->currentInput);







>
>







1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
	     */

	    if (zshPtr->stream.avail_in > 0) {
		if (zshPtr->interp) {
		    Tcl_SetResult(zshPtr->interp,
			"Unexpected zlib internal state during decompression",
			TCL_STATIC);
		    Tcl_SetErrorCode(zshPtr->interp, "TCL", "ZIP", "STATE",
			    NULL);
		}
		Tcl_SetByteArrayLength(data, existing);
		return TCL_ERROR;
	    }

	    if (zshPtr->currentInput) {
		Tcl_DecrRefCount(zshPtr->currentInput);
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
	 * Sanity checks.
	 */

	if (mode == TCL_ZLIB_STREAM_DEFLATE && !(chanMode & TCL_WRITABLE)) {
	    Tcl_AppendResult(interp,
		    "compression may only be applied to writable channels",
		    NULL);

	    return TCL_ERROR;
	}
	if (mode == TCL_ZLIB_STREAM_INFLATE && !(chanMode & TCL_READABLE)) {
	    Tcl_AppendResult(interp,
		    "decompression may only be applied to readable channels",
		    NULL);

	    return TCL_ERROR;
	}

	/*
	 * Parse options.
	 */

	level = Z_DEFAULT_COMPRESSION;
	for (i=4 ; i<objc ; i++) {
	    if (Tcl_GetIndexFromObj(interp, objv[i], pushOptions, "option", 0,
		    &option) != TCL_OK) {
		return TCL_ERROR;
	    }
	    switch ((enum pushOptions) option) {
	    case poHeader:
		if (++i > objc-1) {
		    Tcl_AppendResult(interp,
			    "value missing for -header option", NULL);

		    return TCL_ERROR;
		}
		headerObj = objv[i];
		if (Tcl_DictObjSize(interp, headerObj, &dummy) != TCL_OK) {
		    Tcl_AddErrorInfo(interp, "\n    (in -header option)");
		    return TCL_ERROR;
		}
		break;
	    case poLevel:
		if (++i > objc-1) {
		    Tcl_AppendResult(interp,
			    "value missing for -level option", NULL);

		    return TCL_ERROR;
		}
		if (Tcl_GetIntFromObj(interp, objv[i],
			(int *) &level) != TCL_OK) {
		    Tcl_AddErrorInfo(interp, "\n    (in -level option)");
		    return TCL_ERROR;
		}
		if (level < 0 || level > 9) {
		    extraInfoStr = "\n    (in -level option)";
		    goto badLevel;
		}
		break;
	    case poLimit:
		if (++i > objc-1) {
		    Tcl_AppendResult(interp,
			    "value missing for -limit option", NULL);

		    return TCL_ERROR;
		}
		if (Tcl_GetIntFromObj(interp, objv[i],
			(int *) &limit) != TCL_OK) {
		    Tcl_AddErrorInfo(interp, "\n    (in -limit option)");
		    return TCL_ERROR;
		}







>






>


















>












>
















>







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
	 * Sanity checks.
	 */

	if (mode == TCL_ZLIB_STREAM_DEFLATE && !(chanMode & TCL_WRITABLE)) {
	    Tcl_AppendResult(interp,
		    "compression may only be applied to writable channels",
		    NULL);
	    Tcl_SetErrorCode(interp, "TCL", "ZIP", "UNWRITABLE", NULL);
	    return TCL_ERROR;
	}
	if (mode == TCL_ZLIB_STREAM_INFLATE && !(chanMode & TCL_READABLE)) {
	    Tcl_AppendResult(interp,
		    "decompression may only be applied to readable channels",
		    NULL);
	    Tcl_SetErrorCode(interp, "TCL", "ZIP", "UNREADABLE", NULL);
	    return TCL_ERROR;
	}

	/*
	 * Parse options.
	 */

	level = Z_DEFAULT_COMPRESSION;
	for (i=4 ; i<objc ; i++) {
	    if (Tcl_GetIndexFromObj(interp, objv[i], pushOptions, "option", 0,
		    &option) != TCL_OK) {
		return TCL_ERROR;
	    }
	    switch ((enum pushOptions) option) {
	    case poHeader:
		if (++i > objc-1) {
		    Tcl_AppendResult(interp,
			    "value missing for -header option", NULL);
		    Tcl_SetErrorCode(interp, "TCL", "ZIP", "NOVAL", NULL);
		    return TCL_ERROR;
		}
		headerObj = objv[i];
		if (Tcl_DictObjSize(interp, headerObj, &dummy) != TCL_OK) {
		    Tcl_AddErrorInfo(interp, "\n    (in -header option)");
		    return TCL_ERROR;
		}
		break;
	    case poLevel:
		if (++i > objc-1) {
		    Tcl_AppendResult(interp,
			    "value missing for -level option", NULL);
		    Tcl_SetErrorCode(interp, "TCL", "ZIP", "NOVAL", NULL);
		    return TCL_ERROR;
		}
		if (Tcl_GetIntFromObj(interp, objv[i],
			(int *) &level) != TCL_OK) {
		    Tcl_AddErrorInfo(interp, "\n    (in -level option)");
		    return TCL_ERROR;
		}
		if (level < 0 || level > 9) {
		    extraInfoStr = "\n    (in -level option)";
		    goto badLevel;
		}
		break;
	    case poLimit:
		if (++i > objc-1) {
		    Tcl_AppendResult(interp,
			    "value missing for -limit option", NULL);
		    Tcl_SetErrorCode(interp, "TCL", "ZIP", "NOVAL", NULL);
		    return TCL_ERROR;
		}
		if (Tcl_GetIntFromObj(interp, objv[i],
			(int *) &limit) != TCL_OK) {
		    Tcl_AddErrorInfo(interp, "\n    (in -limit option)");
		    return TCL_ERROR;
		}
1981
1982
1983
1984
1985
1986
1987

1988
1989
1990
1991
1992
1993

1994
1995
1996
1997
1998
1999
2000
    }
    };

    return TCL_ERROR;

  badLevel:
    Tcl_AppendResult(interp, "level must be 0 to 9", NULL);

    if (extraInfoStr) {
	Tcl_AddErrorInfo(interp, extraInfoStr);
    }
    return TCL_ERROR;
  badBuffer:
    Tcl_AppendResult(interp, "buffer size must be 32 to 65536", NULL);

    return TCL_ERROR;
}

/*
 *----------------------------------------------------------------------
 *
 * ZlibStreamCmd --







>






>







1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
    }
    };

    return TCL_ERROR;

  badLevel:
    Tcl_AppendResult(interp, "level must be 0 to 9", NULL);
    Tcl_SetErrorCode(interp, "TCL", "VALUE", "COMPRESSIONLEVEL", NULL);
    if (extraInfoStr) {
	Tcl_AddErrorInfo(interp, extraInfoStr);
    }
    return TCL_ERROR;
  badBuffer:
    Tcl_AppendResult(interp, "buffer size must be 32 to 65536", NULL);
    Tcl_SetErrorCode(interp, "TCL", "VALUE", "BUFFERSIZE", NULL);
    return TCL_ERROR;
}

/*
 *----------------------------------------------------------------------
 *
 * ZlibStreamCmd --
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
ZlibStreamCmd(
    ClientData cd,
    Tcl_Interp *interp,
    int objc,
    Tcl_Obj *const objv[])
{
    Tcl_ZlibStream zstream = cd;
    int command, index, count, code, buffersize, flush = -1, i;
    Tcl_Obj *obj;
    static const char *const cmds[] = {
	"add", "checksum", "close", "eof", "finalize", "flush",
	"fullflush", "get", "put", "reset",
	NULL
    };
    enum zlibStreamCommands {







|







2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
ZlibStreamCmd(
    ClientData cd,
    Tcl_Interp *interp,
    int objc,
    Tcl_Obj *const objv[])
{
    Tcl_ZlibStream zstream = cd;
    int command, index, count, code, buffersize = -1, flush = -1, i;
    Tcl_Obj *obj;
    static const char *const cmds[] = {
	"add", "checksum", "close", "eof", "finalize", "flush",
	"fullflush", "get", "put", "reset",
	NULL
    };
    enum zlibStreamCommands {
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
		}
		break;
	    case ao_buffer: /* -buffer */
		if (i == objc-2) {
		    Tcl_AppendResult(interp, "\"-buffer\" option must be "
			    "followed by integer decompression buffersize",
			    NULL);

		    return TCL_ERROR;
		}
		if (Tcl_GetIntFromObj(interp, objv[i+1],
			&buffersize) != TCL_OK) {
		    return TCL_ERROR;







		}
	    }

	    if (flush == -2) {
		Tcl_AppendResult(interp, "\"-flush\", \"-fullflush\" and "
			"\"-finalize\" options are mutually exclusive", NULL);

		return TCL_ERROR;
	    }
	}
	if (flush == -1) {
	    flush = 0;
	}

	if (Tcl_ZlibStreamPut(zstream, objv[objc-1],
		flush) != TCL_OK) {
	    return TCL_ERROR;
	}
	TclNewObj(obj);
	code = Tcl_ZlibStreamGet(zstream, obj, -1);
	if (code == TCL_OK) {
	    Tcl_SetObjResult(interp, obj);
	} else {
	    TclDecrRefCount(obj);
	}
	return code;








>





>
>
>
>
>
>
>






>







|
<



|







2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116

2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
		}
		break;
	    case ao_buffer: /* -buffer */
		if (i == objc-2) {
		    Tcl_AppendResult(interp, "\"-buffer\" option must be "
			    "followed by integer decompression buffersize",
			    NULL);
		    Tcl_SetErrorCode(interp, "TCL", "ZIP", "NOVAL", NULL);
		    return TCL_ERROR;
		}
		if (Tcl_GetIntFromObj(interp, objv[i+1],
			&buffersize) != TCL_OK) {
		    return TCL_ERROR;
		}
		if (buffersize < 1 || buffersize > 65536) {
		    Tcl_AppendResult(interp,
			    "buffer size must be 32 to 65536", NULL);
		    Tcl_SetErrorCode(interp, "TCL", "VALUE", "BUFFERSIZE",
			    NULL);
		    return TCL_ERROR;
		}
	    }

	    if (flush == -2) {
		Tcl_AppendResult(interp, "\"-flush\", \"-fullflush\" and "
			"\"-finalize\" options are mutually exclusive", NULL);
		Tcl_SetErrorCode(interp, "TCL", "ZIP", "EXCLUSIVE", NULL);
		return TCL_ERROR;
	    }
	}
	if (flush == -1) {
	    flush = 0;
	}

	if (Tcl_ZlibStreamPut(zstream, objv[objc-1], flush) != TCL_OK) {

	    return TCL_ERROR;
	}
	TclNewObj(obj);
	code = Tcl_ZlibStreamGet(zstream, obj, buffersize);
	if (code == TCL_OK) {
	    Tcl_SetObjResult(interp, obj);
	} else {
	    TclDecrRefCount(obj);
	}
	return code;

2139
2140
2141
2142
2143
2144
2145

2146
2147
2148
2149
2150
2151
2152
		Tcl_AppendResult(interp,
			"\"-buffer\" option not supported here", NULL);
		return TCL_ERROR;
	    }
	    if (flush == -2) {
		Tcl_AppendResult(interp, "\"-flush\", \"-fullflush\" and "
			"\"-finalize\" options are mutually exclusive", NULL);

		return TCL_ERROR;
	    }
	}
	if (flush == -1) {
	    flush = 0;
	}
	return Tcl_ZlibStreamPut(zstream, objv[objc-1], flush);







>







2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
		Tcl_AppendResult(interp,
			"\"-buffer\" option not supported here", NULL);
		return TCL_ERROR;
	    }
	    if (flush == -2) {
		Tcl_AppendResult(interp, "\"-flush\", \"-fullflush\" and "
			"\"-finalize\" options are mutually exclusive", NULL);
		Tcl_SetErrorCode(interp, "TCL", "ZIP", "EXCLUSIVE", NULL);
		return TCL_ERROR;
	    }
	}
	if (flush == -1) {
	    flush = 0;
	}
	return Tcl_ZlibStreamPut(zstream, objv[objc-1], flush);
2249
2250
2251
2252
2253
2254
2255




2256





2257
2258
2259
2260
2261
2262
2263
ZlibTransformClose(
    ClientData instanceData,
    Tcl_Interp *interp)
{
    ZlibChannelData *cd = instanceData;
    int e, result = TCL_OK;





    ZlibTransformTimerKill(cd);





    if (cd->mode == TCL_ZLIB_STREAM_DEFLATE) {
	cd->outStream.avail_in = 0;
	do {
	    cd->outStream.next_out = (Bytef *) cd->outBuffer;
	    cd->outStream.avail_out = (unsigned) cd->outAllocated;
	    e = deflate(&cd->outStream, Z_FINISH);
	    if (e != Z_OK && e != Z_STREAM_END) {







>
>
>
>

>
>
>
>
>







2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
ZlibTransformClose(
    ClientData instanceData,
    Tcl_Interp *interp)
{
    ZlibChannelData *cd = instanceData;
    int e, result = TCL_OK;

    /*
     * Delete the support timer.
     */

    ZlibTransformTimerKill(cd);

    /*
     * Flush any data waiting to be compressed.
     */

    if (cd->mode == TCL_ZLIB_STREAM_DEFLATE) {
	cd->outStream.avail_in = 0;
	do {
	    cd->outStream.next_out = (Bytef *) cd->outBuffer;
	    cd->outStream.avail_out = (unsigned) cd->outAllocated;
	    e = deflate(&cd->outStream, Z_FINISH);
	    if (e != Z_OK && e != Z_STREAM_END) {
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
			}
		    }
		    result = TCL_ERROR;
		    break;
		}
	    }
	} while (e != Z_STREAM_END);
	e = deflateEnd(&cd->inStream);
    } else {
	e = inflateEnd(&cd->outStream);
    }





    if (cd->inBuffer) {
	ckfree(cd->inBuffer);
	cd->inBuffer = NULL;
    }
    if (cd->outBuffer) {
	ckfree(cd->outBuffer);
	cd->outBuffer = NULL;
    }

    return result;
}

static int
ZlibTransformInput(
    ClientData instanceData,
    char *buf,







|

|


>
>
>
>








>







2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
			}
		    }
		    result = TCL_ERROR;
		    break;
		}
	    }
	} while (e != Z_STREAM_END);
	e = deflateEnd(&cd->outStream);
    } else {
	e = inflateEnd(&cd->inStream);
    }

    /*
     * Release all memory.
     */

    if (cd->inBuffer) {
	ckfree(cd->inBuffer);
	cd->inBuffer = NULL;
    }
    if (cd->outBuffer) {
	ckfree(cd->outBuffer);
	cd->outBuffer = NULL;
    }
    ckfree(cd);
    return result;
}

static int
ZlibTransformInput(
    ClientData instanceData,
    char *buf,
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457

2458
2459
2460




2461
2462
2463
2464
2465
2466
2467
    if (e != Z_OK) {
	Tcl_SetChannelError(cd->parent,
		Tcl_NewStringObj(cd->outStream.msg, -1));
	*errorCodePtr = EINVAL;
	return -1;
    }

    return toWrite - cd->outStream.avail_out;
}

static int
ZlibTransformSetOption(			/* not used */
    ClientData instanceData,
    Tcl_Interp *interp,
    const char *optionName,
    const char *value)
{
    ZlibChannelData *cd = instanceData;
    Tcl_DriverSetOptionProc *setOptionProc =
	    Tcl_ChannelSetOptionProc(Tcl_GetChannelType(cd->parent));
    static const char *chanOptions = "flush";
    int haveFlushOpt = (cd->mode == TCL_ZLIB_STREAM_DEFLATE);

    if (haveFlushOpt && optionName && strcmp(optionName, "-flush") == 0) {
	int flushType;

	if (value[0] == 'f' && strcmp(value, "full") == 0) {
	    flushType = Z_FULL_FLUSH;
	    goto doFlush;
	}
	if (value[0] == 's' && strcmp(value, "sync") == 0) {
	    flushType = Z_SYNC_FLUSH;
	    goto doFlush;
	}
	Tcl_AppendResult(interp, "unknown -flush type \"", value,
		"\": must be full or sync", NULL);

	return TCL_ERROR;

    doFlush:




	cd->outStream.avail_in = 0;
	do {
	    int e;

	    cd->outStream.next_out = (Bytef *) cd->outBuffer;
	    cd->outStream.avail_out = cd->outAllocated;








|




















<
<
|

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







2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483


2484
2485

2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
    if (e != Z_OK) {
	Tcl_SetChannelError(cd->parent,
		Tcl_NewStringObj(cd->outStream.msg, -1));
	*errorCodePtr = EINVAL;
	return -1;
    }

    return toWrite - cd->outStream.avail_in;
}

static int
ZlibTransformSetOption(			/* not used */
    ClientData instanceData,
    Tcl_Interp *interp,
    const char *optionName,
    const char *value)
{
    ZlibChannelData *cd = instanceData;
    Tcl_DriverSetOptionProc *setOptionProc =
	    Tcl_ChannelSetOptionProc(Tcl_GetChannelType(cd->parent));
    static const char *chanOptions = "flush";
    int haveFlushOpt = (cd->mode == TCL_ZLIB_STREAM_DEFLATE);

    if (haveFlushOpt && optionName && strcmp(optionName, "-flush") == 0) {
	int flushType;

	if (value[0] == 'f' && strcmp(value, "full") == 0) {
	    flushType = Z_FULL_FLUSH;


	} else if (value[0] == 's' && strcmp(value, "sync") == 0) {
	    flushType = Z_SYNC_FLUSH;

	} else {
	    Tcl_AppendResult(interp, "unknown -flush type \"", value,
		    "\": must be full or sync", NULL);
	    Tcl_SetErrorCode(interp, "TCL", "VALUE", "FLUSH", NULL);
	    return TCL_ERROR;
	}

	/*
	 * Try to actually do the flush now.
	 */

	cd->outStream.avail_in = 0;
	do {
	    int e;

	    cd->outStream.next_out = (Bytef *) cd->outBuffer;
	    cd->outStream.avail_out = cd->outAllocated;

2833
2834
2835
2836
2837
2838
2839

2840
2841
2842
2843
2844
2845
2846
    int mode,
    int format,
    int level,
    Tcl_Obj *dictObj,
    Tcl_ZlibStream *zshandle)
{
    Tcl_SetResult(interp, "unimplemented", TCL_STATIC);

    return TCL_ERROR;
}

int
Tcl_ZlibStreamClose(
    Tcl_ZlibStream zshandle)
{







>







2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
    int mode,
    int format,
    int level,
    Tcl_Obj *dictObj,
    Tcl_ZlibStream *zshandle)
{
    Tcl_SetResult(interp, "unimplemented", TCL_STATIC);
    Tcl_SetErrorCode(interp, "TCL", "UNIMPLEMENTED", NULL);
    return TCL_ERROR;
}

int
Tcl_ZlibStreamClose(
    Tcl_ZlibStream zshandle)
{
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
    Tcl_Interp *interp,
    int format,
    Tcl_Obj *data,
    int level,
    Tcl_Obj *gzipHeaderDictObj)
{
    Tcl_SetResult(interp, "unimplemented", TCL_STATIC);

    return TCL_ERROR;
}

int
Tcl_ZlibInflate(
    Tcl_Interp *interp,
    int format,
    Tcl_Obj *data,
    int bufferSize,
    Tcl_Obj *gzipHeaderDictObj)
{
    Tcl_SetResult(interp, "unimplemented", TCL_STATIC);

    return TCL_ERROR;
}

unsigned int
Tcl_ZlibCRC32(
    unsigned int crc,
    const char *buf,







>












>







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
2960
2961
2962
    Tcl_Interp *interp,
    int format,
    Tcl_Obj *data,
    int level,
    Tcl_Obj *gzipHeaderDictObj)
{
    Tcl_SetResult(interp, "unimplemented", TCL_STATIC);
    Tcl_SetErrorCode(interp, "TCL", "UNIMPLEMENTED", NULL);
    return TCL_ERROR;
}

int
Tcl_ZlibInflate(
    Tcl_Interp *interp,
    int format,
    Tcl_Obj *data,
    int bufferSize,
    Tcl_Obj *gzipHeaderDictObj)
{
    Tcl_SetResult(interp, "unimplemented", TCL_STATIC);
    Tcl_SetErrorCode(interp, "TCL", "UNIMPLEMENTED", NULL);
    return TCL_ERROR;
}

unsigned int
Tcl_ZlibCRC32(
    unsigned int crc,
    const char *buf,

Changes to library/http/http.tcl.

680
681
682
683
684
685
686

687
688
689
690
691
692



693
694
695
696
697
698
699
        if {$state(-protocol) > 1.0 && !$state(-keepalive)} {
	    puts $sock "Connection: close" ;# RFC2616 sec 8.1.2.1
        }
        if {[info exists phost] && ($phost ne "") && $state(-keepalive)} {
	    puts $sock "Proxy-Connection: Keep-Alive"
        }
        set accept_encoding_seen 0

	foreach {key value} $state(-headers) {
	    if {[string equal -nocase $key "host"]} {
		continue
	    }
	    if {[string equal -nocase $key "accept-encoding"]} {
		set accept_encoding_seen 1



	    }
	    set value [string map [list \n "" \r ""] $value]
	    set key [string trim $key]
	    if {[string equal -nocase $key "content-length"]} {
		set contDone 1
		set state(querylength) $value
	    }







>






>
>
>







680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
        if {$state(-protocol) > 1.0 && !$state(-keepalive)} {
	    puts $sock "Connection: close" ;# RFC2616 sec 8.1.2.1
        }
        if {[info exists phost] && ($phost ne "") && $state(-keepalive)} {
	    puts $sock "Proxy-Connection: Keep-Alive"
        }
        set accept_encoding_seen 0
	set content_type_seen 0
	foreach {key value} $state(-headers) {
	    if {[string equal -nocase $key "host"]} {
		continue
	    }
	    if {[string equal -nocase $key "accept-encoding"]} {
		set accept_encoding_seen 1
	    }
	    if {[string equal -nocase $key "content-type"]} {
		set content_type_seen 1
	    }
	    set value [string map [list \n "" \r ""] $value]
	    set key [string trim $key]
	    if {[string equal -nocase $key "content-length"]} {
		set contDone 1
		set state(querylength) $value
	    }
729
730
731
732
733
734
735

736

737
738
739
740
741
742
743
	# data. Having both fileevents active changes the timing and the
	# behavior, but no two platforms (among Solaris, Linux, and NT) behave
	# the same, and none behave all that well in any case. Servers should
	# always read their POST data if they expect the client to read their
	# response.

	if {$isQuery || $isQueryChannel} {

	    puts $sock "Content-Type: $state(-type)"

	    if {!$contDone} {
		puts $sock "Content-Length: $state(querylength)"
	    }
	    puts $sock ""
	    fconfigure $sock -translation {auto binary}
	    fileevent $sock writable [list http::Write $token]
	} else {







>
|
>







733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
	# data. Having both fileevents active changes the timing and the
	# behavior, but no two platforms (among Solaris, Linux, and NT) behave
	# the same, and none behave all that well in any case. Servers should
	# always read their POST data if they expect the client to read their
	# response.

	if {$isQuery || $isQueryChannel} {
	    if {!$content_type_seen} {
		puts $sock "Content-Type: $state(-type)"
	    }
	    if {!$contDone} {
		puts $sock "Content-Length: $state(querylength)"
	    }
	    puts $sock ""
	    fconfigure $sock -translation {auto binary}
	    fileevent $sock writable [list http::Write $token]
	} else {

Changes to library/init.tcl.

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#

if {[info commands package] == ""} {
    error "version mismatch: library\nscripts expect Tcl version 7.5b1 or later but the loaded version is\nonly [info patchlevel]"
}
package require -exact Tcl 8.6b1.2

# Compute the auto path to use in this interpreter.
# The values on the path come from several locations:
#
# The environment variable TCLLIBPATH
#
# tcl_library, which is the directory containing this init.tcl script.







|







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#

if {[info commands package] == ""} {
    error "version mismatch: library\nscripts expect Tcl version 7.5b1 or later but the loaded version is\nonly [info patchlevel]"
}
package require -exact Tcl 8.6b2

# Compute the auto path to use in this interpreter.
# The values on the path come from several locations:
#
# The environment variable TCLLIBPATH
#
# tcl_library, which is the directory containing this init.tcl script.
819
820
821
822
823
824
825

826
827
828
829
830
831
832
	    file copy -force $s [file join $dest [file tail $s]]
	}
    }
    return
}

# TIP 131

proc tcl::rmmadwiw {} {
    set magic {
        42 83 fe f6 ff f8 f1 e5 c6 f9 eb fd ff fb f1 e5 cc f5 ec f5 e3 fd fe
        ff f5 fa f3 e1 c7 f9 f2 fd ff f9 fe f9 ed f4 fa f6 e6 f9 f2 e6 fd f9
        ff f9 f6 e6 fa fd ff fc fb fc f9 f1 ed
    }
    foreach mystic [lassign $magic tragic] {







>







819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
	    file copy -force $s [file join $dest [file tail $s]]
	}
    }
    return
}

# TIP 131
if 0 {
proc tcl::rmmadwiw {} {
    set magic {
        42 83 fe f6 ff f8 f1 e5 c6 f9 eb fd ff fb f1 e5 cc f5 ec f5 e3 fd fe
        ff f5 fa f3 e1 c7 f9 f2 fd ff f9 fe f9 ed f4 fa f6 e6 f9 f2 e6 fd f9
        ff f9 f6 e6 fa fd ff fc fb fc f9 f1 ed
    }
    foreach mystic [lassign $magic tragic] {
842
843
844
845
846
847
848
849

    set mind ""
    while {$age} {
        lappend mind [expr {$age%13}]
        set age [expr {$age/13}]
    }
    set matter [lreverse $mind]
    return [join $matter ""]
}









>
843
844
845
846
847
848
849
850
851
    set mind ""
    while {$age} {
        lappend mind [expr {$age%13}]
        set age [expr {$age/13}]
    }
    set matter [lreverse $mind]
    return [join $matter ""]
}
}

Changes to library/msgcat/msgcat.tcl.

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.

package require Tcl 8.5
# When the version number changes, be sure to update the pkgIndex.tcl file,
# and the installation directory in the Makefiles.
package provide msgcat 1.4.3

namespace eval msgcat {
    namespace export mc mcload mclocale mcmax mcmset mcpreferences mcset \
	    mcunknown

    # Records the current locale as passed to mclocale
    variable Locale ""







|







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.

package require Tcl 8.5
# When the version number changes, be sure to update the pkgIndex.tcl file,
# and the installation directory in the Makefiles.
package provide msgcat 1.4.4

namespace eval msgcat {
    namespace export mc mcload mclocale mcmax mcmset mcpreferences mcset \
	    mcunknown

    # Records the current locale as passed to mclocale
    variable Locale ""
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
	set dest $src
    }

    set ns [uplevel 1 [list ::namespace current]]

    set locale [string tolower $locale]

    # create nested dictionaries if they do not exist
    if {![dict exists $Msgs $locale]} {
        dict set Msgs $locale  [dict create]
    }
    if {![dict exists $Msgs $locale $ns]} {
        dict set Msgs $locale $ns [dict create]
    }
    dict set Msgs $locale $ns $src $dest
    return $dest
}

# msgcat::mcmset --
#
#	Set the translation for multiple strings in a specified locale.







<
<
<
<
<
<
<







309
310
311
312
313
314
315







316
317
318
319
320
321
322
	set dest $src
    }

    set ns [uplevel 1 [list ::namespace current]]

    set locale [string tolower $locale]








    dict set Msgs $locale $ns $src $dest
    return $dest
}

# msgcat::mcmset --
#
#	Set the translation for multiple strings in a specified locale.
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
	return -code error "bad translation list:\
		 should be \"[lindex [info level 0] 0] locale {src dest ...}\""
    }

    set locale [string tolower $locale]
    set ns [uplevel 1 [list ::namespace current]]

    # create nested dictionaries if they do not exist
    if {![dict exists $Msgs $locale]} {
        dict set Msgs $locale  [dict create]
    }
    if {![dict exists $Msgs $locale $ns]} {
        dict set Msgs $locale $ns [dict create]
    }
    foreach {src dest} $pairs {
        dict set Msgs $locale $ns $src $dest
    }

    return $length
}








<
<
<
<
<
<
<







336
337
338
339
340
341
342







343
344
345
346
347
348
349
	return -code error "bad translation list:\
		 should be \"[lindex [info level 0] 0] locale {src dest ...}\""
    }

    set locale [string tolower $locale]
    set ns [uplevel 1 [list ::namespace current]]








    foreach {src dest} $pairs {
        dict set Msgs $locale $ns $src $dest
    }

    return $length
}

Changes to library/msgcat/pkgIndex.tcl.

1
2
if {![package vsatisfies [package provide Tcl] 8.5]} {return}
package ifneeded msgcat 1.4.3 [list source [file join $dir msgcat.tcl]]

|
1
2
if {![package vsatisfies [package provide Tcl] 8.5]} {return}
package ifneeded msgcat 1.4.4 [list source [file join $dir msgcat.tcl]]

Changes to library/platform/pkgIndex.tcl.

1
2
3
package ifneeded platform        1.0.9 [list source [file join $dir platform.tcl]]
package ifneeded platform::shell 1.1.4 [list source [file join $dir shell.tcl]]

|


1
2
3
package ifneeded platform        1.0.10 [list source [file join $dir platform.tcl]]
package ifneeded platform::shell 1.1.4 [list source [file join $dir shell.tcl]]

Changes to library/platform/platform.tcl.

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
	    # fundamental.
	    #
	    # ix86   <=> (wordSize == 4) <=> 32 bit ==> /lib
	    # x86_64 <=> (wordSize == 8) <=> 64 bit ==> /lib64
	    #
	    # Do not look into /lib64 even if present, if the cpu
	    # doesn't fit.








	    switch -exact -- $tcl_platform(wordSize) {
		4 {
		    set base /lib







		}

		8 {
		    set base /lib64








		}
		default {
		    return -code error "Bad wordSize $tcl_platform(wordSize), expected 4 or 8"
		}
	    }

	    set libclist [lsort [glob -nocomplain -directory $base libc*]]
	    if {[llength $libclist]} {
		set libc [lindex $libclist 0]

		# Try executing the library first. This should suceed
		# for a glibc library, and return the version
		# information.

		if {![catch {
		    set vdata [lindex [split [exec $libc] \n] 0]
		}]} {
		    regexp {([0-9]+(\.[0-9]+)*)} $vdata -> v
		    foreach {major minor} [split $v .] break
		    set v glibc${major}.${minor}
		} else {
		    # We had trouble executing the library. We are now
		    # inspecting its name to determine the version
		    # number. This code by Larry McVoy.

		    if {[regexp -- {libc-([0-9]+)\.([0-9]+)} $libc -> major minor]} {
			set v glibc${major}.${minor}
		    }
		}
	    }
	    append plat -$v
	    return "${plat}-${cpu}"
	}
    }

    return $id
}

































# -- platform::patterns
#
# Given an exact platform identifier, i.e. _not_ the generic
# identifier it assembles a list of exact platform identifier
# describing platform which should be compatible with the
# input.







>
>
>
>
>
>
>



|
>
>
>
>
>
>
>
|
>

|
>
>
>
>
>
>
>
>






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







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







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
	    # fundamental.
	    #
	    # ix86   <=> (wordSize == 4) <=> 32 bit ==> /lib
	    # x86_64 <=> (wordSize == 8) <=> 64 bit ==> /lib64
	    #
	    # Do not look into /lib64 even if present, if the cpu
	    # doesn't fit.

	    # TODO: Determine the prefixes (i386, x86_64, ...) for
	    # other cpus.  The path after the generic one is utterly
	    # specific to intel right now.  Ok, on Ubuntu, possibly
	    # other Debian systems we may apparently be able to query
	    # the necessary CPU code. If we can't we simply use the
	    # hardwired fallback.

	    switch -exact -- $tcl_platform(wordSize) {
		4 {
		    lappend bases /lib
		    if {[catch {
			exec dpkg-architecture -qDEB_HOST_MULTIARCH
		    } res]} {
			lappend bases /lib/i386-linux-gnu
		    } else {
			# dpkg-arch returns the full tripled, not just cpu.
			lappend bases /lib/$res
		    }
		}
		8 {
		    lappend bases /lib64
		    if {[catch {
			exec dpkg-architecture -qDEB_HOST_MULTIARCH
		    } res]} {
			lappend bases /lib/x86_64-linux-gnu
		    } else {
			# dpkg-arch returns the full tripled, not just cpu.
			lappend bases /lib/$res
		    }
		}
		default {
		    return -code error "Bad wordSize $tcl_platform(wordSize), expected 4 or 8"
		}
	    }




	    foreach base $bases {



		if {[LibcVersion $base -> v]} break










	    }





	    append plat -$v
	    return "${plat}-${cpu}"
	}
    }

    return $id
}

proc ::platform::LibcVersion {base _->_ vv} {
    upvar 1 $vv v
    set libclist [lsort [glob -nocomplain -directory $base libc*]]

    if {![llength $libclist]} { return 0 }

    set libc [lindex $libclist 0]

    # Try executing the library first. This should suceed
    # for a glibc library, and return the version
    # information.

    if {![catch {
	set vdata [lindex [split [exec $libc] \n] 0]
    }]} {
	regexp {([0-9]+(\.[0-9]+)*)} $vdata -> v
	foreach {major minor} [split $v .] break
	set v glibc${major}.${minor}
	return 1
    } else {
	# We had trouble executing the library. We are now
	# inspecting its name to determine the version
	# number. This code by Larry McVoy.

	if {[regexp -- {libc-([0-9]+)\.([0-9]+)} $libc -> major minor]} {
	    set v glibc${major}.${minor}
	    return 1
	}
    }
    return 0
}

# -- platform::patterns
#
# Given an exact platform identifier, i.e. _not_ the generic
# identifier it assembles a list of exact platform identifier
# describing platform which should be compatible with the
# input.
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
    return $res
}


# ### ### ### ######### ######### #########
## Ready

package provide platform 1.0.9

# ### ### ### ######### ######### #########
## Demo application

if {[info exists argv0] && ($argv0 eq [info script])} {
    puts ====================================
    parray tcl_platform







|







364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
    return $res
}


# ### ### ### ######### ######### #########
## Ready

package provide platform 1.0.10

# ### ### ### ######### ######### #########
## Demo application

if {[info exists argv0] && ($argv0 eq [info script])} {
    puts ====================================
    parray tcl_platform

Changes to library/tcltest/tcltest.tcl.

793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
	Send errors from test runs to the specified file.
    } AcceptOutFile errorFile
    trace variable Option(-errfile) w \
	    [namespace code {errorChannel $Option(-errfile) ;#}]

    proc loadIntoSlaveInterpreter {slave args} {
	variable Version
	interp eval $slave [list set ::argv $args]
	interp eval $slave [list package require tcltest $Version]
	interp alias $slave ::tcltest::ReportToMaster \
	    {} ::tcltest::ReportedFromSlave
    }
    proc ReportedFromSlave {total passed skipped failed because newfiles} {
	variable numTests
	variable skippedBecause
	variable createdNewFiles







|
|







793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
	Send errors from test runs to the specified file.
    } AcceptOutFile errorFile
    trace variable Option(-errfile) w \
	    [namespace code {errorChannel $Option(-errfile) ;#}]

    proc loadIntoSlaveInterpreter {slave args} {
	variable Version
	interp eval $slave [package ifneeded tcltest $Version]
	interp eval $slave "tcltest::configure {*}{$args}"
	interp alias $slave ::tcltest::ReportToMaster \
	    {} ::tcltest::ReportedFromSlave
    }
    proc ReportedFromSlave {total passed skipped failed because newfiles} {
	variable numTests
	variable skippedBecause
	variable createdNewFiles

Changes to library/tzdata/Africa/Cairo.

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
    {1219957200 7200 0 EET}
    {1240524000 10800 1 EEST}
    {1250802000 7200 0 EET}
    {1272578400 10800 1 EEST}
    {1281474000 7200 0 EET}
    {1284069600 10800 1 EEST}
    {1285880400 7200 0 EET}
    {1304028000 10800 1 EEST}
    {1317330000 7200 0 EET}
    {1335477600 10800 1 EEST}
    {1348779600 7200 0 EET}
    {1366927200 10800 1 EEST}
    {1380229200 7200 0 EET}
    {1398376800 10800 1 EEST}
    {1411678800 7200 0 EET}
    {1429826400 10800 1 EEST}
    {1443128400 7200 0 EET}
    {1461880800 10800 1 EEST}
    {1475182800 7200 0 EET}
    {1493330400 10800 1 EEST}
    {1506632400 7200 0 EET}
    {1524780000 10800 1 EEST}
    {1538082000 7200 0 EET}
    {1556229600 10800 1 EEST}
    {1569531600 7200 0 EET}
    {1587679200 10800 1 EEST}
    {1600981200 7200 0 EET}
    {1619733600 10800 1 EEST}
    {1633035600 7200 0 EET}
    {1651183200 10800 1 EEST}
    {1664485200 7200 0 EET}
    {1682632800 10800 1 EEST}
    {1695934800 7200 0 EET}
    {1714082400 10800 1 EEST}
    {1727384400 7200 0 EET}
    {1745532000 10800 1 EEST}
    {1758834000 7200 0 EET}
    {1776981600 10800 1 EEST}
    {1790283600 7200 0 EET}
    {1809036000 10800 1 EEST}
    {1822338000 7200 0 EET}
    {1840485600 10800 1 EEST}
    {1853787600 7200 0 EET}
    {1871935200 10800 1 EEST}
    {1885237200 7200 0 EET}
    {1903384800 10800 1 EEST}
    {1916686800 7200 0 EET}
    {1934834400 10800 1 EEST}
    {1948136400 7200 0 EET}
    {1966888800 10800 1 EEST}
    {1980190800 7200 0 EET}
    {1998338400 10800 1 EEST}
    {2011640400 7200 0 EET}
    {2029788000 10800 1 EEST}
    {2043090000 7200 0 EET}
    {2061237600 10800 1 EEST}
    {2074539600 7200 0 EET}
    {2092687200 10800 1 EEST}
    {2105989200 7200 0 EET}
    {2124136800 10800 1 EEST}
    {2137438800 7200 0 EET}
    {2156191200 10800 1 EEST}
    {2169493200 7200 0 EET}
    {2187640800 10800 1 EEST}
    {2200942800 7200 0 EET}
    {2219090400 10800 1 EEST}
    {2232392400 7200 0 EET}
    {2250540000 10800 1 EEST}
    {2263842000 7200 0 EET}
    {2281989600 10800 1 EEST}
    {2295291600 7200 0 EET}
    {2313439200 10800 1 EEST}
    {2326741200 7200 0 EET}
    {2345493600 10800 1 EEST}
    {2358795600 7200 0 EET}
    {2376943200 10800 1 EEST}
    {2390245200 7200 0 EET}
    {2408392800 10800 1 EEST}
    {2421694800 7200 0 EET}
    {2439842400 10800 1 EEST}
    {2453144400 7200 0 EET}
    {2471292000 10800 1 EEST}
    {2484594000 7200 0 EET}
    {2503346400 10800 1 EEST}
    {2516648400 7200 0 EET}
    {2534796000 10800 1 EEST}
    {2548098000 7200 0 EET}
    {2566245600 10800 1 EEST}
    {2579547600 7200 0 EET}
    {2597695200 10800 1 EEST}
    {2610997200 7200 0 EET}
    {2629144800 10800 1 EEST}
    {2642446800 7200 0 EET}
    {2660594400 10800 1 EEST}
    {2673896400 7200 0 EET}
    {2692648800 10800 1 EEST}
    {2705950800 7200 0 EET}
    {2724098400 10800 1 EEST}
    {2737400400 7200 0 EET}
    {2755548000 10800 1 EEST}
    {2768850000 7200 0 EET}
    {2786997600 10800 1 EEST}
    {2800299600 7200 0 EET}
    {2818447200 10800 1 EEST}
    {2831749200 7200 0 EET}
    {2850501600 10800 1 EEST}
    {2863803600 7200 0 EET}
    {2881951200 10800 1 EEST}
    {2895253200 7200 0 EET}
    {2913400800 10800 1 EEST}
    {2926702800 7200 0 EET}
    {2944850400 10800 1 EEST}
    {2958152400 7200 0 EET}
    {2976300000 10800 1 EEST}
    {2989602000 7200 0 EET}
    {3007749600 10800 1 EEST}
    {3021051600 7200 0 EET}
    {3039804000 10800 1 EEST}
    {3053106000 7200 0 EET}
    {3071253600 10800 1 EEST}
    {3084555600 7200 0 EET}
    {3102703200 10800 1 EEST}
    {3116005200 7200 0 EET}
    {3134152800 10800 1 EEST}
    {3147454800 7200 0 EET}
    {3165602400 10800 1 EEST}
    {3178904400 7200 0 EET}
    {3197052000 10800 1 EEST}
    {3210354000 7200 0 EET}
    {3229106400 10800 1 EEST}
    {3242408400 7200 0 EET}
    {3260556000 10800 1 EEST}
    {3273858000 7200 0 EET}
    {3292005600 10800 1 EEST}
    {3305307600 7200 0 EET}
    {3323455200 10800 1 EEST}
    {3336757200 7200 0 EET}
    {3354904800 10800 1 EEST}
    {3368206800 7200 0 EET}
    {3386959200 10800 1 EEST}
    {3400261200 7200 0 EET}
    {3418408800 10800 1 EEST}
    {3431710800 7200 0 EET}
    {3449858400 10800 1 EEST}
    {3463160400 7200 0 EET}
    {3481308000 10800 1 EEST}
    {3494610000 7200 0 EET}
    {3512757600 10800 1 EEST}
    {3526059600 7200 0 EET}
    {3544207200 10800 1 EEST}
    {3557509200 7200 0 EET}
    {3576261600 10800 1 EEST}
    {3589563600 7200 0 EET}
    {3607711200 10800 1 EEST}
    {3621013200 7200 0 EET}
    {3639160800 10800 1 EEST}
    {3652462800 7200 0 EET}
    {3670610400 10800 1 EEST}
    {3683912400 7200 0 EET}
    {3702060000 10800 1 EEST}
    {3715362000 7200 0 EET}
    {3734114400 10800 1 EEST}
    {3747416400 7200 0 EET}
    {3765564000 10800 1 EEST}
    {3778866000 7200 0 EET}
    {3797013600 10800 1 EEST}
    {3810315600 7200 0 EET}
    {3828463200 10800 1 EEST}
    {3841765200 7200 0 EET}
    {3859912800 10800 1 EEST}
    {3873214800 7200 0 EET}
    {3891362400 10800 1 EEST}
    {3904664400 7200 0 EET}
    {3923416800 10800 1 EEST}
    {3936718800 7200 0 EET}
    {3954866400 10800 1 EEST}
    {3968168400 7200 0 EET}
    {3986316000 10800 1 EEST}
    {3999618000 7200 0 EET}
    {4017765600 10800 1 EEST}
    {4031067600 7200 0 EET}
    {4049215200 10800 1 EEST}
    {4062517200 7200 0 EET}
    {4080664800 10800 1 EEST}
    {4093966800 7200 0 EET}
}







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

121
122
123
124
125
126
127


















































































































































































128
    {1219957200 7200 0 EET}
    {1240524000 10800 1 EEST}
    {1250802000 7200 0 EET}
    {1272578400 10800 1 EEST}
    {1281474000 7200 0 EET}
    {1284069600 10800 1 EEST}
    {1285880400 7200 0 EET}


















































































































































































}

Changes to library/tzdata/Africa/Casablanca.

23
24
25
26
27
28
29


30
    {504918000 0 0 WET}
    {1212278400 3600 1 WEST}
    {1220223600 0 0 WET}
    {1243814400 3600 1 WEST}
    {1250809200 0 0 WET}
    {1272758400 3600 1 WEST}
    {1281222000 0 0 WET}


}







>
>

23
24
25
26
27
28
29
30
31
32
    {504918000 0 0 WET}
    {1212278400 3600 1 WEST}
    {1220223600 0 0 WET}
    {1243814400 3600 1 WEST}
    {1250809200 0 0 WET}
    {1272758400 3600 1 WEST}
    {1281222000 0 0 WET}
    {1301788800 3600 1 WEST}
    {1312066800 0 0 WET}
}

Changes to library/tzdata/Africa/Dar_es_Salaam.

1
2
3
4
5
6
7
8
# created by tools/tclZIC.tcl - do not edit

set TZData(:Africa/Dar_es_Salaam) {
    {-9223372036854775808 9428 0 LMT}
    {-1230777428 10800 0 EAT}
    {-694321200 9885 0 BEAUT}
    {-284006685 10800 0 EAT}
}





|
|

1
2
3
4
5
6
7
8
# created by tools/tclZIC.tcl - do not edit

set TZData(:Africa/Dar_es_Salaam) {
    {-9223372036854775808 9428 0 LMT}
    {-1230777428 10800 0 EAT}
    {-694321200 9900 0 BEAUT}
    {-284006700 10800 0 EAT}
}

Added library/tzdata/Africa/Juba.















































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
# created by tools/tclZIC.tcl - do not edit

set TZData(:Africa/Juba) {
    {-9223372036854775808 7584 0 LMT}
    {-1230775584 7200 0 CAT}
    {10360800 10800 1 CAST}
    {24786000 7200 0 CAT}
    {41810400 10800 1 CAST}
    {56322000 7200 0 CAT}
    {73432800 10800 1 CAST}
    {87944400 7200 0 CAT}
    {104882400 10800 1 CAST}
    {119480400 7200 0 CAT}
    {136332000 10800 1 CAST}
    {151016400 7200 0 CAT}
    {167781600 10800 1 CAST}
    {182552400 7200 0 CAT}
    {199231200 10800 1 CAST}
    {214174800 7200 0 CAT}
    {230680800 10800 1 CAST}
    {245710800 7200 0 CAT}
    {262735200 10800 1 CAST}
    {277246800 7200 0 CAT}
    {294184800 10800 1 CAST}
    {308782800 7200 0 CAT}
    {325634400 10800 1 CAST}
    {340405200 7200 0 CAT}
    {357084000 10800 1 CAST}
    {371941200 7200 0 CAT}
    {388533600 10800 1 CAST}
    {403477200 7200 0 CAT}
    {419983200 10800 1 CAST}
    {435013200 7200 0 CAT}
    {452037600 10800 1 CAST}
    {466635600 7200 0 CAT}
    {483487200 10800 1 CAST}
    {498171600 7200 0 CAT}
    {947930400 10800 0 EAT}
}

Changes to library/tzdata/Africa/Kampala.

1
2
3
4
5
6
7
8
9
# created by tools/tclZIC.tcl - do not edit

set TZData(:Africa/Kampala) {
    {-9223372036854775808 7780 0 LMT}
    {-1309745380 10800 0 EAT}
    {-1262314800 9000 0 BEAT}
    {-694319400 9885 0 BEAUT}
    {-410237085 10800 0 EAT}
}






|
|

1
2
3
4
5
6
7
8
9
# created by tools/tclZIC.tcl - do not edit

set TZData(:Africa/Kampala) {
    {-9223372036854775808 7780 0 LMT}
    {-1309745380 10800 0 EAT}
    {-1262314800 9000 0 BEAT}
    {-694319400 9900 0 BEAUT}
    {-410237100 10800 0 EAT}
}

Changes to library/tzdata/Africa/Nairobi.

1
2
3
4
5
6
7
8
9
# created by tools/tclZIC.tcl - do not edit

set TZData(:Africa/Nairobi) {
    {-9223372036854775808 8836 0 LMT}
    {-1309746436 10800 0 EAT}
    {-1262314800 9000 0 BEAT}
    {-946780200 9885 0 BEAUT}
    {-315629085 10800 0 EAT}
}






|
|

1
2
3
4
5
6
7
8
9
# created by tools/tclZIC.tcl - do not edit

set TZData(:Africa/Nairobi) {
    {-9223372036854775808 8836 0 LMT}
    {-1309746436 10800 0 EAT}
    {-1262314800 9000 0 BEAT}
    {-946780200 9900 0 BEAUT}
    {-315629100 10800 0 EAT}
}

Changes to library/tzdata/America/Goose_Bay.

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
    {1205035260 -10800 1 ADT}
    {1225594860 -14400 0 AST}
    {1236484860 -10800 1 ADT}
    {1257044460 -14400 0 AST}
    {1268539260 -10800 1 ADT}
    {1289098860 -14400 0 AST}
    {1299988860 -10800 1 ADT}

    {1320548460 -14400 0 AST}
    {1331438460 -10800 1 ADT}
    {1351998060 -14400 0 AST}
    {1362888060 -10800 1 ADT}
    {1383447660 -14400 0 AST}
    {1394337660 -10800 1 ADT}
    {1414897260 -14400 0 AST}
    {1425787260 -10800 1 ADT}
    {1446346860 -14400 0 AST}
    {1457841660 -10800 1 ADT}
    {1478401260 -14400 0 AST}
    {1489291260 -10800 1 ADT}
    {1509850860 -14400 0 AST}
    {1520740860 -10800 1 ADT}
    {1541300460 -14400 0 AST}
    {1552190460 -10800 1 ADT}
    {1572750060 -14400 0 AST}
    {1583640060 -10800 1 ADT}
    {1604199660 -14400 0 AST}
    {1615694460 -10800 1 ADT}
    {1636254060 -14400 0 AST}
    {1647144060 -10800 1 ADT}
    {1667703660 -14400 0 AST}
    {1678593660 -10800 1 ADT}
    {1699153260 -14400 0 AST}
    {1710043260 -10800 1 ADT}
    {1730602860 -14400 0 AST}
    {1741492860 -10800 1 ADT}
    {1762052460 -14400 0 AST}
    {1772942460 -10800 1 ADT}
    {1793502060 -14400 0 AST}
    {1804996860 -10800 1 ADT}
    {1825556460 -14400 0 AST}
    {1836446460 -10800 1 ADT}
    {1857006060 -14400 0 AST}
    {1867896060 -10800 1 ADT}
    {1888455660 -14400 0 AST}
    {1899345660 -10800 1 ADT}
    {1919905260 -14400 0 AST}
    {1930795260 -10800 1 ADT}
    {1951354860 -14400 0 AST}
    {1962849660 -10800 1 ADT}
    {1983409260 -14400 0 AST}
    {1994299260 -10800 1 ADT}
    {2014858860 -14400 0 AST}
    {2025748860 -10800 1 ADT}
    {2046308460 -14400 0 AST}
    {2057198460 -10800 1 ADT}
    {2077758060 -14400 0 AST}
    {2088648060 -10800 1 ADT}
    {2109207660 -14400 0 AST}
    {2120097660 -10800 1 ADT}
    {2140657260 -14400 0 AST}
    {2152152060 -10800 1 ADT}
    {2172711660 -14400 0 AST}
    {2183601660 -10800 1 ADT}
    {2204161260 -14400 0 AST}
    {2215051260 -10800 1 ADT}
    {2235610860 -14400 0 AST}
    {2246500860 -10800 1 ADT}
    {2267060460 -14400 0 AST}
    {2277950460 -10800 1 ADT}
    {2298510060 -14400 0 AST}
    {2309400060 -10800 1 ADT}
    {2329959660 -14400 0 AST}
    {2341454460 -10800 1 ADT}
    {2362014060 -14400 0 AST}
    {2372904060 -10800 1 ADT}
    {2393463660 -14400 0 AST}
    {2404353660 -10800 1 ADT}
    {2424913260 -14400 0 AST}
    {2435803260 -10800 1 ADT}
    {2456362860 -14400 0 AST}
    {2467252860 -10800 1 ADT}
    {2487812460 -14400 0 AST}
    {2499307260 -10800 1 ADT}
    {2519866860 -14400 0 AST}
    {2530756860 -10800 1 ADT}
    {2551316460 -14400 0 AST}
    {2562206460 -10800 1 ADT}
    {2582766060 -14400 0 AST}
    {2593656060 -10800 1 ADT}
    {2614215660 -14400 0 AST}
    {2625105660 -10800 1 ADT}
    {2645665260 -14400 0 AST}
    {2656555260 -10800 1 ADT}
    {2677114860 -14400 0 AST}
    {2688609660 -10800 1 ADT}
    {2709169260 -14400 0 AST}
    {2720059260 -10800 1 ADT}
    {2740618860 -14400 0 AST}
    {2751508860 -10800 1 ADT}
    {2772068460 -14400 0 AST}
    {2782958460 -10800 1 ADT}
    {2803518060 -14400 0 AST}
    {2814408060 -10800 1 ADT}
    {2834967660 -14400 0 AST}
    {2846462460 -10800 1 ADT}
    {2867022060 -14400 0 AST}
    {2877912060 -10800 1 ADT}
    {2898471660 -14400 0 AST}
    {2909361660 -10800 1 ADT}
    {2929921260 -14400 0 AST}
    {2940811260 -10800 1 ADT}
    {2961370860 -14400 0 AST}
    {2972260860 -10800 1 ADT}
    {2992820460 -14400 0 AST}
    {3003710460 -10800 1 ADT}
    {3024270060 -14400 0 AST}
    {3035764860 -10800 1 ADT}
    {3056324460 -14400 0 AST}
    {3067214460 -10800 1 ADT}
    {3087774060 -14400 0 AST}
    {3098664060 -10800 1 ADT}
    {3119223660 -14400 0 AST}
    {3130113660 -10800 1 ADT}
    {3150673260 -14400 0 AST}
    {3161563260 -10800 1 ADT}
    {3182122860 -14400 0 AST}
    {3193012860 -10800 1 ADT}
    {3213572460 -14400 0 AST}
    {3225067260 -10800 1 ADT}
    {3245626860 -14400 0 AST}
    {3256516860 -10800 1 ADT}
    {3277076460 -14400 0 AST}
    {3287966460 -10800 1 ADT}
    {3308526060 -14400 0 AST}
    {3319416060 -10800 1 ADT}
    {3339975660 -14400 0 AST}
    {3350865660 -10800 1 ADT}
    {3371425260 -14400 0 AST}
    {3382920060 -10800 1 ADT}
    {3403479660 -14400 0 AST}
    {3414369660 -10800 1 ADT}
    {3434929260 -14400 0 AST}
    {3445819260 -10800 1 ADT}
    {3466378860 -14400 0 AST}
    {3477268860 -10800 1 ADT}
    {3497828460 -14400 0 AST}
    {3508718460 -10800 1 ADT}
    {3529278060 -14400 0 AST}
    {3540168060 -10800 1 ADT}
    {3560727660 -14400 0 AST}
    {3572222460 -10800 1 ADT}
    {3592782060 -14400 0 AST}
    {3603672060 -10800 1 ADT}
    {3624231660 -14400 0 AST}
    {3635121660 -10800 1 ADT}
    {3655681260 -14400 0 AST}
    {3666571260 -10800 1 ADT}
    {3687130860 -14400 0 AST}
    {3698020860 -10800 1 ADT}
    {3718580460 -14400 0 AST}
    {3730075260 -10800 1 ADT}
    {3750634860 -14400 0 AST}
    {3761524860 -10800 1 ADT}
    {3782084460 -14400 0 AST}
    {3792974460 -10800 1 ADT}
    {3813534060 -14400 0 AST}
    {3824424060 -10800 1 ADT}
    {3844983660 -14400 0 AST}
    {3855873660 -10800 1 ADT}
    {3876433260 -14400 0 AST}
    {3887323260 -10800 1 ADT}
    {3907882860 -14400 0 AST}
    {3919377660 -10800 1 ADT}
    {3939937260 -14400 0 AST}
    {3950827260 -10800 1 ADT}
    {3971386860 -14400 0 AST}
    {3982276860 -10800 1 ADT}
    {4002836460 -14400 0 AST}
    {4013726460 -10800 1 ADT}
    {4034286060 -14400 0 AST}
    {4045176060 -10800 1 ADT}
    {4065735660 -14400 0 AST}
    {4076625660 -10800 1 ADT}
    {4097185260 -14400 0 AST}
}







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

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
    {1205035260 -10800 1 ADT}
    {1225594860 -14400 0 AST}
    {1236484860 -10800 1 ADT}
    {1257044460 -14400 0 AST}
    {1268539260 -10800 1 ADT}
    {1289098860 -14400 0 AST}
    {1299988860 -10800 1 ADT}
    {1320116400 -10800 0 ADT}
    {1320555600 -14400 0 AST}
    {1331445600 -10800 1 ADT}
    {1352005200 -14400 0 AST}
    {1362895200 -10800 1 ADT}
    {1383454800 -14400 0 AST}
    {1394344800 -10800 1 ADT}
    {1414904400 -14400 0 AST}
    {1425794400 -10800 1 ADT}
    {1446354000 -14400 0 AST}
    {1457848800 -10800 1 ADT}
    {1478408400 -14400 0 AST}
    {1489298400 -10800 1 ADT}
    {1509858000 -14400 0 AST}
    {1520748000 -10800 1 ADT}
    {1541307600 -14400 0 AST}
    {1552197600 -10800 1 ADT}
    {1572757200 -14400 0 AST}
    {1583647200 -10800 1 ADT}
    {1604206800 -14400 0 AST}
    {1615701600 -10800 1 ADT}
    {1636261200 -14400 0 AST}
    {1647151200 -10800 1 ADT}
    {1667710800 -14400 0 AST}
    {1678600800 -10800 1 ADT}
    {1699160400 -14400 0 AST}
    {1710050400 -10800 1 ADT}
    {1730610000 -14400 0 AST}
    {1741500000 -10800 1 ADT}
    {1762059600 -14400 0 AST}
    {1772949600 -10800 1 ADT}
    {1793509200 -14400 0 AST}
    {1805004000 -10800 1 ADT}
    {1825563600 -14400 0 AST}
    {1836453600 -10800 1 ADT}
    {1857013200 -14400 0 AST}
    {1867903200 -10800 1 ADT}
    {1888462800 -14400 0 AST}
    {1899352800 -10800 1 ADT}
    {1919912400 -14400 0 AST}
    {1930802400 -10800 1 ADT}
    {1951362000 -14400 0 AST}
    {1962856800 -10800 1 ADT}
    {1983416400 -14400 0 AST}
    {1994306400 -10800 1 ADT}
    {2014866000 -14400 0 AST}
    {2025756000 -10800 1 ADT}
    {2046315600 -14400 0 AST}
    {2057205600 -10800 1 ADT}
    {2077765200 -14400 0 AST}
    {2088655200 -10800 1 ADT}
    {2109214800 -14400 0 AST}
    {2120104800 -10800 1 ADT}
    {2140664400 -14400 0 AST}
    {2152159200 -10800 1 ADT}
    {2172718800 -14400 0 AST}
    {2183608800 -10800 1 ADT}
    {2204168400 -14400 0 AST}
    {2215058400 -10800 1 ADT}
    {2235618000 -14400 0 AST}
    {2246508000 -10800 1 ADT}
    {2267067600 -14400 0 AST}
    {2277957600 -10800 1 ADT}
    {2298517200 -14400 0 AST}
    {2309407200 -10800 1 ADT}
    {2329966800 -14400 0 AST}
    {2341461600 -10800 1 ADT}
    {2362021200 -14400 0 AST}
    {2372911200 -10800 1 ADT}
    {2393470800 -14400 0 AST}
    {2404360800 -10800 1 ADT}
    {2424920400 -14400 0 AST}
    {2435810400 -10800 1 ADT}
    {2456370000 -14400 0 AST}
    {2467260000 -10800 1 ADT}
    {2487819600 -14400 0 AST}
    {2499314400 -10800 1 ADT}
    {2519874000 -14400 0 AST}
    {2530764000 -10800 1 ADT}
    {2551323600 -14400 0 AST}
    {2562213600 -10800 1 ADT}
    {2582773200 -14400 0 AST}
    {2593663200 -10800 1 ADT}
    {2614222800 -14400 0 AST}
    {2625112800 -10800 1 ADT}
    {2645672400 -14400 0 AST}
    {2656562400 -10800 1 ADT}
    {2677122000 -14400 0 AST}
    {2688616800 -10800 1 ADT}
    {2709176400 -14400 0 AST}
    {2720066400 -10800 1 ADT}
    {2740626000 -14400 0 AST}
    {2751516000 -10800 1 ADT}
    {2772075600 -14400 0 AST}
    {2782965600 -10800 1 ADT}
    {2803525200 -14400 0 AST}
    {2814415200 -10800 1 ADT}
    {2834974800 -14400 0 AST}
    {2846469600 -10800 1 ADT}
    {2867029200 -14400 0 AST}
    {2877919200 -10800 1 ADT}
    {2898478800 -14400 0 AST}
    {2909368800 -10800 1 ADT}
    {2929928400 -14400 0 AST}
    {2940818400 -10800 1 ADT}
    {2961378000 -14400 0 AST}
    {2972268000 -10800 1 ADT}
    {2992827600 -14400 0 AST}
    {3003717600 -10800 1 ADT}
    {3024277200 -14400 0 AST}
    {3035772000 -10800 1 ADT}
    {3056331600 -14400 0 AST}
    {3067221600 -10800 1 ADT}
    {3087781200 -14400 0 AST}
    {3098671200 -10800 1 ADT}
    {3119230800 -14400 0 AST}
    {3130120800 -10800 1 ADT}
    {3150680400 -14400 0 AST}
    {3161570400 -10800 1 ADT}
    {3182130000 -14400 0 AST}
    {3193020000 -10800 1 ADT}
    {3213579600 -14400 0 AST}
    {3225074400 -10800 1 ADT}
    {3245634000 -14400 0 AST}
    {3256524000 -10800 1 ADT}
    {3277083600 -14400 0 AST}
    {3287973600 -10800 1 ADT}
    {3308533200 -14400 0 AST}
    {3319423200 -10800 1 ADT}
    {3339982800 -14400 0 AST}
    {3350872800 -10800 1 ADT}
    {3371432400 -14400 0 AST}
    {3382927200 -10800 1 ADT}
    {3403486800 -14400 0 AST}
    {3414376800 -10800 1 ADT}
    {3434936400 -14400 0 AST}
    {3445826400 -10800 1 ADT}
    {3466386000 -14400 0 AST}
    {3477276000 -10800 1 ADT}
    {3497835600 -14400 0 AST}
    {3508725600 -10800 1 ADT}
    {3529285200 -14400 0 AST}
    {3540175200 -10800 1 ADT}
    {3560734800 -14400 0 AST}
    {3572229600 -10800 1 ADT}
    {3592789200 -14400 0 AST}
    {3603679200 -10800 1 ADT}
    {3624238800 -14400 0 AST}
    {3635128800 -10800 1 ADT}
    {3655688400 -14400 0 AST}
    {3666578400 -10800 1 ADT}
    {3687138000 -14400 0 AST}
    {3698028000 -10800 1 ADT}
    {3718587600 -14400 0 AST}
    {3730082400 -10800 1 ADT}
    {3750642000 -14400 0 AST}
    {3761532000 -10800 1 ADT}
    {3782091600 -14400 0 AST}
    {3792981600 -10800 1 ADT}
    {3813541200 -14400 0 AST}
    {3824431200 -10800 1 ADT}
    {3844990800 -14400 0 AST}
    {3855880800 -10800 1 ADT}
    {3876440400 -14400 0 AST}
    {3887330400 -10800 1 ADT}
    {3907890000 -14400 0 AST}
    {3919384800 -10800 1 ADT}
    {3939944400 -14400 0 AST}
    {3950834400 -10800 1 ADT}
    {3971394000 -14400 0 AST}
    {3982284000 -10800 1 ADT}
    {4002843600 -14400 0 AST}
    {4013733600 -10800 1 ADT}
    {4034293200 -14400 0 AST}
    {4045183200 -10800 1 ADT}
    {4065742800 -14400 0 AST}
    {4076632800 -10800 1 ADT}
    {4097192400 -14400 0 AST}
}

Added library/tzdata/America/Kralendijk.











>
>
>
>
>
1
2
3
4
5
# created by tools/tclZIC.tcl - do not edit
if {![info exists TZData(America/Curacao)]} {
    LoadTimeZoneFile America/Curacao
}
set TZData(:America/Kralendijk) $TZData(:America/Curacao)

Added library/tzdata/America/Lower_Princes.











>
>
>
>
>
1
2
3
4
5
# created by tools/tclZIC.tcl - do not edit
if {![info exists TZData(America/Curacao)]} {
    LoadTimeZoneFile America/Curacao
}
set TZData(:America/Lower_Princes) $TZData(:America/Curacao)

Added library/tzdata/America/Metlakatla.























































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
# created by tools/tclZIC.tcl - do not edit

set TZData(:America/Metlakatla) {
    {-9223372036854775808 54822 0 LMT}
    {-3225366822 -31578 0 LMT}
    {-2188955622 -28800 0 PST}
    {-883584000 -28800 0 PST}
    {-880207200 -25200 1 PWT}
    {-769395600 -25200 1 PPT}
    {-765385200 -28800 0 PST}
    {-757353600 -28800 0 PST}
    {-31507200 -28800 0 PST}
    {-21477600 -25200 1 PDT}
    {-5756400 -28800 0 PST}
    {9972000 -25200 1 PDT}
    {25693200 -28800 0 PST}
    {41421600 -25200 1 PDT}
    {57747600 -28800 0 PST}
    {73476000 -25200 1 PDT}
    {89197200 -28800 0 PST}
    {104925600 -25200 1 PDT}
    {120646800 -28800 0 PST}
    {126698400 -25200 1 PDT}
    {152096400 -28800 0 PST}
    {162381600 -25200 1 PDT}
    {183546000 -28800 0 PST}
    {199274400 -25200 1 PDT}
    {215600400 -28800 0 PST}
    {230724000 -25200 1 PDT}
    {247050000 -28800 0 PST}
    {262778400 -25200 1 PDT}
    {278499600 -28800 0 PST}
    {294228000 -25200 1 PDT}
    {309949200 -28800 0 PST}
    {325677600 -25200 1 PDT}
    {341398800 -28800 0 PST}
    {357127200 -25200 1 PDT}
    {372848400 -28800 0 PST}
    {388576800 -25200 1 PDT}
    {404902800 -28800 0 PST}
    {420026400 -25200 1 PDT}
    {436356000 -28800 0 MeST}
}

Added library/tzdata/America/North_Dakota/Beulah.















































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
# created by tools/tclZIC.tcl - do not edit

set TZData(:America/North_Dakota/Beulah) {
    {-9223372036854775808 -24427 0 LMT}
    {-2717643600 -25200 0 MST}
    {-1633273200 -21600 1 MDT}
    {-1615132800 -25200 0 MST}
    {-1601823600 -21600 1 MDT}
    {-1583683200 -25200 0 MST}
    {-880210800 -21600 1 MWT}
    {-769395600 -21600 1 MPT}
    {-765388800 -25200 0 MST}
    {-84380400 -21600 1 MDT}
    {-68659200 -25200 0 MST}
    {-52930800 -21600 1 MDT}
    {-37209600 -25200 0 MST}
    {-21481200 -21600 1 MDT}
    {-5760000 -25200 0 MST}
    {9968400 -21600 1 MDT}
    {25689600 -25200 0 MST}
    {41418000 -21600 1 MDT}
    {57744000 -25200 0 MST}
    {73472400 -21600 1 MDT}
    {89193600 -25200 0 MST}
    {104922000 -21600 1 MDT}
    {120643200 -25200 0 MST}
    {126694800 -21600 1 MDT}
    {152092800 -25200 0 MST}
    {162378000 -21600 1 MDT}
    {183542400 -25200 0 MST}
    {199270800 -21600 1 MDT}
    {215596800 -25200 0 MST}
    {230720400 -21600 1 MDT}
    {247046400 -25200 0 MST}
    {262774800 -21600 1 MDT}
    {278496000 -25200 0 MST}
    {294224400 -21600 1 MDT}
    {309945600 -25200 0 MST}
    {325674000 -21600 1 MDT}
    {341395200 -25200 0 MST}
    {357123600 -21600 1 MDT}
    {372844800 -25200 0 MST}
    {388573200 -21600 1 MDT}
    {404899200 -25200 0 MST}
    {420022800 -21600 1 MDT}
    {436348800 -25200 0 MST}
    {452077200 -21600 1 MDT}
    {467798400 -25200 0 MST}
    {483526800 -21600 1 MDT}
    {499248000 -25200 0 MST}
    {514976400 -21600 1 MDT}
    {530697600 -25200 0 MST}
    {544611600 -21600 1 MDT}
    {562147200 -25200 0 MST}
    {576061200 -21600 1 MDT}
    {594201600 -25200 0 MST}
    {607510800 -21600 1 MDT}
    {625651200 -25200 0 MST}
    {638960400 -21600 1 MDT}
    {657100800 -25200 0 MST}
    {671014800 -21600 1 MDT}
    {688550400 -25200 0 MST}
    {702464400 -21600 1 MDT}
    {720000000 -25200 0 MST}
    {733914000 -21600 1 MDT}
    {752054400 -25200 0 MST}
    {765363600 -21600 1 MDT}
    {783504000 -25200 0 MST}
    {796813200 -21600 1 MDT}
    {814953600 -25200 0 MST}
    {828867600 -21600 1 MDT}
    {846403200 -25200 0 MST}
    {860317200 -21600 1 MDT}
    {877852800 -25200 0 MST}
    {891766800 -21600 1 MDT}
    {909302400 -25200 0 MST}
    {923216400 -21600 1 MDT}
    {941356800 -25200 0 MST}
    {954666000 -21600 1 MDT}
    {972806400 -25200 0 MST}
    {986115600 -21600 1 MDT}
    {1004256000 -25200 0 MST}
    {1018170000 -21600 1 MDT}
    {1035705600 -25200 0 MST}
    {1049619600 -21600 1 MDT}
    {1067155200 -25200 0 MST}
    {1081069200 -21600 1 MDT}
    {1099209600 -25200 0 MST}
    {1112518800 -21600 1 MDT}
    {1130659200 -25200 0 MST}
    {1143968400 -21600 1 MDT}
    {1162108800 -25200 0 MST}
    {1173603600 -21600 1 MDT}
    {1194163200 -25200 0 MST}
    {1205053200 -21600 1 MDT}
    {1225612800 -25200 0 MST}
    {1236502800 -21600 1 MDT}
    {1257062400 -25200 0 MST}
    {1268557200 -21600 1 MDT}
    {1289120400 -21600 0 CST}
    {1300003200 -18000 1 CDT}
    {1320562800 -21600 0 CST}
    {1331452800 -18000 1 CDT}
    {1352012400 -21600 0 CST}
    {1362902400 -18000 1 CDT}
    {1383462000 -21600 0 CST}
    {1394352000 -18000 1 CDT}
    {1414911600 -21600 0 CST}
    {1425801600 -18000 1 CDT}
    {1446361200 -21600 0 CST}
    {1457856000 -18000 1 CDT}
    {1478415600 -21600 0 CST}
    {1489305600 -18000 1 CDT}
    {1509865200 -21600 0 CST}
    {1520755200 -18000 1 CDT}
    {1541314800 -21600 0 CST}
    {1552204800 -18000 1 CDT}
    {1572764400 -21600 0 CST}
    {1583654400 -18000 1 CDT}
    {1604214000 -21600 0 CST}
    {1615708800 -18000 1 CDT}
    {1636268400 -21600 0 CST}
    {1647158400 -18000 1 CDT}
    {1667718000 -21600 0 CST}
    {1678608000 -18000 1 CDT}
    {1699167600 -21600 0 CST}
    {1710057600 -18000 1 CDT}
    {1730617200 -21600 0 CST}
    {1741507200 -18000 1 CDT}
    {1762066800 -21600 0 CST}
    {1772956800 -18000 1 CDT}
    {1793516400 -21600 0 CST}
    {1805011200 -18000 1 CDT}
    {1825570800 -21600 0 CST}
    {1836460800 -18000 1 CDT}
    {1857020400 -21600 0 CST}
    {1867910400 -18000 1 CDT}
    {1888470000 -21600 0 CST}
    {1899360000 -18000 1 CDT}
    {1919919600 -21600 0 CST}
    {1930809600 -18000 1 CDT}
    {1951369200 -21600 0 CST}
    {1962864000 -18000 1 CDT}
    {1983423600 -21600 0 CST}
    {1994313600 -18000 1 CDT}
    {2014873200 -21600 0 CST}
    {2025763200 -18000 1 CDT}
    {2046322800 -21600 0 CST}
    {2057212800 -18000 1 CDT}
    {2077772400 -21600 0 CST}
    {2088662400 -18000 1 CDT}
    {2109222000 -21600 0 CST}
    {2120112000 -18000 1 CDT}
    {2140671600 -21600 0 CST}
    {2152166400 -18000 1 CDT}
    {2172726000 -21600 0 CST}
    {2183616000 -18000 1 CDT}
    {2204175600 -21600 0 CST}
    {2215065600 -18000 1 CDT}
    {2235625200 -21600 0 CST}
    {2246515200 -18000 1 CDT}
    {2267074800 -21600 0 CST}
    {2277964800 -18000 1 CDT}
    {2298524400 -21600 0 CST}
    {2309414400 -18000 1 CDT}
    {2329974000 -21600 0 CST}
    {2341468800 -18000 1 CDT}
    {2362028400 -21600 0 CST}
    {2372918400 -18000 1 CDT}
    {2393478000 -21600 0 CST}
    {2404368000 -18000 1 CDT}
    {2424927600 -21600 0 CST}
    {2435817600 -18000 1 CDT}
    {2456377200 -21600 0 CST}
    {2467267200 -18000 1 CDT}
    {2487826800 -21600 0 CST}
    {2499321600 -18000 1 CDT}
    {2519881200 -21600 0 CST}
    {2530771200 -18000 1 CDT}
    {2551330800 -21600 0 CST}
    {2562220800 -18000 1 CDT}
    {2582780400 -21600 0 CST}
    {2593670400 -18000 1 CDT}
    {2614230000 -21600 0 CST}
    {2625120000 -18000 1 CDT}
    {2645679600 -21600 0 CST}
    {2656569600 -18000 1 CDT}
    {2677129200 -21600 0 CST}
    {2688624000 -18000 1 CDT}
    {2709183600 -21600 0 CST}
    {2720073600 -18000 1 CDT}
    {2740633200 -21600 0 CST}
    {2751523200 -18000 1 CDT}
    {2772082800 -21600 0 CST}
    {2782972800 -18000 1 CDT}
    {2803532400 -21600 0 CST}
    {2814422400 -18000 1 CDT}
    {2834982000 -21600 0 CST}
    {2846476800 -18000 1 CDT}
    {2867036400 -21600 0 CST}
    {2877926400 -18000 1 CDT}
    {2898486000 -21600 0 CST}
    {2909376000 -18000 1 CDT}
    {2929935600 -21600 0 CST}
    {2940825600 -18000 1 CDT}
    {2961385200 -21600 0 CST}
    {2972275200 -18000 1 CDT}
    {2992834800 -21600 0 CST}
    {3003724800 -18000 1 CDT}
    {3024284400 -21600 0 CST}
    {3035779200 -18000 1 CDT}
    {3056338800 -21600 0 CST}
    {3067228800 -18000 1 CDT}
    {3087788400 -21600 0 CST}
    {3098678400 -18000 1 CDT}
    {3119238000 -21600 0 CST}
    {3130128000 -18000 1 CDT}
    {3150687600 -21600 0 CST}
    {3161577600 -18000 1 CDT}
    {3182137200 -21600 0 CST}
    {3193027200 -18000 1 CDT}
    {3213586800 -21600 0 CST}
    {3225081600 -18000 1 CDT}
    {3245641200 -21600 0 CST}
    {3256531200 -18000 1 CDT}
    {3277090800 -21600 0 CST}
    {3287980800 -18000 1 CDT}
    {3308540400 -21600 0 CST}
    {3319430400 -18000 1 CDT}
    {3339990000 -21600 0 CST}
    {3350880000 -18000 1 CDT}
    {3371439600 -21600 0 CST}
    {3382934400 -18000 1 CDT}
    {3403494000 -21600 0 CST}
    {3414384000 -18000 1 CDT}
    {3434943600 -21600 0 CST}
    {3445833600 -18000 1 CDT}
    {3466393200 -21600 0 CST}
    {3477283200 -18000 1 CDT}
    {3497842800 -21600 0 CST}
    {3508732800 -18000 1 CDT}
    {3529292400 -21600 0 CST}
    {3540182400 -18000 1 CDT}
    {3560742000 -21600 0 CST}
    {3572236800 -18000 1 CDT}
    {3592796400 -21600 0 CST}
    {3603686400 -18000 1 CDT}
    {3624246000 -21600 0 CST}
    {3635136000 -18000 1 CDT}
    {3655695600 -21600 0 CST}
    {3666585600 -18000 1 CDT}
    {3687145200 -21600 0 CST}
    {3698035200 -18000 1 CDT}
    {3718594800 -21600 0 CST}
    {3730089600 -18000 1 CDT}
    {3750649200 -21600 0 CST}
    {3761539200 -18000 1 CDT}
    {3782098800 -21600 0 CST}
    {3792988800 -18000 1 CDT}
    {3813548400 -21600 0 CST}
    {3824438400 -18000 1 CDT}
    {3844998000 -21600 0 CST}
    {3855888000 -18000 1 CDT}
    {3876447600 -21600 0 CST}
    {3887337600 -18000 1 CDT}
    {3907897200 -21600 0 CST}
    {3919392000 -18000 1 CDT}
    {3939951600 -21600 0 CST}
    {3950841600 -18000 1 CDT}
    {3971401200 -21600 0 CST}
    {3982291200 -18000 1 CDT}
    {4002850800 -21600 0 CST}
    {4013740800 -18000 1 CDT}
    {4034300400 -21600 0 CST}
    {4045190400 -18000 1 CDT}
    {4065750000 -21600 0 CST}
    {4076640000 -18000 1 CDT}
    {4097199600 -21600 0 CST}
}

Changes to library/tzdata/America/Resolute.

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
    {1067151600 -21600 0 CST}
    {1081065600 -18000 1 CDT}
    {1099206000 -21600 0 CST}
    {1112515200 -18000 1 CDT}
    {1130655600 -21600 0 CST}
    {1143964800 -18000 1 CDT}
    {1162108800 -18000 0 EST}
    {1162710000 -18000 0 EST}
    {1173596400 -18000 0 CDT}
    {1194159600 -18000 0 EST}
    {1205046000 -18000 0 CDT}
    {1225609200 -18000 0 EST}
    {1236495600 -18000 0 CDT}
    {1257058800 -18000 0 EST}
    {1268550000 -18000 0 CDT}
    {1289113200 -18000 0 EST}
    {1299999600 -18000 0 CDT}
    {1320562800 -18000 0 EST}
    {1331449200 -18000 0 CDT}
    {1352012400 -18000 0 EST}
    {1362898800 -18000 0 CDT}
    {1383462000 -18000 0 EST}
    {1394348400 -18000 0 CDT}
    {1414911600 -18000 0 EST}
    {1425798000 -18000 0 CDT}
    {1446361200 -18000 0 EST}
    {1457852400 -18000 0 CDT}
    {1478415600 -18000 0 EST}
    {1489302000 -18000 0 CDT}
    {1509865200 -18000 0 EST}
    {1520751600 -18000 0 CDT}


    {1541314800 -18000 0 EST}
    {1552201200 -18000 0 CDT}
    {1572764400 -18000 0 EST}
    {1583650800 -18000 0 CDT}
    {1604214000 -18000 0 EST}
    {1615705200 -18000 0 CDT}
    {1636268400 -18000 0 EST}
    {1647154800 -18000 0 CDT}
    {1667718000 -18000 0 EST}
    {1678604400 -18000 0 CDT}
    {1699167600 -18000 0 EST}
    {1710054000 -18000 0 CDT}
    {1730617200 -18000 0 EST}
    {1741503600 -18000 0 CDT}
    {1762066800 -18000 0 EST}
    {1772953200 -18000 0 CDT}
    {1793516400 -18000 0 EST}
    {1805007600 -18000 0 CDT}
    {1825570800 -18000 0 EST}
    {1836457200 -18000 0 CDT}
    {1857020400 -18000 0 EST}
    {1867906800 -18000 0 CDT}
    {1888470000 -18000 0 EST}
    {1899356400 -18000 0 CDT}
    {1919919600 -18000 0 EST}
    {1930806000 -18000 0 CDT}
    {1951369200 -18000 0 EST}
    {1962860400 -18000 0 CDT}
    {1983423600 -18000 0 EST}
    {1994310000 -18000 0 CDT}
    {2014873200 -18000 0 EST}
    {2025759600 -18000 0 CDT}
    {2046322800 -18000 0 EST}
    {2057209200 -18000 0 CDT}
    {2077772400 -18000 0 EST}
    {2088658800 -18000 0 CDT}
    {2109222000 -18000 0 EST}
    {2120108400 -18000 0 CDT}
    {2140671600 -18000 0 EST}
    {2152162800 -18000 0 CDT}
    {2172726000 -18000 0 EST}
    {2183612400 -18000 0 CDT}
    {2204175600 -18000 0 EST}
    {2215062000 -18000 0 CDT}
    {2235625200 -18000 0 EST}
    {2246511600 -18000 0 CDT}
    {2267074800 -18000 0 EST}
    {2277961200 -18000 0 CDT}
    {2298524400 -18000 0 EST}
    {2309410800 -18000 0 CDT}
    {2329974000 -18000 0 EST}
    {2341465200 -18000 0 CDT}
    {2362028400 -18000 0 EST}
    {2372914800 -18000 0 CDT}
    {2393478000 -18000 0 EST}
    {2404364400 -18000 0 CDT}
    {2424927600 -18000 0 EST}
    {2435814000 -18000 0 CDT}
    {2456377200 -18000 0 EST}
    {2467263600 -18000 0 CDT}
    {2487826800 -18000 0 EST}
    {2499318000 -18000 0 CDT}
    {2519881200 -18000 0 EST}
    {2530767600 -18000 0 CDT}
    {2551330800 -18000 0 EST}
    {2562217200 -18000 0 CDT}
    {2582780400 -18000 0 EST}
    {2593666800 -18000 0 CDT}
    {2614230000 -18000 0 EST}
    {2625116400 -18000 0 CDT}


    {2645679600 -18000 0 EST}
    {2656566000 -18000 0 CDT}
    {2677129200 -18000 0 EST}
    {2688620400 -18000 0 CDT}
    {2709183600 -18000 0 EST}
    {2720070000 -18000 0 CDT}
    {2740633200 -18000 0 EST}
    {2751519600 -18000 0 CDT}
    {2772082800 -18000 0 EST}
    {2782969200 -18000 0 CDT}
    {2803532400 -18000 0 EST}
    {2814418800 -18000 0 CDT}
    {2834982000 -18000 0 EST}
    {2846473200 -18000 0 CDT}
    {2867036400 -18000 0 EST}
    {2877922800 -18000 0 CDT}
    {2898486000 -18000 0 EST}
    {2909372400 -18000 0 CDT}
    {2929935600 -18000 0 EST}
    {2940822000 -18000 0 CDT}

    {2961385200 -18000 0 EST}
    {2972271600 -18000 0 CDT}
    {2992834800 -18000 0 EST}
    {3003721200 -18000 0 CDT}
    {3024284400 -18000 0 EST}
    {3035775600 -18000 0 CDT}
    {3056338800 -18000 0 EST}
    {3067225200 -18000 0 CDT}
    {3087788400 -18000 0 EST}
    {3098674800 -18000 0 CDT}
    {3119238000 -18000 0 EST}
    {3130124400 -18000 0 CDT}
    {3150687600 -18000 0 EST}
    {3161574000 -18000 0 CDT}
    {3182137200 -18000 0 EST}
    {3193023600 -18000 0 CDT}
    {3213586800 -18000 0 EST}
    {3225078000 -18000 0 CDT}
    {3245641200 -18000 0 EST}
    {3256527600 -18000 0 CDT}
    {3277090800 -18000 0 EST}
    {3287977200 -18000 0 CDT}
    {3308540400 -18000 0 EST}
    {3319426800 -18000 0 CDT}

    {3339990000 -18000 0 EST}
    {3350876400 -18000 0 CDT}
    {3371439600 -18000 0 EST}
    {3382930800 -18000 0 CDT}
    {3403494000 -18000 0 EST}
    {3414380400 -18000 0 CDT}
    {3434943600 -18000 0 EST}
    {3445830000 -18000 0 CDT}
    {3466393200 -18000 0 EST}
    {3477279600 -18000 0 CDT}
    {3497842800 -18000 0 EST}
    {3508729200 -18000 0 CDT}
    {3529292400 -18000 0 EST}
    {3540178800 -18000 0 CDT}
    {3560742000 -18000 0 EST}
    {3572233200 -18000 0 CDT}
    {3592796400 -18000 0 EST}
    {3603682800 -18000 0 CDT}
    {3624246000 -18000 0 EST}
    {3635132400 -18000 0 CDT}
    {3655695600 -18000 0 EST}
    {3666582000 -18000 0 CDT}
    {3687145200 -18000 0 EST}
    {3698031600 -18000 0 CDT}
    {3718594800 -18000 0 EST}
    {3730086000 -18000 0 CDT}
    {3750649200 -18000 0 EST}
    {3761535600 -18000 0 CDT}
    {3782098800 -18000 0 EST}
    {3792985200 -18000 0 CDT}
    {3813548400 -18000 0 EST}
    {3824434800 -18000 0 CDT}
    {3844998000 -18000 0 EST}
    {3855884400 -18000 0 CDT}
    {3876447600 -18000 0 EST}
    {3887334000 -18000 0 CDT}
    {3907897200 -18000 0 EST}
    {3919388400 -18000 0 CDT}
    {3939951600 -18000 0 EST}
    {3950838000 -18000 0 CDT}
    {3971401200 -18000 0 EST}
    {3982287600 -18000 0 CDT}
    {4002850800 -18000 0 EST}
    {4013737200 -18000 0 CDT}
    {4034300400 -18000 0 EST}
    {4045186800 -18000 0 CDT}
    {4065750000 -18000 0 EST}
    {4076636400 -18000 0 CDT}
    {4097199600 -18000 0 EST}
}







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

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
    {1067151600 -21600 0 CST}
    {1081065600 -18000 1 CDT}
    {1099206000 -21600 0 CST}
    {1112515200 -18000 1 CDT}
    {1130655600 -21600 0 CST}
    {1143964800 -18000 1 CDT}
    {1162108800 -18000 0 EST}
    {1173600000 -18000 0 CDT}

    {1194159600 -21600 0 CST}
    {1205049600 -18000 1 CDT}
    {1225609200 -21600 0 CST}
    {1236499200 -18000 1 CDT}
    {1257058800 -21600 0 CST}
    {1268553600 -18000 1 CDT}
    {1289113200 -21600 0 CST}
    {1300003200 -18000 1 CDT}
    {1320562800 -21600 0 CST}
    {1331452800 -18000 1 CDT}
    {1352012400 -21600 0 CST}
    {1362902400 -18000 1 CDT}
    {1383462000 -21600 0 CST}
    {1394352000 -18000 1 CDT}
    {1414911600 -21600 0 CST}
    {1425801600 -18000 1 CDT}
    {1446361200 -21600 0 CST}
    {1457856000 -18000 1 CDT}
    {1478415600 -21600 0 CST}


    {1489305600 -18000 1 CDT}
    {1509865200 -21600 0 CST}
    {1520755200 -18000 1 CDT}
    {1541314800 -21600 0 CST}
    {1552204800 -18000 1 CDT}
    {1572764400 -21600 0 CST}
    {1583654400 -18000 1 CDT}
    {1604214000 -21600 0 CST}
    {1615708800 -18000 1 CDT}
    {1636268400 -21600 0 CST}
    {1647158400 -18000 1 CDT}
    {1667718000 -21600 0 CST}
    {1678608000 -18000 1 CDT}
    {1699167600 -21600 0 CST}
    {1710057600 -18000 1 CDT}
    {1730617200 -21600 0 CST}
    {1741507200 -18000 1 CDT}
    {1762066800 -21600 0 CST}
    {1772956800 -18000 1 CDT}
    {1793516400 -21600 0 CST}
    {1805011200 -18000 1 CDT}
    {1825570800 -21600 0 CST}
    {1836460800 -18000 1 CDT}
    {1857020400 -21600 0 CST}
    {1867910400 -18000 1 CDT}
    {1888470000 -21600 0 CST}
    {1899360000 -18000 1 CDT}
    {1919919600 -21600 0 CST}
    {1930809600 -18000 1 CDT}
    {1951369200 -21600 0 CST}
    {1962864000 -18000 1 CDT}
    {1983423600 -21600 0 CST}
    {1994313600 -18000 1 CDT}
    {2014873200 -21600 0 CST}
    {2025763200 -18000 1 CDT}
    {2046322800 -21600 0 CST}
    {2057212800 -18000 1 CDT}
    {2077772400 -21600 0 CST}
    {2088662400 -18000 1 CDT}
    {2109222000 -21600 0 CST}
    {2120112000 -18000 1 CDT}
    {2140671600 -21600 0 CST}
    {2152166400 -18000 1 CDT}
    {2172726000 -21600 0 CST}
    {2183616000 -18000 1 CDT}
    {2204175600 -21600 0 CST}
    {2215065600 -18000 1 CDT}
    {2235625200 -21600 0 CST}
    {2246515200 -18000 1 CDT}
    {2267074800 -21600 0 CST}
    {2277964800 -18000 1 CDT}
    {2298524400 -21600 0 CST}
    {2309414400 -18000 1 CDT}
    {2329974000 -21600 0 CST}
    {2341468800 -18000 1 CDT}
    {2362028400 -21600 0 CST}
    {2372918400 -18000 1 CDT}
    {2393478000 -21600 0 CST}
    {2404368000 -18000 1 CDT}
    {2424927600 -21600 0 CST}
    {2435817600 -18000 1 CDT}
    {2456377200 -21600 0 CST}
    {2467267200 -18000 1 CDT}
    {2487826800 -21600 0 CST}
    {2499321600 -18000 1 CDT}
    {2519881200 -21600 0 CST}
    {2530771200 -18000 1 CDT}
    {2551330800 -21600 0 CST}
    {2562220800 -18000 1 CDT}
    {2582780400 -21600 0 CST}


    {2593670400 -18000 1 CDT}
    {2614230000 -21600 0 CST}
    {2625120000 -18000 1 CDT}
    {2645679600 -21600 0 CST}
    {2656569600 -18000 1 CDT}
    {2677129200 -21600 0 CST}
    {2688624000 -18000 1 CDT}
    {2709183600 -21600 0 CST}
    {2720073600 -18000 1 CDT}
    {2740633200 -21600 0 CST}
    {2751523200 -18000 1 CDT}
    {2772082800 -21600 0 CST}
    {2782972800 -18000 1 CDT}
    {2803532400 -21600 0 CST}
    {2814422400 -18000 1 CDT}
    {2834982000 -21600 0 CST}
    {2846476800 -18000 1 CDT}
    {2867036400 -21600 0 CST}
    {2877926400 -18000 1 CDT}
    {2898486000 -21600 0 CST}
    {2909376000 -18000 1 CDT}
    {2929935600 -21600 0 CST}
    {2940825600 -18000 1 CDT}
    {2961385200 -21600 0 CST}
    {2972275200 -18000 1 CDT}

    {2992834800 -21600 0 CST}
    {3003724800 -18000 1 CDT}
    {3024284400 -21600 0 CST}
    {3035779200 -18000 1 CDT}
    {3056338800 -21600 0 CST}
    {3067228800 -18000 1 CDT}
    {3087788400 -21600 0 CST}
    {3098678400 -18000 1 CDT}
    {3119238000 -21600 0 CST}
    {3130128000 -18000 1 CDT}
    {3150687600 -21600 0 CST}
    {3161577600 -18000 1 CDT}
    {3182137200 -21600 0 CST}
    {3193027200 -18000 1 CDT}
    {3213586800 -21600 0 CST}
    {3225081600 -18000 1 CDT}
    {3245641200 -21600 0 CST}
    {3256531200 -18000 1 CDT}
    {3277090800 -21600 0 CST}
    {3287980800 -18000 1 CDT}
    {3308540400 -21600 0 CST}
    {3319430400 -18000 1 CDT}
    {3339990000 -21600 0 CST}
    {3350880000 -18000 1 CDT}

    {3371439600 -21600 0 CST}
    {3382934400 -18000 1 CDT}
    {3403494000 -21600 0 CST}
    {3414384000 -18000 1 CDT}
    {3434943600 -21600 0 CST}
    {3445833600 -18000 1 CDT}
    {3466393200 -21600 0 CST}
    {3477283200 -18000 1 CDT}
    {3497842800 -21600 0 CST}
    {3508732800 -18000 1 CDT}
    {3529292400 -21600 0 CST}
    {3540182400 -18000 1 CDT}
    {3560742000 -21600 0 CST}
    {3572236800 -18000 1 CDT}
    {3592796400 -21600 0 CST}
    {3603686400 -18000 1 CDT}
    {3624246000 -21600 0 CST}
    {3635136000 -18000 1 CDT}
    {3655695600 -21600 0 CST}
    {3666585600 -18000 1 CDT}
    {3687145200 -21600 0 CST}
    {3698035200 -18000 1 CDT}
    {3718594800 -21600 0 CST}
    {3730089600 -18000 1 CDT}
    {3750649200 -21600 0 CST}
    {3761539200 -18000 1 CDT}
    {3782098800 -21600 0 CST}
    {3792988800 -18000 1 CDT}
    {3813548400 -21600 0 CST}
    {3824438400 -18000 1 CDT}
    {3844998000 -21600 0 CST}
    {3855888000 -18000 1 CDT}
    {3876447600 -21600 0 CST}
    {3887337600 -18000 1 CDT}
    {3907897200 -21600 0 CST}
    {3919392000 -18000 1 CDT}
    {3939951600 -21600 0 CST}
    {3950841600 -18000 1 CDT}
    {3971401200 -21600 0 CST}
    {3982291200 -18000 1 CDT}
    {4002850800 -21600 0 CST}
    {4013740800 -18000 1 CDT}
    {4034300400 -21600 0 CST}
    {4045190400 -18000 1 CDT}
    {4065750000 -21600 0 CST}
    {4076640000 -18000 1 CDT}
    {4097199600 -21600 0 CST}
}

Changes to library/tzdata/America/Santiago.

106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
    {1192334400 -10800 1 CLST}
    {1206846000 -14400 0 CLT}
    {1223784000 -10800 1 CLST}
    {1237086000 -14400 0 CLT}
    {1255233600 -10800 1 CLST}
    {1270350000 -14400 0 CLT}
    {1286683200 -10800 1 CLST}
    {1301799600 -14400 0 CLT}
    {1318132800 -10800 1 CLST}
    {1331434800 -14400 0 CLT}
    {1350187200 -10800 1 CLST}
    {1362884400 -14400 0 CLT}
    {1381636800 -10800 1 CLST}
    {1394334000 -14400 0 CLT}
    {1413086400 -10800 1 CLST}
    {1426388400 -14400 0 CLT}







|
|







106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
    {1192334400 -10800 1 CLST}
    {1206846000 -14400 0 CLT}
    {1223784000 -10800 1 CLST}
    {1237086000 -14400 0 CLT}
    {1255233600 -10800 1 CLST}
    {1270350000 -14400 0 CLT}
    {1286683200 -10800 1 CLST}
    {1304823600 -14400 0 CLT}
    {1313899200 -10800 1 CLST}
    {1331434800 -14400 0 CLT}
    {1350187200 -10800 1 CLST}
    {1362884400 -14400 0 CLT}
    {1381636800 -10800 1 CLST}
    {1394334000 -14400 0 CLT}
    {1413086400 -10800 1 CLST}
    {1426388400 -14400 0 CLT}

Added library/tzdata/America/Sitka.







































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
# created by tools/tclZIC.tcl - do not edit

set TZData(:America/Sitka) {
    {-9223372036854775808 -53927 0 LMT}
    {-3225258073 -32473 0 LMT}
    {-2188954727 -28800 0 PST}
    {-883584000 -28800 0 PST}
    {-880207200 -25200 1 PWT}
    {-769395600 -25200 1 PPT}
    {-765385200 -28800 0 PST}
    {-757353600 -28800 0 PST}
    {-31507200 -28800 0 PST}
    {-21477600 -25200 1 PDT}
    {-5756400 -28800 0 PST}
    {9972000 -25200 1 PDT}
    {25693200 -28800 0 PST}
    {41421600 -25200 1 PDT}
    {57747600 -28800 0 PST}
    {73476000 -25200 1 PDT}
    {89197200 -28800 0 PST}
    {104925600 -25200 1 PDT}
    {120646800 -28800 0 PST}
    {126698400 -25200 1 PDT}
    {152096400 -28800 0 PST}
    {162381600 -25200 1 PDT}
    {183546000 -28800 0 PST}
    {199274400 -25200 1 PDT}
    {215600400 -28800 0 PST}
    {230724000 -25200 1 PDT}
    {247050000 -28800 0 PST}
    {262778400 -25200 1 PDT}
    {278499600 -28800 0 PST}
    {294228000 -25200 1 PDT}
    {309949200 -28800 0 PST}
    {325677600 -25200 1 PDT}
    {341398800 -28800 0 PST}
    {357127200 -25200 1 PDT}
    {372848400 -28800 0 PST}
    {388576800 -25200 1 PDT}
    {404902800 -28800 0 PST}
    {420026400 -25200 1 PDT}
    {439030800 -32400 0 AKST}
    {452084400 -28800 1 AKDT}
    {467805600 -32400 0 AKST}
    {483534000 -28800 1 AKDT}
    {499255200 -32400 0 AKST}
    {514983600 -28800 1 AKDT}
    {530704800 -32400 0 AKST}
    {544618800 -28800 1 AKDT}
    {562154400 -32400 0 AKST}
    {576068400 -28800 1 AKDT}
    {594208800 -32400 0 AKST}
    {607518000 -28800 1 AKDT}
    {625658400 -32400 0 AKST}
    {638967600 -28800 1 AKDT}
    {657108000 -32400 0 AKST}
    {671022000 -28800 1 AKDT}
    {688557600 -32400 0 AKST}
    {702471600 -28800 1 AKDT}
    {720007200 -32400 0 AKST}
    {733921200 -28800 1 AKDT}
    {752061600 -32400 0 AKST}
    {765370800 -28800 1 AKDT}
    {783511200 -32400 0 AKST}
    {796820400 -28800 1 AKDT}
    {814960800 -32400 0 AKST}
    {828874800 -28800 1 AKDT}
    {846410400 -32400 0 AKST}
    {860324400 -28800 1 AKDT}
    {877860000 -32400 0 AKST}
    {891774000 -28800 1 AKDT}
    {909309600 -32400 0 AKST}
    {923223600 -28800 1 AKDT}
    {941364000 -32400 0 AKST}
    {954673200 -28800 1 AKDT}
    {972813600 -32400 0 AKST}
    {986122800 -28800 1 AKDT}
    {1004263200 -32400 0 AKST}
    {1018177200 -28800 1 AKDT}
    {1035712800 -32400 0 AKST}
    {1049626800 -28800 1 AKDT}
    {1067162400 -32400 0 AKST}
    {1081076400 -28800 1 AKDT}
    {1099216800 -32400 0 AKST}
    {1112526000 -28800 1 AKDT}
    {1130666400 -32400 0 AKST}
    {1143975600 -28800 1 AKDT}
    {1162116000 -32400 0 AKST}
    {1173610800 -28800 1 AKDT}
    {1194170400 -32400 0 AKST}
    {1205060400 -28800 1 AKDT}
    {1225620000 -32400 0 AKST}
    {1236510000 -28800 1 AKDT}
    {1257069600 -32400 0 AKST}
    {1268564400 -28800 1 AKDT}
    {1289124000 -32400 0 AKST}
    {1300014000 -28800 1 AKDT}
    {1320573600 -32400 0 AKST}
    {1331463600 -28800 1 AKDT}
    {1352023200 -32400 0 AKST}
    {1362913200 -28800 1 AKDT}
    {1383472800 -32400 0 AKST}
    {1394362800 -28800 1 AKDT}
    {1414922400 -32400 0 AKST}
    {1425812400 -28800 1 AKDT}
    {1446372000 -32400 0 AKST}
    {1457866800 -28800 1 AKDT}
    {1478426400 -32400 0 AKST}
    {1489316400 -28800 1 AKDT}
    {1509876000 -32400 0 AKST}
    {1520766000 -28800 1 AKDT}
    {1541325600 -32400 0 AKST}
    {1552215600 -28800 1 AKDT}
    {1572775200 -32400 0 AKST}
    {1583665200 -28800 1 AKDT}
    {1604224800 -32400 0 AKST}
    {1615719600 -28800 1 AKDT}
    {1636279200 -32400 0 AKST}
    {1647169200 -28800 1 AKDT}
    {1667728800 -32400 0 AKST}
    {1678618800 -28800 1 AKDT}
    {1699178400 -32400 0 AKST}
    {1710068400 -28800 1 AKDT}
    {1730628000 -32400 0 AKST}
    {1741518000 -28800 1 AKDT}
    {1762077600 -32400 0 AKST}
    {1772967600 -28800 1 AKDT}
    {1793527200 -32400 0 AKST}
    {1805022000 -28800 1 AKDT}
    {1825581600 -32400 0 AKST}
    {1836471600 -28800 1 AKDT}
    {1857031200 -32400 0 AKST}
    {1867921200 -28800 1 AKDT}
    {1888480800 -32400 0 AKST}
    {1899370800 -28800 1 AKDT}
    {1919930400 -32400 0 AKST}
    {1930820400 -28800 1 AKDT}
    {1951380000 -32400 0 AKST}
    {1962874800 -28800 1 AKDT}
    {1983434400 -32400 0 AKST}
    {1994324400 -28800 1 AKDT}
    {2014884000 -32400 0 AKST}
    {2025774000 -28800 1 AKDT}
    {2046333600 -32400 0 AKST}
    {2057223600 -28800 1 AKDT}
    {2077783200 -32400 0 AKST}
    {2088673200 -28800 1 AKDT}
    {2109232800 -32400 0 AKST}
    {2120122800 -28800 1 AKDT}
    {2140682400 -32400 0 AKST}
    {2152177200 -28800 1 AKDT}
    {2172736800 -32400 0 AKST}
    {2183626800 -28800 1 AKDT}
    {2204186400 -32400 0 AKST}
    {2215076400 -28800 1 AKDT}
    {2235636000 -32400 0 AKST}
    {2246526000 -28800 1 AKDT}
    {2267085600 -32400 0 AKST}
    {2277975600 -28800 1 AKDT}
    {2298535200 -32400 0 AKST}
    {2309425200 -28800 1 AKDT}
    {2329984800 -32400 0 AKST}
    {2341479600 -28800 1 AKDT}
    {2362039200 -32400 0 AKST}
    {2372929200 -28800 1 AKDT}
    {2393488800 -32400 0 AKST}
    {2404378800 -28800 1 AKDT}
    {2424938400 -32400 0 AKST}
    {2435828400 -28800 1 AKDT}
    {2456388000 -32400 0 AKST}
    {2467278000 -28800 1 AKDT}
    {2487837600 -32400 0 AKST}
    {2499332400 -28800 1 AKDT}
    {2519892000 -32400 0 AKST}
    {2530782000 -28800 1 AKDT}
    {2551341600 -32400 0 AKST}
    {2562231600 -28800 1 AKDT}
    {2582791200 -32400 0 AKST}
    {2593681200 -28800 1 AKDT}
    {2614240800 -32400 0 AKST}
    {2625130800 -28800 1 AKDT}
    {2645690400 -32400 0 AKST}
    {2656580400 -28800 1 AKDT}
    {2677140000 -32400 0 AKST}
    {2688634800 -28800 1 AKDT}
    {2709194400 -32400 0 AKST}
    {2720084400 -28800 1 AKDT}
    {2740644000 -32400 0 AKST}
    {2751534000 -28800 1 AKDT}
    {2772093600 -32400 0 AKST}
    {2782983600 -28800 1 AKDT}
    {2803543200 -32400 0 AKST}
    {2814433200 -28800 1 AKDT}
    {2834992800 -32400 0 AKST}
    {2846487600 -28800 1 AKDT}
    {2867047200 -32400 0 AKST}
    {2877937200 -28800 1 AKDT}
    {2898496800 -32400 0 AKST}
    {2909386800 -28800 1 AKDT}
    {2929946400 -32400 0 AKST}
    {2940836400 -28800 1 AKDT}
    {2961396000 -32400 0 AKST}
    {2972286000 -28800 1 AKDT}
    {2992845600 -32400 0 AKST}
    {3003735600 -28800 1 AKDT}
    {3024295200 -32400 0 AKST}
    {3035790000 -28800 1 AKDT}
    {3056349600 -32400 0 AKST}
    {3067239600 -28800 1 AKDT}
    {3087799200 -32400 0 AKST}
    {3098689200 -28800 1 AKDT}
    {3119248800 -32400 0 AKST}
    {3130138800 -28800 1 AKDT}
    {3150698400 -32400 0 AKST}
    {3161588400 -28800 1 AKDT}
    {3182148000 -32400 0 AKST}
    {3193038000 -28800 1 AKDT}
    {3213597600 -32400 0 AKST}
    {3225092400 -28800 1 AKDT}
    {3245652000 -32400 0 AKST}
    {3256542000 -28800 1 AKDT}
    {3277101600 -32400 0 AKST}
    {3287991600 -28800 1 AKDT}
    {3308551200 -32400 0 AKST}
    {3319441200 -28800 1 AKDT}
    {3340000800 -32400 0 AKST}
    {3350890800 -28800 1 AKDT}
    {3371450400 -32400 0 AKST}
    {3382945200 -28800 1 AKDT}
    {3403504800 -32400 0 AKST}
    {3414394800 -28800 1 AKDT}
    {3434954400 -32400 0 AKST}
    {3445844400 -28800 1 AKDT}
    {3466404000 -32400 0 AKST}
    {3477294000 -28800 1 AKDT}
    {3497853600 -32400 0 AKST}
    {3508743600 -28800 1 AKDT}
    {3529303200 -32400 0 AKST}
    {3540193200 -28800 1 AKDT}
    {3560752800 -32400 0 AKST}
    {3572247600 -28800 1 AKDT}
    {3592807200 -32400 0 AKST}
    {3603697200 -28800 1 AKDT}
    {3624256800 -32400 0 AKST}
    {3635146800 -28800 1 AKDT}
    {3655706400 -32400 0 AKST}
    {3666596400 -28800 1 AKDT}
    {3687156000 -32400 0 AKST}
    {3698046000 -28800 1 AKDT}
    {3718605600 -32400 0 AKST}
    {3730100400 -28800 1 AKDT}
    {3750660000 -32400 0 AKST}
    {3761550000 -28800 1 AKDT}
    {3782109600 -32400 0 AKST}
    {3792999600 -28800 1 AKDT}
    {3813559200 -32400 0 AKST}
    {3824449200 -28800 1 AKDT}
    {3845008800 -32400 0 AKST}
    {3855898800 -28800 1 AKDT}
    {3876458400 -32400 0 AKST}
    {3887348400 -28800 1 AKDT}
    {3907908000 -32400 0 AKST}
    {3919402800 -28800 1 AKDT}
    {3939962400 -32400 0 AKST}
    {3950852400 -28800 1 AKDT}
    {3971412000 -32400 0 AKST}
    {3982302000 -28800 1 AKDT}
    {4002861600 -32400 0 AKST}
    {4013751600 -28800 1 AKDT}
    {4034311200 -32400 0 AKST}
    {4045201200 -28800 1 AKDT}
    {4065760800 -32400 0 AKST}
    {4076650800 -28800 1 AKDT}
    {4097210400 -32400 0 AKST}
}

Changes to library/tzdata/America/St_Johns.

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
    {1205033460 -9000 1 NDT}
    {1225593060 -12600 0 NST}
    {1236483060 -9000 1 NDT}
    {1257042660 -12600 0 NST}
    {1268537460 -9000 1 NDT}
    {1289097060 -12600 0 NST}
    {1299987060 -9000 1 NDT}

    {1320546660 -12600 0 NST}
    {1331436660 -9000 1 NDT}
    {1351996260 -12600 0 NST}
    {1362886260 -9000 1 NDT}
    {1383445860 -12600 0 NST}
    {1394335860 -9000 1 NDT}
    {1414895460 -12600 0 NST}
    {1425785460 -9000 1 NDT}
    {1446345060 -12600 0 NST}
    {1457839860 -9000 1 NDT}
    {1478399460 -12600 0 NST}
    {1489289460 -9000 1 NDT}
    {1509849060 -12600 0 NST}
    {1520739060 -9000 1 NDT}
    {1541298660 -12600 0 NST}
    {1552188660 -9000 1 NDT}
    {1572748260 -12600 0 NST}
    {1583638260 -9000 1 NDT}
    {1604197860 -12600 0 NST}
    {1615692660 -9000 1 NDT}
    {1636252260 -12600 0 NST}
    {1647142260 -9000 1 NDT}
    {1667701860 -12600 0 NST}
    {1678591860 -9000 1 NDT}
    {1699151460 -12600 0 NST}
    {1710041460 -9000 1 NDT}
    {1730601060 -12600 0 NST}
    {1741491060 -9000 1 NDT}
    {1762050660 -12600 0 NST}
    {1772940660 -9000 1 NDT}
    {1793500260 -12600 0 NST}
    {1804995060 -9000 1 NDT}
    {1825554660 -12600 0 NST}
    {1836444660 -9000 1 NDT}
    {1857004260 -12600 0 NST}
    {1867894260 -9000 1 NDT}
    {1888453860 -12600 0 NST}
    {1899343860 -9000 1 NDT}
    {1919903460 -12600 0 NST}
    {1930793460 -9000 1 NDT}
    {1951353060 -12600 0 NST}
    {1962847860 -9000 1 NDT}
    {1983407460 -12600 0 NST}
    {1994297460 -9000 1 NDT}
    {2014857060 -12600 0 NST}
    {2025747060 -9000 1 NDT}
    {2046306660 -12600 0 NST}
    {2057196660 -9000 1 NDT}
    {2077756260 -12600 0 NST}
    {2088646260 -9000 1 NDT}
    {2109205860 -12600 0 NST}
    {2120095860 -9000 1 NDT}
    {2140655460 -12600 0 NST}
    {2152150260 -9000 1 NDT}
    {2172709860 -12600 0 NST}
    {2183599860 -9000 1 NDT}
    {2204159460 -12600 0 NST}
    {2215049460 -9000 1 NDT}
    {2235609060 -12600 0 NST}
    {2246499060 -9000 1 NDT}
    {2267058660 -12600 0 NST}
    {2277948660 -9000 1 NDT}
    {2298508260 -12600 0 NST}
    {2309398260 -9000 1 NDT}
    {2329957860 -12600 0 NST}
    {2341452660 -9000 1 NDT}
    {2362012260 -12600 0 NST}
    {2372902260 -9000 1 NDT}
    {2393461860 -12600 0 NST}
    {2404351860 -9000 1 NDT}
    {2424911460 -12600 0 NST}
    {2435801460 -9000 1 NDT}
    {2456361060 -12600 0 NST}
    {2467251060 -9000 1 NDT}
    {2487810660 -12600 0 NST}
    {2499305460 -9000 1 NDT}
    {2519865060 -12600 0 NST}
    {2530755060 -9000 1 NDT}
    {2551314660 -12600 0 NST}
    {2562204660 -9000 1 NDT}
    {2582764260 -12600 0 NST}
    {2593654260 -9000 1 NDT}
    {2614213860 -12600 0 NST}
    {2625103860 -9000 1 NDT}
    {2645663460 -12600 0 NST}
    {2656553460 -9000 1 NDT}
    {2677113060 -12600 0 NST}
    {2688607860 -9000 1 NDT}
    {2709167460 -12600 0 NST}
    {2720057460 -9000 1 NDT}
    {2740617060 -12600 0 NST}
    {2751507060 -9000 1 NDT}
    {2772066660 -12600 0 NST}
    {2782956660 -9000 1 NDT}
    {2803516260 -12600 0 NST}
    {2814406260 -9000 1 NDT}
    {2834965860 -12600 0 NST}
    {2846460660 -9000 1 NDT}
    {2867020260 -12600 0 NST}
    {2877910260 -9000 1 NDT}
    {2898469860 -12600 0 NST}
    {2909359860 -9000 1 NDT}
    {2929919460 -12600 0 NST}
    {2940809460 -9000 1 NDT}
    {2961369060 -12600 0 NST}
    {2972259060 -9000 1 NDT}
    {2992818660 -12600 0 NST}
    {3003708660 -9000 1 NDT}
    {3024268260 -12600 0 NST}
    {3035763060 -9000 1 NDT}
    {3056322660 -12600 0 NST}
    {3067212660 -9000 1 NDT}
    {3087772260 -12600 0 NST}
    {3098662260 -9000 1 NDT}
    {3119221860 -12600 0 NST}
    {3130111860 -9000 1 NDT}
    {3150671460 -12600 0 NST}
    {3161561460 -9000 1 NDT}
    {3182121060 -12600 0 NST}
    {3193011060 -9000 1 NDT}
    {3213570660 -12600 0 NST}
    {3225065460 -9000 1 NDT}
    {3245625060 -12600 0 NST}
    {3256515060 -9000 1 NDT}
    {3277074660 -12600 0 NST}
    {3287964660 -9000 1 NDT}
    {3308524260 -12600 0 NST}
    {3319414260 -9000 1 NDT}
    {3339973860 -12600 0 NST}
    {3350863860 -9000 1 NDT}
    {3371423460 -12600 0 NST}
    {3382918260 -9000 1 NDT}
    {3403477860 -12600 0 NST}
    {3414367860 -9000 1 NDT}
    {3434927460 -12600 0 NST}
    {3445817460 -9000 1 NDT}
    {3466377060 -12600 0 NST}
    {3477267060 -9000 1 NDT}
    {3497826660 -12600 0 NST}
    {3508716660 -9000 1 NDT}
    {3529276260 -12600 0 NST}
    {3540166260 -9000 1 NDT}
    {3560725860 -12600 0 NST}
    {3572220660 -9000 1 NDT}
    {3592780260 -12600 0 NST}
    {3603670260 -9000 1 NDT}
    {3624229860 -12600 0 NST}
    {3635119860 -9000 1 NDT}
    {3655679460 -12600 0 NST}
    {3666569460 -9000 1 NDT}
    {3687129060 -12600 0 NST}
    {3698019060 -9000 1 NDT}
    {3718578660 -12600 0 NST}
    {3730073460 -9000 1 NDT}
    {3750633060 -12600 0 NST}
    {3761523060 -9000 1 NDT}
    {3782082660 -12600 0 NST}
    {3792972660 -9000 1 NDT}
    {3813532260 -12600 0 NST}
    {3824422260 -9000 1 NDT}
    {3844981860 -12600 0 NST}
    {3855871860 -9000 1 NDT}
    {3876431460 -12600 0 NST}
    {3887321460 -9000 1 NDT}
    {3907881060 -12600 0 NST}
    {3919375860 -9000 1 NDT}
    {3939935460 -12600 0 NST}
    {3950825460 -9000 1 NDT}
    {3971385060 -12600 0 NST}
    {3982275060 -9000 1 NDT}
    {4002834660 -12600 0 NST}
    {4013724660 -9000 1 NDT}
    {4034284260 -12600 0 NST}
    {4045174260 -9000 1 NDT}
    {4065733860 -12600 0 NST}
    {4076623860 -9000 1 NDT}
    {4097183460 -12600 0 NST}
}







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

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
    {1205033460 -9000 1 NDT}
    {1225593060 -12600 0 NST}
    {1236483060 -9000 1 NDT}
    {1257042660 -12600 0 NST}
    {1268537460 -9000 1 NDT}
    {1289097060 -12600 0 NST}
    {1299987060 -9000 1 NDT}
    {1320114600 -9000 0 NDT}
    {1320553800 -12600 0 NST}
    {1331443800 -9000 1 NDT}
    {1352003400 -12600 0 NST}
    {1362893400 -9000 1 NDT}
    {1383453000 -12600 0 NST}
    {1394343000 -9000 1 NDT}
    {1414902600 -12600 0 NST}
    {1425792600 -9000 1 NDT}
    {1446352200 -12600 0 NST}
    {1457847000 -9000 1 NDT}
    {1478406600 -12600 0 NST}
    {1489296600 -9000 1 NDT}
    {1509856200 -12600 0 NST}
    {1520746200 -9000 1 NDT}
    {1541305800 -12600 0 NST}
    {1552195800 -9000 1 NDT}
    {1572755400 -12600 0 NST}
    {1583645400 -9000 1 NDT}
    {1604205000 -12600 0 NST}
    {1615699800 -9000 1 NDT}
    {1636259400 -12600 0 NST}
    {1647149400 -9000 1 NDT}
    {1667709000 -12600 0 NST}
    {1678599000 -9000 1 NDT}
    {1699158600 -12600 0 NST}
    {1710048600 -9000 1 NDT}
    {1730608200 -12600 0 NST}
    {1741498200 -9000 1 NDT}
    {1762057800 -12600 0 NST}
    {1772947800 -9000 1 NDT}
    {1793507400 -12600 0 NST}
    {1805002200 -9000 1 NDT}
    {1825561800 -12600 0 NST}
    {1836451800 -9000 1 NDT}
    {1857011400 -12600 0 NST}
    {1867901400 -9000 1 NDT}
    {1888461000 -12600 0 NST}
    {1899351000 -9000 1 NDT}
    {1919910600 -12600 0 NST}
    {1930800600 -9000 1 NDT}
    {1951360200 -12600 0 NST}
    {1962855000 -9000 1 NDT}
    {1983414600 -12600 0 NST}
    {1994304600 -9000 1 NDT}
    {2014864200 -12600 0 NST}
    {2025754200 -9000 1 NDT}
    {2046313800 -12600 0 NST}
    {2057203800 -9000 1 NDT}
    {2077763400 -12600 0 NST}
    {2088653400 -9000 1 NDT}
    {2109213000 -12600 0 NST}
    {2120103000 -9000 1 NDT}
    {2140662600 -12600 0 NST}
    {2152157400 -9000 1 NDT}
    {2172717000 -12600 0 NST}
    {2183607000 -9000 1 NDT}
    {2204166600 -12600 0 NST}
    {2215056600 -9000 1 NDT}
    {2235616200 -12600 0 NST}
    {2246506200 -9000 1 NDT}
    {2267065800 -12600 0 NST}
    {2277955800 -9000 1 NDT}
    {2298515400 -12600 0 NST}
    {2309405400 -9000 1 NDT}
    {2329965000 -12600 0 NST}
    {2341459800 -9000 1 NDT}
    {2362019400 -12600 0 NST}
    {2372909400 -9000 1 NDT}
    {2393469000 -12600 0 NST}
    {2404359000 -9000 1 NDT}
    {2424918600 -12600 0 NST}
    {2435808600 -9000 1 NDT}
    {2456368200 -12600 0 NST}
    {2467258200 -9000 1 NDT}
    {2487817800 -12600 0 NST}
    {2499312600 -9000 1 NDT}
    {2519872200 -12600 0 NST}
    {2530762200 -9000 1 NDT}
    {2551321800 -12600 0 NST}
    {2562211800 -9000 1 NDT}
    {2582771400 -12600 0 NST}
    {2593661400 -9000 1 NDT}
    {2614221000 -12600 0 NST}
    {2625111000 -9000 1 NDT}
    {2645670600 -12600 0 NST}
    {2656560600 -9000 1 NDT}
    {2677120200 -12600 0 NST}
    {2688615000 -9000 1 NDT}
    {2709174600 -12600 0 NST}
    {2720064600 -9000 1 NDT}
    {2740624200 -12600 0 NST}
    {2751514200 -9000 1 NDT}
    {2772073800 -12600 0 NST}
    {2782963800 -9000 1 NDT}
    {2803523400 -12600 0 NST}
    {2814413400 -9000 1 NDT}
    {2834973000 -12600 0 NST}
    {2846467800 -9000 1 NDT}
    {2867027400 -12600 0 NST}
    {2877917400 -9000 1 NDT}
    {2898477000 -12600 0 NST}
    {2909367000 -9000 1 NDT}
    {2929926600 -12600 0 NST}
    {2940816600 -9000 1 NDT}
    {2961376200 -12600 0 NST}
    {2972266200 -9000 1 NDT}
    {2992825800 -12600 0 NST}
    {3003715800 -9000 1 NDT}
    {3024275400 -12600 0 NST}
    {3035770200 -9000 1 NDT}
    {3056329800 -12600 0 NST}
    {3067219800 -9000 1 NDT}
    {3087779400 -12600 0 NST}
    {3098669400 -9000 1 NDT}
    {3119229000 -12600 0 NST}
    {3130119000 -9000 1 NDT}
    {3150678600 -12600 0 NST}
    {3161568600 -9000 1 NDT}
    {3182128200 -12600 0 NST}
    {3193018200 -9000 1 NDT}
    {3213577800 -12600 0 NST}
    {3225072600 -9000 1 NDT}
    {3245632200 -12600 0 NST}
    {3256522200 -9000 1 NDT}
    {3277081800 -12600 0 NST}
    {3287971800 -9000 1 NDT}
    {3308531400 -12600 0 NST}
    {3319421400 -9000 1 NDT}
    {3339981000 -12600 0 NST}
    {3350871000 -9000 1 NDT}
    {3371430600 -12600 0 NST}
    {3382925400 -9000 1 NDT}
    {3403485000 -12600 0 NST}
    {3414375000 -9000 1 NDT}
    {3434934600 -12600 0 NST}
    {3445824600 -9000 1 NDT}
    {3466384200 -12600 0 NST}
    {3477274200 -9000 1 NDT}
    {3497833800 -12600 0 NST}
    {3508723800 -9000 1 NDT}
    {3529283400 -12600 0 NST}
    {3540173400 -9000 1 NDT}
    {3560733000 -12600 0 NST}
    {3572227800 -9000 1 NDT}
    {3592787400 -12600 0 NST}
    {3603677400 -9000 1 NDT}
    {3624237000 -12600 0 NST}
    {3635127000 -9000 1 NDT}
    {3655686600 -12600 0 NST}
    {3666576600 -9000 1 NDT}
    {3687136200 -12600 0 NST}
    {3698026200 -9000 1 NDT}
    {3718585800 -12600 0 NST}
    {3730080600 -9000 1 NDT}
    {3750640200 -12600 0 NST}
    {3761530200 -9000 1 NDT}
    {3782089800 -12600 0 NST}
    {3792979800 -9000 1 NDT}
    {3813539400 -12600 0 NST}
    {3824429400 -9000 1 NDT}
    {3844989000 -12600 0 NST}
    {3855879000 -9000 1 NDT}
    {3876438600 -12600 0 NST}
    {3887328600 -9000 1 NDT}
    {3907888200 -12600 0 NST}
    {3919383000 -9000 1 NDT}
    {3939942600 -12600 0 NST}
    {3950832600 -9000 1 NDT}
    {3971392200 -12600 0 NST}
    {3982282200 -9000 1 NDT}
    {4002841800 -12600 0 NST}
    {4013731800 -9000 1 NDT}
    {4034291400 -12600 0 NST}
    {4045181400 -9000 1 NDT}
    {4065741000 -12600 0 NST}
    {4076631000 -9000 1 NDT}
    {4097190600 -12600 0 NST}
}

Changes to library/tzdata/Asia/Anadyr.

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
    {1206799200 46800 1 ANAST}
    {1224943200 43200 0 ANAT}
    {1238248800 46800 1 ANAST}
    {1256392800 43200 0 ANAT}
    {1269698400 39600 0 ANAMMTT}
    {1269702000 43200 1 ANAST}
    {1288450800 39600 0 ANAT}
    {1301151600 43200 1 ANAST}
    {1319900400 39600 0 ANAT}
    {1332601200 43200 1 ANAST}
    {1351350000 39600 0 ANAT}
    {1364655600 43200 1 ANAST}
    {1382799600 39600 0 ANAT}
    {1396105200 43200 1 ANAST}
    {1414249200 39600 0 ANAT}
    {1427554800 43200 1 ANAST}
    {1445698800 39600 0 ANAT}
    {1459004400 43200 1 ANAST}
    {1477753200 39600 0 ANAT}
    {1490454000 43200 1 ANAST}
    {1509202800 39600 0 ANAT}
    {1521903600 43200 1 ANAST}
    {1540652400 39600 0 ANAT}
    {1553958000 43200 1 ANAST}
    {1572102000 39600 0 ANAT}
    {1585407600 43200 1 ANAST}
    {1603551600 39600 0 ANAT}
    {1616857200 43200 1 ANAST}
    {1635606000 39600 0 ANAT}
    {1648306800 43200 1 ANAST}
    {1667055600 39600 0 ANAT}
    {1679756400 43200 1 ANAST}
    {1698505200 39600 0 ANAT}
    {1711810800 43200 1 ANAST}
    {1729954800 39600 0 ANAT}
    {1743260400 43200 1 ANAST}
    {1761404400 39600 0 ANAT}
    {1774710000 43200 1 ANAST}
    {1792854000 39600 0 ANAT}
    {1806159600 43200 1 ANAST}
    {1824908400 39600 0 ANAT}
    {1837609200 43200 1 ANAST}
    {1856358000 39600 0 ANAT}
    {1869058800 43200 1 ANAST}
    {1887807600 39600 0 ANAT}
    {1901113200 43200 1 ANAST}
    {1919257200 39600 0 ANAT}
    {1932562800 43200 1 ANAST}
    {1950706800 39600 0 ANAT}
    {1964012400 43200 1 ANAST}
    {1982761200 39600 0 ANAT}
    {1995462000 43200 1 ANAST}
    {2014210800 39600 0 ANAT}
    {2026911600 43200 1 ANAST}
    {2045660400 39600 0 ANAT}
    {2058361200 43200 1 ANAST}
    {2077110000 39600 0 ANAT}
    {2090415600 43200 1 ANAST}
    {2108559600 39600 0 ANAT}
    {2121865200 43200 1 ANAST}
    {2140009200 39600 0 ANAT}
    {2153314800 43200 1 ANAST}
    {2172063600 39600 0 ANAT}
    {2184764400 43200 1 ANAST}
    {2203513200 39600 0 ANAT}
    {2216214000 43200 1 ANAST}
    {2234962800 39600 0 ANAT}
    {2248268400 43200 1 ANAST}
    {2266412400 39600 0 ANAT}
    {2279718000 43200 1 ANAST}
    {2297862000 39600 0 ANAT}
    {2311167600 43200 1 ANAST}
    {2329311600 39600 0 ANAT}
    {2342617200 43200 1 ANAST}
    {2361366000 39600 0 ANAT}
    {2374066800 43200 1 ANAST}
    {2392815600 39600 0 ANAT}
    {2405516400 43200 1 ANAST}
    {2424265200 39600 0 ANAT}
    {2437570800 43200 1 ANAST}
    {2455714800 39600 0 ANAT}
    {2469020400 43200 1 ANAST}
    {2487164400 39600 0 ANAT}
    {2500470000 43200 1 ANAST}
    {2519218800 39600 0 ANAT}
    {2531919600 43200 1 ANAST}
    {2550668400 39600 0 ANAT}
    {2563369200 43200 1 ANAST}
    {2582118000 39600 0 ANAT}
    {2595423600 43200 1 ANAST}
    {2613567600 39600 0 ANAT}
    {2626873200 43200 1 ANAST}
    {2645017200 39600 0 ANAT}
    {2658322800 43200 1 ANAST}
    {2676466800 39600 0 ANAT}
    {2689772400 43200 1 ANAST}
    {2708521200 39600 0 ANAT}
    {2721222000 43200 1 ANAST}
    {2739970800 39600 0 ANAT}
    {2752671600 43200 1 ANAST}
    {2771420400 39600 0 ANAT}
    {2784726000 43200 1 ANAST}
    {2802870000 39600 0 ANAT}
    {2816175600 43200 1 ANAST}
    {2834319600 39600 0 ANAT}
    {2847625200 43200 1 ANAST}
    {2866374000 39600 0 ANAT}
    {2879074800 43200 1 ANAST}
    {2897823600 39600 0 ANAT}
    {2910524400 43200 1 ANAST}
    {2929273200 39600 0 ANAT}
    {2941974000 43200 1 ANAST}
    {2960722800 39600 0 ANAT}
    {2974028400 43200 1 ANAST}
    {2992172400 39600 0 ANAT}
    {3005478000 43200 1 ANAST}
    {3023622000 39600 0 ANAT}
    {3036927600 43200 1 ANAST}
    {3055676400 39600 0 ANAT}
    {3068377200 43200 1 ANAST}
    {3087126000 39600 0 ANAT}
    {3099826800 43200 1 ANAST}
    {3118575600 39600 0 ANAT}
    {3131881200 43200 1 ANAST}
    {3150025200 39600 0 ANAT}
    {3163330800 43200 1 ANAST}
    {3181474800 39600 0 ANAT}
    {3194780400 43200 1 ANAST}
    {3212924400 39600 0 ANAT}
    {3226230000 43200 1 ANAST}
    {3244978800 39600 0 ANAT}
    {3257679600 43200 1 ANAST}
    {3276428400 39600 0 ANAT}
    {3289129200 43200 1 ANAST}
    {3307878000 39600 0 ANAT}
    {3321183600 43200 1 ANAST}
    {3339327600 39600 0 ANAT}
    {3352633200 43200 1 ANAST}
    {3370777200 39600 0 ANAT}
    {3384082800 43200 1 ANAST}
    {3402831600 39600 0 ANAT}
    {3415532400 43200 1 ANAST}
    {3434281200 39600 0 ANAT}
    {3446982000 43200 1 ANAST}
    {3465730800 39600 0 ANAT}
    {3479036400 43200 1 ANAST}
    {3497180400 39600 0 ANAT}
    {3510486000 43200 1 ANAST}
    {3528630000 39600 0 ANAT}
    {3541935600 43200 1 ANAST}
    {3560079600 39600 0 ANAT}
    {3573385200 43200 1 ANAST}
    {3592134000 39600 0 ANAT}
    {3604834800 43200 1 ANAST}
    {3623583600 39600 0 ANAT}
    {3636284400 43200 1 ANAST}
    {3655033200 39600 0 ANAT}
    {3668338800 43200 1 ANAST}
    {3686482800 39600 0 ANAT}
    {3699788400 43200 1 ANAST}
    {3717932400 39600 0 ANAT}
    {3731238000 43200 1 ANAST}
    {3749986800 39600 0 ANAT}
    {3762687600 43200 1 ANAST}
    {3781436400 39600 0 ANAT}
    {3794137200 43200 1 ANAST}
    {3812886000 39600 0 ANAT}
    {3825586800 43200 1 ANAST}
    {3844335600 39600 0 ANAT}
    {3857641200 43200 1 ANAST}
    {3875785200 39600 0 ANAT}
    {3889090800 43200 1 ANAST}
    {3907234800 39600 0 ANAT}
    {3920540400 43200 1 ANAST}
    {3939289200 39600 0 ANAT}
    {3951990000 43200 1 ANAST}
    {3970738800 39600 0 ANAT}
    {3983439600 43200 1 ANAST}
    {4002188400 39600 0 ANAT}
    {4015494000 43200 1 ANAST}
    {4033638000 39600 0 ANAT}
    {4046943600 43200 1 ANAST}
    {4065087600 39600 0 ANAT}
    {4078393200 43200 1 ANAST}
    {4096537200 39600 0 ANAT}
}







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

64
65
66
67
68
69
70
71

















































































































































































72
    {1206799200 46800 1 ANAST}
    {1224943200 43200 0 ANAT}
    {1238248800 46800 1 ANAST}
    {1256392800 43200 0 ANAT}
    {1269698400 39600 0 ANAMMTT}
    {1269702000 43200 1 ANAST}
    {1288450800 39600 0 ANAT}
    {1301151600 43200 0 ANAT}

















































































































































































}

Changes to library/tzdata/Asia/Gaza.

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
    {1113516000 10800 1 EEST}
    {1128380400 7200 0 EET}
    {1143842400 10800 1 EEST}
    {1158872400 7200 0 EET}
    {1175378400 10800 1 EEST}
    {1189638000 7200 0 EET}
    {1207000800 10800 1 EEST}
    {1219964400 7200 0 EET}
    {1238104800 10800 1 EEST}
    {1252018800 7200 0 EET}
    {1269640860 10800 1 EEST}
    {1281474000 7200 0 EET}
    {1283472000 7200 0 EET}
    {1301090460 10800 1 EEST}
    {1314918000 7200 0 EET}
    {1333144860 10800 1 EEST}
    {1346972400 7200 0 EET}
    {1364594460 10800 1 EEST}
    {1378422000 7200 0 EET}
    {1396044060 10800 1 EEST}
    {1409871600 7200 0 EET}
    {1427493660 10800 1 EEST}
    {1441321200 7200 0 EET}
    {1458943260 10800 1 EEST}
    {1472770800 7200 0 EET}
    {1490392860 10800 1 EEST}
    {1504220400 7200 0 EET}
    {1522447260 10800 1 EEST}
    {1536274800 7200 0 EET}
    {1553896860 10800 1 EEST}
    {1567724400 7200 0 EET}
    {1585346460 10800 1 EEST}
    {1599174000 7200 0 EET}
    {1616796060 10800 1 EEST}
    {1630623600 7200 0 EET}
    {1648245660 10800 1 EEST}
    {1662073200 7200 0 EET}
    {1679695260 10800 1 EEST}
    {1693522800 7200 0 EET}
    {1711749660 10800 1 EEST}
    {1725577200 7200 0 EET}
    {1743199260 10800 1 EEST}
    {1757026800 7200 0 EET}
    {1774648860 10800 1 EEST}
    {1788476400 7200 0 EET}
    {1806098460 10800 1 EEST}
    {1819926000 7200 0 EET}
    {1837548060 10800 1 EEST}
    {1851375600 7200 0 EET}
    {1869602460 10800 1 EEST}
    {1883430000 7200 0 EET}
    {1901052060 10800 1 EEST}
    {1914879600 7200 0 EET}
    {1932501660 10800 1 EEST}
    {1946329200 7200 0 EET}
    {1963951260 10800 1 EEST}
    {1977778800 7200 0 EET}
    {1995400860 10800 1 EEST}
    {2009228400 7200 0 EET}
    {2026850460 10800 1 EEST}
    {2040678000 7200 0 EET}
    {2058904860 10800 1 EEST}
    {2072732400 7200 0 EET}
    {2090354460 10800 1 EEST}
    {2104182000 7200 0 EET}
    {2121804060 10800 1 EEST}
    {2135631600 7200 0 EET}
    {2153253660 10800 1 EEST}
    {2167081200 7200 0 EET}
    {2184703260 10800 1 EEST}
    {2198530800 7200 0 EET}
    {2216757660 10800 1 EEST}
    {2230585200 7200 0 EET}
    {2248207260 10800 1 EEST}
    {2262034800 7200 0 EET}
    {2279656860 10800 1 EEST}
    {2293484400 7200 0 EET}
    {2311106460 10800 1 EEST}
    {2324934000 7200 0 EET}
    {2342556060 10800 1 EEST}
    {2356383600 7200 0 EET}
    {2374005660 10800 1 EEST}
    {2387833200 7200 0 EET}
    {2406060060 10800 1 EEST}
    {2419887600 7200 0 EET}
    {2437509660 10800 1 EEST}
    {2451337200 7200 0 EET}
    {2468959260 10800 1 EEST}
    {2482786800 7200 0 EET}
    {2500408860 10800 1 EEST}
    {2514236400 7200 0 EET}
    {2531858460 10800 1 EEST}
    {2545686000 7200 0 EET}
    {2563308060 10800 1 EEST}
    {2577135600 7200 0 EET}
    {2595362460 10800 1 EEST}
    {2609190000 7200 0 EET}
    {2626812060 10800 1 EEST}
    {2640639600 7200 0 EET}
    {2658261660 10800 1 EEST}
    {2672089200 7200 0 EET}
    {2689711260 10800 1 EEST}
    {2703538800 7200 0 EET}
    {2721160860 10800 1 EEST}
    {2734988400 7200 0 EET}
    {2753215260 10800 1 EEST}
    {2767042800 7200 0 EET}
    {2784664860 10800 1 EEST}
    {2798492400 7200 0 EET}
    {2816114460 10800 1 EEST}
    {2829942000 7200 0 EET}
    {2847564060 10800 1 EEST}
    {2861391600 7200 0 EET}
    {2879013660 10800 1 EEST}
    {2892841200 7200 0 EET}
    {2910463260 10800 1 EEST}
    {2924290800 7200 0 EET}
    {2942517660 10800 1 EEST}
    {2956345200 7200 0 EET}
    {2973967260 10800 1 EEST}
    {2987794800 7200 0 EET}
    {3005416860 10800 1 EEST}
    {3019244400 7200 0 EET}
    {3036866460 10800 1 EEST}
    {3050694000 7200 0 EET}
    {3068316060 10800 1 EEST}
    {3082143600 7200 0 EET}
    {3100370460 10800 1 EEST}
    {3114198000 7200 0 EET}
    {3131820060 10800 1 EEST}
    {3145647600 7200 0 EET}
    {3163269660 10800 1 EEST}
    {3177097200 7200 0 EET}
    {3194719260 10800 1 EEST}
    {3208546800 7200 0 EET}
    {3226168860 10800 1 EEST}
    {3239996400 7200 0 EET}
    {3257618460 10800 1 EEST}
    {3271446000 7200 0 EET}
    {3289672860 10800 1 EEST}
    {3303500400 7200 0 EET}
    {3321122460 10800 1 EEST}
    {3334950000 7200 0 EET}
    {3352572060 10800 1 EEST}
    {3366399600 7200 0 EET}
    {3384021660 10800 1 EEST}
    {3397849200 7200 0 EET}
    {3415471260 10800 1 EEST}
    {3429298800 7200 0 EET}
    {3446920860 10800 1 EEST}
    {3460748400 7200 0 EET}
    {3478975260 10800 1 EEST}
    {3492802800 7200 0 EET}
    {3510424860 10800 1 EEST}
    {3524252400 7200 0 EET}
    {3541874460 10800 1 EEST}
    {3555702000 7200 0 EET}
    {3573324060 10800 1 EEST}
    {3587151600 7200 0 EET}
    {3604773660 10800 1 EEST}
    {3618601200 7200 0 EET}
    {3636828060 10800 1 EEST}
    {3650655600 7200 0 EET}
    {3668277660 10800 1 EEST}
    {3682105200 7200 0 EET}
    {3699727260 10800 1 EEST}
    {3713554800 7200 0 EET}
    {3731176860 10800 1 EEST}
    {3745004400 7200 0 EET}
    {3762626460 10800 1 EEST}
    {3776454000 7200 0 EET}
    {3794076060 10800 1 EEST}
    {3807903600 7200 0 EET}
    {3826130460 10800 1 EEST}
    {3839958000 7200 0 EET}
    {3857580060 10800 1 EEST}
    {3871407600 7200 0 EET}
    {3889029660 10800 1 EEST}
    {3902857200 7200 0 EET}
    {3920479260 10800 1 EEST}
    {3934306800 7200 0 EET}
    {3951928860 10800 1 EEST}
    {3965756400 7200 0 EET}
    {3983983260 10800 1 EEST}
    {3997810800 7200 0 EET}
    {4015432860 10800 1 EEST}
    {4029260400 7200 0 EET}
    {4046882460 10800 1 EEST}
    {4060710000 7200 0 EET}
    {4078332060 10800 1 EEST}
    {4092159600 7200 0 EET}
}







|




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

85
86
87
88
89
90
91
92
93
94
95
96

































97




























































































98




















































99
    {1113516000 10800 1 EEST}
    {1128380400 7200 0 EET}
    {1143842400 10800 1 EEST}
    {1158872400 7200 0 EET}
    {1175378400 10800 1 EEST}
    {1189638000 7200 0 EET}
    {1207000800 10800 1 EEST}
    {1219957200 7200 0 EET}
    {1238104800 10800 1 EEST}
    {1252018800 7200 0 EET}
    {1269640860 10800 1 EEST}
    {1281474000 7200 0 EET}

































    {1301738460 10800 1 EEST}




























































































    {1312146000 7200 0 EET}




















































}

Changes to library/tzdata/Asia/Irkutsk.

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
    {1193508000 28800 0 IRKT}
    {1206813600 32400 1 IRKST}
    {1224957600 28800 0 IRKT}
    {1238263200 32400 1 IRKST}
    {1256407200 28800 0 IRKT}
    {1269712800 32400 1 IRKST}
    {1288461600 28800 0 IRKT}
    {1301162400 32400 1 IRKST}
    {1319911200 28800 0 IRKT}
    {1332612000 32400 1 IRKST}
    {1351360800 28800 0 IRKT}
    {1364666400 32400 1 IRKST}
    {1382810400 28800 0 IRKT}
    {1396116000 32400 1 IRKST}
    {1414260000 28800 0 IRKT}
    {1427565600 32400 1 IRKST}
    {1445709600 28800 0 IRKT}
    {1459015200 32400 1 IRKST}
    {1477764000 28800 0 IRKT}
    {1490464800 32400 1 IRKST}
    {1509213600 28800 0 IRKT}
    {1521914400 32400 1 IRKST}
    {1540663200 28800 0 IRKT}
    {1553968800 32400 1 IRKST}
    {1572112800 28800 0 IRKT}
    {1585418400 32400 1 IRKST}
    {1603562400 28800 0 IRKT}
    {1616868000 32400 1 IRKST}
    {1635616800 28800 0 IRKT}
    {1648317600 32400 1 IRKST}
    {1667066400 28800 0 IRKT}
    {1679767200 32400 1 IRKST}
    {1698516000 28800 0 IRKT}
    {1711821600 32400 1 IRKST}
    {1729965600 28800 0 IRKT}
    {1743271200 32400 1 IRKST}
    {1761415200 28800 0 IRKT}
    {1774720800 32400 1 IRKST}
    {1792864800 28800 0 IRKT}
    {1806170400 32400 1 IRKST}
    {1824919200 28800 0 IRKT}
    {1837620000 32400 1 IRKST}
    {1856368800 28800 0 IRKT}
    {1869069600 32400 1 IRKST}
    {1887818400 28800 0 IRKT}
    {1901124000 32400 1 IRKST}
    {1919268000 28800 0 IRKT}
    {1932573600 32400 1 IRKST}
    {1950717600 28800 0 IRKT}
    {1964023200 32400 1 IRKST}
    {1982772000 28800 0 IRKT}
    {1995472800 32400 1 IRKST}
    {2014221600 28800 0 IRKT}
    {2026922400 32400 1 IRKST}
    {2045671200 28800 0 IRKT}
    {2058372000 32400 1 IRKST}
    {2077120800 28800 0 IRKT}
    {2090426400 32400 1 IRKST}
    {2108570400 28800 0 IRKT}
    {2121876000 32400 1 IRKST}
    {2140020000 28800 0 IRKT}
    {2153325600 32400 1 IRKST}
    {2172074400 28800 0 IRKT}
    {2184775200 32400 1 IRKST}
    {2203524000 28800 0 IRKT}
    {2216224800 32400 1 IRKST}
    {2234973600 28800 0 IRKT}
    {2248279200 32400 1 IRKST}
    {2266423200 28800 0 IRKT}
    {2279728800 32400 1 IRKST}
    {2297872800 28800 0 IRKT}
    {2311178400 32400 1 IRKST}
    {2329322400 28800 0 IRKT}
    {2342628000 32400 1 IRKST}
    {2361376800 28800 0 IRKT}
    {2374077600 32400 1 IRKST}
    {2392826400 28800 0 IRKT}
    {2405527200 32400 1 IRKST}
    {2424276000 28800 0 IRKT}
    {2437581600 32400 1 IRKST}
    {2455725600 28800 0 IRKT}
    {2469031200 32400 1 IRKST}
    {2487175200 28800 0 IRKT}
    {2500480800 32400 1 IRKST}
    {2519229600 28800 0 IRKT}
    {2531930400 32400 1 IRKST}
    {2550679200 28800 0 IRKT}
    {2563380000 32400 1 IRKST}
    {2582128800 28800 0 IRKT}
    {2595434400 32400 1 IRKST}
    {2613578400 28800 0 IRKT}
    {2626884000 32400 1 IRKST}
    {2645028000 28800 0 IRKT}
    {2658333600 32400 1 IRKST}
    {2676477600 28800 0 IRKT}
    {2689783200 32400 1 IRKST}
    {2708532000 28800 0 IRKT}
    {2721232800 32400 1 IRKST}
    {2739981600 28800 0 IRKT}
    {2752682400 32400 1 IRKST}
    {2771431200 28800 0 IRKT}
    {2784736800 32400 1 IRKST}
    {2802880800 28800 0 IRKT}
    {2816186400 32400 1 IRKST}
    {2834330400 28800 0 IRKT}
    {2847636000 32400 1 IRKST}
    {2866384800 28800 0 IRKT}
    {2879085600 32400 1 IRKST}
    {2897834400 28800 0 IRKT}
    {2910535200 32400 1 IRKST}
    {2929284000 28800 0 IRKT}
    {2941984800 32400 1 IRKST}
    {2960733600 28800 0 IRKT}
    {2974039200 32400 1 IRKST}
    {2992183200 28800 0 IRKT}
    {3005488800 32400 1 IRKST}
    {3023632800 28800 0 IRKT}
    {3036938400 32400 1 IRKST}
    {3055687200 28800 0 IRKT}
    {3068388000 32400 1 IRKST}
    {3087136800 28800 0 IRKT}
    {3099837600 32400 1 IRKST}
    {3118586400 28800 0 IRKT}
    {3131892000 32400 1 IRKST}
    {3150036000 28800 0 IRKT}
    {3163341600 32400 1 IRKST}
    {3181485600 28800 0 IRKT}
    {3194791200 32400 1 IRKST}
    {3212935200 28800 0 IRKT}
    {3226240800 32400 1 IRKST}
    {3244989600 28800 0 IRKT}
    {3257690400 32400 1 IRKST}
    {3276439200 28800 0 IRKT}
    {3289140000 32400 1 IRKST}
    {3307888800 28800 0 IRKT}
    {3321194400 32400 1 IRKST}
    {3339338400 28800 0 IRKT}
    {3352644000 32400 1 IRKST}
    {3370788000 28800 0 IRKT}
    {3384093600 32400 1 IRKST}
    {3402842400 28800 0 IRKT}
    {3415543200 32400 1 IRKST}
    {3434292000 28800 0 IRKT}
    {3446992800 32400 1 IRKST}
    {3465741600 28800 0 IRKT}
    {3479047200 32400 1 IRKST}
    {3497191200 28800 0 IRKT}
    {3510496800 32400 1 IRKST}
    {3528640800 28800 0 IRKT}
    {3541946400 32400 1 IRKST}
    {3560090400 28800 0 IRKT}
    {3573396000 32400 1 IRKST}
    {3592144800 28800 0 IRKT}
    {3604845600 32400 1 IRKST}
    {3623594400 28800 0 IRKT}
    {3636295200 32400 1 IRKST}
    {3655044000 28800 0 IRKT}
    {3668349600 32400 1 IRKST}
    {3686493600 28800 0 IRKT}
    {3699799200 32400 1 IRKST}
    {3717943200 28800 0 IRKT}
    {3731248800 32400 1 IRKST}
    {3749997600 28800 0 IRKT}
    {3762698400 32400 1 IRKST}
    {3781447200 28800 0 IRKT}
    {3794148000 32400 1 IRKST}
    {3812896800 28800 0 IRKT}
    {3825597600 32400 1 IRKST}
    {3844346400 28800 0 IRKT}
    {3857652000 32400 1 IRKST}
    {3875796000 28800 0 IRKT}
    {3889101600 32400 1 IRKST}
    {3907245600 28800 0 IRKT}
    {3920551200 32400 1 IRKST}
    {3939300000 28800 0 IRKT}
    {3952000800 32400 1 IRKST}
    {3970749600 28800 0 IRKT}
    {3983450400 32400 1 IRKST}
    {4002199200 28800 0 IRKT}
    {4015504800 32400 1 IRKST}
    {4033648800 28800 0 IRKT}
    {4046954400 32400 1 IRKST}
    {4065098400 28800 0 IRKT}
    {4078404000 32400 1 IRKST}
    {4096548000 28800 0 IRKT}
}







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

63
64
65
66
67
68
69
70

















































































































































































71
    {1193508000 28800 0 IRKT}
    {1206813600 32400 1 IRKST}
    {1224957600 28800 0 IRKT}
    {1238263200 32400 1 IRKST}
    {1256407200 28800 0 IRKT}
    {1269712800 32400 1 IRKST}
    {1288461600 28800 0 IRKT}
    {1301162400 32400 0 IRKT}

















































































































































































}

Changes to library/tzdata/Asia/Kamchatka.

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
    {1206799200 46800 1 PETST}
    {1224943200 43200 0 PETT}
    {1238248800 46800 1 PETST}
    {1256392800 43200 0 PETT}
    {1269698400 39600 0 PETMMTT}
    {1269702000 43200 1 PETST}
    {1288450800 39600 0 PETT}
    {1301151600 43200 1 PETST}
    {1319900400 39600 0 PETT}
    {1332601200 43200 1 PETST}
    {1351350000 39600 0 PETT}
    {1364655600 43200 1 PETST}
    {1382799600 39600 0 PETT}
    {1396105200 43200 1 PETST}
    {1414249200 39600 0 PETT}
    {1427554800 43200 1 PETST}
    {1445698800 39600 0 PETT}
    {1459004400 43200 1 PETST}
    {1477753200 39600 0 PETT}
    {1490454000 43200 1 PETST}
    {1509202800 39600 0 PETT}
    {1521903600 43200 1 PETST}
    {1540652400 39600 0 PETT}
    {1553958000 43200 1 PETST}
    {1572102000 39600 0 PETT}
    {1585407600 43200 1 PETST}
    {1603551600 39600 0 PETT}
    {1616857200 43200 1 PETST}
    {1635606000 39600 0 PETT}
    {1648306800 43200 1 PETST}
    {1667055600 39600 0 PETT}
    {1679756400 43200 1 PETST}
    {1698505200 39600 0 PETT}
    {1711810800 43200 1 PETST}
    {1729954800 39600 0 PETT}
    {1743260400 43200 1 PETST}
    {1761404400 39600 0 PETT}
    {1774710000 43200 1 PETST}
    {1792854000 39600 0 PETT}
    {1806159600 43200 1 PETST}
    {1824908400 39600 0 PETT}
    {1837609200 43200 1 PETST}
    {1856358000 39600 0 PETT}
    {1869058800 43200 1 PETST}
    {1887807600 39600 0 PETT}
    {1901113200 43200 1 PETST}
    {1919257200 39600 0 PETT}
    {1932562800 43200 1 PETST}
    {1950706800 39600 0 PETT}
    {1964012400 43200 1 PETST}
    {1982761200 39600 0 PETT}
    {1995462000 43200 1 PETST}
    {2014210800 39600 0 PETT}
    {2026911600 43200 1 PETST}
    {2045660400 39600 0 PETT}
    {2058361200 43200 1 PETST}
    {2077110000 39600 0 PETT}
    {2090415600 43200 1 PETST}
    {2108559600 39600 0 PETT}
    {2121865200 43200 1 PETST}
    {2140009200 39600 0 PETT}
    {2153314800 43200 1 PETST}
    {2172063600 39600 0 PETT}
    {2184764400 43200 1 PETST}
    {2203513200 39600 0 PETT}
    {2216214000 43200 1 PETST}
    {2234962800 39600 0 PETT}
    {2248268400 43200 1 PETST}
    {2266412400 39600 0 PETT}
    {2279718000 43200 1 PETST}
    {2297862000 39600 0 PETT}
    {2311167600 43200 1 PETST}
    {2329311600 39600 0 PETT}
    {2342617200 43200 1 PETST}
    {2361366000 39600 0 PETT}
    {2374066800 43200 1 PETST}
    {2392815600 39600 0 PETT}
    {2405516400 43200 1 PETST}
    {2424265200 39600 0 PETT}
    {2437570800 43200 1 PETST}
    {2455714800 39600 0 PETT}
    {2469020400 43200 1 PETST}
    {2487164400 39600 0 PETT}
    {2500470000 43200 1 PETST}
    {2519218800 39600 0 PETT}
    {2531919600 43200 1 PETST}
    {2550668400 39600 0 PETT}
    {2563369200 43200 1 PETST}
    {2582118000 39600 0 PETT}
    {2595423600 43200 1 PETST}
    {2613567600 39600 0 PETT}
    {2626873200 43200 1 PETST}
    {2645017200 39600 0 PETT}
    {2658322800 43200 1 PETST}
    {2676466800 39600 0 PETT}
    {2689772400 43200 1 PETST}
    {2708521200 39600 0 PETT}
    {2721222000 43200 1 PETST}
    {2739970800 39600 0 PETT}
    {2752671600 43200 1 PETST}
    {2771420400 39600 0 PETT}
    {2784726000 43200 1 PETST}
    {2802870000 39600 0 PETT}
    {2816175600 43200 1 PETST}
    {2834319600 39600 0 PETT}
    {2847625200 43200 1 PETST}
    {2866374000 39600 0 PETT}
    {2879074800 43200 1 PETST}
    {2897823600 39600 0 PETT}
    {2910524400 43200 1 PETST}
    {2929273200 39600 0 PETT}
    {2941974000 43200 1 PETST}
    {2960722800 39600 0 PETT}
    {2974028400 43200 1 PETST}
    {2992172400 39600 0 PETT}
    {3005478000 43200 1 PETST}
    {3023622000 39600 0 PETT}
    {3036927600 43200 1 PETST}
    {3055676400 39600 0 PETT}
    {3068377200 43200 1 PETST}
    {3087126000 39600 0 PETT}
    {3099826800 43200 1 PETST}
    {3118575600 39600 0 PETT}
    {3131881200 43200 1 PETST}
    {3150025200 39600 0 PETT}
    {3163330800 43200 1 PETST}
    {3181474800 39600 0 PETT}
    {3194780400 43200 1 PETST}
    {3212924400 39600 0 PETT}
    {3226230000 43200 1 PETST}
    {3244978800 39600 0 PETT}
    {3257679600 43200 1 PETST}
    {3276428400 39600 0 PETT}
    {3289129200 43200 1 PETST}
    {3307878000 39600 0 PETT}
    {3321183600 43200 1 PETST}
    {3339327600 39600 0 PETT}
    {3352633200 43200 1 PETST}
    {3370777200 39600 0 PETT}
    {3384082800 43200 1 PETST}
    {3402831600 39600 0 PETT}
    {3415532400 43200 1 PETST}
    {3434281200 39600 0 PETT}
    {3446982000 43200 1 PETST}
    {3465730800 39600 0 PETT}
    {3479036400 43200 1 PETST}
    {3497180400 39600 0 PETT}
    {3510486000 43200 1 PETST}
    {3528630000 39600 0 PETT}
    {3541935600 43200 1 PETST}
    {3560079600 39600 0 PETT}
    {3573385200 43200 1 PETST}
    {3592134000 39600 0 PETT}
    {3604834800 43200 1 PETST}
    {3623583600 39600 0 PETT}
    {3636284400 43200 1 PETST}
    {3655033200 39600 0 PETT}
    {3668338800 43200 1 PETST}
    {3686482800 39600 0 PETT}
    {3699788400 43200 1 PETST}
    {3717932400 39600 0 PETT}
    {3731238000 43200 1 PETST}
    {3749986800 39600 0 PETT}
    {3762687600 43200 1 PETST}
    {3781436400 39600 0 PETT}
    {3794137200 43200 1 PETST}
    {3812886000 39600 0 PETT}
    {3825586800 43200 1 PETST}
    {3844335600 39600 0 PETT}
    {3857641200 43200 1 PETST}
    {3875785200 39600 0 PETT}
    {3889090800 43200 1 PETST}
    {3907234800 39600 0 PETT}
    {3920540400 43200 1 PETST}
    {3939289200 39600 0 PETT}
    {3951990000 43200 1 PETST}
    {3970738800 39600 0 PETT}
    {3983439600 43200 1 PETST}
    {4002188400 39600 0 PETT}
    {4015494000 43200 1 PETST}
    {4033638000 39600 0 PETT}
    {4046943600 43200 1 PETST}
    {4065087600 39600 0 PETT}
    {4078393200 43200 1 PETST}
    {4096537200 39600 0 PETT}
}







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

63
64
65
66
67
68
69
70

















































































































































































71
    {1206799200 46800 1 PETST}
    {1224943200 43200 0 PETT}
    {1238248800 46800 1 PETST}
    {1256392800 43200 0 PETT}
    {1269698400 39600 0 PETMMTT}
    {1269702000 43200 1 PETST}
    {1288450800 39600 0 PETT}
    {1301151600 43200 0 PETT}

















































































































































































}

Changes to library/tzdata/Asia/Krasnoyarsk.

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
    {1193511600 25200 0 KRAT}
    {1206817200 28800 1 KRAST}
    {1224961200 25200 0 KRAT}
    {1238266800 28800 1 KRAST}
    {1256410800 25200 0 KRAT}
    {1269716400 28800 1 KRAST}
    {1288465200 25200 0 KRAT}
    {1301166000 28800 1 KRAST}
    {1319914800 25200 0 KRAT}
    {1332615600 28800 1 KRAST}
    {1351364400 25200 0 KRAT}
    {1364670000 28800 1 KRAST}
    {1382814000 25200 0 KRAT}
    {1396119600 28800 1 KRAST}
    {1414263600 25200 0 KRAT}
    {1427569200 28800 1 KRAST}
    {1445713200 25200 0 KRAT}
    {1459018800 28800 1 KRAST}
    {1477767600 25200 0 KRAT}
    {1490468400 28800 1 KRAST}
    {1509217200 25200 0 KRAT}
    {1521918000 28800 1 KRAST}
    {1540666800 25200 0 KRAT}
    {1553972400 28800 1 KRAST}
    {1572116400 25200 0 KRAT}
    {1585422000 28800 1 KRAST}
    {1603566000 25200 0 KRAT}
    {1616871600 28800 1 KRAST}
    {1635620400 25200 0 KRAT}
    {1648321200 28800 1 KRAST}
    {1667070000 25200 0 KRAT}
    {1679770800 28800 1 KRAST}
    {1698519600 25200 0 KRAT}
    {1711825200 28800 1 KRAST}
    {1729969200 25200 0 KRAT}
    {1743274800 28800 1 KRAST}
    {1761418800 25200 0 KRAT}
    {1774724400 28800 1 KRAST}
    {1792868400 25200 0 KRAT}
    {1806174000 28800 1 KRAST}
    {1824922800 25200 0 KRAT}
    {1837623600 28800 1 KRAST}
    {1856372400 25200 0 KRAT}
    {1869073200 28800 1 KRAST}
    {1887822000 25200 0 KRAT}
    {1901127600 28800 1 KRAST}
    {1919271600 25200 0 KRAT}
    {1932577200 28800 1 KRAST}
    {1950721200 25200 0 KRAT}
    {1964026800 28800 1 KRAST}
    {1982775600 25200 0 KRAT}
    {1995476400 28800 1 KRAST}
    {2014225200 25200 0 KRAT}
    {2026926000 28800 1 KRAST}
    {2045674800 25200 0 KRAT}
    {2058375600 28800 1 KRAST}
    {2077124400 25200 0 KRAT}
    {2090430000 28800 1 KRAST}
    {2108574000 25200 0 KRAT}
    {2121879600 28800 1 KRAST}
    {2140023600 25200 0 KRAT}
    {2153329200 28800 1 KRAST}
    {2172078000 25200 0 KRAT}
    {2184778800 28800 1 KRAST}
    {2203527600 25200 0 KRAT}
    {2216228400 28800 1 KRAST}
    {2234977200 25200 0 KRAT}
    {2248282800 28800 1 KRAST}
    {2266426800 25200 0 KRAT}
    {2279732400 28800 1 KRAST}
    {2297876400 25200 0 KRAT}
    {2311182000 28800 1 KRAST}
    {2329326000 25200 0 KRAT}
    {2342631600 28800 1 KRAST}
    {2361380400 25200 0 KRAT}
    {2374081200 28800 1 KRAST}
    {2392830000 25200 0 KRAT}
    {2405530800 28800 1 KRAST}
    {2424279600 25200 0 KRAT}
    {2437585200 28800 1 KRAST}
    {2455729200 25200 0 KRAT}
    {2469034800 28800 1 KRAST}
    {2487178800 25200 0 KRAT}
    {2500484400 28800 1 KRAST}
    {2519233200 25200 0 KRAT}
    {2531934000 28800 1 KRAST}
    {2550682800 25200 0 KRAT}
    {2563383600 28800 1 KRAST}
    {2582132400 25200 0 KRAT}
    {2595438000 28800 1 KRAST}
    {2613582000 25200 0 KRAT}
    {2626887600 28800 1 KRAST}
    {2645031600 25200 0 KRAT}
    {2658337200 28800 1 KRAST}
    {2676481200 25200 0 KRAT}
    {2689786800 28800 1 KRAST}
    {2708535600 25200 0 KRAT}
    {2721236400 28800 1 KRAST}
    {2739985200 25200 0 KRAT}
    {2752686000 28800 1 KRAST}
    {2771434800 25200 0 KRAT}
    {2784740400 28800 1 KRAST}
    {2802884400 25200 0 KRAT}
    {2816190000 28800 1 KRAST}
    {2834334000 25200 0 KRAT}
    {2847639600 28800 1 KRAST}
    {2866388400 25200 0 KRAT}
    {2879089200 28800 1 KRAST}
    {2897838000 25200 0 KRAT}
    {2910538800 28800 1 KRAST}
    {2929287600 25200 0 KRAT}
    {2941988400 28800 1 KRAST}
    {2960737200 25200 0 KRAT}
    {2974042800 28800 1 KRAST}
    {2992186800 25200 0 KRAT}
    {3005492400 28800 1 KRAST}
    {3023636400 25200 0 KRAT}
    {3036942000 28800 1 KRAST}
    {3055690800 25200 0 KRAT}
    {3068391600 28800 1 KRAST}
    {3087140400 25200 0 KRAT}
    {3099841200 28800 1 KRAST}
    {3118590000 25200 0 KRAT}
    {3131895600 28800 1 KRAST}
    {3150039600 25200 0 KRAT}
    {3163345200 28800 1 KRAST}
    {3181489200 25200 0 KRAT}
    {3194794800 28800 1 KRAST}
    {3212938800 25200 0 KRAT}
    {3226244400 28800 1 KRAST}
    {3244993200 25200 0 KRAT}
    {3257694000 28800 1 KRAST}
    {3276442800 25200 0 KRAT}
    {3289143600 28800 1 KRAST}
    {3307892400 25200 0 KRAT}
    {3321198000 28800 1 KRAST}
    {3339342000 25200 0 KRAT}
    {3352647600 28800 1 KRAST}
    {3370791600 25200 0 KRAT}
    {3384097200 28800 1 KRAST}
    {3402846000 25200 0 KRAT}
    {3415546800 28800 1 KRAST}
    {3434295600 25200 0 KRAT}
    {3446996400 28800 1 KRAST}
    {3465745200 25200 0 KRAT}
    {3479050800 28800 1 KRAST}
    {3497194800 25200 0 KRAT}
    {3510500400 28800 1 KRAST}
    {3528644400 25200 0 KRAT}
    {3541950000 28800 1 KRAST}
    {3560094000 25200 0 KRAT}
    {3573399600 28800 1 KRAST}
    {3592148400 25200 0 KRAT}
    {3604849200 28800 1 KRAST}
    {3623598000 25200 0 KRAT}
    {3636298800 28800 1 KRAST}
    {3655047600 25200 0 KRAT}
    {3668353200 28800 1 KRAST}
    {3686497200 25200 0 KRAT}
    {3699802800 28800 1 KRAST}
    {3717946800 25200 0 KRAT}
    {3731252400 28800 1 KRAST}
    {3750001200 25200 0 KRAT}
    {3762702000 28800 1 KRAST}
    {3781450800 25200 0 KRAT}
    {3794151600 28800 1 KRAST}
    {3812900400 25200 0 KRAT}
    {3825601200 28800 1 KRAST}
    {3844350000 25200 0 KRAT}
    {3857655600 28800 1 KRAST}
    {3875799600 25200 0 KRAT}
    {3889105200 28800 1 KRAST}
    {3907249200 25200 0 KRAT}
    {3920554800 28800 1 KRAST}
    {3939303600 25200 0 KRAT}
    {3952004400 28800 1 KRAST}
    {3970753200 25200 0 KRAT}
    {3983454000 28800 1 KRAST}
    {4002202800 25200 0 KRAT}
    {4015508400 28800 1 KRAST}
    {4033652400 25200 0 KRAT}
    {4046958000 28800 1 KRAST}
    {4065102000 25200 0 KRAT}
    {4078407600 28800 1 KRAST}
    {4096551600 25200 0 KRAT}
}







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

62
63
64
65
66
67
68
69

















































































































































































70
    {1193511600 25200 0 KRAT}
    {1206817200 28800 1 KRAST}
    {1224961200 25200 0 KRAT}
    {1238266800 28800 1 KRAST}
    {1256410800 25200 0 KRAT}
    {1269716400 28800 1 KRAST}
    {1288465200 25200 0 KRAT}
    {1301166000 28800 0 KRAT}

















































































































































































}

Changes to library/tzdata/Asia/Magadan.

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
    {1193497200 39600 0 MAGT}
    {1206802800 43200 1 MAGST}
    {1224946800 39600 0 MAGT}
    {1238252400 43200 1 MAGST}
    {1256396400 39600 0 MAGT}
    {1269702000 43200 1 MAGST}
    {1288450800 39600 0 MAGT}
    {1301151600 43200 1 MAGST}
    {1319900400 39600 0 MAGT}
    {1332601200 43200 1 MAGST}
    {1351350000 39600 0 MAGT}
    {1364655600 43200 1 MAGST}
    {1382799600 39600 0 MAGT}
    {1396105200 43200 1 MAGST}
    {1414249200 39600 0 MAGT}
    {1427554800 43200 1 MAGST}
    {1445698800 39600 0 MAGT}
    {1459004400 43200 1 MAGST}
    {1477753200 39600 0 MAGT}
    {1490454000 43200 1 MAGST}
    {1509202800 39600 0 MAGT}
    {1521903600 43200 1 MAGST}
    {1540652400 39600 0 MAGT}
    {1553958000 43200 1 MAGST}
    {1572102000 39600 0 MAGT}
    {1585407600 43200 1 MAGST}
    {1603551600 39600 0 MAGT}
    {1616857200 43200 1 MAGST}
    {1635606000 39600 0 MAGT}
    {1648306800 43200 1 MAGST}
    {1667055600 39600 0 MAGT}
    {1679756400 43200 1 MAGST}
    {1698505200 39600 0 MAGT}
    {1711810800 43200 1 MAGST}
    {1729954800 39600 0 MAGT}
    {1743260400 43200 1 MAGST}
    {1761404400 39600 0 MAGT}
    {1774710000 43200 1 MAGST}
    {1792854000 39600 0 MAGT}
    {1806159600 43200 1 MAGST}
    {1824908400 39600 0 MAGT}
    {1837609200 43200 1 MAGST}
    {1856358000 39600 0 MAGT}
    {1869058800 43200 1 MAGST}
    {1887807600 39600 0 MAGT}
    {1901113200 43200 1 MAGST}
    {1919257200 39600 0 MAGT}
    {1932562800 43200 1 MAGST}
    {1950706800 39600 0 MAGT}
    {1964012400 43200 1 MAGST}
    {1982761200 39600 0 MAGT}
    {1995462000 43200 1 MAGST}
    {2014210800 39600 0 MAGT}
    {2026911600 43200 1 MAGST}
    {2045660400 39600 0 MAGT}
    {2058361200 43200 1 MAGST}
    {2077110000 39600 0 MAGT}
    {2090415600 43200 1 MAGST}
    {2108559600 39600 0 MAGT}
    {2121865200 43200 1 MAGST}
    {2140009200 39600 0 MAGT}
    {2153314800 43200 1 MAGST}
    {2172063600 39600 0 MAGT}
    {2184764400 43200 1 MAGST}
    {2203513200 39600 0 MAGT}
    {2216214000 43200 1 MAGST}
    {2234962800 39600 0 MAGT}
    {2248268400 43200 1 MAGST}
    {2266412400 39600 0 MAGT}
    {2279718000 43200 1 MAGST}
    {2297862000 39600 0 MAGT}
    {2311167600 43200 1 MAGST}
    {2329311600 39600 0 MAGT}
    {2342617200 43200 1 MAGST}
    {2361366000 39600 0 MAGT}
    {2374066800 43200 1 MAGST}
    {2392815600 39600 0 MAGT}
    {2405516400 43200 1 MAGST}
    {2424265200 39600 0 MAGT}
    {2437570800 43200 1 MAGST}
    {2455714800 39600 0 MAGT}
    {2469020400 43200 1 MAGST}
    {2487164400 39600 0 MAGT}
    {2500470000 43200 1 MAGST}
    {2519218800 39600 0 MAGT}
    {2531919600 43200 1 MAGST}
    {2550668400 39600 0 MAGT}
    {2563369200 43200 1 MAGST}
    {2582118000 39600 0 MAGT}
    {2595423600 43200 1 MAGST}
    {2613567600 39600 0 MAGT}
    {2626873200 43200 1 MAGST}
    {2645017200 39600 0 MAGT}
    {2658322800 43200 1 MAGST}
    {2676466800 39600 0 MAGT}
    {2689772400 43200 1 MAGST}
    {2708521200 39600 0 MAGT}
    {2721222000 43200 1 MAGST}
    {2739970800 39600 0 MAGT}
    {2752671600 43200 1 MAGST}
    {2771420400 39600 0 MAGT}
    {2784726000 43200 1 MAGST}
    {2802870000 39600 0 MAGT}
    {2816175600 43200 1 MAGST}
    {2834319600 39600 0 MAGT}
    {2847625200 43200 1 MAGST}
    {2866374000 39600 0 MAGT}
    {2879074800 43200 1 MAGST}
    {2897823600 39600 0 MAGT}
    {2910524400 43200 1 MAGST}
    {2929273200 39600 0 MAGT}
    {2941974000 43200 1 MAGST}
    {2960722800 39600 0 MAGT}
    {2974028400 43200 1 MAGST}
    {2992172400 39600 0 MAGT}
    {3005478000 43200 1 MAGST}
    {3023622000 39600 0 MAGT}
    {3036927600 43200 1 MAGST}
    {3055676400 39600 0 MAGT}
    {3068377200 43200 1 MAGST}
    {3087126000 39600 0 MAGT}
    {3099826800 43200 1 MAGST}
    {3118575600 39600 0 MAGT}
    {3131881200 43200 1 MAGST}
    {3150025200 39600 0 MAGT}
    {3163330800 43200 1 MAGST}
    {3181474800 39600 0 MAGT}
    {3194780400 43200 1 MAGST}
    {3212924400 39600 0 MAGT}
    {3226230000 43200 1 MAGST}
    {3244978800 39600 0 MAGT}
    {3257679600 43200 1 MAGST}
    {3276428400 39600 0 MAGT}
    {3289129200 43200 1 MAGST}
    {3307878000 39600 0 MAGT}
    {3321183600 43200 1 MAGST}
    {3339327600 39600 0 MAGT}
    {3352633200 43200 1 MAGST}
    {3370777200 39600 0 MAGT}
    {3384082800 43200 1 MAGST}
    {3402831600 39600 0 MAGT}
    {3415532400 43200 1 MAGST}
    {3434281200 39600 0 MAGT}
    {3446982000 43200 1 MAGST}
    {3465730800 39600 0 MAGT}
    {3479036400 43200 1 MAGST}
    {3497180400 39600 0 MAGT}
    {3510486000 43200 1 MAGST}
    {3528630000 39600 0 MAGT}
    {3541935600 43200 1 MAGST}
    {3560079600 39600 0 MAGT}
    {3573385200 43200 1 MAGST}
    {3592134000 39600 0 MAGT}
    {3604834800 43200 1 MAGST}
    {3623583600 39600 0 MAGT}
    {3636284400 43200 1 MAGST}
    {3655033200 39600 0 MAGT}
    {3668338800 43200 1 MAGST}
    {3686482800 39600 0 MAGT}
    {3699788400 43200 1 MAGST}
    {3717932400 39600 0 MAGT}
    {3731238000 43200 1 MAGST}
    {3749986800 39600 0 MAGT}
    {3762687600 43200 1 MAGST}
    {3781436400 39600 0 MAGT}
    {3794137200 43200 1 MAGST}
    {3812886000 39600 0 MAGT}
    {3825586800 43200 1 MAGST}
    {3844335600 39600 0 MAGT}
    {3857641200 43200 1 MAGST}
    {3875785200 39600 0 MAGT}
    {3889090800 43200 1 MAGST}
    {3907234800 39600 0 MAGT}
    {3920540400 43200 1 MAGST}
    {3939289200 39600 0 MAGT}
    {3951990000 43200 1 MAGST}
    {3970738800 39600 0 MAGT}
    {3983439600 43200 1 MAGST}
    {4002188400 39600 0 MAGT}
    {4015494000 43200 1 MAGST}
    {4033638000 39600 0 MAGT}
    {4046943600 43200 1 MAGST}
    {4065087600 39600 0 MAGT}
    {4078393200 43200 1 MAGST}
    {4096537200 39600 0 MAGT}
}







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

62
63
64
65
66
67
68
69

















































































































































































70
    {1193497200 39600 0 MAGT}
    {1206802800 43200 1 MAGST}
    {1224946800 39600 0 MAGT}
    {1238252400 43200 1 MAGST}
    {1256396400 39600 0 MAGT}
    {1269702000 43200 1 MAGST}
    {1288450800 39600 0 MAGT}
    {1301151600 43200 0 MAGT}

















































































































































































}

Changes to library/tzdata/Asia/Novokuznetsk.

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
    {1206817200 28800 1 KRAST}
    {1224961200 25200 0 KRAT}
    {1238266800 28800 1 KRAST}
    {1256410800 25200 0 KRAT}
    {1269716400 21600 0 NOVMMTT}
    {1269720000 25200 1 NOVST}
    {1288468800 21600 0 NOVT}
    {1301169600 25200 1 NOVST}
    {1319918400 21600 0 NOVT}
    {1332619200 25200 1 NOVST}
    {1351368000 21600 0 NOVT}
    {1364673600 25200 1 NOVST}
    {1382817600 21600 0 NOVT}
    {1396123200 25200 1 NOVST}
    {1414267200 21600 0 NOVT}
    {1427572800 25200 1 NOVST}
    {1445716800 21600 0 NOVT}
    {1459022400 25200 1 NOVST}
    {1477771200 21600 0 NOVT}
    {1490472000 25200 1 NOVST}
    {1509220800 21600 0 NOVT}
    {1521921600 25200 1 NOVST}
    {1540670400 21600 0 NOVT}
    {1553976000 25200 1 NOVST}
    {1572120000 21600 0 NOVT}
    {1585425600 25200 1 NOVST}
    {1603569600 21600 0 NOVT}
    {1616875200 25200 1 NOVST}
    {1635624000 21600 0 NOVT}
    {1648324800 25200 1 NOVST}
    {1667073600 21600 0 NOVT}
    {1679774400 25200 1 NOVST}
    {1698523200 21600 0 NOVT}
    {1711828800 25200 1 NOVST}
    {1729972800 21600 0 NOVT}
    {1743278400 25200 1 NOVST}
    {1761422400 21600 0 NOVT}
    {1774728000 25200 1 NOVST}
    {1792872000 21600 0 NOVT}
    {1806177600 25200 1 NOVST}
    {1824926400 21600 0 NOVT}
    {1837627200 25200 1 NOVST}
    {1856376000 21600 0 NOVT}
    {1869076800 25200 1 NOVST}
    {1887825600 21600 0 NOVT}
    {1901131200 25200 1 NOVST}
    {1919275200 21600 0 NOVT}
    {1932580800 25200 1 NOVST}
    {1950724800 21600 0 NOVT}
    {1964030400 25200 1 NOVST}
    {1982779200 21600 0 NOVT}
    {1995480000 25200 1 NOVST}
    {2014228800 21600 0 NOVT}
    {2026929600 25200 1 NOVST}
    {2045678400 21600 0 NOVT}
    {2058379200 25200 1 NOVST}
    {2077128000 21600 0 NOVT}
    {2090433600 25200 1 NOVST}
    {2108577600 21600 0 NOVT}
    {2121883200 25200 1 NOVST}
    {2140027200 21600 0 NOVT}
    {2153332800 25200 1 NOVST}
    {2172081600 21600 0 NOVT}
    {2184782400 25200 1 NOVST}
    {2203531200 21600 0 NOVT}
    {2216232000 25200 1 NOVST}
    {2234980800 21600 0 NOVT}
    {2248286400 25200 1 NOVST}
    {2266430400 21600 0 NOVT}
    {2279736000 25200 1 NOVST}
    {2297880000 21600 0 NOVT}
    {2311185600 25200 1 NOVST}
    {2329329600 21600 0 NOVT}
    {2342635200 25200 1 NOVST}
    {2361384000 21600 0 NOVT}
    {2374084800 25200 1 NOVST}
    {2392833600 21600 0 NOVT}
    {2405534400 25200 1 NOVST}
    {2424283200 21600 0 NOVT}
    {2437588800 25200 1 NOVST}
    {2455732800 21600 0 NOVT}
    {2469038400 25200 1 NOVST}
    {2487182400 21600 0 NOVT}
    {2500488000 25200 1 NOVST}
    {2519236800 21600 0 NOVT}
    {2531937600 25200 1 NOVST}
    {2550686400 21600 0 NOVT}
    {2563387200 25200 1 NOVST}
    {2582136000 21600 0 NOVT}
    {2595441600 25200 1 NOVST}
    {2613585600 21600 0 NOVT}
    {2626891200 25200 1 NOVST}
    {2645035200 21600 0 NOVT}
    {2658340800 25200 1 NOVST}
    {2676484800 21600 0 NOVT}
    {2689790400 25200 1 NOVST}
    {2708539200 21600 0 NOVT}
    {2721240000 25200 1 NOVST}
    {2739988800 21600 0 NOVT}
    {2752689600 25200 1 NOVST}
    {2771438400 21600 0 NOVT}
    {2784744000 25200 1 NOVST}
    {2802888000 21600 0 NOVT}
    {2816193600 25200 1 NOVST}
    {2834337600 21600 0 NOVT}
    {2847643200 25200 1 NOVST}
    {2866392000 21600 0 NOVT}
    {2879092800 25200 1 NOVST}
    {2897841600 21600 0 NOVT}
    {2910542400 25200 1 NOVST}
    {2929291200 21600 0 NOVT}
    {2941992000 25200 1 NOVST}
    {2960740800 21600 0 NOVT}
    {2974046400 25200 1 NOVST}
    {2992190400 21600 0 NOVT}
    {3005496000 25200 1 NOVST}
    {3023640000 21600 0 NOVT}
    {3036945600 25200 1 NOVST}
    {3055694400 21600 0 NOVT}
    {3068395200 25200 1 NOVST}
    {3087144000 21600 0 NOVT}
    {3099844800 25200 1 NOVST}
    {3118593600 21600 0 NOVT}
    {3131899200 25200 1 NOVST}
    {3150043200 21600 0 NOVT}
    {3163348800 25200 1 NOVST}
    {3181492800 21600 0 NOVT}
    {3194798400 25200 1 NOVST}
    {3212942400 21600 0 NOVT}
    {3226248000 25200 1 NOVST}
    {3244996800 21600 0 NOVT}
    {3257697600 25200 1 NOVST}
    {3276446400 21600 0 NOVT}
    {3289147200 25200 1 NOVST}
    {3307896000 21600 0 NOVT}
    {3321201600 25200 1 NOVST}
    {3339345600 21600 0 NOVT}
    {3352651200 25200 1 NOVST}
    {3370795200 21600 0 NOVT}
    {3384100800 25200 1 NOVST}
    {3402849600 21600 0 NOVT}
    {3415550400 25200 1 NOVST}
    {3434299200 21600 0 NOVT}
    {3447000000 25200 1 NOVST}
    {3465748800 21600 0 NOVT}
    {3479054400 25200 1 NOVST}
    {3497198400 21600 0 NOVT}
    {3510504000 25200 1 NOVST}
    {3528648000 21600 0 NOVT}
    {3541953600 25200 1 NOVST}
    {3560097600 21600 0 NOVT}
    {3573403200 25200 1 NOVST}
    {3592152000 21600 0 NOVT}
    {3604852800 25200 1 NOVST}
    {3623601600 21600 0 NOVT}
    {3636302400 25200 1 NOVST}
    {3655051200 21600 0 NOVT}
    {3668356800 25200 1 NOVST}
    {3686500800 21600 0 NOVT}
    {3699806400 25200 1 NOVST}
    {3717950400 21600 0 NOVT}
    {3731256000 25200 1 NOVST}
    {3750004800 21600 0 NOVT}
    {3762705600 25200 1 NOVST}
    {3781454400 21600 0 NOVT}
    {3794155200 25200 1 NOVST}
    {3812904000 21600 0 NOVT}
    {3825604800 25200 1 NOVST}
    {3844353600 21600 0 NOVT}
    {3857659200 25200 1 NOVST}
    {3875803200 21600 0 NOVT}
    {3889108800 25200 1 NOVST}
    {3907252800 21600 0 NOVT}
    {3920558400 25200 1 NOVST}
    {3939307200 21600 0 NOVT}
    {3952008000 25200 1 NOVST}
    {3970756800 21600 0 NOVT}
    {3983457600 25200 1 NOVST}
    {4002206400 21600 0 NOVT}
    {4015512000 25200 1 NOVST}
    {4033656000 21600 0 NOVT}
    {4046961600 25200 1 NOVST}
    {4065105600 21600 0 NOVT}
    {4078411200 25200 1 NOVST}
    {4096555200 21600 0 NOVT}
}







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

63
64
65
66
67
68
69
70

















































































































































































71
    {1206817200 28800 1 KRAST}
    {1224961200 25200 0 KRAT}
    {1238266800 28800 1 KRAST}
    {1256410800 25200 0 KRAT}
    {1269716400 21600 0 NOVMMTT}
    {1269720000 25200 1 NOVST}
    {1288468800 21600 0 NOVT}
    {1301169600 25200 0 NOVT}

















































































































































































}

Changes to library/tzdata/Asia/Novosibirsk.

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
    {1193515200 21600 0 NOVT}
    {1206820800 25200 1 NOVST}
    {1224964800 21600 0 NOVT}
    {1238270400 25200 1 NOVST}
    {1256414400 21600 0 NOVT}
    {1269720000 25200 1 NOVST}
    {1288468800 21600 0 NOVT}
    {1301169600 25200 1 NOVST}
    {1319918400 21600 0 NOVT}
    {1332619200 25200 1 NOVST}
    {1351368000 21600 0 NOVT}
    {1364673600 25200 1 NOVST}
    {1382817600 21600 0 NOVT}
    {1396123200 25200 1 NOVST}
    {1414267200 21600 0 NOVT}
    {1427572800 25200 1 NOVST}
    {1445716800 21600 0 NOVT}
    {1459022400 25200 1 NOVST}
    {1477771200 21600 0 NOVT}
    {1490472000 25200 1 NOVST}
    {1509220800 21600 0 NOVT}
    {1521921600 25200 1 NOVST}
    {1540670400 21600 0 NOVT}
    {1553976000 25200 1 NOVST}
    {1572120000 21600 0 NOVT}
    {1585425600 25200 1 NOVST}
    {1603569600 21600 0 NOVT}
    {1616875200 25200 1 NOVST}
    {1635624000 21600 0 NOVT}
    {1648324800 25200 1 NOVST}
    {1667073600 21600 0 NOVT}
    {1679774400 25200 1 NOVST}
    {1698523200 21600 0 NOVT}
    {1711828800 25200 1 NOVST}
    {1729972800 21600 0 NOVT}
    {1743278400 25200 1 NOVST}
    {1761422400 21600 0 NOVT}
    {1774728000 25200 1 NOVST}
    {1792872000 21600 0 NOVT}
    {1806177600 25200 1 NOVST}
    {1824926400 21600 0 NOVT}
    {1837627200 25200 1 NOVST}
    {1856376000 21600 0 NOVT}
    {1869076800 25200 1 NOVST}
    {1887825600 21600 0 NOVT}
    {1901131200 25200 1 NOVST}
    {1919275200 21600 0 NOVT}
    {1932580800 25200 1 NOVST}
    {1950724800 21600 0 NOVT}
    {1964030400 25200 1 NOVST}
    {1982779200 21600 0 NOVT}
    {1995480000 25200 1 NOVST}
    {2014228800 21600 0 NOVT}
    {2026929600 25200 1 NOVST}
    {2045678400 21600 0 NOVT}
    {2058379200 25200 1 NOVST}
    {2077128000 21600 0 NOVT}
    {2090433600 25200 1 NOVST}
    {2108577600 21600 0 NOVT}
    {2121883200 25200 1 NOVST}
    {2140027200 21600 0 NOVT}
    {2153332800 25200 1 NOVST}
    {2172081600 21600 0 NOVT}
    {2184782400 25200 1 NOVST}
    {2203531200 21600 0 NOVT}
    {2216232000 25200 1 NOVST}
    {2234980800 21600 0 NOVT}
    {2248286400 25200 1 NOVST}
    {2266430400 21600 0 NOVT}
    {2279736000 25200 1 NOVST}
    {2297880000 21600 0 NOVT}
    {2311185600 25200 1 NOVST}
    {2329329600 21600 0 NOVT}
    {2342635200 25200 1 NOVST}
    {2361384000 21600 0 NOVT}
    {2374084800 25200 1 NOVST}
    {2392833600 21600 0 NOVT}
    {2405534400 25200 1 NOVST}
    {2424283200 21600 0 NOVT}
    {2437588800 25200 1 NOVST}
    {2455732800 21600 0 NOVT}
    {2469038400 25200 1 NOVST}
    {2487182400 21600 0 NOVT}
    {2500488000 25200 1 NOVST}
    {2519236800 21600 0 NOVT}
    {2531937600 25200 1 NOVST}
    {2550686400 21600 0 NOVT}
    {2563387200 25200 1 NOVST}
    {2582136000 21600 0 NOVT}
    {2595441600 25200 1 NOVST}
    {2613585600 21600 0 NOVT}
    {2626891200 25200 1 NOVST}
    {2645035200 21600 0 NOVT}
    {2658340800 25200 1 NOVST}
    {2676484800 21600 0 NOVT}
    {2689790400 25200 1 NOVST}
    {2708539200 21600 0 NOVT}
    {2721240000 25200 1 NOVST}
    {2739988800 21600 0 NOVT}
    {2752689600 25200 1 NOVST}
    {2771438400 21600 0 NOVT}
    {2784744000 25200 1 NOVST}
    {2802888000 21600 0 NOVT}
    {2816193600 25200 1 NOVST}
    {2834337600 21600 0 NOVT}
    {2847643200 25200 1 NOVST}
    {2866392000 21600 0 NOVT}
    {2879092800 25200 1 NOVST}
    {2897841600 21600 0 NOVT}
    {2910542400 25200 1 NOVST}
    {2929291200 21600 0 NOVT}
    {2941992000 25200 1 NOVST}
    {2960740800 21600 0 NOVT}
    {2974046400 25200 1 NOVST}
    {2992190400 21600 0 NOVT}
    {3005496000 25200 1 NOVST}
    {3023640000 21600 0 NOVT}
    {3036945600 25200 1 NOVST}
    {3055694400 21600 0 NOVT}
    {3068395200 25200 1 NOVST}
    {3087144000 21600 0 NOVT}
    {3099844800 25200 1 NOVST}
    {3118593600 21600 0 NOVT}
    {3131899200 25200 1 NOVST}
    {3150043200 21600 0 NOVT}
    {3163348800 25200 1 NOVST}
    {3181492800 21600 0 NOVT}
    {3194798400 25200 1 NOVST}
    {3212942400 21600 0 NOVT}
    {3226248000 25200 1 NOVST}
    {3244996800 21600 0 NOVT}
    {3257697600 25200 1 NOVST}
    {3276446400 21600 0 NOVT}
    {3289147200 25200 1 NOVST}
    {3307896000 21600 0 NOVT}
    {3321201600 25200 1 NOVST}
    {3339345600 21600 0 NOVT}
    {3352651200 25200 1 NOVST}
    {3370795200 21600 0 NOVT}
    {3384100800 25200 1 NOVST}
    {3402849600 21600 0 NOVT}
    {3415550400 25200 1 NOVST}
    {3434299200 21600 0 NOVT}
    {3447000000 25200 1 NOVST}
    {3465748800 21600 0 NOVT}
    {3479054400 25200 1 NOVST}
    {3497198400 21600 0 NOVT}
    {3510504000 25200 1 NOVST}
    {3528648000 21600 0 NOVT}
    {3541953600 25200 1 NOVST}
    {3560097600 21600 0 NOVT}
    {3573403200 25200 1 NOVST}
    {3592152000 21600 0 NOVT}
    {3604852800 25200 1 NOVST}
    {3623601600 21600 0 NOVT}
    {3636302400 25200 1 NOVST}
    {3655051200 21600 0 NOVT}
    {3668356800 25200 1 NOVST}
    {3686500800 21600 0 NOVT}
    {3699806400 25200 1 NOVST}
    {3717950400 21600 0 NOVT}
    {3731256000 25200 1 NOVST}
    {3750004800 21600 0 NOVT}
    {3762705600 25200 1 NOVST}
    {3781454400 21600 0 NOVT}
    {3794155200 25200 1 NOVST}
    {3812904000 21600 0 NOVT}
    {3825604800 25200 1 NOVST}
    {3844353600 21600 0 NOVT}
    {3857659200 25200 1 NOVST}
    {3875803200 21600 0 NOVT}
    {3889108800 25200 1 NOVST}
    {3907252800 21600 0 NOVT}
    {3920558400 25200 1 NOVST}
    {3939307200 21600 0 NOVT}
    {3952008000 25200 1 NOVST}
    {3970756800 21600 0 NOVT}
    {3983457600 25200 1 NOVST}
    {4002206400 21600 0 NOVT}
    {4015512000 25200 1 NOVST}
    {4033656000 21600 0 NOVT}
    {4046961600 25200 1 NOVST}
    {4065105600 21600 0 NOVT}
    {4078411200 25200 1 NOVST}
    {4096555200 21600 0 NOVT}
}







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

63
64
65
66
67
68
69
70

















































































































































































71
    {1193515200 21600 0 NOVT}
    {1206820800 25200 1 NOVST}
    {1224964800 21600 0 NOVT}
    {1238270400 25200 1 NOVST}
    {1256414400 21600 0 NOVT}
    {1269720000 25200 1 NOVST}
    {1288468800 21600 0 NOVT}
    {1301169600 25200 0 NOVT}

















































































































































































}

Changes to library/tzdata/Asia/Omsk.

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
    {1193515200 21600 0 OMST}
    {1206820800 25200 1 OMSST}
    {1224964800 21600 0 OMST}
    {1238270400 25200 1 OMSST}
    {1256414400 21600 0 OMST}
    {1269720000 25200 1 OMSST}
    {1288468800 21600 0 OMST}
    {1301169600 25200 1 OMSST}
    {1319918400 21600 0 OMST}
    {1332619200 25200 1 OMSST}
    {1351368000 21600 0 OMST}
    {1364673600 25200 1 OMSST}
    {1382817600 21600 0 OMST}
    {1396123200 25200 1 OMSST}
    {1414267200 21600 0 OMST}
    {1427572800 25200 1 OMSST}
    {1445716800 21600 0 OMST}
    {1459022400 25200 1 OMSST}
    {1477771200 21600 0 OMST}
    {1490472000 25200 1 OMSST}
    {1509220800 21600 0 OMST}
    {1521921600 25200 1 OMSST}
    {1540670400 21600 0 OMST}
    {1553976000 25200 1 OMSST}
    {1572120000 21600 0 OMST}
    {1585425600 25200 1 OMSST}
    {1603569600 21600 0 OMST}
    {1616875200 25200 1 OMSST}
    {1635624000 21600 0 OMST}
    {1648324800 25200 1 OMSST}
    {1667073600 21600 0 OMST}
    {1679774400 25200 1 OMSST}
    {1698523200 21600 0 OMST}
    {1711828800 25200 1 OMSST}
    {1729972800 21600 0 OMST}
    {1743278400 25200 1 OMSST}
    {1761422400 21600 0 OMST}
    {1774728000 25200 1 OMSST}
    {1792872000 21600 0 OMST}
    {1806177600 25200 1 OMSST}
    {1824926400 21600 0 OMST}
    {1837627200 25200 1 OMSST}
    {1856376000 21600 0 OMST}
    {1869076800 25200 1 OMSST}
    {1887825600 21600 0 OMST}
    {1901131200 25200 1 OMSST}
    {1919275200 21600 0 OMST}
    {1932580800 25200 1 OMSST}
    {1950724800 21600 0 OMST}
    {1964030400 25200 1 OMSST}
    {1982779200 21600 0 OMST}
    {1995480000 25200 1 OMSST}
    {2014228800 21600 0 OMST}
    {2026929600 25200 1 OMSST}
    {2045678400 21600 0 OMST}
    {2058379200 25200 1 OMSST}
    {2077128000 21600 0 OMST}
    {2090433600 25200 1 OMSST}
    {2108577600 21600 0 OMST}
    {2121883200 25200 1 OMSST}
    {2140027200 21600 0 OMST}
    {2153332800 25200 1 OMSST}
    {2172081600 21600 0 OMST}
    {2184782400 25200 1 OMSST}
    {2203531200 21600 0 OMST}
    {2216232000 25200 1 OMSST}
    {2234980800 21600 0 OMST}
    {2248286400 25200 1 OMSST}
    {2266430400 21600 0 OMST}
    {2279736000 25200 1 OMSST}
    {2297880000 21600 0 OMST}
    {2311185600 25200 1 OMSST}
    {2329329600 21600 0 OMST}
    {2342635200 25200 1 OMSST}
    {2361384000 21600 0 OMST}
    {2374084800 25200 1 OMSST}
    {2392833600 21600 0 OMST}
    {2405534400 25200 1 OMSST}
    {2424283200 21600 0 OMST}
    {2437588800 25200 1 OMSST}
    {2455732800 21600 0 OMST}
    {2469038400 25200 1 OMSST}
    {2487182400 21600 0 OMST}
    {2500488000 25200 1 OMSST}
    {2519236800 21600 0 OMST}
    {2531937600 25200 1 OMSST}
    {2550686400 21600 0 OMST}
    {2563387200 25200 1 OMSST}
    {2582136000 21600 0 OMST}
    {2595441600 25200 1 OMSST}
    {2613585600 21600 0 OMST}
    {2626891200 25200 1 OMSST}
    {2645035200 21600 0 OMST}
    {2658340800 25200 1 OMSST}
    {2676484800 21600 0 OMST}
    {2689790400 25200 1 OMSST}
    {2708539200 21600 0 OMST}
    {2721240000 25200 1 OMSST}
    {2739988800 21600 0 OMST}
    {2752689600 25200 1 OMSST}
    {2771438400 21600 0 OMST}
    {2784744000 25200 1 OMSST}
    {2802888000 21600 0 OMST}
    {2816193600 25200 1 OMSST}
    {2834337600 21600 0 OMST}
    {2847643200 25200 1 OMSST}
    {2866392000 21600 0 OMST}
    {2879092800 25200 1 OMSST}
    {2897841600 21600 0 OMST}
    {2910542400 25200 1 OMSST}
    {2929291200 21600 0 OMST}
    {2941992000 25200 1 OMSST}
    {2960740800 21600 0 OMST}
    {2974046400 25200 1 OMSST}
    {2992190400 21600 0 OMST}
    {3005496000 25200 1 OMSST}
    {3023640000 21600 0 OMST}
    {3036945600 25200 1 OMSST}
    {3055694400 21600 0 OMST}
    {3068395200 25200 1 OMSST}
    {3087144000 21600 0 OMST}
    {3099844800 25200 1 OMSST}
    {3118593600 21600 0 OMST}
    {3131899200 25200 1 OMSST}
    {3150043200 21600 0 OMST}
    {3163348800 25200 1 OMSST}
    {3181492800 21600 0 OMST}
    {3194798400 25200 1 OMSST}
    {3212942400 21600 0 OMST}
    {3226248000 25200 1 OMSST}
    {3244996800 21600 0 OMST}
    {3257697600 25200 1 OMSST}
    {3276446400 21600 0 OMST}
    {3289147200 25200 1 OMSST}
    {3307896000 21600 0 OMST}
    {3321201600 25200 1 OMSST}
    {3339345600 21600 0 OMST}
    {3352651200 25200 1 OMSST}
    {3370795200 21600 0 OMST}
    {3384100800 25200 1 OMSST}
    {3402849600 21600 0 OMST}
    {3415550400 25200 1 OMSST}
    {3434299200 21600 0 OMST}
    {3447000000 25200 1 OMSST}
    {3465748800 21600 0 OMST}
    {3479054400 25200 1 OMSST}
    {3497198400 21600 0 OMST}
    {3510504000 25200 1 OMSST}
    {3528648000 21600 0 OMST}
    {3541953600 25200 1 OMSST}
    {3560097600 21600 0 OMST}
    {3573403200 25200 1 OMSST}
    {3592152000 21600 0 OMST}
    {3604852800 25200 1 OMSST}
    {3623601600 21600 0 OMST}
    {3636302400 25200 1 OMSST}
    {3655051200 21600 0 OMST}
    {3668356800 25200 1 OMSST}
    {3686500800 21600 0 OMST}
    {3699806400 25200 1 OMSST}
    {3717950400 21600 0 OMST}
    {3731256000 25200 1 OMSST}
    {3750004800 21600 0 OMST}
    {3762705600 25200 1 OMSST}
    {3781454400 21600 0 OMST}
    {3794155200 25200 1 OMSST}
    {3812904000 21600 0 OMST}
    {3825604800 25200 1 OMSST}
    {3844353600 21600 0 OMST}
    {3857659200 25200 1 OMSST}
    {3875803200 21600 0 OMST}
    {3889108800 25200 1 OMSST}
    {3907252800 21600 0 OMST}
    {3920558400 25200 1 OMSST}
    {3939307200 21600 0 OMST}
    {3952008000 25200 1 OMSST}
    {3970756800 21600 0 OMST}
    {3983457600 25200 1 OMSST}
    {4002206400 21600 0 OMST}
    {4015512000 25200 1 OMSST}
    {4033656000 21600 0 OMST}
    {4046961600 25200 1 OMSST}
    {4065105600 21600 0 OMST}
    {4078411200 25200 1 OMSST}
    {4096555200 21600 0 OMST}
}







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

62
63
64
65
66
67
68
69

















































































































































































70
    {1193515200 21600 0 OMST}
    {1206820800 25200 1 OMSST}
    {1224964800 21600 0 OMST}
    {1238270400 25200 1 OMSST}
    {1256414400 21600 0 OMST}
    {1269720000 25200 1 OMSST}
    {1288468800 21600 0 OMST}
    {1301169600 25200 0 OMST}

















































































































































































}

Changes to library/tzdata/Asia/Sakhalin.

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
    {1193500800 36000 0 SAKT}
    {1206806400 39600 1 SAKST}
    {1224950400 36000 0 SAKT}
    {1238256000 39600 1 SAKST}
    {1256400000 36000 0 SAKT}
    {1269705600 39600 1 SAKST}
    {1288454400 36000 0 SAKT}
    {1301155200 39600 1 SAKST}
    {1319904000 36000 0 SAKT}
    {1332604800 39600 1 SAKST}
    {1351353600 36000 0 SAKT}
    {1364659200 39600 1 SAKST}
    {1382803200 36000 0 SAKT}
    {1396108800 39600 1 SAKST}
    {1414252800 36000 0 SAKT}
    {1427558400 39600 1 SAKST}
    {1445702400 36000 0 SAKT}
    {1459008000 39600 1 SAKST}
    {1477756800 36000 0 SAKT}
    {1490457600 39600 1 SAKST}
    {1509206400 36000 0 SAKT}
    {1521907200 39600 1 SAKST}
    {1540656000 36000 0 SAKT}
    {1553961600 39600 1 SAKST}
    {1572105600 36000 0 SAKT}
    {1585411200 39600 1 SAKST}
    {1603555200 36000 0 SAKT}
    {1616860800 39600 1 SAKST}
    {1635609600 36000 0 SAKT}
    {1648310400 39600 1 SAKST}
    {1667059200 36000 0 SAKT}
    {1679760000 39600 1 SAKST}
    {1698508800 36000 0 SAKT}
    {1711814400 39600 1 SAKST}
    {1729958400 36000 0 SAKT}
    {1743264000 39600 1 SAKST}
    {1761408000 36000 0 SAKT}
    {1774713600 39600 1 SAKST}
    {1792857600 36000 0 SAKT}
    {1806163200 39600 1 SAKST}
    {1824912000 36000 0 SAKT}
    {1837612800 39600 1 SAKST}
    {1856361600 36000 0 SAKT}
    {1869062400 39600 1 SAKST}
    {1887811200 36000 0 SAKT}
    {1901116800 39600 1 SAKST}
    {1919260800 36000 0 SAKT}
    {1932566400 39600 1 SAKST}
    {1950710400 36000 0 SAKT}
    {1964016000 39600 1 SAKST}
    {1982764800 36000 0 SAKT}
    {1995465600 39600 1 SAKST}
    {2014214400 36000 0 SAKT}
    {2026915200 39600 1 SAKST}
    {2045664000 36000 0 SAKT}
    {2058364800 39600 1 SAKST}
    {2077113600 36000 0 SAKT}
    {2090419200 39600 1 SAKST}
    {2108563200 36000 0 SAKT}
    {2121868800 39600 1 SAKST}
    {2140012800 36000 0 SAKT}
    {2153318400 39600 1 SAKST}
    {2172067200 36000 0 SAKT}
    {2184768000 39600 1 SAKST}
    {2203516800 36000 0 SAKT}
    {2216217600 39600 1 SAKST}
    {2234966400 36000 0 SAKT}
    {2248272000 39600 1 SAKST}
    {2266416000 36000 0 SAKT}
    {2279721600 39600 1 SAKST}
    {2297865600 36000 0 SAKT}
    {2311171200 39600 1 SAKST}
    {2329315200 36000 0 SAKT}
    {2342620800 39600 1 SAKST}
    {2361369600 36000 0 SAKT}
    {2374070400 39600 1 SAKST}
    {2392819200 36000 0 SAKT}
    {2405520000 39600 1 SAKST}
    {2424268800 36000 0 SAKT}
    {2437574400 39600 1 SAKST}
    {2455718400 36000 0 SAKT}
    {2469024000 39600 1 SAKST}
    {2487168000 36000 0 SAKT}
    {2500473600 39600 1 SAKST}
    {2519222400 36000 0 SAKT}
    {2531923200 39600 1 SAKST}
    {2550672000 36000 0 SAKT}
    {2563372800 39600 1 SAKST}
    {2582121600 36000 0 SAKT}
    {2595427200 39600 1 SAKST}
    {2613571200 36000 0 SAKT}
    {2626876800 39600 1 SAKST}
    {2645020800 36000 0 SAKT}
    {2658326400 39600 1 SAKST}
    {2676470400 36000 0 SAKT}
    {2689776000 39600 1 SAKST}
    {2708524800 36000 0 SAKT}
    {2721225600 39600 1 SAKST}
    {2739974400 36000 0 SAKT}
    {2752675200 39600 1 SAKST}
    {2771424000 36000 0 SAKT}
    {2784729600 39600 1 SAKST}
    {2802873600 36000 0 SAKT}
    {2816179200 39600 1 SAKST}
    {2834323200 36000 0 SAKT}
    {2847628800 39600 1 SAKST}
    {2866377600 36000 0 SAKT}
    {2879078400 39600 1 SAKST}
    {2897827200 36000 0 SAKT}
    {2910528000 39600 1 SAKST}
    {2929276800 36000 0 SAKT}
    {2941977600 39600 1 SAKST}
    {2960726400 36000 0 SAKT}
    {2974032000 39600 1 SAKST}
    {2992176000 36000 0 SAKT}
    {3005481600 39600 1 SAKST}
    {3023625600 36000 0 SAKT}
    {3036931200 39600 1 SAKST}
    {3055680000 36000 0 SAKT}
    {3068380800 39600 1 SAKST}
    {3087129600 36000 0 SAKT}
    {3099830400 39600 1 SAKST}
    {3118579200 36000 0 SAKT}
    {3131884800 39600 1 SAKST}
    {3150028800 36000 0 SAKT}
    {3163334400 39600 1 SAKST}
    {3181478400 36000 0 SAKT}
    {3194784000 39600 1 SAKST}
    {3212928000 36000 0 SAKT}
    {3226233600 39600 1 SAKST}
    {3244982400 36000 0 SAKT}
    {3257683200 39600 1 SAKST}
    {3276432000 36000 0 SAKT}
    {3289132800 39600 1 SAKST}
    {3307881600 36000 0 SAKT}
    {3321187200 39600 1 SAKST}
    {3339331200 36000 0 SAKT}
    {3352636800 39600 1 SAKST}
    {3370780800 36000 0 SAKT}
    {3384086400 39600 1 SAKST}
    {3402835200 36000 0 SAKT}
    {3415536000 39600 1 SAKST}
    {3434284800 36000 0 SAKT}
    {3446985600 39600 1 SAKST}
    {3465734400 36000 0 SAKT}
    {3479040000 39600 1 SAKST}
    {3497184000 36000 0 SAKT}
    {3510489600 39600 1 SAKST}
    {3528633600 36000 0 SAKT}
    {3541939200 39600 1 SAKST}
    {3560083200 36000 0 SAKT}
    {3573388800 39600 1 SAKST}
    {3592137600 36000 0 SAKT}
    {3604838400 39600 1 SAKST}
    {3623587200 36000 0 SAKT}
    {3636288000 39600 1 SAKST}
    {3655036800 36000 0 SAKT}
    {3668342400 39600 1 SAKST}
    {3686486400 36000 0 SAKT}
    {3699792000 39600 1 SAKST}
    {3717936000 36000 0 SAKT}
    {3731241600 39600 1 SAKST}
    {3749990400 36000 0 SAKT}
    {3762691200 39600 1 SAKST}
    {3781440000 36000 0 SAKT}
    {3794140800 39600 1 SAKST}
    {3812889600 36000 0 SAKT}
    {3825590400 39600 1 SAKST}
    {3844339200 36000 0 SAKT}
    {3857644800 39600 1 SAKST}
    {3875788800 36000 0 SAKT}
    {3889094400 39600 1 SAKST}
    {3907238400 36000 0 SAKT}
    {3920544000 39600 1 SAKST}
    {3939292800 36000 0 SAKT}
    {3951993600 39600 1 SAKST}
    {3970742400 36000 0 SAKT}
    {3983443200 39600 1 SAKST}
    {4002192000 36000 0 SAKT}
    {4015497600 39600 1 SAKST}
    {4033641600 36000 0 SAKT}
    {4046947200 39600 1 SAKST}
    {4065091200 36000 0 SAKT}
    {4078396800 39600 1 SAKST}
    {4096540800 36000 0 SAKT}
}







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

64
65
66
67
68
69
70
71

















































































































































































72
    {1193500800 36000 0 SAKT}
    {1206806400 39600 1 SAKST}
    {1224950400 36000 0 SAKT}
    {1238256000 39600 1 SAKST}
    {1256400000 36000 0 SAKT}
    {1269705600 39600 1 SAKST}
    {1288454400 36000 0 SAKT}
    {1301155200 39600 0 SAKT}

















































































































































































}

Changes to library/tzdata/Asia/Vladivostok.

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
    {1193500800 36000 0 VLAT}
    {1206806400 39600 1 VLAST}
    {1224950400 36000 0 VLAT}
    {1238256000 39600 1 VLAST}
    {1256400000 36000 0 VLAT}
    {1269705600 39600 1 VLAST}
    {1288454400 36000 0 VLAT}
    {1301155200 39600 1 VLAST}
    {1319904000 36000 0 VLAT}
    {1332604800 39600 1 VLAST}
    {1351353600 36000 0 VLAT}
    {1364659200 39600 1 VLAST}
    {1382803200 36000 0 VLAT}
    {1396108800 39600 1 VLAST}
    {1414252800 36000 0 VLAT}
    {1427558400 39600 1 VLAST}
    {1445702400 36000 0 VLAT}
    {1459008000 39600 1 VLAST}
    {1477756800 36000 0 VLAT}
    {1490457600 39600 1 VLAST}
    {1509206400 36000 0 VLAT}
    {1521907200 39600 1 VLAST}
    {1540656000 36000 0 VLAT}
    {1553961600 39600 1 VLAST}
    {1572105600 36000 0 VLAT}
    {1585411200 39600 1 VLAST}
    {1603555200 36000 0 VLAT}
    {1616860800 39600 1 VLAST}
    {1635609600 36000 0 VLAT}
    {1648310400 39600 1 VLAST}
    {1667059200 36000 0 VLAT}
    {1679760000 39600 1 VLAST}
    {1698508800 36000 0 VLAT}
    {1711814400 39600 1 VLAST}
    {1729958400 36000 0 VLAT}
    {1743264000 39600 1 VLAST}
    {1761408000 36000 0 VLAT}
    {1774713600 39600 1 VLAST}
    {1792857600 36000 0 VLAT}
    {1806163200 39600 1 VLAST}
    {1824912000 36000 0 VLAT}
    {1837612800 39600 1 VLAST}
    {1856361600 36000 0 VLAT}
    {1869062400 39600 1 VLAST}
    {1887811200 36000 0 VLAT}
    {1901116800 39600 1 VLAST}
    {1919260800 36000 0 VLAT}
    {1932566400 39600 1 VLAST}
    {1950710400 36000 0 VLAT}
    {1964016000 39600 1 VLAST}
    {1982764800 36000 0 VLAT}
    {1995465600 39600 1 VLAST}
    {2014214400 36000 0 VLAT}
    {2026915200 39600 1 VLAST}
    {2045664000 36000 0 VLAT}
    {2058364800 39600 1 VLAST}
    {2077113600 36000 0 VLAT}
    {2090419200 39600 1 VLAST}
    {2108563200 36000 0 VLAT}
    {2121868800 39600 1 VLAST}
    {2140012800 36000 0 VLAT}
    {2153318400 39600 1 VLAST}
    {2172067200 36000 0 VLAT}
    {2184768000 39600 1 VLAST}
    {2203516800 36000 0 VLAT}
    {2216217600 39600 1 VLAST}
    {2234966400 36000 0 VLAT}
    {2248272000 39600 1 VLAST}
    {2266416000 36000 0 VLAT}
    {2279721600 39600 1 VLAST}
    {2297865600 36000 0 VLAT}
    {2311171200 39600 1 VLAST}
    {2329315200 36000 0 VLAT}
    {2342620800 39600 1 VLAST}
    {2361369600 36000 0 VLAT}
    {2374070400 39600 1 VLAST}
    {2392819200 36000 0 VLAT}
    {2405520000 39600 1 VLAST}
    {2424268800 36000 0 VLAT}
    {2437574400 39600 1 VLAST}
    {2455718400 36000 0 VLAT}
    {2469024000 39600 1 VLAST}
    {2487168000 36000 0 VLAT}
    {2500473600 39600 1 VLAST}
    {2519222400 36000 0 VLAT}
    {2531923200 39600 1 VLAST}
    {2550672000 36000 0 VLAT}
    {2563372800 39600 1 VLAST}
    {2582121600 36000 0 VLAT}
    {2595427200 39600 1 VLAST}
    {2613571200 36000 0 VLAT}
    {2626876800 39600 1 VLAST}
    {2645020800 36000 0 VLAT}
    {2658326400 39600 1 VLAST}
    {2676470400 36000 0 VLAT}
    {2689776000 39600 1 VLAST}
    {2708524800 36000 0 VLAT}
    {2721225600 39600 1 VLAST}
    {2739974400 36000 0 VLAT}
    {2752675200 39600 1 VLAST}
    {2771424000 36000 0 VLAT}
    {2784729600 39600 1 VLAST}
    {2802873600 36000 0 VLAT}
    {2816179200 39600 1 VLAST}
    {2834323200 36000 0 VLAT}
    {2847628800 39600 1 VLAST}
    {2866377600 36000 0 VLAT}
    {2879078400 39600 1 VLAST}
    {2897827200 36000 0 VLAT}
    {2910528000 39600 1 VLAST}
    {2929276800 36000 0 VLAT}
    {2941977600 39600 1 VLAST}
    {2960726400 36000 0 VLAT}
    {2974032000 39600 1 VLAST}
    {2992176000 36000 0 VLAT}
    {3005481600 39600 1 VLAST}
    {3023625600 36000 0 VLAT}
    {3036931200 39600 1 VLAST}
    {3055680000 36000 0 VLAT}
    {3068380800 39600 1 VLAST}
    {3087129600 36000 0 VLAT}
    {3099830400 39600 1 VLAST}
    {3118579200 36000 0 VLAT}
    {3131884800 39600 1 VLAST}
    {3150028800 36000 0 VLAT}
    {3163334400 39600 1 VLAST}
    {3181478400 36000 0 VLAT}
    {3194784000 39600 1 VLAST}
    {3212928000 36000 0 VLAT}
    {3226233600 39600 1 VLAST}
    {3244982400 36000 0 VLAT}
    {3257683200 39600 1 VLAST}
    {3276432000 36000 0 VLAT}
    {3289132800 39600 1 VLAST}
    {3307881600 36000 0 VLAT}
    {3321187200 39600 1 VLAST}
    {3339331200 36000 0 VLAT}
    {3352636800 39600 1 VLAST}
    {3370780800 36000 0 VLAT}
    {3384086400 39600 1 VLAST}
    {3402835200 36000 0 VLAT}
    {3415536000 39600 1 VLAST}
    {3434284800 36000 0 VLAT}
    {3446985600 39600 1 VLAST}
    {3465734400 36000 0 VLAT}
    {3479040000 39600 1 VLAST}
    {3497184000 36000 0 VLAT}
    {3510489600 39600 1 VLAST}
    {3528633600 36000 0 VLAT}
    {3541939200 39600 1 VLAST}
    {3560083200 36000 0 VLAT}
    {3573388800 39600 1 VLAST}
    {3592137600 36000 0 VLAT}
    {3604838400 39600 1 VLAST}
    {3623587200 36000 0 VLAT}
    {3636288000 39600 1 VLAST}
    {3655036800 36000 0 VLAT}
    {3668342400 39600 1 VLAST}
    {3686486400 36000 0 VLAT}
    {3699792000 39600 1 VLAST}
    {3717936000 36000 0 VLAT}
    {3731241600 39600 1 VLAST}
    {3749990400 36000 0 VLAT}
    {3762691200 39600 1 VLAST}
    {3781440000 36000 0 VLAT}
    {3794140800 39600 1 VLAST}
    {3812889600 36000 0 VLAT}
    {3825590400 39600 1 VLAST}
    {3844339200 36000 0 VLAT}
    {3857644800 39600 1 VLAST}
    {3875788800 36000 0 VLAT}
    {3889094400 39600 1 VLAST}
    {3907238400 36000 0 VLAT}
    {3920544000 39600 1 VLAST}
    {3939292800 36000 0 VLAT}
    {3951993600 39600 1 VLAST}
    {3970742400 36000 0 VLAT}
    {3983443200 39600 1 VLAST}
    {4002192000 36000 0 VLAT}
    {4015497600 39600 1 VLAST}
    {4033641600 36000 0 VLAT}
    {4046947200 39600 1 VLAST}
    {4065091200 36000 0 VLAT}
    {4078396800 39600 1 VLAST}
    {4096540800 36000 0 VLAT}
}







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

62
63
64
65
66
67
68
69

















































































































































































70
    {1193500800 36000 0 VLAT}
    {1206806400 39600 1 VLAST}
    {1224950400 36000 0 VLAT}
    {1238256000 39600 1 VLAST}
    {1256400000 36000 0 VLAT}
    {1269705600 39600 1 VLAST}
    {1288454400 36000 0 VLAT}
    {1301155200 39600 0 VLAT}

















































































































































































}

Changes to library/tzdata/Asia/Yakutsk.

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
    {1193504400 32400 0 YAKT}
    {1206810000 36000 1 YAKST}
    {1224954000 32400 0 YAKT}
    {1238259600 36000 1 YAKST}
    {1256403600 32400 0 YAKT}
    {1269709200 36000 1 YAKST}
    {1288458000 32400 0 YAKT}
    {1301158800 36000 1 YAKST}
    {1319907600 32400 0 YAKT}
    {1332608400 36000 1 YAKST}
    {1351357200 32400 0 YAKT}
    {1364662800 36000 1 YAKST}
    {1382806800 32400 0 YAKT}
    {1396112400 36000 1 YAKST}
    {1414256400 32400 0 YAKT}
    {1427562000 36000 1 YAKST}
    {1445706000 32400 0 YAKT}
    {1459011600 36000 1 YAKST}
    {1477760400 32400 0 YAKT}
    {1490461200 36000 1 YAKST}
    {1509210000 32400 0 YAKT}
    {1521910800 36000 1 YAKST}
    {1540659600 32400 0 YAKT}
    {1553965200 36000 1 YAKST}
    {1572109200 32400 0 YAKT}
    {1585414800 36000 1 YAKST}
    {1603558800 32400 0 YAKT}
    {1616864400 36000 1 YAKST}
    {1635613200 32400 0 YAKT}
    {1648314000 36000 1 YAKST}
    {1667062800 32400 0 YAKT}
    {1679763600 36000 1 YAKST}
    {1698512400 32400 0 YAKT}
    {1711818000 36000 1 YAKST}
    {1729962000 32400 0 YAKT}
    {1743267600 36000 1 YAKST}
    {1761411600 32400 0 YAKT}
    {1774717200 36000 1 YAKST}
    {1792861200 32400 0 YAKT}
    {1806166800 36000 1 YAKST}
    {1824915600 32400 0 YAKT}
    {1837616400 36000 1 YAKST}
    {1856365200 32400 0 YAKT}
    {1869066000 36000 1 YAKST}
    {1887814800 32400 0 YAKT}
    {1901120400 36000 1 YAKST}
    {1919264400 32400 0 YAKT}
    {1932570000 36000 1 YAKST}
    {1950714000 32400 0 YAKT}
    {1964019600 36000 1 YAKST}
    {1982768400 32400 0 YAKT}
    {1995469200 36000 1 YAKST}
    {2014218000 32400 0 YAKT}
    {2026918800 36000 1 YAKST}
    {2045667600 32400 0 YAKT}
    {2058368400 36000 1 YAKST}
    {2077117200 32400 0 YAKT}
    {2090422800 36000 1 YAKST}
    {2108566800 32400 0 YAKT}
    {2121872400 36000 1 YAKST}
    {2140016400 32400 0 YAKT}
    {2153322000 36000 1 YAKST}
    {2172070800 32400 0 YAKT}
    {2184771600 36000 1 YAKST}
    {2203520400 32400 0 YAKT}
    {2216221200 36000 1 YAKST}
    {2234970000 32400 0 YAKT}
    {2248275600 36000 1 YAKST}
    {2266419600 32400 0 YAKT}
    {2279725200 36000 1 YAKST}
    {2297869200 32400 0 YAKT}
    {2311174800 36000 1 YAKST}
    {2329318800 32400 0 YAKT}
    {2342624400 36000 1 YAKST}
    {2361373200 32400 0 YAKT}
    {2374074000 36000 1 YAKST}
    {2392822800 32400 0 YAKT}
    {2405523600 36000 1 YAKST}
    {2424272400 32400 0 YAKT}
    {2437578000 36000 1 YAKST}
    {2455722000 32400 0 YAKT}
    {2469027600 36000 1 YAKST}
    {2487171600 32400 0 YAKT}
    {2500477200 36000 1 YAKST}
    {2519226000 32400 0 YAKT}
    {2531926800 36000 1 YAKST}
    {2550675600 32400 0 YAKT}
    {2563376400 36000 1 YAKST}
    {2582125200 32400 0 YAKT}
    {2595430800 36000 1 YAKST}
    {2613574800 32400 0 YAKT}
    {2626880400 36000 1 YAKST}
    {2645024400 32400 0 YAKT}
    {2658330000 36000 1 YAKST}
    {2676474000 32400 0 YAKT}
    {2689779600 36000 1 YAKST}
    {2708528400 32400 0 YAKT}
    {2721229200 36000 1 YAKST}
    {2739978000 32400 0 YAKT}
    {2752678800 36000 1 YAKST}
    {2771427600 32400 0 YAKT}
    {2784733200 36000 1 YAKST}
    {2802877200 32400 0 YAKT}
    {2816182800 36000 1 YAKST}
    {2834326800 32400 0 YAKT}
    {2847632400 36000 1 YAKST}
    {2866381200 32400 0 YAKT}
    {2879082000 36000 1 YAKST}
    {2897830800 32400 0 YAKT}
    {2910531600 36000 1 YAKST}
    {2929280400 32400 0 YAKT}
    {2941981200 36000 1 YAKST}
    {2960730000 32400 0 YAKT}
    {2974035600 36000 1 YAKST}
    {2992179600 32400 0 YAKT}
    {3005485200 36000 1 YAKST}
    {3023629200 32400 0 YAKT}
    {3036934800 36000 1 YAKST}
    {3055683600 32400 0 YAKT}
    {3068384400 36000 1 YAKST}
    {3087133200 32400 0 YAKT}
    {3099834000 36000 1 YAKST}
    {3118582800 32400 0 YAKT}
    {3131888400 36000 1 YAKST}
    {3150032400 32400 0 YAKT}
    {3163338000 36000 1 YAKST}
    {3181482000 32400 0 YAKT}
    {3194787600 36000 1 YAKST}
    {3212931600 32400 0 YAKT}
    {3226237200 36000 1 YAKST}
    {3244986000 32400 0 YAKT}
    {3257686800 36000 1 YAKST}
    {3276435600 32400 0 YAKT}
    {3289136400 36000 1 YAKST}
    {3307885200 32400 0 YAKT}
    {3321190800 36000 1 YAKST}
    {3339334800 32400 0 YAKT}
    {3352640400 36000 1 YAKST}
    {3370784400 32400 0 YAKT}
    {3384090000 36000 1 YAKST}
    {3402838800 32400 0 YAKT}
    {3415539600 36000 1 YAKST}
    {3434288400 32400 0 YAKT}
    {3446989200 36000 1 YAKST}
    {3465738000 32400 0 YAKT}
    {3479043600 36000 1 YAKST}
    {3497187600 32400 0 YAKT}
    {3510493200 36000 1 YAKST}
    {3528637200 32400 0 YAKT}
    {3541942800 36000 1 YAKST}
    {3560086800 32400 0 YAKT}
    {3573392400 36000 1 YAKST}
    {3592141200 32400 0 YAKT}
    {3604842000 36000 1 YAKST}
    {3623590800 32400 0 YAKT}
    {3636291600 36000 1 YAKST}
    {3655040400 32400 0 YAKT}
    {3668346000 36000 1 YAKST}
    {3686490000 32400 0 YAKT}
    {3699795600 36000 1 YAKST}
    {3717939600 32400 0 YAKT}
    {3731245200 36000 1 YAKST}
    {3749994000 32400 0 YAKT}
    {3762694800 36000 1 YAKST}
    {3781443600 32400 0 YAKT}
    {3794144400 36000 1 YAKST}
    {3812893200 32400 0 YAKT}
    {3825594000 36000 1 YAKST}
    {3844342800 32400 0 YAKT}
    {3857648400 36000 1 YAKST}
    {3875792400 32400 0 YAKT}
    {3889098000 36000 1 YAKST}
    {3907242000 32400 0 YAKT}
    {3920547600 36000 1 YAKST}
    {3939296400 32400 0 YAKT}
    {3951997200 36000 1 YAKST}
    {3970746000 32400 0 YAKT}
    {3983446800 36000 1 YAKST}
    {4002195600 32400 0 YAKT}
    {4015501200 36000 1 YAKST}
    {4033645200 32400 0 YAKT}
    {4046950800 36000 1 YAKST}
    {4065094800 32400 0 YAKT}
    {4078400400 36000 1 YAKST}
    {4096544400 32400 0 YAKT}
}







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

62
63
64
65
66
67
68
69

















































































































































































70
    {1193504400 32400 0 YAKT}
    {1206810000 36000 1 YAKST}
    {1224954000 32400 0 YAKT}
    {1238259600 36000 1 YAKST}
    {1256403600 32400 0 YAKT}
    {1269709200 36000 1 YAKST}
    {1288458000 32400 0 YAKT}
    {1301158800 36000 0 YAKT}

















































































































































































}

Changes to library/tzdata/Asia/Yekaterinburg.

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
    {1193518800 18000 0 YEKT}
    {1206824400 21600 1 YEKST}
    {1224968400 18000 0 YEKT}
    {1238274000 21600 1 YEKST}
    {1256418000 18000 0 YEKT}
    {1269723600 21600 1 YEKST}
    {1288472400 18000 0 YEKT}
    {1301173200 21600 1 YEKST}
    {1319922000 18000 0 YEKT}
    {1332622800 21600 1 YEKST}
    {1351371600 18000 0 YEKT}
    {1364677200 21600 1 YEKST}
    {1382821200 18000 0 YEKT}
    {1396126800 21600 1 YEKST}
    {1414270800 18000 0 YEKT}
    {1427576400 21600 1 YEKST}
    {1445720400 18000 0 YEKT}
    {1459026000 21600 1 YEKST}
    {1477774800 18000 0 YEKT}
    {1490475600 21600 1 YEKST}
    {1509224400 18000 0 YEKT}
    {1521925200 21600 1 YEKST}
    {1540674000 18000 0 YEKT}
    {1553979600 21600 1 YEKST}
    {1572123600 18000 0 YEKT}
    {1585429200 21600 1 YEKST}
    {1603573200 18000 0 YEKT}
    {1616878800 21600 1 YEKST}
    {1635627600 18000 0 YEKT}
    {1648328400 21600 1 YEKST}
    {1667077200 18000 0 YEKT}
    {1679778000 21600 1 YEKST}
    {1698526800 18000 0 YEKT}
    {1711832400 21600 1 YEKST}
    {1729976400 18000 0 YEKT}
    {1743282000 21600 1 YEKST}
    {1761426000 18000 0 YEKT}
    {1774731600 21600 1 YEKST}
    {1792875600 18000 0 YEKT}
    {1806181200 21600 1 YEKST}
    {1824930000 18000 0 YEKT}
    {1837630800 21600 1 YEKST}
    {1856379600 18000 0 YEKT}
    {1869080400 21600 1 YEKST}
    {1887829200 18000 0 YEKT}
    {1901134800 21600 1 YEKST}
    {1919278800 18000 0 YEKT}
    {1932584400 21600 1 YEKST}
    {1950728400 18000 0 YEKT}
    {1964034000 21600 1 YEKST}
    {1982782800 18000 0 YEKT}
    {1995483600 21600 1 YEKST}
    {2014232400 18000 0 YEKT}
    {2026933200 21600 1 YEKST}
    {2045682000 18000 0 YEKT}
    {2058382800 21600 1 YEKST}
    {2077131600 18000 0 YEKT}
    {2090437200 21600 1 YEKST}
    {2108581200 18000 0 YEKT}
    {2121886800 21600 1 YEKST}
    {2140030800 18000 0 YEKT}
    {2153336400 21600 1 YEKST}
    {2172085200 18000 0 YEKT}
    {2184786000 21600 1 YEKST}
    {2203534800 18000 0 YEKT}
    {2216235600 21600 1 YEKST}
    {2234984400 18000 0 YEKT}
    {2248290000 21600 1 YEKST}
    {2266434000 18000 0 YEKT}
    {2279739600 21600 1 YEKST}
    {2297883600 18000 0 YEKT}
    {2311189200 21600 1 YEKST}
    {2329333200 18000 0 YEKT}
    {2342638800 21600 1 YEKST}
    {2361387600 18000 0 YEKT}
    {2374088400 21600 1 YEKST}
    {2392837200 18000 0 YEKT}
    {2405538000 21600 1 YEKST}
    {2424286800 18000 0 YEKT}
    {2437592400 21600 1 YEKST}
    {2455736400 18000 0 YEKT}
    {2469042000 21600 1 YEKST}
    {2487186000 18000 0 YEKT}
    {2500491600 21600 1 YEKST}
    {2519240400 18000 0 YEKT}
    {2531941200 21600 1 YEKST}
    {2550690000 18000 0 YEKT}
    {2563390800 21600 1 YEKST}
    {2582139600 18000 0 YEKT}
    {2595445200 21600 1 YEKST}
    {2613589200 18000 0 YEKT}
    {2626894800 21600 1 YEKST}
    {2645038800 18000 0 YEKT}
    {2658344400 21600 1 YEKST}
    {2676488400 18000 0 YEKT}
    {2689794000 21600 1 YEKST}
    {2708542800 18000 0 YEKT}
    {2721243600 21600 1 YEKST}
    {2739992400 18000 0 YEKT}
    {2752693200 21600 1 YEKST}
    {2771442000 18000 0 YEKT}
    {2784747600 21600 1 YEKST}
    {2802891600 18000 0 YEKT}
    {2816197200 21600 1 YEKST}
    {2834341200 18000 0 YEKT}
    {2847646800 21600 1 YEKST}
    {2866395600 18000 0 YEKT}
    {2879096400 21600 1 YEKST}
    {2897845200 18000 0 YEKT}
    {2910546000 21600 1 YEKST}
    {2929294800 18000 0 YEKT}
    {2941995600 21600 1 YEKST}
    {2960744400 18000 0 YEKT}
    {2974050000 21600 1 YEKST}
    {2992194000 18000 0 YEKT}
    {3005499600 21600 1 YEKST}
    {3023643600 18000 0 YEKT}
    {3036949200 21600 1 YEKST}
    {3055698000 18000 0 YEKT}
    {3068398800 21600 1 YEKST}
    {3087147600 18000 0 YEKT}
    {3099848400 21600 1 YEKST}
    {3118597200 18000 0 YEKT}
    {3131902800 21600 1 YEKST}
    {3150046800 18000 0 YEKT}
    {3163352400 21600 1 YEKST}
    {3181496400 18000 0 YEKT}
    {3194802000 21600 1 YEKST}
    {3212946000 18000 0 YEKT}
    {3226251600 21600 1 YEKST}
    {3245000400 18000 0 YEKT}
    {3257701200 21600 1 YEKST}
    {3276450000 18000 0 YEKT}
    {3289150800 21600 1 YEKST}
    {3307899600 18000 0 YEKT}
    {3321205200 21600 1 YEKST}
    {3339349200 18000 0 YEKT}
    {3352654800 21600 1 YEKST}
    {3370798800 18000 0 YEKT}
    {3384104400 21600 1 YEKST}
    {3402853200 18000 0 YEKT}
    {3415554000 21600 1 YEKST}
    {3434302800 18000 0 YEKT}
    {3447003600 21600 1 YEKST}
    {3465752400 18000 0 YEKT}
    {3479058000 21600 1 YEKST}
    {3497202000 18000 0 YEKT}
    {3510507600 21600 1 YEKST}
    {3528651600 18000 0 YEKT}
    {3541957200 21600 1 YEKST}
    {3560101200 18000 0 YEKT}
    {3573406800 21600 1 YEKST}
    {3592155600 18000 0 YEKT}
    {3604856400 21600 1 YEKST}
    {3623605200 18000 0 YEKT}
    {3636306000 21600 1 YEKST}
    {3655054800 18000 0 YEKT}
    {3668360400 21600 1 YEKST}
    {3686504400 18000 0 YEKT}
    {3699810000 21600 1 YEKST}
    {3717954000 18000 0 YEKT}
    {3731259600 21600 1 YEKST}
    {3750008400 18000 0 YEKT}
    {3762709200 21600 1 YEKST}
    {3781458000 18000 0 YEKT}
    {3794158800 21600 1 YEKST}
    {3812907600 18000 0 YEKT}
    {3825608400 21600 1 YEKST}
    {3844357200 18000 0 YEKT}
    {3857662800 21600 1 YEKST}
    {3875806800 18000 0 YEKT}
    {3889112400 21600 1 YEKST}
    {3907256400 18000 0 YEKT}
    {3920562000 21600 1 YEKST}
    {3939310800 18000 0 YEKT}
    {3952011600 21600 1 YEKST}
    {3970760400 18000 0 YEKT}
    {3983461200 21600 1 YEKST}
    {4002210000 18000 0 YEKT}
    {4015515600 21600 1 YEKST}
    {4033659600 18000 0 YEKT}
    {4046965200 21600 1 YEKST}
    {4065109200 18000 0 YEKT}
    {4078414800 21600 1 YEKST}
    {4096558800 18000 0 YEKT}
}







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

62
63
64
65
66
67
68
69

















































































































































































70
    {1193518800 18000 0 YEKT}
    {1206824400 21600 1 YEKST}
    {1224968400 18000 0 YEKT}
    {1238274000 21600 1 YEKST}
    {1256418000 18000 0 YEKT}
    {1269723600 21600 1 YEKST}
    {1288472400 18000 0 YEKT}
    {1301173200 21600 0 YEKT}

















































































































































































}

Changes to library/tzdata/Atlantic/Stanley.

68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
    {1188712800 -10800 1 FKST}
    {1208667600 -14400 0 FKT}
    {1220767200 -10800 1 FKST}
    {1240117200 -14400 0 FKT}
    {1252216800 -10800 1 FKST}
    {1271566800 -14400 0 FKT}
    {1283666400 -10800 1 FKST}
    {1303016400 -14400 0 FKT}
    {1315116000 -10800 1 FKST}
    {1334466000 -14400 0 FKT}
    {1346565600 -10800 1 FKST}
    {1366520400 -14400 0 FKT}
    {1378015200 -10800 1 FKST}
    {1397970000 -14400 0 FKT}
    {1410069600 -10800 1 FKST}
    {1429419600 -14400 0 FKT}







<
|







68
69
70
71
72
73
74

75
76
77
78
79
80
81
82
    {1188712800 -10800 1 FKST}
    {1208667600 -14400 0 FKT}
    {1220767200 -10800 1 FKST}
    {1240117200 -14400 0 FKT}
    {1252216800 -10800 1 FKST}
    {1271566800 -14400 0 FKT}
    {1283666400 -10800 1 FKST}

    {1315112400 -10800 1 FKST}
    {1334466000 -14400 0 FKT}
    {1346565600 -10800 1 FKST}
    {1366520400 -14400 0 FKT}
    {1378015200 -10800 1 FKST}
    {1397970000 -14400 0 FKT}
    {1410069600 -10800 1 FKST}
    {1429419600 -14400 0 FKT}

Changes to library/tzdata/Europe/Kaliningrad.

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
    {1193529600 7200 0 EET}
    {1206835200 10800 1 EEST}
    {1224979200 7200 0 EET}
    {1238284800 10800 1 EEST}
    {1256428800 7200 0 EET}
    {1269734400 10800 1 EEST}
    {1288483200 7200 0 EET}
    {1301184000 10800 1 EEST}
    {1319932800 7200 0 EET}
    {1332633600 10800 1 EEST}
    {1351382400 7200 0 EET}
    {1364688000 10800 1 EEST}
    {1382832000 7200 0 EET}
    {1396137600 10800 1 EEST}
    {1414281600 7200 0 EET}
    {1427587200 10800 1 EEST}
    {1445731200 7200 0 EET}
    {1459036800 10800 1 EEST}
    {1477785600 7200 0 EET}
    {1490486400 10800 1 EEST}
    {1509235200 7200 0 EET}
    {1521936000 10800 1 EEST}
    {1540684800 7200 0 EET}
    {1553990400 10800 1 EEST}
    {1572134400 7200 0 EET}
    {1585440000 10800 1 EEST}
    {1603584000 7200 0 EET}
    {1616889600 10800 1 EEST}
    {1635638400 7200 0 EET}
    {1648339200 10800 1 EEST}
    {1667088000 7200 0 EET}
    {1679788800 10800 1 EEST}
    {1698537600 7200 0 EET}
    {1711843200 10800 1 EEST}
    {1729987200 7200 0 EET}
    {1743292800 10800 1 EEST}
    {1761436800 7200 0 EET}
    {1774742400 10800 1 EEST}
    {1792886400 7200 0 EET}
    {1806192000 10800 1 EEST}
    {1824940800 7200 0 EET}
    {1837641600 10800 1 EEST}
    {1856390400 7200 0 EET}
    {1869091200 10800 1 EEST}
    {1887840000 7200 0 EET}
    {1901145600 10800 1 EEST}
    {1919289600 7200 0 EET}
    {1932595200 10800 1 EEST}
    {1950739200 7200 0 EET}
    {1964044800 10800 1 EEST}
    {1982793600 7200 0 EET}
    {1995494400 10800 1 EEST}
    {2014243200 7200 0 EET}
    {2026944000 10800 1 EEST}
    {2045692800 7200 0 EET}
    {2058393600 10800 1 EEST}
    {2077142400 7200 0 EET}
    {2090448000 10800 1 EEST}
    {2108592000 7200 0 EET}
    {2121897600 10800 1 EEST}
    {2140041600 7200 0 EET}
    {2153347200 10800 1 EEST}
    {2172096000 7200 0 EET}
    {2184796800 10800 1 EEST}
    {2203545600 7200 0 EET}
    {2216246400 10800 1 EEST}
    {2234995200 7200 0 EET}
    {2248300800 10800 1 EEST}
    {2266444800 7200 0 EET}
    {2279750400 10800 1 EEST}
    {2297894400 7200 0 EET}
    {2311200000 10800 1 EEST}
    {2329344000 7200 0 EET}
    {2342649600 10800 1 EEST}
    {2361398400 7200 0 EET}
    {2374099200 10800 1 EEST}
    {2392848000 7200 0 EET}
    {2405548800 10800 1 EEST}
    {2424297600 7200 0 EET}
    {2437603200 10800 1 EEST}
    {2455747200 7200 0 EET}
    {2469052800 10800 1 EEST}
    {2487196800 7200 0 EET}
    {2500502400 10800 1 EEST}
    {2519251200 7200 0 EET}
    {2531952000 10800 1 EEST}
    {2550700800 7200 0 EET}
    {2563401600 10800 1 EEST}
    {2582150400 7200 0 EET}
    {2595456000 10800 1 EEST}
    {2613600000 7200 0 EET}
    {2626905600 10800 1 EEST}
    {2645049600 7200 0 EET}
    {2658355200 10800 1 EEST}
    {2676499200 7200 0 EET}
    {2689804800 10800 1 EEST}
    {2708553600 7200 0 EET}
    {2721254400 10800 1 EEST}
    {2740003200 7200 0 EET}
    {2752704000 10800 1 EEST}
    {2771452800 7200 0 EET}
    {2784758400 10800 1 EEST}
    {2802902400 7200 0 EET}
    {2816208000 10800 1 EEST}
    {2834352000 7200 0 EET}
    {2847657600 10800 1 EEST}
    {2866406400 7200 0 EET}
    {2879107200 10800 1 EEST}
    {2897856000 7200 0 EET}
    {2910556800 10800 1 EEST}
    {2929305600 7200 0 EET}
    {2942006400 10800 1 EEST}
    {2960755200 7200 0 EET}
    {2974060800 10800 1 EEST}
    {2992204800 7200 0 EET}
    {3005510400 10800 1 EEST}
    {3023654400 7200 0 EET}
    {3036960000 10800 1 EEST}
    {3055708800 7200 0 EET}
    {3068409600 10800 1 EEST}
    {3087158400 7200 0 EET}
    {3099859200 10800 1 EEST}
    {3118608000 7200 0 EET}
    {3131913600 10800 1 EEST}
    {3150057600 7200 0 EET}
    {3163363200 10800 1 EEST}
    {3181507200 7200 0 EET}
    {3194812800 10800 1 EEST}
    {3212956800 7200 0 EET}
    {3226262400 10800 1 EEST}
    {3245011200 7200 0 EET}
    {3257712000 10800 1 EEST}
    {3276460800 7200 0 EET}
    {3289161600 10800 1 EEST}
    {3307910400 7200 0 EET}
    {3321216000 10800 1 EEST}
    {3339360000 7200 0 EET}
    {3352665600 10800 1 EEST}
    {3370809600 7200 0 EET}
    {3384115200 10800 1 EEST}
    {3402864000 7200 0 EET}
    {3415564800 10800 1 EEST}
    {3434313600 7200 0 EET}
    {3447014400 10800 1 EEST}
    {3465763200 7200 0 EET}
    {3479068800 10800 1 EEST}
    {3497212800 7200 0 EET}
    {3510518400 10800 1 EEST}
    {3528662400 7200 0 EET}
    {3541968000 10800 1 EEST}
    {3560112000 7200 0 EET}
    {3573417600 10800 1 EEST}
    {3592166400 7200 0 EET}
    {3604867200 10800 1 EEST}
    {3623616000 7200 0 EET}
    {3636316800 10800 1 EEST}
    {3655065600 7200 0 EET}
    {3668371200 10800 1 EEST}
    {3686515200 7200 0 EET}
    {3699820800 10800 1 EEST}
    {3717964800 7200 0 EET}
    {3731270400 10800 1 EEST}
    {3750019200 7200 0 EET}
    {3762720000 10800 1 EEST}
    {3781468800 7200 0 EET}
    {3794169600 10800 1 EEST}
    {3812918400 7200 0 EET}
    {3825619200 10800 1 EEST}
    {3844368000 7200 0 EET}
    {3857673600 10800 1 EEST}
    {3875817600 7200 0 EET}
    {3889123200 10800 1 EEST}
    {3907267200 7200 0 EET}
    {3920572800 10800 1 EEST}
    {3939321600 7200 0 EET}
    {3952022400 10800 1 EEST}
    {3970771200 7200 0 EET}
    {3983472000 10800 1 EEST}
    {4002220800 7200 0 EET}
    {4015526400 10800 1 EEST}
    {4033670400 7200 0 EET}
    {4046976000 10800 1 EEST}
    {4065120000 7200 0 EET}
    {4078425600 10800 1 EEST}
    {4096569600 7200 0 EET}
}







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

76
77
78
79
80
81
82
83

















































































































































































84
    {1193529600 7200 0 EET}
    {1206835200 10800 1 EEST}
    {1224979200 7200 0 EET}
    {1238284800 10800 1 EEST}
    {1256428800 7200 0 EET}
    {1269734400 10800 1 EEST}
    {1288483200 7200 0 EET}
    {1301184000 10800 0 FET}

















































































































































































}

Changes to library/tzdata/Europe/Kiev.

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
    {1193533200 7200 0 EET}
    {1206838800 10800 1 EEST}
    {1224982800 7200 0 EET}
    {1238288400 10800 1 EEST}
    {1256432400 7200 0 EET}
    {1269738000 10800 1 EEST}
    {1288486800 7200 0 EET}
    {1301187600 10800 1 EEST}
    {1319936400 7200 0 EET}
    {1332637200 10800 1 EEST}
    {1351386000 7200 0 EET}
    {1364691600 10800 1 EEST}
    {1382835600 7200 0 EET}
    {1396141200 10800 1 EEST}
    {1414285200 7200 0 EET}
    {1427590800 10800 1 EEST}
    {1445734800 7200 0 EET}
    {1459040400 10800 1 EEST}
    {1477789200 7200 0 EET}
    {1490490000 10800 1 EEST}
    {1509238800 7200 0 EET}
    {1521939600 10800 1 EEST}
    {1540688400 7200 0 EET}
    {1553994000 10800 1 EEST}
    {1572138000 7200 0 EET}
    {1585443600 10800 1 EEST}
    {1603587600 7200 0 EET}
    {1616893200 10800 1 EEST}
    {1635642000 7200 0 EET}
    {1648342800 10800 1 EEST}
    {1667091600 7200 0 EET}
    {1679792400 10800 1 EEST}
    {1698541200 7200 0 EET}
    {1711846800 10800 1 EEST}
    {1729990800 7200 0 EET}
    {1743296400 10800 1 EEST}
    {1761440400 7200 0 EET}
    {1774746000 10800 1 EEST}
    {1792890000 7200 0 EET}
    {1806195600 10800 1 EEST}
    {1824944400 7200 0 EET}
    {1837645200 10800 1 EEST}
    {1856394000 7200 0 EET}
    {1869094800 10800 1 EEST}
    {1887843600 7200 0 EET}
    {1901149200 10800 1 EEST}
    {1919293200 7200 0 EET}
    {1932598800 10800 1 EEST}
    {1950742800 7200 0 EET}
    {1964048400 10800 1 EEST}
    {1982797200 7200 0 EET}
    {1995498000 10800 1 EEST}
    {2014246800 7200 0 EET}
    {2026947600 10800 1 EEST}
    {2045696400 7200 0 EET}
    {2058397200 10800 1 EEST}
    {2077146000 7200 0 EET}
    {2090451600 10800 1 EEST}
    {2108595600 7200 0 EET}
    {2121901200 10800 1 EEST}
    {2140045200 7200 0 EET}
    {2153350800 10800 1 EEST}
    {2172099600 7200 0 EET}
    {2184800400 10800 1 EEST}
    {2203549200 7200 0 EET}
    {2216250000 10800 1 EEST}
    {2234998800 7200 0 EET}
    {2248304400 10800 1 EEST}
    {2266448400 7200 0 EET}
    {2279754000 10800 1 EEST}
    {2297898000 7200 0 EET}
    {2311203600 10800 1 EEST}
    {2329347600 7200 0 EET}
    {2342653200 10800 1 EEST}
    {2361402000 7200 0 EET}
    {2374102800 10800 1 EEST}
    {2392851600 7200 0 EET}
    {2405552400 10800 1 EEST}
    {2424301200 7200 0 EET}
    {2437606800 10800 1 EEST}
    {2455750800 7200 0 EET}
    {2469056400 10800 1 EEST}
    {2487200400 7200 0 EET}
    {2500506000 10800 1 EEST}
    {2519254800 7200 0 EET}
    {2531955600 10800 1 EEST}
    {2550704400 7200 0 EET}
    {2563405200 10800 1 EEST}
    {2582154000 7200 0 EET}
    {2595459600 10800 1 EEST}
    {2613603600 7200 0 EET}
    {2626909200 10800 1 EEST}
    {2645053200 7200 0 EET}
    {2658358800 10800 1 EEST}
    {2676502800 7200 0 EET}
    {2689808400 10800 1 EEST}
    {2708557200 7200 0 EET}
    {2721258000 10800 1 EEST}
    {2740006800 7200 0 EET}
    {2752707600 10800 1 EEST}
    {2771456400 7200 0 EET}
    {2784762000 10800 1 EEST}
    {2802906000 7200 0 EET}
    {2816211600 10800 1 EEST}
    {2834355600 7200 0 EET}
    {2847661200 10800 1 EEST}
    {2866410000 7200 0 EET}
    {2879110800 10800 1 EEST}
    {2897859600 7200 0 EET}
    {2910560400 10800 1 EEST}
    {2929309200 7200 0 EET}
    {2942010000 10800 1 EEST}
    {2960758800 7200 0 EET}
    {2974064400 10800 1 EEST}
    {2992208400 7200 0 EET}
    {3005514000 10800 1 EEST}
    {3023658000 7200 0 EET}
    {3036963600 10800 1 EEST}
    {3055712400 7200 0 EET}
    {3068413200 10800 1 EEST}
    {3087162000 7200 0 EET}
    {3099862800 10800 1 EEST}
    {3118611600 7200 0 EET}
    {3131917200 10800 1 EEST}
    {3150061200 7200 0 EET}
    {3163366800 10800 1 EEST}
    {3181510800 7200 0 EET}
    {3194816400 10800 1 EEST}
    {3212960400 7200 0 EET}
    {3226266000 10800 1 EEST}
    {3245014800 7200 0 EET}
    {3257715600 10800 1 EEST}
    {3276464400 7200 0 EET}
    {3289165200 10800 1 EEST}
    {3307914000 7200 0 EET}
    {3321219600 10800 1 EEST}
    {3339363600 7200 0 EET}
    {3352669200 10800 1 EEST}
    {3370813200 7200 0 EET}
    {3384118800 10800 1 EEST}
    {3402867600 7200 0 EET}
    {3415568400 10800 1 EEST}
    {3434317200 7200 0 EET}
    {3447018000 10800 1 EEST}
    {3465766800 7200 0 EET}
    {3479072400 10800 1 EEST}
    {3497216400 7200 0 EET}
    {3510522000 10800 1 EEST}
    {3528666000 7200 0 EET}
    {3541971600 10800 1 EEST}
    {3560115600 7200 0 EET}
    {3573421200 10800 1 EEST}
    {3592170000 7200 0 EET}
    {3604870800 10800 1 EEST}
    {3623619600 7200 0 EET}
    {3636320400 10800 1 EEST}
    {3655069200 7200 0 EET}
    {3668374800 10800 1 EEST}
    {3686518800 7200 0 EET}
    {3699824400 10800 1 EEST}
    {3717968400 7200 0 EET}
    {3731274000 10800 1 EEST}
    {3750022800 7200 0 EET}
    {3762723600 10800 1 EEST}
    {3781472400 7200 0 EET}
    {3794173200 10800 1 EEST}
    {3812922000 7200 0 EET}
    {3825622800 10800 1 EEST}
    {3844371600 7200 0 EET}
    {3857677200 10800 1 EEST}
    {3875821200 7200 0 EET}
    {3889126800 10800 1 EEST}
    {3907270800 7200 0 EET}
    {3920576400 10800 1 EEST}
    {3939325200 7200 0 EET}
    {3952026000 10800 1 EEST}
    {3970774800 7200 0 EET}
    {3983475600 10800 1 EEST}
    {4002224400 7200 0 EET}
    {4015530000 10800 1 EEST}
    {4033674000 7200 0 EET}
    {4046979600 10800 1 EEST}
    {4065123600 7200 0 EET}
    {4078429200 10800 1 EEST}
    {4096573200 7200 0 EET}
}







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

66
67
68
69
70
71
72
73

















































































































































































74
    {1193533200 7200 0 EET}
    {1206838800 10800 1 EEST}
    {1224982800 7200 0 EET}
    {1238288400 10800 1 EEST}
    {1256432400 7200 0 EET}
    {1269738000 10800 1 EEST}
    {1288486800 7200 0 EET}
    {1301187600 10800 0 FET}

















































































































































































}

Changes to library/tzdata/Europe/Minsk.

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
    {1193529600 7200 0 EET}
    {1206835200 10800 1 EEST}
    {1224979200 7200 0 EET}
    {1238284800 10800 1 EEST}
    {1256428800 7200 0 EET}
    {1269734400 10800 1 EEST}
    {1288483200 7200 0 EET}
    {1301184000 10800 1 EEST}
    {1319932800 7200 0 EET}
    {1332633600 10800 1 EEST}
    {1351382400 7200 0 EET}
    {1364688000 10800 1 EEST}
    {1382832000 7200 0 EET}
    {1396137600 10800 1 EEST}
    {1414281600 7200 0 EET}
    {1427587200 10800 1 EEST}
    {1445731200 7200 0 EET}
    {1459036800 10800 1 EEST}
    {1477785600 7200 0 EET}
    {1490486400 10800 1 EEST}
    {1509235200 7200 0 EET}
    {1521936000 10800 1 EEST}
    {1540684800 7200 0 EET}
    {1553990400 10800 1 EEST}
    {1572134400 7200 0 EET}
    {1585440000 10800 1 EEST}
    {1603584000 7200 0 EET}
    {1616889600 10800 1 EEST}
    {1635638400 7200 0 EET}
    {1648339200 10800 1 EEST}
    {1667088000 7200 0 EET}
    {1679788800 10800 1 EEST}
    {1698537600 7200 0 EET}
    {1711843200 10800 1 EEST}
    {1729987200 7200 0 EET}
    {1743292800 10800 1 EEST}
    {1761436800 7200 0 EET}
    {1774742400 10800 1 EEST}
    {1792886400 7200 0 EET}
    {1806192000 10800 1 EEST}
    {1824940800 7200 0 EET}
    {1837641600 10800 1 EEST}
    {1856390400 7200 0 EET}
    {1869091200 10800 1 EEST}
    {1887840000 7200 0 EET}
    {1901145600 10800 1 EEST}
    {1919289600 7200 0 EET}
    {1932595200 10800 1 EEST}
    {1950739200 7200 0 EET}
    {1964044800 10800 1 EEST}
    {1982793600 7200 0 EET}
    {1995494400 10800 1 EEST}
    {2014243200 7200 0 EET}
    {2026944000 10800 1 EEST}
    {2045692800 7200 0 EET}
    {2058393600 10800 1 EEST}
    {2077142400 7200 0 EET}
    {2090448000 10800 1 EEST}
    {2108592000 7200 0 EET}
    {2121897600 10800 1 EEST}
    {2140041600 7200 0 EET}
    {2153347200 10800 1 EEST}
    {2172096000 7200 0 EET}
    {2184796800 10800 1 EEST}
    {2203545600 7200 0 EET}
    {2216246400 10800 1 EEST}
    {2234995200 7200 0 EET}
    {2248300800 10800 1 EEST}
    {2266444800 7200 0 EET}
    {2279750400 10800 1 EEST}
    {2297894400 7200 0 EET}
    {2311200000 10800 1 EEST}
    {2329344000 7200 0 EET}
    {2342649600 10800 1 EEST}
    {2361398400 7200 0 EET}
    {2374099200 10800 1 EEST}
    {2392848000 7200 0 EET}
    {2405548800 10800 1 EEST}
    {2424297600 7200 0 EET}
    {2437603200 10800 1 EEST}
    {2455747200 7200 0 EET}
    {2469052800 10800 1 EEST}
    {2487196800 7200 0 EET}
    {2500502400 10800 1 EEST}
    {2519251200 7200 0 EET}
    {2531952000 10800 1 EEST}
    {2550700800 7200 0 EET}
    {2563401600 10800 1 EEST}
    {2582150400 7200 0 EET}
    {2595456000 10800 1 EEST}
    {2613600000 7200 0 EET}
    {2626905600 10800 1 EEST}
    {2645049600 7200 0 EET}
    {2658355200 10800 1 EEST}
    {2676499200 7200 0 EET}
    {2689804800 10800 1 EEST}
    {2708553600 7200 0 EET}
    {2721254400 10800 1 EEST}
    {2740003200 7200 0 EET}
    {2752704000 10800 1 EEST}
    {2771452800 7200 0 EET}
    {2784758400 10800 1 EEST}
    {2802902400 7200 0 EET}
    {2816208000 10800 1 EEST}
    {2834352000 7200 0 EET}
    {2847657600 10800 1 EEST}
    {2866406400 7200 0 EET}
    {2879107200 10800 1 EEST}
    {2897856000 7200 0 EET}
    {2910556800 10800 1 EEST}
    {2929305600 7200 0 EET}
    {2942006400 10800 1 EEST}
    {2960755200 7200 0 EET}
    {2974060800 10800 1 EEST}
    {2992204800 7200 0 EET}
    {3005510400 10800 1 EEST}
    {3023654400 7200 0 EET}
    {3036960000 10800 1 EEST}
    {3055708800 7200 0 EET}
    {3068409600 10800 1 EEST}
    {3087158400 7200 0 EET}
    {3099859200 10800 1 EEST}
    {3118608000 7200 0 EET}
    {3131913600 10800 1 EEST}
    {3150057600 7200 0 EET}
    {3163363200 10800 1 EEST}
    {3181507200 7200 0 EET}
    {3194812800 10800 1 EEST}
    {3212956800 7200 0 EET}
    {3226262400 10800 1 EEST}
    {3245011200 7200 0 EET}
    {3257712000 10800 1 EEST}
    {3276460800 7200 0 EET}
    {3289161600 10800 1 EEST}
    {3307910400 7200 0 EET}
    {3321216000 10800 1 EEST}
    {3339360000 7200 0 EET}
    {3352665600 10800 1 EEST}
    {3370809600 7200 0 EET}
    {3384115200 10800 1 EEST}
    {3402864000 7200 0 EET}
    {3415564800 10800 1 EEST}
    {3434313600 7200 0 EET}
    {3447014400 10800 1 EEST}
    {3465763200 7200 0 EET}
    {3479068800 10800 1 EEST}
    {3497212800 7200 0 EET}
    {3510518400 10800 1 EEST}
    {3528662400 7200 0 EET}
    {3541968000 10800 1 EEST}
    {3560112000 7200 0 EET}
    {3573417600 10800 1 EEST}
    {3592166400 7200 0 EET}
    {3604867200 10800 1 EEST}
    {3623616000 7200 0 EET}
    {3636316800 10800 1 EEST}
    {3655065600 7200 0 EET}
    {3668371200 10800 1 EEST}
    {3686515200 7200 0 EET}
    {3699820800 10800 1 EEST}
    {3717964800 7200 0 EET}
    {3731270400 10800 1 EEST}
    {3750019200 7200 0 EET}
    {3762720000 10800 1 EEST}
    {3781468800 7200 0 EET}
    {3794169600 10800 1 EEST}
    {3812918400 7200 0 EET}
    {3825619200 10800 1 EEST}
    {3844368000 7200 0 EET}
    {3857673600 10800 1 EEST}
    {3875817600 7200 0 EET}
    {3889123200 10800 1 EEST}
    {3907267200 7200 0 EET}
    {3920572800 10800 1 EEST}
    {3939321600 7200 0 EET}
    {3952022400 10800 1 EEST}
    {3970771200 7200 0 EET}
    {3983472000 10800 1 EEST}
    {4002220800 7200 0 EET}
    {4015526400 10800 1 EEST}
    {4033670400 7200 0 EET}
    {4046976000 10800 1 EEST}
    {4065120000 7200 0 EET}
    {4078425600 10800 1 EEST}
    {4096569600 7200 0 EET}
}







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

66
67
68
69
70
71
72
73

















































































































































































74
    {1193529600 7200 0 EET}
    {1206835200 10800 1 EEST}
    {1224979200 7200 0 EET}
    {1238284800 10800 1 EEST}
    {1256428800 7200 0 EET}
    {1269734400 10800 1 EEST}
    {1288483200 7200 0 EET}
    {1301184000 10800 0 FET}

















































































































































































}

Changes to library/tzdata/Europe/Moscow.

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
    {1193526000 10800 0 MSK}
    {1206831600 14400 1 MSD}
    {1224975600 10800 0 MSK}
    {1238281200 14400 1 MSD}
    {1256425200 10800 0 MSK}
    {1269730800 14400 1 MSD}
    {1288479600 10800 0 MSK}
    {1301180400 14400 1 MSD}
    {1319929200 10800 0 MSK}
    {1332630000 14400 1 MSD}
    {1351378800 10800 0 MSK}
    {1364684400 14400 1 MSD}
    {1382828400 10800 0 MSK}
    {1396134000 14400 1 MSD}
    {1414278000 10800 0 MSK}
    {1427583600 14400 1 MSD}
    {1445727600 10800 0 MSK}
    {1459033200 14400 1 MSD}
    {1477782000 10800 0 MSK}
    {1490482800 14400 1 MSD}
    {1509231600 10800 0 MSK}
    {1521932400 14400 1 MSD}
    {1540681200 10800 0 MSK}
    {1553986800 14400 1 MSD}
    {1572130800 10800 0 MSK}
    {1585436400 14400 1 MSD}
    {1603580400 10800 0 MSK}
    {1616886000 14400 1 MSD}
    {1635634800 10800 0 MSK}
    {1648335600 14400 1 MSD}
    {1667084400 10800 0 MSK}
    {1679785200 14400 1 MSD}
    {1698534000 10800 0 MSK}
    {1711839600 14400 1 MSD}
    {1729983600 10800 0 MSK}
    {1743289200 14400 1 MSD}
    {1761433200 10800 0 MSK}
    {1774738800 14400 1 MSD}
    {1792882800 10800 0 MSK}
    {1806188400 14400 1 MSD}
    {1824937200 10800 0 MSK}
    {1837638000 14400 1 MSD}
    {1856386800 10800 0 MSK}
    {1869087600 14400 1 MSD}
    {1887836400 10800 0 MSK}
    {1901142000 14400 1 MSD}
    {1919286000 10800 0 MSK}
    {1932591600 14400 1 MSD}
    {1950735600 10800 0 MSK}
    {1964041200 14400 1 MSD}
    {1982790000 10800 0 MSK}
    {1995490800 14400 1 MSD}
    {2014239600 10800 0 MSK}
    {2026940400 14400 1 MSD}
    {2045689200 10800 0 MSK}
    {2058390000 14400 1 MSD}
    {2077138800 10800 0 MSK}
    {2090444400 14400 1 MSD}
    {2108588400 10800 0 MSK}
    {2121894000 14400 1 MSD}
    {2140038000 10800 0 MSK}
    {2153343600 14400 1 MSD}
    {2172092400 10800 0 MSK}
    {2184793200 14400 1 MSD}
    {2203542000 10800 0 MSK}
    {2216242800 14400 1 MSD}
    {2234991600 10800 0 MSK}
    {2248297200 14400 1 MSD}
    {2266441200 10800 0 MSK}
    {2279746800 14400 1 MSD}
    {2297890800 10800 0 MSK}
    {2311196400 14400 1 MSD}
    {2329340400 10800 0 MSK}
    {2342646000 14400 1 MSD}
    {2361394800 10800 0 MSK}
    {2374095600 14400 1 MSD}
    {2392844400 10800 0 MSK}
    {2405545200 14400 1 MSD}
    {2424294000 10800 0 MSK}
    {2437599600 14400 1 MSD}
    {2455743600 10800 0 MSK}
    {2469049200 14400 1 MSD}
    {2487193200 10800 0 MSK}
    {2500498800 14400 1 MSD}
    {2519247600 10800 0 MSK}
    {2531948400 14400 1 MSD}
    {2550697200 10800 0 MSK}
    {2563398000 14400 1 MSD}
    {2582146800 10800 0 MSK}
    {2595452400 14400 1 MSD}
    {2613596400 10800 0 MSK}
    {2626902000 14400 1 MSD}
    {2645046000 10800 0 MSK}
    {2658351600 14400 1 MSD}
    {2676495600 10800 0 MSK}
    {2689801200 14400 1 MSD}
    {2708550000 10800 0 MSK}
    {2721250800 14400 1 MSD}
    {2739999600 10800 0 MSK}
    {2752700400 14400 1 MSD}
    {2771449200 10800 0 MSK}
    {2784754800 14400 1 MSD}
    {2802898800 10800 0 MSK}
    {2816204400 14400 1 MSD}
    {2834348400 10800 0 MSK}
    {2847654000 14400 1 MSD}
    {2866402800 10800 0 MSK}
    {2879103600 14400 1 MSD}
    {2897852400 10800 0 MSK}
    {2910553200 14400 1 MSD}
    {2929302000 10800 0 MSK}
    {2942002800 14400 1 MSD}
    {2960751600 10800 0 MSK}
    {2974057200 14400 1 MSD}
    {2992201200 10800 0 MSK}
    {3005506800 14400 1 MSD}
    {3023650800 10800 0 MSK}
    {3036956400 14400 1 MSD}
    {3055705200 10800 0 MSK}
    {3068406000 14400 1 MSD}
    {3087154800 10800 0 MSK}
    {3099855600 14400 1 MSD}
    {3118604400 10800 0 MSK}
    {3131910000 14400 1 MSD}
    {3150054000 10800 0 MSK}
    {3163359600 14400 1 MSD}
    {3181503600 10800 0 MSK}
    {3194809200 14400 1 MSD}
    {3212953200 10800 0 MSK}
    {3226258800 14400 1 MSD}
    {3245007600 10800 0 MSK}
    {3257708400 14400 1 MSD}
    {3276457200 10800 0 MSK}
    {3289158000 14400 1 MSD}
    {3307906800 10800 0 MSK}
    {3321212400 14400 1 MSD}
    {3339356400 10800 0 MSK}
    {3352662000 14400 1 MSD}
    {3370806000 10800 0 MSK}
    {3384111600 14400 1 MSD}
    {3402860400 10800 0 MSK}
    {3415561200 14400 1 MSD}
    {3434310000 10800 0 MSK}
    {3447010800 14400 1 MSD}
    {3465759600 10800 0 MSK}
    {3479065200 14400 1 MSD}
    {3497209200 10800 0 MSK}
    {3510514800 14400 1 MSD}
    {3528658800 10800 0 MSK}
    {3541964400 14400 1 MSD}
    {3560108400 10800 0 MSK}
    {3573414000 14400 1 MSD}
    {3592162800 10800 0 MSK}
    {3604863600 14400 1 MSD}
    {3623612400 10800 0 MSK}
    {3636313200 14400 1 MSD}
    {3655062000 10800 0 MSK}
    {3668367600 14400 1 MSD}
    {3686511600 10800 0 MSK}
    {3699817200 14400 1 MSD}
    {3717961200 10800 0 MSK}
    {3731266800 14400 1 MSD}
    {3750015600 10800 0 MSK}
    {3762716400 14400 1 MSD}
    {3781465200 10800 0 MSK}
    {3794166000 14400 1 MSD}
    {3812914800 10800 0 MSK}
    {3825615600 14400 1 MSD}
    {3844364400 10800 0 MSK}
    {3857670000 14400 1 MSD}
    {3875814000 10800 0 MSK}
    {3889119600 14400 1 MSD}
    {3907263600 10800 0 MSK}
    {3920569200 14400 1 MSD}
    {3939318000 10800 0 MSK}
    {3952018800 14400 1 MSD}
    {3970767600 10800 0 MSK}
    {3983468400 14400 1 MSD}
    {4002217200 10800 0 MSK}
    {4015522800 14400 1 MSD}
    {4033666800 10800 0 MSK}
    {4046972400 14400 1 MSD}
    {4065116400 10800 0 MSK}
    {4078422000 14400 1 MSD}
    {4096566000 10800 0 MSK}
}







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

75
76
77
78
79
80
81
82

















































































































































































83
    {1193526000 10800 0 MSK}
    {1206831600 14400 1 MSD}
    {1224975600 10800 0 MSK}
    {1238281200 14400 1 MSD}
    {1256425200 10800 0 MSK}
    {1269730800 14400 1 MSD}
    {1288479600 10800 0 MSK}
    {1301180400 14400 0 MSK}

















































































































































































}

Changes to library/tzdata/Europe/Samara.

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
    {1206828000 18000 1 SAMST}
    {1224972000 14400 0 SAMT}
    {1238277600 18000 1 SAMST}
    {1256421600 14400 0 SAMT}
    {1269727200 10800 0 SAMMMTT}
    {1269730800 14400 1 SAMST}
    {1288479600 10800 0 SAMT}
    {1301180400 14400 1 SAMST}
    {1319929200 10800 0 SAMT}
    {1332630000 14400 1 SAMST}
    {1351378800 10800 0 SAMT}
    {1364684400 14400 1 SAMST}
    {1382828400 10800 0 SAMT}
    {1396134000 14400 1 SAMST}
    {1414278000 10800 0 SAMT}
    {1427583600 14400 1 SAMST}
    {1445727600 10800 0 SAMT}
    {1459033200 14400 1 SAMST}
    {1477782000 10800 0 SAMT}
    {1490482800 14400 1 SAMST}
    {1509231600 10800 0 SAMT}
    {1521932400 14400 1 SAMST}
    {1540681200 10800 0 SAMT}
    {1553986800 14400 1 SAMST}
    {1572130800 10800 0 SAMT}
    {1585436400 14400 1 SAMST}
    {1603580400 10800 0 SAMT}
    {1616886000 14400 1 SAMST}
    {1635634800 10800 0 SAMT}
    {1648335600 14400 1 SAMST}
    {1667084400 10800 0 SAMT}
    {1679785200 14400 1 SAMST}
    {1698534000 10800 0 SAMT}
    {1711839600 14400 1 SAMST}
    {1729983600 10800 0 SAMT}
    {1743289200 14400 1 SAMST}
    {1761433200 10800 0 SAMT}
    {1774738800 14400 1 SAMST}
    {1792882800 10800 0 SAMT}
    {1806188400 14400 1 SAMST}
    {1824937200 10800 0 SAMT}
    {1837638000 14400 1 SAMST}
    {1856386800 10800 0 SAMT}
    {1869087600 14400 1 SAMST}
    {1887836400 10800 0 SAMT}
    {1901142000 14400 1 SAMST}
    {1919286000 10800 0 SAMT}
    {1932591600 14400 1 SAMST}
    {1950735600 10800 0 SAMT}
    {1964041200 14400 1 SAMST}
    {1982790000 10800 0 SAMT}
    {1995490800 14400 1 SAMST}
    {2014239600 10800 0 SAMT}
    {2026940400 14400 1 SAMST}
    {2045689200 10800 0 SAMT}
    {2058390000 14400 1 SAMST}
    {2077138800 10800 0 SAMT}
    {2090444400 14400 1 SAMST}
    {2108588400 10800 0 SAMT}
    {2121894000 14400 1 SAMST}
    {2140038000 10800 0 SAMT}
    {2153343600 14400 1 SAMST}
    {2172092400 10800 0 SAMT}
    {2184793200 14400 1 SAMST}
    {2203542000 10800 0 SAMT}
    {2216242800 14400 1 SAMST}
    {2234991600 10800 0 SAMT}
    {2248297200 14400 1 SAMST}
    {2266441200 10800 0 SAMT}
    {2279746800 14400 1 SAMST}
    {2297890800 10800 0 SAMT}
    {2311196400 14400 1 SAMST}
    {2329340400 10800 0 SAMT}
    {2342646000 14400 1 SAMST}
    {2361394800 10800 0 SAMT}
    {2374095600 14400 1 SAMST}
    {2392844400 10800 0 SAMT}
    {2405545200 14400 1 SAMST}
    {2424294000 10800 0 SAMT}
    {2437599600 14400 1 SAMST}
    {2455743600 10800 0 SAMT}
    {2469049200 14400 1 SAMST}
    {2487193200 10800 0 SAMT}
    {2500498800 14400 1 SAMST}
    {2519247600 10800 0 SAMT}
    {2531948400 14400 1 SAMST}
    {2550697200 10800 0 SAMT}
    {2563398000 14400 1 SAMST}
    {2582146800 10800 0 SAMT}
    {2595452400 14400 1 SAMST}
    {2613596400 10800 0 SAMT}
    {2626902000 14400 1 SAMST}
    {2645046000 10800 0 SAMT}
    {2658351600 14400 1 SAMST}
    {2676495600 10800 0 SAMT}
    {2689801200 14400 1 SAMST}
    {2708550000 10800 0 SAMT}
    {2721250800 14400 1 SAMST}
    {2739999600 10800 0 SAMT}
    {2752700400 14400 1 SAMST}
    {2771449200 10800 0 SAMT}
    {2784754800 14400 1 SAMST}
    {2802898800 10800 0 SAMT}
    {2816204400 14400 1 SAMST}
    {2834348400 10800 0 SAMT}
    {2847654000 14400 1 SAMST}
    {2866402800 10800 0 SAMT}
    {2879103600 14400 1 SAMST}
    {2897852400 10800 0 SAMT}
    {2910553200 14400 1 SAMST}
    {2929302000 10800 0 SAMT}
    {2942002800 14400 1 SAMST}
    {2960751600 10800 0 SAMT}
    {2974057200 14400 1 SAMST}
    {2992201200 10800 0 SAMT}
    {3005506800 14400 1 SAMST}
    {3023650800 10800 0 SAMT}
    {3036956400 14400 1 SAMST}
    {3055705200 10800 0 SAMT}
    {3068406000 14400 1 SAMST}
    {3087154800 10800 0 SAMT}
    {3099855600 14400 1 SAMST}
    {3118604400 10800 0 SAMT}
    {3131910000 14400 1 SAMST}
    {3150054000 10800 0 SAMT}
    {3163359600 14400 1 SAMST}
    {3181503600 10800 0 SAMT}
    {3194809200 14400 1 SAMST}
    {3212953200 10800 0 SAMT}
    {3226258800 14400 1 SAMST}
    {3245007600 10800 0 SAMT}
    {3257708400 14400 1 SAMST}
    {3276457200 10800 0 SAMT}
    {3289158000 14400 1 SAMST}
    {3307906800 10800 0 SAMT}
    {3321212400 14400 1 SAMST}
    {3339356400 10800 0 SAMT}
    {3352662000 14400 1 SAMST}
    {3370806000 10800 0 SAMT}
    {3384111600 14400 1 SAMST}
    {3402860400 10800 0 SAMT}
    {3415561200 14400 1 SAMST}
    {3434310000 10800 0 SAMT}
    {3447010800 14400 1 SAMST}
    {3465759600 10800 0 SAMT}
    {3479065200 14400 1 SAMST}
    {3497209200 10800 0 SAMT}
    {3510514800 14400 1 SAMST}
    {3528658800 10800 0 SAMT}
    {3541964400 14400 1 SAMST}
    {3560108400 10800 0 SAMT}
    {3573414000 14400 1 SAMST}
    {3592162800 10800 0 SAMT}
    {3604863600 14400 1 SAMST}
    {3623612400 10800 0 SAMT}
    {3636313200 14400 1 SAMST}
    {3655062000 10800 0 SAMT}
    {3668367600 14400 1 SAMST}
    {3686511600 10800 0 SAMT}
    {3699817200 14400 1 SAMST}
    {3717961200 10800 0 SAMT}
    {3731266800 14400 1 SAMST}
    {3750015600 10800 0 SAMT}
    {3762716400 14400 1 SAMST}
    {3781465200 10800 0 SAMT}
    {3794166000 14400 1 SAMST}
    {3812914800 10800 0 SAMT}
    {3825615600 14400 1 SAMST}
    {3844364400 10800 0 SAMT}
    {3857670000 14400 1 SAMST}
    {3875814000 10800 0 SAMT}
    {3889119600 14400 1 SAMST}
    {3907263600 10800 0 SAMT}
    {3920569200 14400 1 SAMST}
    {3939318000 10800 0 SAMT}
    {3952018800 14400 1 SAMST}
    {3970767600 10800 0 SAMT}
    {3983468400 14400 1 SAMST}
    {4002217200 10800 0 SAMT}
    {4015522800 14400 1 SAMST}
    {4033666800 10800 0 SAMT}
    {4046972400 14400 1 SAMST}
    {4065116400 10800 0 SAMT}
    {4078422000 14400 1 SAMST}
    {4096566000 10800 0 SAMT}
}







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

65
66
67
68
69
70
71
72

















































































































































































73
    {1206828000 18000 1 SAMST}
    {1224972000 14400 0 SAMT}
    {1238277600 18000 1 SAMST}
    {1256421600 14400 0 SAMT}
    {1269727200 10800 0 SAMMMTT}
    {1269730800 14400 1 SAMST}
    {1288479600 10800 0 SAMT}
    {1301180400 14400 0 SAMT}

















































































































































































}

Changes to library/tzdata/Europe/Simferopol.

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
    {1193533200 7200 0 EET}
    {1206838800 10800 1 EEST}
    {1224982800 7200 0 EET}
    {1238288400 10800 1 EEST}
    {1256432400 7200 0 EET}
    {1269738000 10800 1 EEST}
    {1288486800 7200 0 EET}
    {1301187600 10800 1 EEST}
    {1319936400 7200 0 EET}
    {1332637200 10800 1 EEST}
    {1351386000 7200 0 EET}
    {1364691600 10800 1 EEST}
    {1382835600 7200 0 EET}
    {1396141200 10800 1 EEST}
    {1414285200 7200 0 EET}
    {1427590800 10800 1 EEST}
    {1445734800 7200 0 EET}
    {1459040400 10800 1 EEST}
    {1477789200 7200 0 EET}
    {1490490000 10800 1 EEST}
    {1509238800 7200 0 EET}
    {1521939600 10800 1 EEST}
    {1540688400 7200 0 EET}
    {1553994000 10800 1 EEST}
    {1572138000 7200 0 EET}
    {1585443600 10800 1 EEST}
    {1603587600 7200 0 EET}
    {1616893200 10800 1 EEST}
    {1635642000 7200 0 EET}
    {1648342800 10800 1 EEST}
    {1667091600 7200 0 EET}
    {1679792400 10800 1 EEST}
    {1698541200 7200 0 EET}
    {1711846800 10800 1 EEST}
    {1729990800 7200 0 EET}
    {1743296400 10800 1 EEST}
    {1761440400 7200 0 EET}
    {1774746000 10800 1 EEST}
    {1792890000 7200 0 EET}
    {1806195600 10800 1 EEST}
    {1824944400 7200 0 EET}
    {1837645200 10800 1 EEST}
    {1856394000 7200 0 EET}
    {1869094800 10800 1 EEST}
    {1887843600 7200 0 EET}
    {1901149200 10800 1 EEST}
    {1919293200 7200 0 EET}
    {1932598800 10800 1 EEST}
    {1950742800 7200 0 EET}
    {1964048400 10800 1 EEST}
    {1982797200 7200 0 EET}
    {1995498000 10800 1 EEST}
    {2014246800 7200 0 EET}
    {2026947600 10800 1 EEST}
    {2045696400 7200 0 EET}
    {2058397200 10800 1 EEST}
    {2077146000 7200 0 EET}
    {2090451600 10800 1 EEST}
    {2108595600 7200 0 EET}
    {2121901200 10800 1 EEST}
    {2140045200 7200 0 EET}
    {2153350800 10800 1 EEST}
    {2172099600 7200 0 EET}
    {2184800400 10800 1 EEST}
    {2203549200 7200 0 EET}
    {2216250000 10800 1 EEST}
    {2234998800 7200 0 EET}
    {2248304400 10800 1 EEST}
    {2266448400 7200 0 EET}
    {2279754000 10800 1 EEST}
    {2297898000 7200 0 EET}
    {2311203600 10800 1 EEST}
    {2329347600 7200 0 EET}
    {2342653200 10800 1 EEST}
    {2361402000 7200 0 EET}
    {2374102800 10800 1 EEST}
    {2392851600 7200 0 EET}
    {2405552400 10800 1 EEST}
    {2424301200 7200 0 EET}
    {2437606800 10800 1 EEST}
    {2455750800 7200 0 EET}
    {2469056400 10800 1 EEST}
    {2487200400 7200 0 EET}
    {2500506000 10800 1 EEST}
    {2519254800 7200 0 EET}
    {2531955600 10800 1 EEST}
    {2550704400 7200 0 EET}
    {2563405200 10800 1 EEST}
    {2582154000 7200 0 EET}
    {2595459600 10800 1 EEST}
    {2613603600 7200 0 EET}
    {2626909200 10800 1 EEST}
    {2645053200 7200 0 EET}
    {2658358800 10800 1 EEST}
    {2676502800 7200 0 EET}
    {2689808400 10800 1 EEST}
    {2708557200 7200 0 EET}
    {2721258000 10800 1 EEST}
    {2740006800 7200 0 EET}
    {2752707600 10800 1 EEST}
    {2771456400 7200 0 EET}
    {2784762000 10800 1 EEST}
    {2802906000 7200 0 EET}
    {2816211600 10800 1 EEST}
    {2834355600 7200 0 EET}
    {2847661200 10800 1 EEST}
    {2866410000 7200 0 EET}
    {2879110800 10800 1 EEST}
    {2897859600 7200 0 EET}
    {2910560400 10800 1 EEST}
    {2929309200 7200 0 EET}
    {2942010000 10800 1 EEST}
    {2960758800 7200 0 EET}
    {2974064400 10800 1 EEST}
    {2992208400 7200 0 EET}
    {3005514000 10800 1 EEST}
    {3023658000 7200 0 EET}
    {3036963600 10800 1 EEST}
    {3055712400 7200 0 EET}
    {3068413200 10800 1 EEST}
    {3087162000 7200 0 EET}
    {3099862800 10800 1 EEST}
    {3118611600 7200 0 EET}
    {3131917200 10800 1 EEST}
    {3150061200 7200 0 EET}
    {3163366800 10800 1 EEST}
    {3181510800 7200 0 EET}
    {3194816400 10800 1 EEST}
    {3212960400 7200 0 EET}
    {3226266000 10800 1 EEST}
    {3245014800 7200 0 EET}
    {3257715600 10800 1 EEST}
    {3276464400 7200 0 EET}
    {3289165200 10800 1 EEST}
    {3307914000 7200 0 EET}
    {3321219600 10800 1 EEST}
    {3339363600 7200 0 EET}
    {3352669200 10800 1 EEST}
    {3370813200 7200 0 EET}
    {3384118800 10800 1 EEST}
    {3402867600 7200 0 EET}
    {3415568400 10800 1 EEST}
    {3434317200 7200 0 EET}
    {3447018000 10800 1 EEST}
    {3465766800 7200 0 EET}
    {3479072400 10800 1 EEST}
    {3497216400 7200 0 EET}
    {3510522000 10800 1 EEST}
    {3528666000 7200 0 EET}
    {3541971600 10800 1 EEST}
    {3560115600 7200 0 EET}
    {3573421200 10800 1 EEST}
    {3592170000 7200 0 EET}
    {3604870800 10800 1 EEST}
    {3623619600 7200 0 EET}
    {3636320400 10800 1 EEST}
    {3655069200 7200 0 EET}
    {3668374800 10800 1 EEST}
    {3686518800 7200 0 EET}
    {3699824400 10800 1 EEST}
    {3717968400 7200 0 EET}
    {3731274000 10800 1 EEST}
    {3750022800 7200 0 EET}
    {3762723600 10800 1 EEST}
    {3781472400 7200 0 EET}
    {3794173200 10800 1 EEST}
    {3812922000 7200 0 EET}
    {3825622800 10800 1 EEST}
    {3844371600 7200 0 EET}
    {3857677200 10800 1 EEST}
    {3875821200 7200 0 EET}
    {3889126800 10800 1 EEST}
    {3907270800 7200 0 EET}
    {3920576400 10800 1 EEST}
    {3939325200 7200 0 EET}
    {3952026000 10800 1 EEST}
    {3970774800 7200 0 EET}
    {3983475600 10800 1 EEST}
    {4002224400 7200 0 EET}
    {4015530000 10800 1 EEST}
    {4033674000 7200 0 EET}
    {4046979600 10800 1 EEST}
    {4065123600 7200 0 EET}
    {4078429200 10800 1 EEST}
    {4096573200 7200 0 EET}
}







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

68
69
70
71
72
73
74
75

















































































































































































76
    {1193533200 7200 0 EET}
    {1206838800 10800 1 EEST}
    {1224982800 7200 0 EET}
    {1238288400 10800 1 EEST}
    {1256432400 7200 0 EET}
    {1269738000 10800 1 EEST}
    {1288486800 7200 0 EET}
    {1301187600 10800 0 FET}

















































































































































































}

Changes to library/tzdata/Europe/Uzhgorod.

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
    {1193533200 7200 0 EET}
    {1206838800 10800 1 EEST}
    {1224982800 7200 0 EET}
    {1238288400 10800 1 EEST}
    {1256432400 7200 0 EET}
    {1269738000 10800 1 EEST}
    {1288486800 7200 0 EET}
    {1301187600 10800 1 EEST}
    {1319936400 7200 0 EET}
    {1332637200 10800 1 EEST}
    {1351386000 7200 0 EET}
    {1364691600 10800 1 EEST}
    {1382835600 7200 0 EET}
    {1396141200 10800 1 EEST}
    {1414285200 7200 0 EET}
    {1427590800 10800 1 EEST}
    {1445734800 7200 0 EET}
    {1459040400 10800 1 EEST}
    {1477789200 7200 0 EET}
    {1490490000 10800 1 EEST}
    {1509238800 7200 0 EET}
    {1521939600 10800 1 EEST}
    {1540688400 7200 0 EET}
    {1553994000 10800 1 EEST}
    {1572138000 7200 0 EET}
    {1585443600 10800 1 EEST}
    {1603587600 7200 0 EET}
    {1616893200 10800 1 EEST}
    {1635642000 7200 0 EET}
    {1648342800 10800 1 EEST}
    {1667091600 7200 0 EET}
    {1679792400 10800 1 EEST}
    {1698541200 7200 0 EET}
    {1711846800 10800 1 EEST}
    {1729990800 7200 0 EET}
    {1743296400 10800 1 EEST}
    {1761440400 7200 0 EET}
    {1774746000 10800 1 EEST}
    {1792890000 7200 0 EET}
    {1806195600 10800 1 EEST}
    {1824944400 7200 0 EET}
    {1837645200 10800 1 EEST}
    {1856394000 7200 0 EET}
    {1869094800 10800 1 EEST}
    {1887843600 7200 0 EET}
    {1901149200 10800 1 EEST}
    {1919293200 7200 0 EET}
    {1932598800 10800 1 EEST}
    {1950742800 7200 0 EET}
    {1964048400 10800 1 EEST}
    {1982797200 7200 0 EET}
    {1995498000 10800 1 EEST}
    {2014246800 7200 0 EET}
    {2026947600 10800 1 EEST}
    {2045696400 7200 0 EET}
    {2058397200 10800 1 EEST}
    {2077146000 7200 0 EET}
    {2090451600 10800 1 EEST}
    {2108595600 7200 0 EET}
    {2121901200 10800 1 EEST}
    {2140045200 7200 0 EET}
    {2153350800 10800 1 EEST}
    {2172099600 7200 0 EET}
    {2184800400 10800 1 EEST}
    {2203549200 7200 0 EET}
    {2216250000 10800 1 EEST}
    {2234998800 7200 0 EET}
    {2248304400 10800 1 EEST}
    {2266448400 7200 0 EET}
    {2279754000 10800 1 EEST}
    {2297898000 7200 0 EET}
    {2311203600 10800 1 EEST}
    {2329347600 7200 0 EET}
    {2342653200 10800 1 EEST}
    {2361402000 7200 0 EET}
    {2374102800 10800 1 EEST}
    {2392851600 7200 0 EET}
    {2405552400 10800 1 EEST}
    {2424301200 7200 0 EET}
    {2437606800 10800 1 EEST}
    {2455750800 7200 0 EET}
    {2469056400 10800 1 EEST}
    {2487200400 7200 0 EET}
    {2500506000 10800 1 EEST}
    {2519254800 7200 0 EET}
    {2531955600 10800 1 EEST}
    {2550704400 7200 0 EET}
    {2563405200 10800 1 EEST}
    {2582154000 7200 0 EET}
    {2595459600 10800 1 EEST}
    {2613603600 7200 0 EET}
    {2626909200 10800 1 EEST}
    {2645053200 7200 0 EET}
    {2658358800 10800 1 EEST}
    {2676502800 7200 0 EET}
    {2689808400 10800 1 EEST}
    {2708557200 7200 0 EET}
    {2721258000 10800 1 EEST}
    {2740006800 7200 0 EET}
    {2752707600 10800 1 EEST}
    {2771456400 7200 0 EET}
    {2784762000 10800 1 EEST}
    {2802906000 7200 0 EET}
    {2816211600 10800 1 EEST}
    {2834355600 7200 0 EET}
    {2847661200 10800 1 EEST}
    {2866410000 7200 0 EET}
    {2879110800 10800 1 EEST}
    {2897859600 7200 0 EET}
    {2910560400 10800 1 EEST}
    {2929309200 7200 0 EET}
    {2942010000 10800 1 EEST}
    {2960758800 7200 0 EET}
    {2974064400 10800 1 EEST}
    {2992208400 7200 0 EET}
    {3005514000 10800 1 EEST}
    {3023658000 7200 0 EET}
    {3036963600 10800 1 EEST}
    {3055712400 7200 0 EET}
    {3068413200 10800 1 EEST}
    {3087162000 7200 0 EET}
    {3099862800 10800 1 EEST}
    {3118611600 7200 0 EET}
    {3131917200 10800 1 EEST}
    {3150061200 7200 0 EET}
    {3163366800 10800 1 EEST}
    {3181510800 7200 0 EET}
    {3194816400 10800 1 EEST}
    {3212960400 7200 0 EET}
    {3226266000 10800 1 EEST}
    {3245014800 7200 0 EET}
    {3257715600 10800 1 EEST}
    {3276464400 7200 0 EET}
    {3289165200 10800 1 EEST}
    {3307914000 7200 0 EET}
    {3321219600 10800 1 EEST}
    {3339363600 7200 0 EET}
    {3352669200 10800 1 EEST}
    {3370813200 7200 0 EET}
    {3384118800 10800 1 EEST}
    {3402867600 7200 0 EET}
    {3415568400 10800 1 EEST}
    {3434317200 7200 0 EET}
    {3447018000 10800 1 EEST}
    {3465766800 7200 0 EET}
    {3479072400 10800 1 EEST}
    {3497216400 7200 0 EET}
    {3510522000 10800 1 EEST}
    {3528666000 7200 0 EET}
    {3541971600 10800 1 EEST}
    {3560115600 7200 0 EET}
    {3573421200 10800 1 EEST}
    {3592170000 7200 0 EET}
    {3604870800 10800 1 EEST}
    {3623619600 7200 0 EET}
    {3636320400 10800 1 EEST}
    {3655069200 7200 0 EET}
    {3668374800 10800 1 EEST}
    {3686518800 7200 0 EET}
    {3699824400 10800 1 EEST}
    {3717968400 7200 0 EET}
    {3731274000 10800 1 EEST}
    {3750022800 7200 0 EET}
    {3762723600 10800 1 EEST}
    {3781472400 7200 0 EET}
    {3794173200 10800 1 EEST}
    {3812922000 7200 0 EET}
    {3825622800 10800 1 EEST}
    {3844371600 7200 0 EET}
    {3857677200 10800 1 EEST}
    {3875821200 7200 0 EET}
    {3889126800 10800 1 EEST}
    {3907270800 7200 0 EET}
    {3920576400 10800 1 EEST}
    {3939325200 7200 0 EET}
    {3952026000 10800 1 EEST}
    {3970774800 7200 0 EET}
    {3983475600 10800 1 EEST}
    {4002224400 7200 0 EET}
    {4015530000 10800 1 EEST}
    {4033674000 7200 0 EET}
    {4046979600 10800 1 EEST}
    {4065123600 7200 0 EET}
    {4078429200 10800 1 EEST}
    {4096573200 7200 0 EET}
}







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

69
70
71
72
73
74
75
76

















































































































































































77
    {1193533200 7200 0 EET}
    {1206838800 10800 1 EEST}
    {1224982800 7200 0 EET}
    {1238288400 10800 1 EEST}
    {1256432400 7200 0 EET}
    {1269738000 10800 1 EEST}
    {1288486800 7200 0 EET}
    {1301187600 10800 0 FET}

















































































































































































}

Changes to library/tzdata/Europe/Volgograd.

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
    {1193526000 10800 0 VOLT}
    {1206831600 14400 1 VOLST}
    {1224975600 10800 0 VOLT}
    {1238281200 14400 1 VOLST}
    {1256425200 10800 0 VOLT}
    {1269730800 14400 1 VOLST}
    {1288479600 10800 0 VOLT}
    {1301180400 14400 1 VOLST}
    {1319929200 10800 0 VOLT}
    {1332630000 14400 1 VOLST}
    {1351378800 10800 0 VOLT}
    {1364684400 14400 1 VOLST}
    {1382828400 10800 0 VOLT}
    {1396134000 14400 1 VOLST}
    {1414278000 10800 0 VOLT}
    {1427583600 14400 1 VOLST}
    {1445727600 10800 0 VOLT}
    {1459033200 14400 1 VOLST}
    {1477782000 10800 0 VOLT}
    {1490482800 14400 1 VOLST}
    {1509231600 10800 0 VOLT}
    {1521932400 14400 1 VOLST}
    {1540681200 10800 0 VOLT}
    {1553986800 14400 1 VOLST}
    {1572130800 10800 0 VOLT}
    {1585436400 14400 1 VOLST}
    {1603580400 10800 0 VOLT}
    {1616886000 14400 1 VOLST}
    {1635634800 10800 0 VOLT}
    {1648335600 14400 1 VOLST}
    {1667084400 10800 0 VOLT}
    {1679785200 14400 1 VOLST}
    {1698534000 10800 0 VOLT}
    {1711839600 14400 1 VOLST}
    {1729983600 10800 0 VOLT}
    {1743289200 14400 1 VOLST}
    {1761433200 10800 0 VOLT}
    {1774738800 14400 1 VOLST}
    {1792882800 10800 0 VOLT}
    {1806188400 14400 1 VOLST}
    {1824937200 10800 0 VOLT}
    {1837638000 14400 1 VOLST}
    {1856386800 10800 0 VOLT}
    {1869087600 14400 1 VOLST}
    {1887836400 10800 0 VOLT}
    {1901142000 14400 1 VOLST}
    {1919286000 10800 0 VOLT}
    {1932591600 14400 1 VOLST}
    {1950735600 10800 0 VOLT}
    {1964041200 14400 1 VOLST}
    {1982790000 10800 0 VOLT}
    {1995490800 14400 1 VOLST}
    {2014239600 10800 0 VOLT}
    {2026940400 14400 1 VOLST}
    {2045689200 10800 0 VOLT}
    {2058390000 14400 1 VOLST}
    {2077138800 10800 0 VOLT}
    {2090444400 14400 1 VOLST}
    {2108588400 10800 0 VOLT}
    {2121894000 14400 1 VOLST}
    {2140038000 10800 0 VOLT}
    {2153343600 14400 1 VOLST}
    {2172092400 10800 0 VOLT}
    {2184793200 14400 1 VOLST}
    {2203542000 10800 0 VOLT}
    {2216242800 14400 1 VOLST}
    {2234991600 10800 0 VOLT}
    {2248297200 14400 1 VOLST}
    {2266441200 10800 0 VOLT}
    {2279746800 14400 1 VOLST}
    {2297890800 10800 0 VOLT}
    {2311196400 14400 1 VOLST}
    {2329340400 10800 0 VOLT}
    {2342646000 14400 1 VOLST}
    {2361394800 10800 0 VOLT}
    {2374095600 14400 1 VOLST}
    {2392844400 10800 0 VOLT}
    {2405545200 14400 1 VOLST}
    {2424294000 10800 0 VOLT}
    {2437599600 14400 1 VOLST}
    {2455743600 10800 0 VOLT}
    {2469049200 14400 1 VOLST}
    {2487193200 10800 0 VOLT}
    {2500498800 14400 1 VOLST}
    {2519247600 10800 0 VOLT}
    {2531948400 14400 1 VOLST}
    {2550697200 10800 0 VOLT}
    {2563398000 14400 1 VOLST}
    {2582146800 10800 0 VOLT}
    {2595452400 14400 1 VOLST}
    {2613596400 10800 0 VOLT}
    {2626902000 14400 1 VOLST}
    {2645046000 10800 0 VOLT}
    {2658351600 14400 1 VOLST}
    {2676495600 10800 0 VOLT}
    {2689801200 14400 1 VOLST}
    {2708550000 10800 0 VOLT}
    {2721250800 14400 1 VOLST}
    {2739999600 10800 0 VOLT}
    {2752700400 14400 1 VOLST}
    {2771449200 10800 0 VOLT}
    {2784754800 14400 1 VOLST}
    {2802898800 10800 0 VOLT}
    {2816204400 14400 1 VOLST}
    {2834348400 10800 0 VOLT}
    {2847654000 14400 1 VOLST}
    {2866402800 10800 0 VOLT}
    {2879103600 14400 1 VOLST}
    {2897852400 10800 0 VOLT}
    {2910553200 14400 1 VOLST}
    {2929302000 10800 0 VOLT}
    {2942002800 14400 1 VOLST}
    {2960751600 10800 0 VOLT}
    {2974057200 14400 1 VOLST}
    {2992201200 10800 0 VOLT}
    {3005506800 14400 1 VOLST}
    {3023650800 10800 0 VOLT}
    {3036956400 14400 1 VOLST}
    {3055705200 10800 0 VOLT}
    {3068406000 14400 1 VOLST}
    {3087154800 10800 0 VOLT}
    {3099855600 14400 1 VOLST}
    {3118604400 10800 0 VOLT}
    {3131910000 14400 1 VOLST}
    {3150054000 10800 0 VOLT}
    {3163359600 14400 1 VOLST}
    {3181503600 10800 0 VOLT}
    {3194809200 14400 1 VOLST}
    {3212953200 10800 0 VOLT}
    {3226258800 14400 1 VOLST}
    {3245007600 10800 0 VOLT}
    {3257708400 14400 1 VOLST}
    {3276457200 10800 0 VOLT}
    {3289158000 14400 1 VOLST}
    {3307906800 10800 0 VOLT}
    {3321212400 14400 1 VOLST}
    {3339356400 10800 0 VOLT}
    {3352662000 14400 1 VOLST}
    {3370806000 10800 0 VOLT}
    {3384111600 14400 1 VOLST}
    {3402860400 10800 0 VOLT}
    {3415561200 14400 1 VOLST}
    {3434310000 10800 0 VOLT}
    {3447010800 14400 1 VOLST}
    {3465759600 10800 0 VOLT}
    {3479065200 14400 1 VOLST}
    {3497209200 10800 0 VOLT}
    {3510514800 14400 1 VOLST}
    {3528658800 10800 0 VOLT}
    {3541964400 14400 1 VOLST}
    {3560108400 10800 0 VOLT}
    {3573414000 14400 1 VOLST}
    {3592162800 10800 0 VOLT}
    {3604863600 14400 1 VOLST}
    {3623612400 10800 0 VOLT}
    {3636313200 14400 1 VOLST}
    {3655062000 10800 0 VOLT}
    {3668367600 14400 1 VOLST}
    {3686511600 10800 0 VOLT}
    {3699817200 14400 1 VOLST}
    {3717961200 10800 0 VOLT}
    {3731266800 14400 1 VOLST}
    {3750015600 10800 0 VOLT}
    {3762716400 14400 1 VOLST}
    {3781465200 10800 0 VOLT}
    {3794166000 14400 1 VOLST}
    {3812914800 10800 0 VOLT}
    {3825615600 14400 1 VOLST}
    {3844364400 10800 0 VOLT}
    {3857670000 14400 1 VOLST}
    {3875814000 10800 0 VOLT}
    {3889119600 14400 1 VOLST}
    {3907263600 10800 0 VOLT}
    {3920569200 14400 1 VOLST}
    {3939318000 10800 0 VOLT}
    {3952018800 14400 1 VOLST}
    {3970767600 10800 0 VOLT}
    {3983468400 14400 1 VOLST}
    {4002217200 10800 0 VOLT}
    {4015522800 14400 1 VOLST}
    {4033666800 10800 0 VOLT}
    {4046972400 14400 1 VOLST}
    {4065116400 10800 0 VOLT}
    {4078422000 14400 1 VOLST}
    {4096566000 10800 0 VOLT}
}







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

62
63
64
65
66
67
68
69

















































































































































































70
    {1193526000 10800 0 VOLT}
    {1206831600 14400 1 VOLST}
    {1224975600 10800 0 VOLT}
    {1238281200 14400 1 VOLST}
    {1256425200 10800 0 VOLT}
    {1269730800 14400 1 VOLST}
    {1288479600 10800 0 VOLT}
    {1301180400 14400 0 VOLT}

















































































































































































}

Changes to library/tzdata/Europe/Zaporozhye.

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
    {1193533200 7200 0 EET}
    {1206838800 10800 1 EEST}
    {1224982800 7200 0 EET}
    {1238288400 10800 1 EEST}
    {1256432400 7200 0 EET}
    {1269738000 10800 1 EEST}
    {1288486800 7200 0 EET}
    {1301187600 10800 1 EEST}
    {1319936400 7200 0 EET}
    {1332637200 10800 1 EEST}
    {1351386000 7200 0 EET}
    {1364691600 10800 1 EEST}
    {1382835600 7200 0 EET}
    {1396141200 10800 1 EEST}
    {1414285200 7200 0 EET}
    {1427590800 10800 1 EEST}
    {1445734800 7200 0 EET}
    {1459040400 10800 1 EEST}
    {1477789200 7200 0 EET}
    {1490490000 10800 1 EEST}
    {1509238800 7200 0 EET}
    {1521939600 10800 1 EEST}
    {1540688400 7200 0 EET}
    {1553994000 10800 1 EEST}
    {1572138000 7200 0 EET}
    {1585443600 10800 1 EEST}
    {1603587600 7200 0 EET}
    {1616893200 10800 1 EEST}
    {1635642000 7200 0 EET}
    {1648342800 10800 1 EEST}
    {1667091600 7200 0 EET}
    {1679792400 10800 1 EEST}
    {1698541200 7200 0 EET}
    {1711846800 10800 1 EEST}
    {1729990800 7200 0 EET}
    {1743296400 10800 1 EEST}
    {1761440400 7200 0 EET}
    {1774746000 10800 1 EEST}
    {1792890000 7200 0 EET}
    {1806195600 10800 1 EEST}
    {1824944400 7200 0 EET}
    {1837645200 10800 1 EEST}
    {1856394000 7200 0 EET}
    {1869094800 10800 1 EEST}
    {1887843600 7200 0 EET}
    {1901149200 10800 1 EEST}
    {1919293200 7200 0 EET}
    {1932598800 10800 1 EEST}
    {1950742800 7200 0 EET}
    {1964048400 10800 1 EEST}
    {1982797200 7200 0 EET}
    {1995498000 10800 1 EEST}
    {2014246800 7200 0 EET}
    {2026947600 10800 1 EEST}
    {2045696400 7200 0 EET}
    {2058397200 10800 1 EEST}
    {2077146000 7200 0 EET}
    {2090451600 10800 1 EEST}
    {2108595600 7200 0 EET}
    {2121901200 10800 1 EEST}
    {2140045200 7200 0 EET}
    {2153350800 10800 1 EEST}
    {2172099600 7200 0 EET}
    {2184800400 10800 1 EEST}
    {2203549200 7200 0 EET}
    {2216250000 10800 1 EEST}
    {2234998800 7200 0 EET}
    {2248304400 10800 1 EEST}
    {2266448400 7200 0 EET}
    {2279754000 10800 1 EEST}
    {2297898000 7200 0 EET}
    {2311203600 10800 1 EEST}
    {2329347600 7200 0 EET}
    {2342653200 10800 1 EEST}
    {2361402000 7200 0 EET}
    {2374102800 10800 1 EEST}
    {2392851600 7200 0 EET}
    {2405552400 10800 1 EEST}
    {2424301200 7200 0 EET}
    {2437606800 10800 1 EEST}
    {2455750800 7200 0 EET}
    {2469056400 10800 1 EEST}
    {2487200400 7200 0 EET}
    {2500506000 10800 1 EEST}
    {2519254800 7200 0 EET}
    {2531955600 10800 1 EEST}
    {2550704400 7200 0 EET}
    {2563405200 10800 1 EEST}
    {2582154000 7200 0 EET}
    {2595459600 10800 1 EEST}
    {2613603600 7200 0 EET}
    {2626909200 10800 1 EEST}
    {2645053200 7200 0 EET}
    {2658358800 10800 1 EEST}
    {2676502800 7200 0 EET}
    {2689808400 10800 1 EEST}
    {2708557200 7200 0 EET}
    {2721258000 10800 1 EEST}
    {2740006800 7200 0 EET}
    {2752707600 10800 1 EEST}
    {2771456400 7200 0 EET}
    {2784762000 10800 1 EEST}
    {2802906000 7200 0 EET}
    {2816211600 10800 1 EEST}
    {2834355600 7200 0 EET}
    {2847661200 10800 1 EEST}
    {2866410000 7200 0 EET}
    {2879110800 10800 1 EEST}
    {2897859600 7200 0 EET}
    {2910560400 10800 1 EEST}
    {2929309200 7200 0 EET}
    {2942010000 10800 1 EEST}
    {2960758800 7200 0 EET}
    {2974064400 10800 1 EEST}
    {2992208400 7200 0 EET}
    {3005514000 10800 1 EEST}
    {3023658000 7200 0 EET}
    {3036963600 10800 1 EEST}
    {3055712400 7200 0 EET}
    {3068413200 10800 1 EEST}
    {3087162000 7200 0 EET}
    {3099862800 10800 1 EEST}
    {3118611600 7200 0 EET}
    {3131917200 10800 1 EEST}
    {3150061200 7200 0 EET}
    {3163366800 10800 1 EEST}
    {3181510800 7200 0 EET}
    {3194816400 10800 1 EEST}
    {3212960400 7200 0 EET}
    {3226266000 10800 1 EEST}
    {3245014800 7200 0 EET}
    {3257715600 10800 1 EEST}
    {3276464400 7200 0 EET}
    {3289165200 10800 1 EEST}
    {3307914000 7200 0 EET}
    {3321219600 10800 1 EEST}
    {3339363600 7200 0 EET}
    {3352669200 10800 1 EEST}
    {3370813200 7200 0 EET}
    {3384118800 10800 1 EEST}
    {3402867600 7200 0 EET}
    {3415568400 10800 1 EEST}
    {3434317200 7200 0 EET}
    {3447018000 10800 1 EEST}
    {3465766800 7200 0 EET}
    {3479072400 10800 1 EEST}
    {3497216400 7200 0 EET}
    {3510522000 10800 1 EEST}
    {3528666000 7200 0 EET}
    {3541971600 10800 1 EEST}
    {3560115600 7200 0 EET}
    {3573421200 10800 1 EEST}
    {3592170000 7200 0 EET}
    {3604870800 10800 1 EEST}
    {3623619600 7200 0 EET}
    {3636320400 10800 1 EEST}
    {3655069200 7200 0 EET}
    {3668374800 10800 1 EEST}
    {3686518800 7200 0 EET}
    {3699824400 10800 1 EEST}
    {3717968400 7200 0 EET}
    {3731274000 10800 1 EEST}
    {3750022800 7200 0 EET}
    {3762723600 10800 1 EEST}
    {3781472400 7200 0 EET}
    {3794173200 10800 1 EEST}
    {3812922000 7200 0 EET}
    {3825622800 10800 1 EEST}
    {3844371600 7200 0 EET}
    {3857677200 10800 1 EEST}
    {3875821200 7200 0 EET}
    {3889126800 10800 1 EEST}
    {3907270800 7200 0 EET}
    {3920576400 10800 1 EEST}
    {3939325200 7200 0 EET}
    {3952026000 10800 1 EEST}
    {3970774800 7200 0 EET}
    {3983475600 10800 1 EEST}
    {4002224400 7200 0 EET}
    {4015530000 10800 1 EEST}
    {4033674000 7200 0 EET}
    {4046979600 10800 1 EEST}
    {4065123600 7200 0 EET}
    {4078429200 10800 1 EEST}
    {4096573200 7200 0 EET}
}







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

67
68
69
70
71
72
73
74

















































































































































































75
    {1193533200 7200 0 EET}
    {1206838800 10800 1 EEST}
    {1224982800 7200 0 EET}
    {1238288400 10800 1 EEST}
    {1256432400 7200 0 EET}
    {1269738000 10800 1 EEST}
    {1288486800 7200 0 EET}
    {1301187600 10800 0 FET}

















































































































































































}

Changes to library/tzdata/Pacific/Apia.

1
2
3
4
5
6
7
8
9



10
# created by tools/tclZIC.tcl - do not edit

set TZData(:Pacific/Apia) {
    {-9223372036854775808 45184 0 LMT}
    {-2855737984 -41216 0 LMT}
    {-1861878784 -41400 0 SAMT}
    {-631110600 -39600 0 WST}
    {1285498800 -36000 1 WSDT}
    {1301752800 -39600 0 WST}



}









>
>
>

1
2
3
4
5
6
7
8
9
10
11
12
13
# created by tools/tclZIC.tcl - do not edit

set TZData(:Pacific/Apia) {
    {-9223372036854775808 45184 0 LMT}
    {-2855737984 -41216 0 LMT}
    {-1861878784 -41400 0 SAMT}
    {-631110600 -39600 0 WST}
    {1285498800 -36000 1 WSDT}
    {1301752800 -39600 0 WST}
    {1316872800 -36000 1 WSDT}
    {1325239200 50400 1 WSDT}
    {1333202400 46800 0 WST}
}

Changes to library/tzdata/Pacific/Easter.

90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
    {1192334400 -18000 1 EASST}
    {1206846000 -21600 0 EAST}
    {1223784000 -18000 1 EASST}
    {1237086000 -21600 0 EAST}
    {1255233600 -18000 1 EASST}
    {1270350000 -21600 0 EAST}
    {1286683200 -18000 1 EASST}
    {1301799600 -21600 0 EAST}
    {1318132800 -18000 1 EASST}
    {1331434800 -21600 0 EAST}
    {1350187200 -18000 1 EASST}
    {1362884400 -21600 0 EAST}
    {1381636800 -18000 1 EASST}
    {1394334000 -21600 0 EAST}
    {1413086400 -18000 1 EASST}
    {1426388400 -21600 0 EAST}







|
|







90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
    {1192334400 -18000 1 EASST}
    {1206846000 -21600 0 EAST}
    {1223784000 -18000 1 EASST}
    {1237086000 -21600 0 EAST}
    {1255233600 -18000 1 EASST}
    {1270350000 -21600 0 EAST}
    {1286683200 -18000 1 EASST}
    {1304823600 -21600 0 EAST}
    {1313899200 -18000 1 EASST}
    {1331434800 -21600 0 EAST}
    {1350187200 -18000 1 EASST}
    {1362884400 -21600 0 EAST}
    {1381636800 -18000 1 EASST}
    {1394334000 -21600 0 EAST}
    {1413086400 -18000 1 EASST}
    {1426388400 -21600 0 EAST}

Changes to library/tzdata/Pacific/Honolulu.

1
2
3
4
5
6
7
8

9
10
# created by tools/tclZIC.tcl - do not edit

set TZData(:Pacific/Honolulu) {
    {-9223372036854775808 -37886 0 LMT}
    {-2334101314 -37800 0 HST}
    {-1157283000 -34200 1 HDT}
    {-1155436200 -37800 0 HST}
    {-880198200 -34200 1 HDT}

    {-712150200 -36000 0 HST}
}








>


1
2
3
4
5
6
7
8
9
10
11
# created by tools/tclZIC.tcl - do not edit

set TZData(:Pacific/Honolulu) {
    {-9223372036854775808 -37886 0 LMT}
    {-2334101314 -37800 0 HST}
    {-1157283000 -34200 1 HDT}
    {-1155436200 -37800 0 HST}
    {-880198200 -34200 1 HDT}
    {-765376200 -37800 0 HST}
    {-712150200 -36000 0 HST}
}

Changes to libtommath/bn_mp_cnt_lsb.c.

16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
 */

static const int lnz[16] = { 
   4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
};

/* Counts the number of lsbs which are zero before the first zero bit */
int mp_cnt_lsb(mp_int *a)
{
   int x;
   mp_digit q, qq;

   /* easy out */
   if (mp_iszero(a) == 1) {
      return 0;







|







16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
 */

static const int lnz[16] = { 
   4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
};

/* Counts the number of lsbs which are zero before the first zero bit */
int mp_cnt_lsb(const mp_int *a)
{
   int x;
   mp_digit q, qq;

   /* easy out */
   if (mp_iszero(a) == 1) {
      return 0;

Changes to macosx/README.

13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
(this page also has a link to searchable archives of the list, please check them
before asking on the list, many questions have already been answered).

- For general Tcl/Tk questions, the newsgroup comp.lang.tcl is your best bet:
	http://groups.google.com/group/comp.lang.tcl/

- The Tcl'ers Wiki also has many pages dealing with Tcl & Tk on Mac OS X, see
	http://wiki.tcl.tk/references/3753!
	http://wiki.tcl.tk/references/8361!

- Please report bugs with Tcl or Tk on Mac OS X to the sourceforge bug trackers:
	Tcl: http://sf.net/tracker/?func=add&group_id=10894&atid=110894
	Tk:  http://sf.net/tracker/?func=add&group_id=12997&atid=112997
please make sure that your report Tk specific bugs to the tktoolkit project bug
tracker rather than the tcl project bug tracker.
Mac OS X specific bugs should in general be assigned to user 'das'.


2. Using Tcl on Mac OS X
------------------------

- At a minimum, Mac OS X 10.3 is required to run Tcl.

- Unless weak-linking is used, Tcl built on Mac OS X 10.x will not run on 10.y







|
|


<
<
<
<
<
|







13
14
15
16
17
18
19
20
21
22
23





24
25
26
27
28
29
30
31
(this page also has a link to searchable archives of the list, please check them
before asking on the list, many questions have already been answered).

- For general Tcl/Tk questions, the newsgroup comp.lang.tcl is your best bet:
	http://groups.google.com/group/comp.lang.tcl/

- The Tcl'ers Wiki also has many pages dealing with Tcl & Tk on Mac OS X, see
	http://wiki.tcl.tk/_/ref?N=3753
	http://wiki.tcl.tk/_/ref?N=8361

- Please report bugs with Tcl or Tk on Mac OS X to the sourceforge bug trackers:





	http://tcl.sourceforge.net/

2. Using Tcl on Mac OS X
------------------------

- At a minimum, Mac OS X 10.3 is required to run Tcl.

- Unless weak-linking is used, Tcl built on Mac OS X 10.x will not run on 10.y

Changes to macosx/Tcl.xcode/project.pbxproj.

100
101
102
103
104
105
106

107
108
109
110
111
112
113
		F96D48E708F272C3004A47F5 /* bn_mp_add.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D426908F272B3004A47F5 /* bn_mp_add.c */; };
		F96D48E808F272C3004A47F5 /* bn_mp_add_d.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D426A08F272B3004A47F5 /* bn_mp_add_d.c */; };
		F96D48EB08F272C3004A47F5 /* bn_mp_clamp.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D426D08F272B3004A47F5 /* bn_mp_clamp.c */; };
		F96D48EC08F272C3004A47F5 /* bn_mp_clear.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D426E08F272B3004A47F5 /* bn_mp_clear.c */; };
		F96D48ED08F272C3004A47F5 /* bn_mp_clear_multi.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D426F08F272B3004A47F5 /* bn_mp_clear_multi.c */; };
		F96D48EE08F272C3004A47F5 /* bn_mp_cmp.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D427008F272B3004A47F5 /* bn_mp_cmp.c */; };
		F96D48F008F272C3004A47F5 /* bn_mp_cmp_mag.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D427208F272B3004A47F5 /* bn_mp_cmp_mag.c */; };

		F96D48F208F272C3004A47F5 /* bn_mp_copy.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D427408F272B3004A47F5 /* bn_mp_copy.c */; };
		F96D48F308F272C3004A47F5 /* bn_mp_count_bits.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D427508F272B3004A47F5 /* bn_mp_count_bits.c */; };
		F96D48F408F272C3004A47F5 /* bn_mp_div.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D427608F272B3004A47F5 /* bn_mp_div.c */; };
		F96D48F508F272C3004A47F5 /* bn_mp_div_2.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D427708F272B3004A47F5 /* bn_mp_div_2.c */; };
		F96D48F608F272C3004A47F5 /* bn_mp_div_2d.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D427808F272B3004A47F5 /* bn_mp_div_2d.c */; };
		F96D48F708F272C3004A47F5 /* bn_mp_div_3.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D427908F272B3004A47F5 /* bn_mp_div_3.c */; };
		F96D48F808F272C3004A47F5 /* bn_mp_div_d.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D427A08F272B3004A47F5 /* bn_mp_div_d.c */; };







>







100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
		F96D48E708F272C3004A47F5 /* bn_mp_add.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D426908F272B3004A47F5 /* bn_mp_add.c */; };
		F96D48E808F272C3004A47F5 /* bn_mp_add_d.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D426A08F272B3004A47F5 /* bn_mp_add_d.c */; };
		F96D48EB08F272C3004A47F5 /* bn_mp_clamp.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D426D08F272B3004A47F5 /* bn_mp_clamp.c */; };
		F96D48EC08F272C3004A47F5 /* bn_mp_clear.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D426E08F272B3004A47F5 /* bn_mp_clear.c */; };
		F96D48ED08F272C3004A47F5 /* bn_mp_clear_multi.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D426F08F272B3004A47F5 /* bn_mp_clear_multi.c */; };
		F96D48EE08F272C3004A47F5 /* bn_mp_cmp.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D427008F272B3004A47F5 /* bn_mp_cmp.c */; };
		F96D48F008F272C3004A47F5 /* bn_mp_cmp_mag.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D427208F272B3004A47F5 /* bn_mp_cmp_mag.c */; };
		F96D48F208F272C3004A47F5 /* bn_mp_cnt_lsb.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D427408F272B3004A47F5 /* bn_mp_cnt_lsb.c */; };
		F96D48F208F272C3004A47F5 /* bn_mp_copy.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D427408F272B3004A47F5 /* bn_mp_copy.c */; };
		F96D48F308F272C3004A47F5 /* bn_mp_count_bits.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D427508F272B3004A47F5 /* bn_mp_count_bits.c */; };
		F96D48F408F272C3004A47F5 /* bn_mp_div.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D427608F272B3004A47F5 /* bn_mp_div.c */; };
		F96D48F508F272C3004A47F5 /* bn_mp_div_2.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D427708F272B3004A47F5 /* bn_mp_div_2.c */; };
		F96D48F608F272C3004A47F5 /* bn_mp_div_2d.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D427808F272B3004A47F5 /* bn_mp_div_2d.c */; };
		F96D48F708F272C3004A47F5 /* bn_mp_div_3.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D427908F272B3004A47F5 /* bn_mp_div_3.c */; };
		F96D48F808F272C3004A47F5 /* bn_mp_div_d.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D427A08F272B3004A47F5 /* bn_mp_div_d.c */; };
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
		F96D446308F272B9004A47F5 /* tclUnixInit.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tclUnixInit.c; sourceTree = "<group>"; };
		F96D446408F272B9004A47F5 /* tclUnixNotfy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tclUnixNotfy.c; sourceTree = "<group>"; };
		F96D446508F272B9004A47F5 /* tclUnixPipe.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tclUnixPipe.c; sourceTree = "<group>"; };
		F96D446608F272B9004A47F5 /* tclUnixPort.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tclUnixPort.h; sourceTree = "<group>"; };
		F96D446708F272B9004A47F5 /* tclUnixSock.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tclUnixSock.c; sourceTree = "<group>"; };
		F96D446808F272B9004A47F5 /* tclUnixTest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tclUnixTest.c; sourceTree = "<group>"; };
		F96D446908F272B9004A47F5 /* tclUnixThrd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tclUnixThrd.c; sourceTree = "<group>"; };
		F96D446A08F272B9004A47F5 /* tclUnixThrd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tclUnixThrd.h; sourceTree = "<group>"; };
		F96D446B08F272B9004A47F5 /* tclUnixTime.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tclUnixTime.c; sourceTree = "<group>"; };
		F96D446C08F272B9004A47F5 /* tclXtNotify.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tclXtNotify.c; sourceTree = "<group>"; };
		F96D446D08F272B9004A47F5 /* tclXtTest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tclXtTest.c; sourceTree = "<group>"; };
		F96D447008F272BA004A47F5 /* aclocal.m4 */ = {isa = PBXFileReference; explicitFileType = text.script.sh; fileEncoding = 4; path = aclocal.m4; sourceTree = "<group>"; };
		F96D447108F272BA004A47F5 /* buildall.vc.bat */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = buildall.vc.bat; sourceTree = "<group>"; };
		F96D447208F272BA004A47F5 /* cat.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cat.c; sourceTree = "<group>"; };
		F96D447308F272BA004A47F5 /* coffbase.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = coffbase.txt; sourceTree = "<group>"; };







<







826
827
828
829
830
831
832

833
834
835
836
837
838
839
		F96D446308F272B9004A47F5 /* tclUnixInit.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tclUnixInit.c; sourceTree = "<group>"; };
		F96D446408F272B9004A47F5 /* tclUnixNotfy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tclUnixNotfy.c; sourceTree = "<group>"; };
		F96D446508F272B9004A47F5 /* tclUnixPipe.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tclUnixPipe.c; sourceTree = "<group>"; };
		F96D446608F272B9004A47F5 /* tclUnixPort.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tclUnixPort.h; sourceTree = "<group>"; };
		F96D446708F272B9004A47F5 /* tclUnixSock.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tclUnixSock.c; sourceTree = "<group>"; };
		F96D446808F272B9004A47F5 /* tclUnixTest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tclUnixTest.c; sourceTree = "<group>"; };
		F96D446908F272B9004A47F5 /* tclUnixThrd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tclUnixThrd.c; sourceTree = "<group>"; };

		F96D446B08F272B9004A47F5 /* tclUnixTime.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tclUnixTime.c; sourceTree = "<group>"; };
		F96D446C08F272B9004A47F5 /* tclXtNotify.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tclXtNotify.c; sourceTree = "<group>"; };
		F96D446D08F272B9004A47F5 /* tclXtTest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tclXtTest.c; sourceTree = "<group>"; };
		F96D447008F272BA004A47F5 /* aclocal.m4 */ = {isa = PBXFileReference; explicitFileType = text.script.sh; fileEncoding = 4; path = aclocal.m4; sourceTree = "<group>"; };
		F96D447108F272BA004A47F5 /* buildall.vc.bat */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = buildall.vc.bat; sourceTree = "<group>"; };
		F96D447208F272BA004A47F5 /* cat.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cat.c; sourceTree = "<group>"; };
		F96D447308F272BA004A47F5 /* coffbase.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = coffbase.txt; sourceTree = "<group>"; };
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
				F96D446308F272B9004A47F5 /* tclUnixInit.c */,
				F96D446408F272B9004A47F5 /* tclUnixNotfy.c */,
				F96D446508F272B9004A47F5 /* tclUnixPipe.c */,
				F96D446608F272B9004A47F5 /* tclUnixPort.h */,
				F96D446708F272B9004A47F5 /* tclUnixSock.c */,
				F96D446808F272B9004A47F5 /* tclUnixTest.c */,
				F96D446908F272B9004A47F5 /* tclUnixThrd.c */,
				F96D446A08F272B9004A47F5 /* tclUnixThrd.h */,
				F96D446B08F272B9004A47F5 /* tclUnixTime.c */,
				F96D446C08F272B9004A47F5 /* tclXtNotify.c */,
				F96D446D08F272B9004A47F5 /* tclXtTest.c */,
			);
			path = unix;
			sourceTree = "<group>";
		};







<







1728
1729
1730
1731
1732
1733
1734

1735
1736
1737
1738
1739
1740
1741
				F96D446308F272B9004A47F5 /* tclUnixInit.c */,
				F96D446408F272B9004A47F5 /* tclUnixNotfy.c */,
				F96D446508F272B9004A47F5 /* tclUnixPipe.c */,
				F96D446608F272B9004A47F5 /* tclUnixPort.h */,
				F96D446708F272B9004A47F5 /* tclUnixSock.c */,
				F96D446808F272B9004A47F5 /* tclUnixTest.c */,
				F96D446908F272B9004A47F5 /* tclUnixThrd.c */,

				F96D446B08F272B9004A47F5 /* tclUnixTime.c */,
				F96D446C08F272B9004A47F5 /* tclXtNotify.c */,
				F96D446D08F272B9004A47F5 /* tclXtTest.c */,
			);
			path = unix;
			sourceTree = "<group>";
		};
2066
2067
2068
2069
2070
2071
2072

2073
2074
2075
2076
2077
2078
2079
				F9E61D2B090A48A4002B3151 /* bn_mp_and.c in Sources */,
				F96D48EB08F272C3004A47F5 /* bn_mp_clamp.c in Sources */,
				F96D48EC08F272C3004A47F5 /* bn_mp_clear.c in Sources */,
				F96D48ED08F272C3004A47F5 /* bn_mp_clear_multi.c in Sources */,
				F96D48EE08F272C3004A47F5 /* bn_mp_cmp.c in Sources */,
				F9E61D28090A481F002B3151 /* bn_mp_cmp_d.c in Sources */,
				F96D48F008F272C3004A47F5 /* bn_mp_cmp_mag.c in Sources */,

				F96D48F208F272C3004A47F5 /* bn_mp_copy.c in Sources */,
				F96D48F308F272C3004A47F5 /* bn_mp_count_bits.c in Sources */,
				F96D48F408F272C3004A47F5 /* bn_mp_div.c in Sources */,
				F96D48F508F272C3004A47F5 /* bn_mp_div_2.c in Sources */,
				F96D48F608F272C3004A47F5 /* bn_mp_div_2d.c in Sources */,
				F96D48F708F272C3004A47F5 /* bn_mp_div_3.c in Sources */,
				F96D48F808F272C3004A47F5 /* bn_mp_div_d.c in Sources */,







>







2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
				F9E61D2B090A48A4002B3151 /* bn_mp_and.c in Sources */,
				F96D48EB08F272C3004A47F5 /* bn_mp_clamp.c in Sources */,
				F96D48EC08F272C3004A47F5 /* bn_mp_clear.c in Sources */,
				F96D48ED08F272C3004A47F5 /* bn_mp_clear_multi.c in Sources */,
				F96D48EE08F272C3004A47F5 /* bn_mp_cmp.c in Sources */,
				F9E61D28090A481F002B3151 /* bn_mp_cmp_d.c in Sources */,
				F96D48F008F272C3004A47F5 /* bn_mp_cmp_mag.c in Sources */,
				F96D48F208F272C3004A47F5 /* bn_mp_cnt_lsb.c in Sources */,
				F96D48F208F272C3004A47F5 /* bn_mp_copy.c in Sources */,
				F96D48F308F272C3004A47F5 /* bn_mp_count_bits.c in Sources */,
				F96D48F408F272C3004A47F5 /* bn_mp_div.c in Sources */,
				F96D48F508F272C3004A47F5 /* bn_mp_div_2.c in Sources */,
				F96D48F608F272C3004A47F5 /* bn_mp_div_2d.c in Sources */,
				F96D48F708F272C3004A47F5 /* bn_mp_div_3.c in Sources */,
				F96D48F808F272C3004A47F5 /* bn_mp_div_d.c in Sources */,

Changes to macosx/Tcl.xcodeproj/project.pbxproj.

100
101
102
103
104
105
106

107
108
109
110
111
112
113
		F96D48E708F272C3004A47F5 /* bn_mp_add.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D426908F272B3004A47F5 /* bn_mp_add.c */; };
		F96D48E808F272C3004A47F5 /* bn_mp_add_d.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D426A08F272B3004A47F5 /* bn_mp_add_d.c */; };
		F96D48EB08F272C3004A47F5 /* bn_mp_clamp.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D426D08F272B3004A47F5 /* bn_mp_clamp.c */; };
		F96D48EC08F272C3004A47F5 /* bn_mp_clear.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D426E08F272B3004A47F5 /* bn_mp_clear.c */; };
		F96D48ED08F272C3004A47F5 /* bn_mp_clear_multi.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D426F08F272B3004A47F5 /* bn_mp_clear_multi.c */; };
		F96D48EE08F272C3004A47F5 /* bn_mp_cmp.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D427008F272B3004A47F5 /* bn_mp_cmp.c */; };
		F96D48F008F272C3004A47F5 /* bn_mp_cmp_mag.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D427208F272B3004A47F5 /* bn_mp_cmp_mag.c */; };

		F96D48F208F272C3004A47F5 /* bn_mp_copy.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D427408F272B3004A47F5 /* bn_mp_copy.c */; };
		F96D48F308F272C3004A47F5 /* bn_mp_count_bits.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D427508F272B3004A47F5 /* bn_mp_count_bits.c */; };
		F96D48F408F272C3004A47F5 /* bn_mp_div.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D427608F272B3004A47F5 /* bn_mp_div.c */; };
		F96D48F508F272C3004A47F5 /* bn_mp_div_2.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D427708F272B3004A47F5 /* bn_mp_div_2.c */; };
		F96D48F608F272C3004A47F5 /* bn_mp_div_2d.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D427808F272B3004A47F5 /* bn_mp_div_2d.c */; };
		F96D48F708F272C3004A47F5 /* bn_mp_div_3.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D427908F272B3004A47F5 /* bn_mp_div_3.c */; };
		F96D48F808F272C3004A47F5 /* bn_mp_div_d.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D427A08F272B3004A47F5 /* bn_mp_div_d.c */; };







>







100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
		F96D48E708F272C3004A47F5 /* bn_mp_add.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D426908F272B3004A47F5 /* bn_mp_add.c */; };
		F96D48E808F272C3004A47F5 /* bn_mp_add_d.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D426A08F272B3004A47F5 /* bn_mp_add_d.c */; };
		F96D48EB08F272C3004A47F5 /* bn_mp_clamp.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D426D08F272B3004A47F5 /* bn_mp_clamp.c */; };
		F96D48EC08F272C3004A47F5 /* bn_mp_clear.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D426E08F272B3004A47F5 /* bn_mp_clear.c */; };
		F96D48ED08F272C3004A47F5 /* bn_mp_clear_multi.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D426F08F272B3004A47F5 /* bn_mp_clear_multi.c */; };
		F96D48EE08F272C3004A47F5 /* bn_mp_cmp.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D427008F272B3004A47F5 /* bn_mp_cmp.c */; };
		F96D48F008F272C3004A47F5 /* bn_mp_cmp_mag.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D427208F272B3004A47F5 /* bn_mp_cmp_mag.c */; };
		F96D48F208F272C3004A47F5 /* bn_mp_cnt_lsb.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D427408F272B3004A47F5 /* bn_mp_cnt_lsb.c */; };
		F96D48F208F272C3004A47F5 /* bn_mp_copy.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D427408F272B3004A47F5 /* bn_mp_copy.c */; };
		F96D48F308F272C3004A47F5 /* bn_mp_count_bits.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D427508F272B3004A47F5 /* bn_mp_count_bits.c */; };
		F96D48F408F272C3004A47F5 /* bn_mp_div.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D427608F272B3004A47F5 /* bn_mp_div.c */; };
		F96D48F508F272C3004A47F5 /* bn_mp_div_2.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D427708F272B3004A47F5 /* bn_mp_div_2.c */; };
		F96D48F608F272C3004A47F5 /* bn_mp_div_2d.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D427808F272B3004A47F5 /* bn_mp_div_2d.c */; };
		F96D48F708F272C3004A47F5 /* bn_mp_div_3.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D427908F272B3004A47F5 /* bn_mp_div_3.c */; };
		F96D48F808F272C3004A47F5 /* bn_mp_div_d.c in Sources */ = {isa = PBXBuildFile; fileRef = F96D427A08F272B3004A47F5 /* bn_mp_div_d.c */; };
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
		F96D446308F272B9004A47F5 /* tclUnixInit.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tclUnixInit.c; sourceTree = "<group>"; };
		F96D446408F272B9004A47F5 /* tclUnixNotfy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tclUnixNotfy.c; sourceTree = "<group>"; };
		F96D446508F272B9004A47F5 /* tclUnixPipe.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tclUnixPipe.c; sourceTree = "<group>"; };
		F96D446608F272B9004A47F5 /* tclUnixPort.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tclUnixPort.h; sourceTree = "<group>"; };
		F96D446708F272B9004A47F5 /* tclUnixSock.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tclUnixSock.c; sourceTree = "<group>"; };
		F96D446808F272B9004A47F5 /* tclUnixTest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tclUnixTest.c; sourceTree = "<group>"; };
		F96D446908F272B9004A47F5 /* tclUnixThrd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tclUnixThrd.c; sourceTree = "<group>"; };
		F96D446A08F272B9004A47F5 /* tclUnixThrd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tclUnixThrd.h; sourceTree = "<group>"; };
		F96D446B08F272B9004A47F5 /* tclUnixTime.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tclUnixTime.c; sourceTree = "<group>"; };
		F96D446C08F272B9004A47F5 /* tclXtNotify.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tclXtNotify.c; sourceTree = "<group>"; };
		F96D446D08F272B9004A47F5 /* tclXtTest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tclXtTest.c; sourceTree = "<group>"; };
		F96D447008F272BA004A47F5 /* aclocal.m4 */ = {isa = PBXFileReference; explicitFileType = text.script.sh; fileEncoding = 4; path = aclocal.m4; sourceTree = "<group>"; };
		F96D447108F272BA004A47F5 /* buildall.vc.bat */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = buildall.vc.bat; sourceTree = "<group>"; };
		F96D447208F272BA004A47F5 /* cat.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cat.c; sourceTree = "<group>"; };
		F96D447308F272BA004A47F5 /* coffbase.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = coffbase.txt; sourceTree = "<group>"; };







<







826
827
828
829
830
831
832

833
834
835
836
837
838
839
		F96D446308F272B9004A47F5 /* tclUnixInit.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tclUnixInit.c; sourceTree = "<group>"; };
		F96D446408F272B9004A47F5 /* tclUnixNotfy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tclUnixNotfy.c; sourceTree = "<group>"; };
		F96D446508F272B9004A47F5 /* tclUnixPipe.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tclUnixPipe.c; sourceTree = "<group>"; };
		F96D446608F272B9004A47F5 /* tclUnixPort.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tclUnixPort.h; sourceTree = "<group>"; };
		F96D446708F272B9004A47F5 /* tclUnixSock.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tclUnixSock.c; sourceTree = "<group>"; };
		F96D446808F272B9004A47F5 /* tclUnixTest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tclUnixTest.c; sourceTree = "<group>"; };
		F96D446908F272B9004A47F5 /* tclUnixThrd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tclUnixThrd.c; sourceTree = "<group>"; };

		F96D446B08F272B9004A47F5 /* tclUnixTime.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tclUnixTime.c; sourceTree = "<group>"; };
		F96D446C08F272B9004A47F5 /* tclXtNotify.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tclXtNotify.c; sourceTree = "<group>"; };
		F96D446D08F272B9004A47F5 /* tclXtTest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tclXtTest.c; sourceTree = "<group>"; };
		F96D447008F272BA004A47F5 /* aclocal.m4 */ = {isa = PBXFileReference; explicitFileType = text.script.sh; fileEncoding = 4; path = aclocal.m4; sourceTree = "<group>"; };
		F96D447108F272BA004A47F5 /* buildall.vc.bat */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = buildall.vc.bat; sourceTree = "<group>"; };
		F96D447208F272BA004A47F5 /* cat.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cat.c; sourceTree = "<group>"; };
		F96D447308F272BA004A47F5 /* coffbase.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = coffbase.txt; sourceTree = "<group>"; };
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
				F96D446308F272B9004A47F5 /* tclUnixInit.c */,
				F96D446408F272B9004A47F5 /* tclUnixNotfy.c */,
				F96D446508F272B9004A47F5 /* tclUnixPipe.c */,
				F96D446608F272B9004A47F5 /* tclUnixPort.h */,
				F96D446708F272B9004A47F5 /* tclUnixSock.c */,
				F96D446808F272B9004A47F5 /* tclUnixTest.c */,
				F96D446908F272B9004A47F5 /* tclUnixThrd.c */,
				F96D446A08F272B9004A47F5 /* tclUnixThrd.h */,
				F96D446B08F272B9004A47F5 /* tclUnixTime.c */,
				F96D446C08F272B9004A47F5 /* tclXtNotify.c */,
				F96D446D08F272B9004A47F5 /* tclXtTest.c */,
			);
			path = unix;
			sourceTree = "<group>";
		};







<







1728
1729
1730
1731
1732
1733
1734

1735
1736
1737
1738
1739
1740
1741
				F96D446308F272B9004A47F5 /* tclUnixInit.c */,
				F96D446408F272B9004A47F5 /* tclUnixNotfy.c */,
				F96D446508F272B9004A47F5 /* tclUnixPipe.c */,
				F96D446608F272B9004A47F5 /* tclUnixPort.h */,
				F96D446708F272B9004A47F5 /* tclUnixSock.c */,
				F96D446808F272B9004A47F5 /* tclUnixTest.c */,
				F96D446908F272B9004A47F5 /* tclUnixThrd.c */,

				F96D446B08F272B9004A47F5 /* tclUnixTime.c */,
				F96D446C08F272B9004A47F5 /* tclXtNotify.c */,
				F96D446D08F272B9004A47F5 /* tclXtTest.c */,
			);
			path = unix;
			sourceTree = "<group>";
		};
2066
2067
2068
2069
2070
2071
2072

2073
2074
2075
2076
2077
2078
2079
				F9E61D2B090A48A4002B3151 /* bn_mp_and.c in Sources */,
				F96D48EB08F272C3004A47F5 /* bn_mp_clamp.c in Sources */,
				F96D48EC08F272C3004A47F5 /* bn_mp_clear.c in Sources */,
				F96D48ED08F272C3004A47F5 /* bn_mp_clear_multi.c in Sources */,
				F96D48EE08F272C3004A47F5 /* bn_mp_cmp.c in Sources */,
				F9E61D28090A481F002B3151 /* bn_mp_cmp_d.c in Sources */,
				F96D48F008F272C3004A47F5 /* bn_mp_cmp_mag.c in Sources */,

				F96D48F208F272C3004A47F5 /* bn_mp_copy.c in Sources */,
				F96D48F308F272C3004A47F5 /* bn_mp_count_bits.c in Sources */,
				F96D48F408F272C3004A47F5 /* bn_mp_div.c in Sources */,
				F96D48F508F272C3004A47F5 /* bn_mp_div_2.c in Sources */,
				F96D48F608F272C3004A47F5 /* bn_mp_div_2d.c in Sources */,
				F96D48F708F272C3004A47F5 /* bn_mp_div_3.c in Sources */,
				F96D48F808F272C3004A47F5 /* bn_mp_div_d.c in Sources */,







>







2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
				F9E61D2B090A48A4002B3151 /* bn_mp_and.c in Sources */,
				F96D48EB08F272C3004A47F5 /* bn_mp_clamp.c in Sources */,
				F96D48EC08F272C3004A47F5 /* bn_mp_clear.c in Sources */,
				F96D48ED08F272C3004A47F5 /* bn_mp_clear_multi.c in Sources */,
				F96D48EE08F272C3004A47F5 /* bn_mp_cmp.c in Sources */,
				F9E61D28090A481F002B3151 /* bn_mp_cmp_d.c in Sources */,
				F96D48F008F272C3004A47F5 /* bn_mp_cmp_mag.c in Sources */,
				F96D48F208F272C3004A47F5 /* bn_mp_cnt_lsb.c in Sources */,
				F96D48F208F272C3004A47F5 /* bn_mp_copy.c in Sources */,
				F96D48F308F272C3004A47F5 /* bn_mp_count_bits.c in Sources */,
				F96D48F408F272C3004A47F5 /* bn_mp_div.c in Sources */,
				F96D48F508F272C3004A47F5 /* bn_mp_div_2.c in Sources */,
				F96D48F608F272C3004A47F5 /* bn_mp_div_2d.c in Sources */,
				F96D48F708F272C3004A47F5 /* bn_mp_div_3.c in Sources */,
				F96D48F808F272C3004A47F5 /* bn_mp_div_d.c in Sources */,

Changes to macosx/tclMacOSXFCmd.c.

196
197
198
199
200
201
202

203
204
205
206
207
208
209
    case MACOSX_RSRCLENGTH_ATTRIBUTE:
	*attributePtrPtr = Tcl_NewWideIntObj(*rsrcForkSize);
	break;
    }
    return TCL_OK;
#else
    Tcl_AppendResult(interp, "Mac OS X file attributes not supported", NULL);

    return TCL_ERROR;
#endif
}

/*
 *---------------------------------------------------------------------------
 *







>







196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
    case MACOSX_RSRCLENGTH_ATTRIBUTE:
	*attributePtrPtr = Tcl_NewWideIntObj(*rsrcForkSize);
	break;
    }
    return TCL_OK;
#else
    Tcl_AppendResult(interp, "Mac OS X file attributes not supported", NULL);
    Tcl_SetErrorCode(interp, "TCL", "UNSUPPORTED", NULL);
    return TCL_ERROR;
#endif
}

/*
 *---------------------------------------------------------------------------
 *
325
326
327
328
329
330
331

332
333
334
335
336
337
338
	     * Only setting rsrclength to 0 to strip a file's resource fork is
	     * supported.
	     */

	    if (newRsrcForkSize != 0) {
		Tcl_AppendResult(interp,
			"setting nonzero rsrclength not supported", NULL);

		return TCL_ERROR;
	    }

	    /*
	     * Construct path to resource fork.
	     */








>







326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
	     * Only setting rsrclength to 0 to strip a file's resource fork is
	     * supported.
	     */

	    if (newRsrcForkSize != 0) {
		Tcl_AppendResult(interp,
			"setting nonzero rsrclength not supported", NULL);
		Tcl_SetErrorCode(interp, "TCL", "UNSUPPORTED", NULL);
		return TCL_ERROR;
	    }

	    /*
	     * Construct path to resource fork.
	     */

365
366
367
368
369
370
371

372
373
374
375
376
377
378
		return TCL_ERROR;
	    }
	}
    }
    return TCL_OK;
#else
    Tcl_AppendResult(interp, "Mac OS X file attributes not supported", NULL);

    return TCL_ERROR;
#endif
}

/*
 *---------------------------------------------------------------------------
 *







>







367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
		return TCL_ERROR;
	    }
	}
    }
    return TCL_OK;
#else
    Tcl_AppendResult(interp, "Mac OS X file attributes not supported", NULL);
    Tcl_SetErrorCode(interp, "TCL", "UNSUPPORTED", NULL);
    return TCL_ERROR;
#endif
}

/*
 *---------------------------------------------------------------------------
 *
632
633
634
635
636
637
638

639
640
641

642
643
644
645
646
647
648
    Tcl_DString ds;
    Tcl_Encoding encoding = Tcl_GetEncoding(NULL, "macRoman");

    string = Tcl_GetStringFromObj(objPtr, &length);
    Tcl_UtfToExternalDString(encoding, string, length, &ds);

    if (Tcl_DStringLength(&ds) > 4) {

	Tcl_AppendResult(interp, "expected Macintosh OS type but got \"",
		string, "\": ", NULL);
	Tcl_SetErrorCode(interp, "TCL", "VALUE", "MAC_OSTYPE", NULL);

	result = TCL_ERROR;
    } else {
	OSType osType;
	char bytes[4] = {'\0','\0','\0','\0'};

	memcpy(bytes, Tcl_DStringValue(&ds), (size_t)Tcl_DStringLength(&ds));
	osType = (OSType) bytes[0] << 24 |







>
|
|
|
>







635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
    Tcl_DString ds;
    Tcl_Encoding encoding = Tcl_GetEncoding(NULL, "macRoman");

    string = Tcl_GetStringFromObj(objPtr, &length);
    Tcl_UtfToExternalDString(encoding, string, length, &ds);

    if (Tcl_DStringLength(&ds) > 4) {
	if (interp) {
	    Tcl_AppendResult(interp, "expected Macintosh OS type but got \"",
		    string, "\": ", NULL);
	    Tcl_SetErrorCode(interp, "TCL", "VALUE", "MAC_OSTYPE", NULL);
	}
	result = TCL_ERROR;
    } else {
	OSType osType;
	char bytes[4] = {'\0','\0','\0','\0'};

	memcpy(bytes, Tcl_DStringValue(&ds), (size_t)Tcl_DStringLength(&ds));
	osType = (OSType) bytes[0] << 24 |

Changes to tests/assemble.test.

26
27
28
29
30
31
32

















33
34
35
36
37
38
39
    set sep {}
    for {set i 0} {$i < 256} {incr i} {
	append s $sep [list set v$i literal$i]
	set sep \n
    }
    return $s
}


















# assemble-1 - TclNRAssembleObjCmd

test assemble-1.1 {wrong # args, direct eval} {
    -body {
	eval [list assemble]
    }







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







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
    set sep {}
    for {set i 0} {$i < 256} {incr i} {
	append s $sep [list set v$i literal$i]
	set sep \n
    }
    return $s
}

testConstraint memory [llength [info commands memory]]
if {[testConstraint memory]} {
    proc getbytes {} {
	set lines [split [memory info] \n]
	return [lindex $lines 3 3]
    }
    proc leaktest {script {iterations 3}} {
	set end [getbytes]
	for {set i 0} {$i < $iterations} {incr i} {
	    uplevel 1 $script
	    set tmp $end
	    set end [getbytes]
	}
	return [expr {$end - $tmp}]
    }
}

# assemble-1 - TclNRAssembleObjCmd

test assemble-1.1 {wrong # args, direct eval} {
    -body {
	eval [list assemble]
    }
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
	assemble {
	    push NaN; uplus
	}
    }
    -returnCodes error
    -result {can't use non-numeric floating-point value as operand of "+"}
}
test assemble-7.43 {tryCvtToNumeric} {
    -body {
	assemble {
	    push NaN; tryCvtToNumeric
	}
    }
    -returnCodes error
    -result {domain error: argument not in valid range}







|







780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
	assemble {
	    push NaN; uplus
	}
    }
    -returnCodes error
    -result {can't use non-numeric floating-point value as operand of "+"}
}
test assemble-7.43.1 {tryCvtToNumeric} {
    -body {
	assemble {
	    push NaN; tryCvtToNumeric
	}
    }
    -returnCodes error
    -result {domain error: argument not in valid range}
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
}
test assemble-15.6 {listIndexImm} {
    -body {
	assemble {push {a b c}; listIndexImm end-1}
    }
    -result b
}
test assemble-15.6 {listIndexImm} {
    -body {
	assemble {push {a b c}; listIndexImm end}
    }
    -result c
}

# assemble-16 - invokeStk







|







1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
}
test assemble-15.6 {listIndexImm} {
    -body {
	assemble {push {a b c}; listIndexImm end-1}
    }
    -result b
}
test assemble-15.7 {listIndexImm} {
    -body {
	assemble {push {a b c}; listIndexImm end}
    }
    -result c
}

# assemble-16 - invokeStk
3194
3195
3196
3197
3198
3199
3200

































































3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
	for {set i 1} {$i < 30} {incr i} {
	    lappend result [ulam $i]
	}
	set result
    }
    -result {1 2 16 4 16 16 52 8 52 16 52 16 40 52 160 16 52 52 88 20 64 52 160 24 88 40 9232 52 88}
}


































































rename fillTables {}
rename assemble {}

::tcltest::cleanupTests
return

# Local Variables:
# mode: tcl
# fill-column: 78
# End:







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











3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
	for {set i 1} {$i < 30} {incr i} {
	    lappend result [ulam $i]
	}
	set result
    }
    -result {1 2 16 4 16 16 52 8 52 16 52 16 40 52 160 16 52 52 88 20 64 52 160 24 88 40 9232 52 88}
}

test assemble-51.1 {memory leak testing} memory {
    leaktest {
	apply {{} {assemble {push hello}}}
    }
} 0
test assemble-51.2 {memory leak testing} memory {
    leaktest {
	apply {{{x 0}} {assemble {incrImm x 1}}}
    }
} 0
test assemble-51.3 {memory leak testing} memory {
    leaktest {
	apply {{n} {
	    assemble {
		load n;		# max
		dup;		# max n
		jump start;     # max n
	    
		label loop;	# max n
		over 1;         # max n max
		over 1;		# max in max n
		ge;             # man n max>=n
		jumpTrue skip;  # max n

		reverse 2;      # n max
		pop;            # n
		dup;            # n n
	    
		label skip;	# max n
		dup;            # max n n
		push 2;         # max n n 2
		mod;            # max n n%2
		jumpTrue odd;   # max n
	    
		push 2;         # max n 2
		div;            # max n/2 -> max n
		jump start;     # max n
	     
		label odd;	# max n
		push 3;         # max n 3
		mult;           # max 3*n
		push 1;         # max 3*n 1
		add;            # max 3*n+1
	    
		label start;	# max n
		dup;		# max n n
		push 1;		# max n n 1
		neq;		# max n n>1
		jumpTrue loop;	# max n
	    
		pop;		# max
	    }
	}} 1
    }
} 0
test assemble-51.4 {memory leak testing} memory {
    leaktest {
	catch {
	    apply {{} {
		assemble {reverse polish notation}
	    }}
	}
    }
} 0

rename fillTables {}
rename assemble {}

::tcltest::cleanupTests
return

# Local Variables:
# mode: tcl
# fill-column: 78
# End:

Changes to tests/async.test.

192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
    set hm [testasync create async3]
} -body {
    apply [list {handle} [concat {
	global aresult
	set aresult {Async event not delivered}
	testasync marklater $handle
	set i 0
    } [string repeat {;incr i;} 1500000] {
	return $aresult
    }]] $hm
} -result {test pattern} -cleanup {
    testasync delete $hm
}

# cleanup







|







192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
    set hm [testasync create async3]
} -body {
    apply [list {handle} [concat {
	global aresult
	set aresult {Async event not delivered}
	testasync marklater $handle
	set i 0
    } "[string repeat {;incr i;} 1500000]after 10;" {
	return $aresult
    }]] $hm
} -result {test pattern} -cleanup {
    testasync delete $hm
}

# cleanup

Changes to tests/binary.test.

2376
2377
2378
2379
2380
2381
2382

















2383
2384
2385
2386
2387
2388
2389
    binary scan [binary format q NaN(3123456789aBc)] w w
    format 0x%016lx [expr {$w & 0xfff3ffffffffffff}]
} 0x7ff3123456789abc
test binary-63.4 {NaN} ieeeFloatingPoint {
    binary scan [binary format q {NaN( 3123456789aBc)}] w w
    format 0x%016lx [expr {$w & 0xfff3ffffffffffff}]
} 0x7ff3123456789abc


















test binary-64.1 {NaN} -constraints ieeeFloatingPoint -body {
    binary scan [binary format w 0x7ff8000000000000] q d
    set d
} -match glob -result NaN*
test binary-64.2 {NaN} -constraints ieeeFloatingPoint -body {
    binary scan [binary format w 0x7ff0123456789aBc] q d







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







2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
    binary scan [binary format q NaN(3123456789aBc)] w w
    format 0x%016lx [expr {$w & 0xfff3ffffffffffff}]
} 0x7ff3123456789abc
test binary-63.4 {NaN} ieeeFloatingPoint {
    binary scan [binary format q {NaN( 3123456789aBc)}] w w
    format 0x%016lx [expr {$w & 0xfff3ffffffffffff}]
} 0x7ff3123456789abc

# Make sure TclParseNumber() rejects invalid nan-hex formats [Bug 3402540]
test binary-63.5 {NaN} -constraints ieeeFloatingPoint -body {
    binary format q Nan(
} -returnCodes error -match glob -result {expected floating-point number*}
test binary-63.6 {NaN} -constraints ieeeFloatingPoint -body {
    binary format q Nan()
} -returnCodes error -match glob -result {expected floating-point number*}
test binary-63.7 {NaN} -constraints ieeeFloatingPoint -body {
    binary format q Nan(g)
} -returnCodes error -match glob -result {expected floating-point number*}
test binary-63.8 {NaN} -constraints ieeeFloatingPoint -body {
    binary format q Nan(1,2)
} -returnCodes error -match glob -result {expected floating-point number*}
test binary-63.9 {NaN} -constraints ieeeFloatingPoint -body {
    binary format q Nan(1234567890abcd)
} -returnCodes error -match glob -result {expected floating-point number*}

test binary-64.1 {NaN} -constraints ieeeFloatingPoint -body {
    binary scan [binary format w 0x7ff8000000000000] q d
    set d
} -match glob -result NaN*
test binary-64.2 {NaN} -constraints ieeeFloatingPoint -body {
    binary scan [binary format w 0x7ff0123456789aBc] q d

Changes to tests/chanio.test.

33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
    testConstraint exec             [llength [info commands exec]]
    testConstraint openpipe         1
    testConstraint fileevent        [llength [info commands fileevent]]
    testConstraint fcopy            [llength [info commands fcopy]]
    testConstraint testfevent       [llength [info commands testfevent]]
    testConstraint testchannelevent [llength [info commands testchannelevent]]
    testConstraint testmainthread   [llength [info commands testmainthread]]
    testConstraint testthread       [llength [info commands testthread]]

    # You need a *very* special environment to do some tests.  In particular,
    # many file systems do not support large-files...
    testConstraint largefileSupport 0

    # some tests can only be run is umask is 2 if "umask" cannot be run, the
    # tests will be skipped.







|







33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
    testConstraint exec             [llength [info commands exec]]
    testConstraint openpipe         1
    testConstraint fileevent        [llength [info commands fileevent]]
    testConstraint fcopy            [llength [info commands fcopy]]
    testConstraint testfevent       [llength [info commands testfevent]]
    testConstraint testchannelevent [llength [info commands testchannelevent]]
    testConstraint testmainthread   [llength [info commands testmainthread]]
    testConstraint thread [expr {0 == [catch {package require Thread 2.6}]}]

    # You need a *very* special environment to do some tests.  In particular,
    # many file systems do not support large-files...
    testConstraint largefileSupport 0

    # some tests can only be run is umask is 2 if "umask" cannot be run, the
    # tests will be skipped.
7409
7410
7411
7412
7413
7414
7415
7416
7417
7418
7419
7420
7421
7422
7423
} {1 {chan gets {normal message from pipe} chan gets {} catch {error message from pipe}}}

test chan-io-59.1 {Thread reference of channels} {testmainthread testchannel} {
    # TIP #10
    # More complicated tests (like that the reference changes as a channel is
    # moved from thread to thread) can be done only in the extension which
    # fully implements the moving of channels between threads, i.e. 'Threads'.
    # Or we have to extend [testthread] as well.
    set f [open $path(longfile) r]
    set result [testchannel mthread $f]
    chan close $f
    string equal $result [testmainthread]
} {1}

test chan-io-60.1 {writing illegal utf sequences} {openpipe fileevent} {







<







7409
7410
7411
7412
7413
7414
7415

7416
7417
7418
7419
7420
7421
7422
} {1 {chan gets {normal message from pipe} chan gets {} catch {error message from pipe}}}

test chan-io-59.1 {Thread reference of channels} {testmainthread testchannel} {
    # TIP #10
    # More complicated tests (like that the reference changes as a channel is
    # moved from thread to thread) can be done only in the extension which
    # fully implements the moving of channels between threads, i.e. 'Threads'.

    set f [open $path(longfile) r]
    set result [testchannel mthread $f]
    chan close $f
    string equal $result [testmainthread]
} {1}

test chan-io-60.1 {writing illegal utf sequences} {openpipe fileevent} {
7490
7491
7492
7493
7494
7495
7496
7497
7498
7499
7500
7501
7502
7503
7504
7505
7506
7507
7508
7509
7510
7511
7512
7513
7514
7515
7516
7517
7518
7519

7520
7521
7522
7523
7524
7525
7526
7527
7528
7529
7530
7531
7532
7533
7534
    lappend res [catch {chan seek $c 0 start}]
    testchannel splice $c
    lappend res [catch {chan seek $c 0 start}]
} -cleanup {
    chan close $c
    removeFile cutsplice
} -result {0 1 0}
# Duplicate of code in "thread.test". Find a better way of doing this without
# duplication. Maybe placement into a proc which transforms to nop after the
# first call, and placement of its defintion in a central location.
if {[testConstraint testthread]} {
    testthread errorproc ThreadError
    proc ThreadError {id info} {
	global threadError
	set threadError $info
    }
    proc ThreadNullError {id info} {
	# ignore
    }
}
test chan-io-70.1 {Transfer channel} -setup {
    set f [makeFile {... dummy ...} cutsplice]
    set res {}
} -constraints {testchannel testthread} -body {
    set c [open $f r]
    lappend res [catch {chan seek $c 0 start}]
    testchannel cut $c
    lappend res [catch {chan seek $c 0 start}]
    set tid [testthread create]
    testthread send $tid [list set c $c]

    lappend res [testthread send $tid {
	testchannel splice $c
	set res [catch {chan seek $c 0 start}]
	chan close $c
	set res
    }]
} -cleanup {
    tcltest::threadReap
    removeFile cutsplice
} -result {0 1 0}

# ### ### ### ######### ######### #########

foreach {n msg expected} {
     0 {}                                 {}







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



|




|
|
>
|






|







7489
7490
7491
7492
7493
7494
7495








7496




7497
7498
7499
7500
7501
7502
7503
7504
7505
7506
7507
7508
7509
7510
7511
7512
7513
7514
7515
7516
7517
7518
7519
7520
7521
7522
    lappend res [catch {chan seek $c 0 start}]
    testchannel splice $c
    lappend res [catch {chan seek $c 0 start}]
} -cleanup {
    chan close $c
    removeFile cutsplice
} -result {0 1 0}













test chan-io-70.1 {Transfer channel} -setup {
    set f [makeFile {... dummy ...} cutsplice]
    set res {}
} -constraints {testchannel thread} -body {
    set c [open $f r]
    lappend res [catch {chan seek $c 0 start}]
    testchannel cut $c
    lappend res [catch {chan seek $c 0 start}]
    set tid [thread::create -preserved]
    thread::send $tid [list set c $c]
    thread::send $tid {load {} Tcltest}
    lappend res [thread::send $tid {
	testchannel splice $c
	set res [catch {chan seek $c 0 start}]
	chan close $c
	set res
    }]
} -cleanup {
    thread::release $tid
    removeFile cutsplice
} -result {0 1 0}

# ### ### ### ######### ######### #########

foreach {n msg expected} {
     0 {}                                 {}
7716
7717
7718
7719
7720
7721
7722
7723
7724
7725
7726
7727
7728
    chan close [lreplace [list a] 0 end]
} -returnCodes error -match glob -result *

# ### ### ### ######### ######### #########

# cleanup
foreach file [list fooBar longfile script output test1 pipe my_script \
	test2 test3 cat stdout kyrillic.txt utf8-fcopy.txt utf8-rp.txt] {
    removeFile $file
}
cleanupTests
}
namespace delete ::tcl::test::io







|





7704
7705
7706
7707
7708
7709
7710
7711
7712
7713
7714
7715
7716
    chan close [lreplace [list a] 0 end]
} -returnCodes error -match glob -result *

# ### ### ### ######### ######### #########

# cleanup
foreach file [list fooBar longfile script output test1 pipe my_script \
	test2 test3 cat kyrillic.txt utf8-fcopy.txt utf8-rp.txt] {
    removeFile $file
}
cleanupTests
}
namespace delete ::tcl::test::io

Changes to tests/coroutine.test.

430
431
432
433
434
435
436

























437
438
439
440
441
442
443
	set end [getbytes]
    }
    set leakedBytes [expr {$end - $start}]
} -cleanup {
    rename getbytes {}
    unset i ns start end
} -result 0


























test coroutine-5.1 {right numLevels on coro return} -constraints {testnrelevels} \
-setup {
    proc nestedYield {{val {}}} {
	yield $val
    }
    proc getNumLevel {} {







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







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
	set end [getbytes]
    }
    set leakedBytes [expr {$end - $start}]
} -cleanup {
    rename getbytes {}
    unset i ns start end
} -result 0

test coroutine-4.6 {compile context, bug #3282869} -setup {
    unset ::x
    proc f x {
	coroutine D eval {yield X$x;yield Y}
    }
} -body {
    f 12
} -cleanup {
    rename f {}
} -returnCodes error -match glob -result {can't read *}

test coroutine-4.7 {compile context, bug #3282869} -setup {
    proc f x {
	coroutine D eval {yield X$x;yield Y$x}
    }
} -body {
    set ::x 15
    set ::x [f 12]
    D
} -cleanup {
    D
    unset ::x
    rename f {}
} -result YX15

test coroutine-5.1 {right numLevels on coro return} -constraints {testnrelevels} \
-setup {
    proc nestedYield {{val {}}} {
	yield $val
    }
    proc getNumLevel {} {

Changes to tests/dict.test.

1354
1355
1356
1357
1358
1359
1360


































































1361
1362
1363
1364
1365
1366
1367
	    }
	}
    }
    string range [append foo OK] end-1 end
} -cleanup {
    unset foo t inner
} -result OK



































































# cleanup
::tcltest::cleanupTests
return

# Local Variables:
# mode: tcl







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







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
	    }
	}
    }
    string range [append foo OK] end-1 end
} -cleanup {
    unset foo t inner
} -result OK
test dict-22.12 {dict with: compiled} {
    apply {{} {
	set d {a 1 b 2}
	list [dict with d {
	    set a $b
	    unset b
	    dict set d c 3
	    list ok
	}] $d
    }}
} {ok {a 2 c 3}}
test dict-22.13 {dict with: compiled} {
    apply {i {
	set d($i) {a 1 b 2}
	list [dict with d($i) {
	    set a $b
	    unset b
	    dict set d($i) c 3
	    list ok
	}] [array get d]
    }} e
} {ok {e {a 2 c 3}}}
test dict-22.14 {dict with: compiled} {
    apply {{} {
	set d {a 1 b 2}
	foreach x {1 2 3} {
	    dict with d {
		incr a $b
		if {$x == 2} break
	    }
	    unset a b
	}
	list $a $b $x $d
    }}
} {5 2 2 {a 5 b 2}}
test dict-22.15 {dict with: compiled} {
    apply {i {
	set d($i) {a 1 b 2}
	foreach x {1 2 3} {
	    dict with d($i) {
		incr a $b
		if {$x == 2} break
	    }
	    unset a b
	}
	list $a $b $x [array get d]
    }} e
} {5 2 2 {e {a 5 b 2}}}
test dict-22.16 {dict with: compiled} {
    apply {{} {
	set d {p {q {a 1 b 2}}}
	dict with d p q {
	    set a $b.$a
	}
	return $d
    }}
} {p {q {a 2.1 b 2}}}
test dict-22.17 {dict with: compiled} {
    apply {i {
	set d($i) {p {q {a 1 b 2}}}
	dict with d($i) p q {
	    set a $b.$a
	}
	array get d
    }} e
} {e {p {q {a 2.1 b 2}}}}

# cleanup
::tcltest::cleanupTests
return

# Local Variables:
# mode: tcl

Changes to tests/encoding.test.

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
# This file contains a collection of tests for tclEncoding.c
# Sourcing this file into Tcl runs the tests and generates output for
# errors.  No output means no errors were found.
#
# Copyright (c) 1997 Sun Microsystems, Inc.
# Copyright (c) 1998-1999 by Scriptics Corporation.
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.

package require tcltest 2

namespace eval ::tcl::test::encoding {
    variable x

namespace import -force ::tcltest::*

proc toutf {args} {
    variable x
    lappend x "toutf $args"
}
proc fromutf {args} {
    variable x
    lappend x "fromutf $args"
}

proc runtests {} {

    variable x

# Some tests require the testencoding command
testConstraint testencoding [llength [info commands testencoding]]
testConstraint exec [llength [info commands exec]]


# TclInitEncodingSubsystem is tested by the rest of this file
# TclFinalizeEncodingSubsystem is not currently tested

test encoding-1.1 {Tcl_GetEncoding: system encoding} {testencoding} {
    testencoding create foo [namespace origin toutf] [namespace origin fromutf]
    set old [encoding system]


    encoding system foo
    set x {}
    encoding convertto abcd


    encoding system $old
    testencoding delete foo
    set x
} {{fromutf }}
test encoding-1.2 {Tcl_GetEncoding: existing encoding} {testencoding} {
    testencoding create foo [namespace origin toutf] [namespace origin fromutf]
    set x {}
    encoding convertto foo abcd
    testencoding delete foo
    set x
} {{fromutf }}
test encoding-1.3 {Tcl_GetEncoding: load encoding} {
    list [encoding convertto jis0208 \u4e4e] \
	[encoding convertfrom jis0208 8C]
} "8C \u4e4e"

test encoding-2.1 {Tcl_FreeEncoding: refcount == 0} {
    encoding convertto jis0208 \u4e4e
} {8C}
test encoding-2.2 {Tcl_FreeEncoding: refcount != 0} {testencoding} {
    set system [encoding system]
    set path [encoding dirs]

    encoding system shiftjis		;# incr ref count
    encoding dirs [list [pwd]]
    set x [encoding convertto shiftjis \u4e4e]	;# old one found   
    encoding system identity
    llength shiftjis		;# Shimmer away any cache of Tcl_Encoding
    lappend x [catch {encoding convertto shiftjis \u4e4e} msg] $msg

    encoding system identity
    encoding dirs $path
    encoding system $system
    set x
} "\u008c\u00c1 1 {unknown encoding \"shiftjis\"}"

test encoding-3.1 {Tcl_GetEncodingName, NULL} {
    set old [encoding system]

    encoding system shiftjis
    set x [encoding system]

    encoding system $old
    set x
} {shiftjis}
test encoding-3.2 {Tcl_GetEncodingName, non-null} {
    set old [fconfigure stdout -encoding]

    fconfigure stdout -encoding jis0208
    set x [fconfigure stdout -encoding]

    fconfigure stdout -encoding $old
    set x
} {jis0208}

test encoding-4.1 {Tcl_GetEncodingNames} {testencoding} {
    cd [makeDirectory tmp]
    makeDirectory [file join tmp encoding]
    makeFile {} [file join tmp encoding junk.enc]
    makeFile {} [file join tmp encoding junk2.enc]
    set path [encoding dirs]
    encoding dirs {}
    catch {unset encodings}
    catch {unset x}

    foreach encoding [encoding names] {
	set encodings($encoding) 1
    }


    encoding dirs [list [file join [pwd] encoding]]
    foreach encoding [encoding names] {
	if {![info exists encodings($encoding)]} {
	    lappend x $encoding
	}
    }


    encoding dirs $path
    cd [workingDirectory]
    removeFile [file join tmp encoding junk2.enc]
    removeFile [file join tmp encoding junk.enc]
    removeDirectory [file join tmp encoding]
    removeDirectory tmp
    lsort $x
} {junk junk2}

test encoding-5.1 {Tcl_SetSystemEncoding} {
    set old [encoding system]

    encoding system jis0208
    set x [encoding convertto \u4e4e]

    encoding system identity
    encoding system $old
    set x
} {8C}
test encoding-5.2 {Tcl_SetSystemEncoding: test ref count} {
    set old [encoding system]
    encoding system $old
    string compare $old [encoding system]
} {0}

test encoding-6.1 {Tcl_CreateEncoding: new} {testencoding} {
    testencoding create foo [namespace code {toutf 1}] \
	[namespace code {fromutf 2}]
    set x {}
    encoding convertfrom foo abcd
    encoding convertto foo abcd
    testencoding delete foo
    set x
} {{toutf 1} {fromutf 2}}
test encoding-6.2 {Tcl_CreateEncoding: replace encoding} {testencoding} {
    testencoding create foo [namespace code {toutf a}] \
	[namespace code {fromutf b}]
    set x {}
    encoding convertfrom foo abcd
    encoding convertto foo abcd
    testencoding delete foo
    set x
} {{toutf a} {fromutf b}}

test encoding-7.1 {Tcl_ExternalToUtfDString: small buffer} {
    encoding convertfrom jis0208 8c8c8c8c
} "\u543e\u543e\u543e\u543e"
test encoding-7.2 {Tcl_UtfToExternalDString: big buffer} {
    set a 8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C

|
|




|
|


















<





>
|



|
<

>
>



>
>


<
|





|









|


>






>



<
|

|

>

|
>

<
|
|

>

|
>

<
|

|


<
<




>



>
>






>
>






<
|

|

>

|
>


<
|













|








|







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
# This file contains a collection of tests for tclEncoding.c
# Sourcing this file into Tcl runs the tests and generates output for errors.
# No output means no errors were found.
#
# Copyright (c) 1997 Sun Microsystems, Inc.
# Copyright (c) 1998-1999 by Scriptics Corporation.
#
# See the file "license.terms" for information on usage and redistribution of
# this file, and for a DISCLAIMER OF ALL WARRANTIES.

package require tcltest 2

namespace eval ::tcl::test::encoding {
    variable x

namespace import -force ::tcltest::*

proc toutf {args} {
    variable x
    lappend x "toutf $args"
}
proc fromutf {args} {
    variable x
    lappend x "fromutf $args"
}

proc runtests {} {

    variable x

# Some tests require the testencoding command
testConstraint testencoding [llength [info commands testencoding]]
testConstraint exec [llength [info commands exec]]
testConstraint testgetdefenc [llength [info commands testgetdefenc]]

# TclInitEncodingSubsystem is tested by the rest of this file
# TclFinalizeEncodingSubsystem is not currently tested

test encoding-1.1 {Tcl_GetEncoding: system encoding} -setup {

    set old [encoding system]
} -constraints {testencoding} -body {
    testencoding create foo [namespace origin toutf] [namespace origin fromutf]
    encoding system foo
    set x {}
    encoding convertto abcd
    return $x
} -cleanup {
    encoding system $old
    testencoding delete foo

} -result {{fromutf }}
test encoding-1.2 {Tcl_GetEncoding: existing encoding} {testencoding} {
    testencoding create foo [namespace origin toutf] [namespace origin fromutf]
    set x {}
    encoding convertto foo abcd
    testencoding delete foo
    return $x
} {{fromutf }}
test encoding-1.3 {Tcl_GetEncoding: load encoding} {
    list [encoding convertto jis0208 \u4e4e] \
	[encoding convertfrom jis0208 8C]
} "8C \u4e4e"

test encoding-2.1 {Tcl_FreeEncoding: refcount == 0} {
    encoding convertto jis0208 \u4e4e
} {8C}
test encoding-2.2 {Tcl_FreeEncoding: refcount != 0} -setup {
    set system [encoding system]
    set path [encoding dirs]
} -constraints {testencoding} -body {
    encoding system shiftjis		;# incr ref count
    encoding dirs [list [pwd]]
    set x [encoding convertto shiftjis \u4e4e]	;# old one found   
    encoding system identity
    llength shiftjis		;# Shimmer away any cache of Tcl_Encoding
    lappend x [catch {encoding convertto shiftjis \u4e4e} msg] $msg
} -cleanup {
    encoding system identity
    encoding dirs $path
    encoding system $system

} -result "\u008c\u00c1 1 {unknown encoding \"shiftjis\"}"

test encoding-3.1 {Tcl_GetEncodingName, NULL} -setup {
    set old [encoding system]
} -body {
    encoding system shiftjis
    encoding system
} -cleanup {
    encoding system $old

} -result {shiftjis}
test encoding-3.2 {Tcl_GetEncodingName, non-null} -setup {
    set old [fconfigure stdout -encoding]
} -body {
    fconfigure stdout -encoding jis0208
    fconfigure stdout -encoding
} -cleanup {
    fconfigure stdout -encoding $old

} -result {jis0208}

test encoding-4.1 {Tcl_GetEncodingNames} -constraints {testencoding} -setup {
    cd [makeDirectory tmp]
    makeDirectory [file join tmp encoding]


    set path [encoding dirs]
    encoding dirs {}
    catch {unset encodings}
    catch {unset x}
} -body {
    foreach encoding [encoding names] {
	set encodings($encoding) 1
    }
    makeFile {} [file join tmp encoding junk.enc]
    makeFile {} [file join tmp encoding junk2.enc]
    encoding dirs [list [file join [pwd] encoding]]
    foreach encoding [encoding names] {
	if {![info exists encodings($encoding)]} {
	    lappend x $encoding
	}
    }
    lsort $x
} -cleanup {
    encoding dirs $path
    cd [workingDirectory]
    removeFile [file join tmp encoding junk2.enc]
    removeFile [file join tmp encoding junk.enc]
    removeDirectory [file join tmp encoding]
    removeDirectory tmp

} -result {junk junk2}

test encoding-5.1 {Tcl_SetSystemEncoding} -setup {
    set old [encoding system]
} -body {
    encoding system jis0208
    encoding convertto \u4e4e
} -cleanup {
    encoding system identity
    encoding system $old

} -result {8C}
test encoding-5.2 {Tcl_SetSystemEncoding: test ref count} {
    set old [encoding system]
    encoding system $old
    string compare $old [encoding system]
} {0}

test encoding-6.1 {Tcl_CreateEncoding: new} {testencoding} {
    testencoding create foo [namespace code {toutf 1}] \
	[namespace code {fromutf 2}]
    set x {}
    encoding convertfrom foo abcd
    encoding convertto foo abcd
    testencoding delete foo
    return $x
} {{toutf 1} {fromutf 2}}
test encoding-6.2 {Tcl_CreateEncoding: replace encoding} {testencoding} {
    testencoding create foo [namespace code {toutf a}] \
	[namespace code {fromutf b}]
    set x {}
    encoding convertfrom foo abcd
    encoding convertto foo abcd
    testencoding delete foo
    return $x
} {{toutf a} {fromutf b}}

test encoding-7.1 {Tcl_ExternalToUtfDString: small buffer} {
    encoding convertfrom jis0208 8c8c8c8c
} "\u543e\u543e\u543e\u543e"
test encoding-7.2 {Tcl_UtfToExternalDString: big buffer} {
    set a 8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C8C
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
    puts -nonewline $f "ab\x8c\xc1g"
    close $f
    set f [open [file join [temporaryDirectory] dummy] r]
    fconfigure $f -translation binary -encoding shiftjis    
    set x [read $f]
    close $f
    file delete [file join [temporaryDirectory] dummy]
    set x
} "ab\u4e4eg"

test encoding-9.1 {Tcl_UtfToExternalDString: small buffer} {
    encoding convertto jis0208 "\u543e\u543e\u543e\u543e"
} {8c8c8c8c}
test encoding-9.2 {Tcl_UtfToExternalDString: big buffer} {
    set a \u4e4e\u4e4e\u4e4e\u4e4e\u4e4e\u4e4e\u4e4e\u4e4e







|







177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
    puts -nonewline $f "ab\x8c\xc1g"
    close $f
    set f [open [file join [temporaryDirectory] dummy] r]
    fconfigure $f -translation binary -encoding shiftjis    
    set x [read $f]
    close $f
    file delete [file join [temporaryDirectory] dummy]
    return $x
} "ab\u4e4eg"

test encoding-9.1 {Tcl_UtfToExternalDString: small buffer} {
    encoding convertto jis0208 "\u543e\u543e\u543e\u543e"
} {8c8c8c8c}
test encoding-9.2 {Tcl_UtfToExternalDString: big buffer} {
    set a \u4e4e\u4e4e\u4e4e\u4e4e\u4e4e\u4e4e\u4e4e\u4e4e
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
    puts -nonewline $f "ab\u4e4eg"
    close $f
    set f [open [file join [temporaryDirectory] dummy] r]
    fconfigure $f -translation binary -encoding iso8859-1
    set x [read $f]
    close $f
    file delete [file join [temporaryDirectory] dummy]
    set x
} "ab\x8c\xc1g"

proc viewable {str} {
    set res ""
    foreach c [split $str {}] {
	if {[string is print $c] && [string is ascii $c]} {
	    append res $c







|







205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
    puts -nonewline $f "ab\u4e4eg"
    close $f
    set f [open [file join [temporaryDirectory] dummy] r]
    fconfigure $f -translation binary -encoding iso8859-1
    set x [read $f]
    close $f
    file delete [file join [temporaryDirectory] dummy]
    return $x
} "ab\x8c\xc1g"

proc viewable {str} {
    set res ""
    foreach c [split $str {}] {
	if {[string is print $c] && [string is ascii $c]} {
	    append res $c
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
} "\u4e4e"
test encoding-11.5 {LoadEncodingFile: escape file} {
    viewable [encoding convertto iso2022 \u4e4e]
} [viewable "\x1b\$B8C\x1b(B"]
test encoding-11.5.1 {LoadEncodingFile: escape file} {
    viewable [encoding convertto iso2022-jp \u4e4e]
} [viewable "\x1b\$B8C\x1b(B"]
test encoding-11.6 {LoadEncodingFile: invalid file} {testencoding} {
    set system [encoding system]
    set path [encoding dirs]
    encoding system identity

    cd [temporaryDirectory]
    encoding dirs [file join tmp encoding]
    makeDirectory tmp
    makeDirectory [file join tmp encoding]
    set f [open [file join tmp encoding splat.enc] w]
    fconfigure $f -translation binary 
    puts $f "abcdefghijklmnop"
    close $f
    set x [list [catch {encoding convertto splat \u4e4e} msg] $msg]

    file delete [file join [temporaryDirectory] tmp encoding splat.enc]
    removeDirectory [file join tmp encoding]
    removeDirectory tmp
    cd [workingDirectory]
    encoding dirs $path
    encoding system $system
    set x
} {1 {invalid encoding file "splat"}}

# OpenEncodingFile is fully tested by the rest of the tests in this file.

test encoding-12.1 {LoadTableEncoding: normal encoding} {
    set x [encoding convertto iso8859-3 \u120]
    append x [encoding convertto iso8859-3 \ud5]
    append x [encoding convertfrom iso8859-3 \xd5]







|



>








|
>






<
|







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
} "\u4e4e"
test encoding-11.5 {LoadEncodingFile: escape file} {
    viewable [encoding convertto iso2022 \u4e4e]
} [viewable "\x1b\$B8C\x1b(B"]
test encoding-11.5.1 {LoadEncodingFile: escape file} {
    viewable [encoding convertto iso2022-jp \u4e4e]
} [viewable "\x1b\$B8C\x1b(B"]
test encoding-11.6 {LoadEncodingFile: invalid file} -constraints {testencoding} -setup {
    set system [encoding system]
    set path [encoding dirs]
    encoding system identity
} -body {
    cd [temporaryDirectory]
    encoding dirs [file join tmp encoding]
    makeDirectory tmp
    makeDirectory [file join tmp encoding]
    set f [open [file join tmp encoding splat.enc] w]
    fconfigure $f -translation binary 
    puts $f "abcdefghijklmnop"
    close $f
    encoding convertto splat \u4e4e
} -returnCodes error -cleanup {
    file delete [file join [temporaryDirectory] tmp encoding splat.enc]
    removeDirectory [file join tmp encoding]
    removeDirectory tmp
    cd [workingDirectory]
    encoding dirs $path
    encoding system $system

} -result {invalid encoding file "splat"}

# OpenEncodingFile is fully tested by the rest of the tests in this file.

test encoding-12.1 {LoadTableEncoding: normal encoding} {
    set x [encoding convertto iso8859-3 \u120]
    append x [encoding convertto iso8859-3 \ud5]
    append x [encoding convertfrom iso8859-3 \xd5]
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
test encoding-14.1 {BinaryProc} {
    encoding convertto identity \x12\x34\x56\xff\x69
} "\x12\x34\x56\xc3\xbf\x69"

test encoding-15.1 {UtfToUtfProc} {
    encoding convertto utf-8 \xa3
} "\xc2\xa3"

test encoding-15.2 {UtfToUtfProc null character output} {
    set x \u0000
    set y [encoding convertto utf-8 \u0000]
    set y [encoding convertfrom identity $y]
    binary scan $y H* z
    list [string bytelength $x] [string bytelength $y] $z
} {2 1 00}

test encoding-15.3 {UtfToUtfProc null character input} {
    set x [encoding convertfrom identity \x00]
    set y [encoding convertfrom utf-8 $x]
    binary scan [encoding convertto identity $y] H* z
    list [string bytelength $x] [string bytelength $y] $z
} {1 2 c080}








<







<







305
306
307
308
309
310
311

312
313
314
315
316
317
318

319
320
321
322
323
324
325
test encoding-14.1 {BinaryProc} {
    encoding convertto identity \x12\x34\x56\xff\x69
} "\x12\x34\x56\xc3\xbf\x69"

test encoding-15.1 {UtfToUtfProc} {
    encoding convertto utf-8 \xa3
} "\xc2\xa3"

test encoding-15.2 {UtfToUtfProc null character output} {
    set x \u0000
    set y [encoding convertto utf-8 \u0000]
    set y [encoding convertfrom identity $y]
    binary scan $y H* z
    list [string bytelength $x] [string bytelength $y] $z
} {2 1 00}

test encoding-15.3 {UtfToUtfProc null character input} {
    set x [encoding convertfrom identity \x00]
    set y [encoding convertfrom utf-8 $x]
    binary scan [encoding convertto identity $y] H* z
    list [string bytelength $x] [string bytelength $y] $z
} {1 2 c080}

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
} [list [string length $iso2022uniData] $iso2022uniData]
test encoding-23.3 {iso2022-jp escape encoding test} {
    # read $fis <size> reads size in chars, not raw bytes.
    set fid [open iso2022.txt r]
    fconfigure $fid -encoding iso2022-jp
    set data [read $fid 50]
    close $fid
    set data
} [string range $iso2022uniData 0 49] ; # 0 .. 49 inclusive == 50
cd [workingDirectory]












test encoding-24.1 {EscapeFreeProc on open channels} -constraints {
	exec
} -setup {
    # Bug #524674 input
    set file [makeFile {
	set f [open [file join [file dirname [info script]] iso2022.txt]]
	fconfigure $f -encoding iso2022-jp
	gets $f
    } iso2022.tcl]
} -body {
    exec [interpreter] $file
} -cleanup {
    removeFile iso2022.tcl
} -result {}


test encoding-24.2 {EscapeFreeProc on open channels} -constraints {
	exec
} -setup {
    # Bug #524674 output
    set file [makeFile {
	encoding system cp1252;	# Bug #2891556 crash revelator
	fconfigure stdout -encoding iso2022-jp
	puts ab\u4e4e\u68d9g
	testfinexit
    } iso2022.tcl]
} -body {
    viewable [exec [interpreter] $file]
} -cleanup {
    removeFile iso2022.tcl
} -result "ab\x1b\$B8C\x1b\$(DD%\x1b(Bg (ab\\u001b\$B8C\\u001b\$(DD%\\u001b(Bg)"

test encoding-24.3 {EscapeFreeProc on open channels} {stdio} {
    # Bug #219314 - if we don't free escape encodings correctly on
    # channel closure, we go boom
    set file [makeFile {
	encoding system iso2022-jp
	set a "\u4e4e\u4e5e\u4e5f"; # 3 Japanese Kanji letters
	puts $a
    } iso2022.tcl]
    set f [open "|[list [interpreter] $file]"]
    fconfigure $f -encoding iso2022-jp







|



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



<
<
<
<
<
<
|
>
|
<
<

|




<
|
<
<
<
|
<

|
|







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
} [list [string length $iso2022uniData] $iso2022uniData]
test encoding-23.3 {iso2022-jp escape encoding test} {
    # read $fis <size> reads size in chars, not raw bytes.
    set fid [open iso2022.txt r]
    fconfigure $fid -encoding iso2022-jp
    set data [read $fid 50]
    close $fid
    return $data
} [string range $iso2022uniData 0 49] ; # 0 .. 49 inclusive == 50
cd [workingDirectory]

# Code to make the next few tests more intelligible; the code being tested
# should be in the body of the test!
proc runInSubprocess {contents {filename iso2022.tcl}} {
    set theFile [makeFile $contents $filename]
    try {
	exec [interpreter] $theFile
    } finally {
	removeFile $theFile
    }
}

test encoding-24.1 {EscapeFreeProc on open channels} exec {
    runInSubprocess {



	set f [open [file join [file dirname [info script]] iso2022.txt]]
	fconfigure $f -encoding iso2022-jp
	gets $f






    }
} {}
test encoding-24.2 {EscapeFreeProc on open channels} exec {


    # Bug #524674 output
    viewable [runInSubprocess {
	encoding system cp1252;	# Bug #2891556 crash revelator
	fconfigure stdout -encoding iso2022-jp
	puts ab\u4e4e\u68d9g
	testfinexit

    }]



} "ab\x1b\$B8C\x1b\$(DD%\x1b(Bg (ab\\u001b\$B8C\\u001b\$(DD%\\u001b(Bg)"

test encoding-24.3 {EscapeFreeProc on open channels} {stdio} {
    # Bug #219314 - if we don't free escape encodings correctly on channel
    # closure, we go boom
    set file [makeFile {
	encoding system iso2022-jp
	set a "\u4e4e\u4e5e\u4e5f"; # 3 Japanese Kanji letters
	puts $a
    } iso2022.tcl]
    set f [open "|[list [interpreter] $file]"]
    fconfigure $f -encoding iso2022-jp
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
	{4F21 4F53}

	{50 21 73 7E}
	{7421 7426}
    } {
	if {[llength $range] == 2} {
	    # for adhoc range. simple {first last}. inclusive.
	    set first [scan [lindex $range 0] %x]
	    set last [scan [lindex $range 1] %x]
	    for {set i $first} {$i <= $last} {incr i} {
		set code $i
		uplevel 1 $command
	    }
	} elseif {[llength $range] == 4} {
	    # for uniform range.
	    set h0 [scan [lindex $range 0] %x]
	    set l0 [scan [lindex $range 1] %x]
	    set hend [scan [lindex $range 2] %x]
	    set lend [scan [lindex $range 3] %x]
	    for {set hi $h0} {$hi <= $hend} {incr hi} {
		for {set lo $l0} {$lo <= $lend} {incr lo} {
		    set code [expr {$hi << 8 | ($lo & 0xff)}]
		    uplevel 1 $command
		}
	    }
	} else {







<
|






|
<
<
<







468
469
470
471
472
473
474

475
476
477
478
479
480
481
482



483
484
485
486
487
488
489
	{4F21 4F53}

	{50 21 73 7E}
	{7421 7426}
    } {
	if {[llength $range] == 2} {
	    # for adhoc range. simple {first last}. inclusive.

	    scan $range %x%x first last
	    for {set i $first} {$i <= $last} {incr i} {
		set code $i
		uplevel 1 $command
	    }
	} elseif {[llength $range] == 4} {
	    # for uniform range.
	    scan $range %x%x%x%x h0 l0 hend lend



	    for {set hi $h0} {$hi <= $hend} {incr hi} {
		for {set lo $l0} {$lo <= $lend} {incr lo} {
		    set code [expr {$hi << 8 | ($lo & 0xff)}]
		    uplevel 1 $command
		}
	    }
	} else {
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





	# For more readable (easy to analyze) output.
	set code [lindex $la 0]
	binary scan [lindex $la 1] H* expected
	binary scan [lindex $lb 1] H* got
	lappend diff [list $code $expected $got]
    }
    set diff
}

# Create char tables.
cd [temporaryDirectory]
foreach enc {cp932 euc-jp iso2022-jp} {
    set f [open $enc.chars w]
    fconfigure $f -encoding binary
    foreach-jisx0208 code {
	puts $f [format "%04X %s" $code [gen-jisx0208-$enc $code]]
    }
    close $f
}
# shiftjis == cp932 for jisx0208.
file copy -force cp932.chars shiftjis.chars

set NUM 0
foreach from {cp932 shiftjis euc-jp iso2022-jp} {
    foreach to {cp932 shiftjis euc-jp iso2022-jp} {
	test encoding-25.[incr NUM] "jisx0208 $from => $to" {
	    cd [temporaryDirectory]

	    set f [open $from.chars]
	    fconfigure $f -encoding $from
	    set out [open $from.$to.tcltestout w]
	    fconfigure $out -encoding $to
	    puts -nonewline $out [read $f]
	    close $out
	    close $f
	    
	    # then compare $to.chars <=> $from.to.tcltestout as binary.
	    set fa [open $to.chars]
	    fconfigure $fa -encoding binary
	    set fb [open $from.$to.tcltestout]
	    fconfigure $fb -encoding binary
	    set diff [channel-diff $fa $fb]


	    close $fa
	    close $fb
	    
	    # Difference should be empty.
	    set diff
	} {}
    }
}

testConstraint testgetdefenc [llength [info commands testgetdefenc]]

test encoding-26.0 {Tcl_GetDefaultEncodingDir} -constraints {
    testgetdefenc 
} -setup {
     set origDir [testgetdefenc]
     testsetdefenc slappy
} -body {
     testgetdefenc
} -cleanup {
     testsetdefenc $origDir
} -result slappy

file delete {*}[glob -directory [temporaryDirectory] *.chars *.tcltestout]
# ===> Cut here <===

# EscapeFreeProc, GetTableEncoding, unilen
# are fully tested by the rest of this file

}
runtests

}

# cleanup
namespace delete ::tcl::test::encoding
::tcltest::cleanupTests
return











|


















|

>







<

|
<
|
<
|
>
>


|
<
<
<



<
<

|

|
|

|

|





|
|
>









>
>
>
>
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

	# For more readable (easy to analyze) output.
	set code [lindex $la 0]
	binary scan [lindex $la 1] H* expected
	binary scan [lindex $lb 1] H* got
	lappend diff [list $code $expected $got]
    }
    return $diff
}

# Create char tables.
cd [temporaryDirectory]
foreach enc {cp932 euc-jp iso2022-jp} {
    set f [open $enc.chars w]
    fconfigure $f -encoding binary
    foreach-jisx0208 code {
	puts $f [format "%04X %s" $code [gen-jisx0208-$enc $code]]
    }
    close $f
}
# shiftjis == cp932 for jisx0208.
file copy -force cp932.chars shiftjis.chars

set NUM 0
foreach from {cp932 shiftjis euc-jp iso2022-jp} {
    foreach to {cp932 shiftjis euc-jp iso2022-jp} {
	test encoding-25.[incr NUM] "jisx0208 $from => $to" -setup {
	    cd [temporaryDirectory]
	} -body {
	    set f [open $from.chars]
	    fconfigure $f -encoding $from
	    set out [open $from.$to.tcltestout w]
	    fconfigure $out -encoding $to
	    puts -nonewline $out [read $f]
	    close $out
	    close $f

	    # then compare $to.chars <=> $from.to.tcltestout as binary.
	    set fa [open $to.chars rb]

	    set fb [open $from.$to.tcltestout rb]

	    channel-diff $fa $fb
	    # Difference should be empty.
	} -cleanup {
	    close $fa
	    close $fb
	} -result {}



    }
}



test encoding-26.0 {Tcl_GetDefaultEncodingDir} -constraints {
    testgetdefenc
} -setup {
    set origDir [testgetdefenc]
    testsetdefenc slappy
} -body {
    testgetdefenc
} -cleanup {
    testsetdefenc $origDir
} -result slappy

file delete {*}[glob -directory [temporaryDirectory] *.chars *.tcltestout]
# ===> Cut here <===

# EscapeFreeProc, GetTableEncoding, unilen are fully tested by the rest of
# this file.

}
runtests

}

# cleanup
namespace delete ::tcl::test::encoding
::tcltest::cleanupTests
return

# Local Variables:
# mode: tcl
# End:

Changes to tests/error.test.

134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
test error-3.2 {errors in catch command} {
    list [catch {catch a b c} msg] $msg
} {0 1}
test error-3.3 {errors in catch command} {
    catch {unset a}
    set a(0) 22
    list [catch {catch {format 44} a} msg] $msg
} {1 {couldn't save command result in variable}}
catch {unset a}

# More tests related to errorInfo and errorCode

test error-4.1 {errorInfo and errorCode variables} {
    list [catch {error msg1 msg2 msg3} msg] $msg $::errorInfo $::errorCode
} {1 msg1 msg2 msg3}







|







134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
test error-3.2 {errors in catch command} {
    list [catch {catch a b c} msg] $msg
} {0 1}
test error-3.3 {errors in catch command} {
    catch {unset a}
    set a(0) 22
    list [catch {catch {format 44} a} msg] $msg
} {1 {can't set "a": variable is array}}
catch {unset a}

# More tests related to errorInfo and errorCode

test error-4.1 {errorInfo and errorCode variables} {
    list [catch {error msg1 msg2 msg3} msg] $msg $::errorInfo $::errorCode
} {1 msg1 msg2 msg3}
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
	throw FOO bar
    } on error {res opts} {
	set r "$res,[dict get $opts -errorcode]"
    }
} {bar,FOO}
test error-12.5 {try with result/opts variable assignment in on handler, vars remain in scope} {
    try { throw FOO bar } on error {res opts} { list d e f }
    set r "$res,[dict get $opts -errorcode]"  
} {bar,FOO}
test error-12.6 {try result is propagated if no matching handler} {
    try { list a b c } on error {} { list d e f }
} {a b c}
test error-12.7 {handler result is propagated if handler executes} {
    try { throw FOO bar } on error {} { list d e f }
} {d e f}







|







413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
	throw FOO bar
    } on error {res opts} {
	set r "$res,[dict get $opts -errorcode]"
    }
} {bar,FOO}
test error-12.5 {try with result/opts variable assignment in on handler, vars remain in scope} {
    try { throw FOO bar } on error {res opts} { list d e f }
    set r "$res,[dict get $opts -errorcode]"
} {bar,FOO}
test error-12.6 {try result is propagated if no matching handler} {
    try { list a b c } on error {} { list d e f }
} {a b c}
test error-12.7 {handler result is propagated if handler executes} {
    try { throw FOO bar } on error {} { list d e f }
} {d e f}
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
    # warning: error message may change
    try list on error {em opts}
} -returnCodes error -match glob -result {wrong # args to on clause: *}
test error-13.8 {try with multiple handlers and finally (ok)} {
    try list on error {} {} trap {} {} {} finally {}
} {}
test error-13.9 {last handler body can't be a fallthrough #1} -body {
    try list on error {} {} on break {} - 
} -returnCodes error -result {last non-finally clause must not have a body of "-"}
test error-13.10 {last handler body can't be a fallthrough #2} -body {
    try list on error {} {} on break {} - finally { list d e f }
} -returnCodes error -result {last non-finally clause must not have a body of "-"}

# try tests - multiple handlers (left-to-right matching, only one runs)

test error-14.1 {try with multiple handlers (only one matches) #1} {
    try { throw FOO bar } on ok {} { list a b c } trap FOO {} { list d e f }
} {d e f}
test error-14.2 {try with multiple handlers (only one matches) #2} {
    try { throw FOO bar } trap FOO {} { list d e f } on ok {} { list a b c } 
} {d e f}
test error-14.3 {try with multiple handlers (only one matches) #3} {
    try {
	throw FOO bar
    } on break {} {
	list x y z
    } trap FOO {} {
	list d e f
    } on ok {} {
	list a b c
    } 
} {d e f}
test error-14.4 {try with multiple matching handlers (only the first in left-to-right order runs) #1} {
    try { throw FOO bar } on error {} { list a b c } trap FOO {} { list d e f }
} {a b c}
test error-14.5 {try with multiple matching handlers (only the first in left-to-right order runs) #2} {
    try { throw FOO bar } trap FOO {} { list d e f } on error {} { list a b c }
} {d e f}







|











|










|







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
    # warning: error message may change
    try list on error {em opts}
} -returnCodes error -match glob -result {wrong # args to on clause: *}
test error-13.8 {try with multiple handlers and finally (ok)} {
    try list on error {} {} trap {} {} {} finally {}
} {}
test error-13.9 {last handler body can't be a fallthrough #1} -body {
    try list on error {} {} on break {} -
} -returnCodes error -result {last non-finally clause must not have a body of "-"}
test error-13.10 {last handler body can't be a fallthrough #2} -body {
    try list on error {} {} on break {} - finally { list d e f }
} -returnCodes error -result {last non-finally clause must not have a body of "-"}

# try tests - multiple handlers (left-to-right matching, only one runs)

test error-14.1 {try with multiple handlers (only one matches) #1} {
    try { throw FOO bar } on ok {} { list a b c } trap FOO {} { list d e f }
} {d e f}
test error-14.2 {try with multiple handlers (only one matches) #2} {
    try { throw FOO bar } trap FOO {} { list d e f } on ok {} { list a b c }
} {d e f}
test error-14.3 {try with multiple handlers (only one matches) #3} {
    try {
	throw FOO bar
    } on break {} {
	list x y z
    } trap FOO {} {
	list d e f
    } on ok {} {
	list a b c
    }
} {d e f}
test error-14.4 {try with multiple matching handlers (only the first in left-to-right order runs) #1} {
    try { throw FOO bar } on error {} { list a b c } trap FOO {} { list d e f }
} {a b c}
test error-14.5 {try with multiple matching handlers (only the first in left-to-right order runs) #2} {
    try { throw FOO bar } trap FOO {} { list d e f } on error {} { list a b c }
} {d e f}
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
} {5}
test error-16.6 {try with variable assignment and propagation #1} {
    # Ensure that the handler variables preserve the exception off the
    # try-body, and are not modified by the exception off the handler
    catch {
	try { throw FOO bar } trap FOO {em} { throw BAR baz }
    }
    set em  
} {bar}
test error-16.7 {try with variable assignment and propagation #2} {
    catch {
	try { throw FOO bar } trap FOO {em opts} { throw BAR baz }
    }
    list $em [dict get $opts -errorcode]  
} {bar FOO}
test error-16.8 {exception chaining (try=ok, handler=error)} {
    #FIXME is the intent of this test correct?  
    catch {
	try { list a b c } on ok {em opts} { throw BAR baz }
    } tryem tryopts
    string equal $opts [dict get $tryopts -during]
} {1}
test error-16.9 {exception chaining (try=error, handler=error)} {
    # The exception off the handler should chain to the exception off the







|





|


|







589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
} {5}
test error-16.6 {try with variable assignment and propagation #1} {
    # Ensure that the handler variables preserve the exception off the
    # try-body, and are not modified by the exception off the handler
    catch {
	try { throw FOO bar } trap FOO {em} { throw BAR baz }
    }
    set em
} {bar}
test error-16.7 {try with variable assignment and propagation #2} {
    catch {
	try { throw FOO bar } trap FOO {em opts} { throw BAR baz }
    }
    list $em [dict get $opts -errorcode]
} {bar FOO}
test error-16.8 {exception chaining (try=ok, handler=error)} {
    #FIXME is the intent of this test correct?
    catch {
	try { list a b c } on ok {em opts} { throw BAR baz }
    } tryem tryopts
    string equal $opts [dict get $tryopts -during]
} {1}
test error-16.9 {exception chaining (try=error, handler=error)} {
    # The exception off the handler should chain to the exception off the
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
    } result
    list $em $result
} {bar {d e f}}
test error-17.11 {successful finally doesn't affect variable assignment or propagation} {
    catch {
	try { throw FOO bar } trap FOO {em opts} { throw BAR baz } finally { list d e f }
    }
    list $em [dict get $opts -errorcode]  
} {bar FOO}

# try tests - propagation (exceptions in finally, exception chaining)

test error-18.1 {try (ok) with exception in finally (error)} -body {
    try { list a b c } finally { throw BAR foo }
} -returnCodes error -result {foo}
test error-18.2 {try (error) with exception in finally (break)} -body {
    try { throw FOO bar } finally { break }
} -returnCodes 3 -result {}
test error-18.3 {try (ok) with handler (ok) and exception in finally (error)} -body {
    try { list a b c } on ok {} { list d e f } finally { throw BAR foo }
} -returnCodes error -result {foo}
test error-18.4 {try (error) with exception in handler (error) and in finally (arb code)} -body {
    try { throw FOO bar } on error {} { throw BAR baz } finally { return -level 0 -code 99 zing }
} -returnCodes 99 -result {zing}
test error-18.5 {exception in finally doesn't affect variable assignment} {
    catch {
	try { throw FOO bar } trap FOO {em opts} { throw BAR baz } finally { throw BAZ zing }
    }
    list $em [dict get $opts -errorcode]  
} {bar FOO}
test error-18.6 {exception chaining in finally (try=ok)} {
    catch {
	list a b c 
    } em expopts
    catch {
	try { list a b c } finally { throw BAR foo }
    } em opts
    string equal $expopts [dict get $opts -during]
} {1}
test error-18.7 {exception chaining in finally (try=error)} {







|




















|



|







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
    } result
    list $em $result
} {bar {d e f}}
test error-17.11 {successful finally doesn't affect variable assignment or propagation} {
    catch {
	try { throw FOO bar } trap FOO {em opts} { throw BAR baz } finally { list d e f }
    }
    list $em [dict get $opts -errorcode]
} {bar FOO}

# try tests - propagation (exceptions in finally, exception chaining)

test error-18.1 {try (ok) with exception in finally (error)} -body {
    try { list a b c } finally { throw BAR foo }
} -returnCodes error -result {foo}
test error-18.2 {try (error) with exception in finally (break)} -body {
    try { throw FOO bar } finally { break }
} -returnCodes 3 -result {}
test error-18.3 {try (ok) with handler (ok) and exception in finally (error)} -body {
    try { list a b c } on ok {} { list d e f } finally { throw BAR foo }
} -returnCodes error -result {foo}
test error-18.4 {try (error) with exception in handler (error) and in finally (arb code)} -body {
    try { throw FOO bar } on error {} { throw BAR baz } finally { return -level 0 -code 99 zing }
} -returnCodes 99 -result {zing}
test error-18.5 {exception in finally doesn't affect variable assignment} {
    catch {
	try { throw FOO bar } trap FOO {em opts} { throw BAR baz } finally { throw BAZ zing }
    }
    list $em [dict get $opts -errorcode]
} {bar FOO}
test error-18.6 {exception chaining in finally (try=ok)} {
    catch {
	list a b c
    } em expopts
    catch {
	try { list a b c } finally { throw BAR foo }
    } em opts
    string equal $expopts [dict get $opts -during]
} {1}
test error-18.7 {exception chaining in finally (try=error)} {
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
test error-19.1 {try with fallthrough body #1} {
    set RES {}
    try { list a b c } on ok { set RES 0 } - on error {} { set RES 1 }
    set RES
} {1}
test error-19.2 {try with fallthrough body #2} {
    set RES {}
    try { 
	throw FOO bar 
    } trap BAR {} {
    } trap FOO {} - trap {} {} {
	set RES foo
    } on error {} {
	set RES err
    }  
    set RES
} {foo}
test error-19.3 {try with cascade fallthrough} {
    set RES {}
    try {
	throw FOO bar
    } trap FOO {} - trap BAR {} - trap {} {} {
	set RES trap
    } on error {} { set RES err }
    set RES
} {trap}
test error-19.4 {multiple unrelated fallthroughs #1} {
    set RES {}
    try {
	throw FOO bar
    } trap FOO {} - trap BAR {} { 
	set RES foo
    } trap {} {} - on error {} {
	set RES err
    } 
    set RES
} {foo}
test error-19.5 {multiple unrelated fallthroughs #2} {
    set RES {}
    try {
	throw BAZ zing
    } trap FOO {} - trap BAR {} { 
	set RES foo
    } trap {} {} - on error {} {
	set RES err
    } 
    set RES
} {err}
proc addmsg msg {
    variable RES
    lappend RES $msg
}
test error-19.6 {compiled try executes all clauses} -setup {







|
|





|















|



|






|



|







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
test error-19.1 {try with fallthrough body #1} {
    set RES {}
    try { list a b c } on ok { set RES 0 } - on error {} { set RES 1 }
    set RES
} {1}
test error-19.2 {try with fallthrough body #2} {
    set RES {}
    try {
	throw FOO bar
    } trap BAR {} {
    } trap FOO {} - trap {} {} {
	set RES foo
    } on error {} {
	set RES err
    }
    set RES
} {foo}
test error-19.3 {try with cascade fallthrough} {
    set RES {}
    try {
	throw FOO bar
    } trap FOO {} - trap BAR {} - trap {} {} {
	set RES trap
    } on error {} { set RES err }
    set RES
} {trap}
test error-19.4 {multiple unrelated fallthroughs #1} {
    set RES {}
    try {
	throw FOO bar
    } trap FOO {} - trap BAR {} {
	set RES foo
    } trap {} {} - on error {} {
	set RES err
    }
    set RES
} {foo}
test error-19.5 {multiple unrelated fallthroughs #2} {
    set RES {}
    try {
	throw BAZ zing
    } trap FOO {} - trap BAR {} {
	set RES foo
    } trap {} {} - on error {} {
	set RES err
    }
    set RES
} {err}
proc addmsg msg {
    variable RES
    lappend RES $msg
}
test error-19.6 {compiled try executes all clauses} -setup {
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061

}
namespace delete ::tcl::test::error

# cleanup
catch {rename p ""}
::tcltest::cleanupTests
return 

# Local Variables:
# mode: tcl
# End:







|




1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061

}
namespace delete ::tcl::test::error

# cleanup
catch {rename p ""}
::tcltest::cleanupTests
return

# Local Variables:
# mode: tcl
# End:

Changes to tests/fileSystem.test.

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
cd [tcltest::temporaryDirectory]
makeFile "test file" gorp.file
makeDirectory dir.dir
makeDirectory [file join dir.dir dirinside.dir]
makeFile "test file in directory" [file join dir.dir inside.file]

testConstraint unusedDrive 0



set drive {}
if {[testConstraint win]} {
    set vols [string map [list :/ {}] [file volumes]]
    for {set i 0} {$i < 26} {incr i} {
	set drive [format %c [expr {$i + 65}]]
	if {$drive ni $vols} {
	    testConstraint unusedDrive 1
	    break
	}
    }
    unset i vols
    # The variable 'drive' will be used below
}

testConstraint moreThanOneDrive 0
set drives [list]
if {[testConstraint win]} {
    set dir [pwd]

    foreach vol [file volumes] {
        if {![catch {cd $vol}]} {
            lappend drives $vol
        }
    }
    if {[llength $drives] > 1} {
        testConstraint moreThanOneDrive 1
    }
    # The variable 'drives' will be used below
    unset vol
    cd $dir
    unset dir
}



proc testPathEqual {one two} {
    if {$one eq $two} {
	return 1
    } else {
	return "not equal: $one $two"
    }

}

testConstraint hasLinks [expr {![catch {
    file link link.file gorp.file
    cd dir.dir
    file link \
	[file join linkinside.file] \







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


|
<
<

>







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
cd [tcltest::temporaryDirectory]
makeFile "test file" gorp.file
makeDirectory dir.dir
makeDirectory [file join dir.dir dirinside.dir]
makeFile "test file in directory" [file join dir.dir inside.file]

testConstraint unusedDrive 0
testConstraint moreThanOneDrive 0
apply {{} {
    # The variables 'drive' and 'drives' will be used below.
    variable drive {} drives {}
    if {[testConstraint win]} {
	set vols [string map [list :/ {}] [file volumes]]
	for {set i 0} {$i < 26} {incr i} {
	    set drive [format %c [expr {$i + 65}]]
	    if {$drive ni $vols} {
		testConstraint unusedDrive 1
		break
	    }
	}







	set dir [pwd]
	try {
	    foreach vol [file volumes] {
		if {![catch {cd $vol}]} {
		    lappend drives $vol
		}
	    }

	    testConstraint moreThanOneDrive [llength $drives]
	} finally {


	    cd $dir

	}
    }
} ::tcl::test::fileSystem}

proc testPathEqual {one two} {
    if {$one eq $two} {
	return "ok"


    }
    return "not equal: $one $two"
}

testConstraint hasLinks [expr {![catch {
    file link link.file gorp.file
    cd dir.dir
    file link \
	[file join linkinside.file] \
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
} {0}
test filesystem-1.1 {link normalisation} {hasLinks} {
   string equal [file normalize dir.dir] [file normalize dir.link]
} {0}
test filesystem-1.2 {link normalisation} {hasLinks unix} {
    testPathEqual [file normalize [file join gorp.file foo]] \
	[file normalize [file join link.file foo]]
} {1}
test filesystem-1.3 {link normalisation} {hasLinks} {
    testPathEqual [file normalize [file join dir.dir foo]] \
	[file normalize [file join dir.link foo]]
} {1}
test filesystem-1.4 {link normalisation} {hasLinks} {
    testPathEqual [file normalize [file join dir.dir inside.file]] \
	[file normalize [file join dir.link inside.file]]
} {1}
test filesystem-1.5 {link normalisation} {hasLinks} {
    testPathEqual [file normalize [file join dir.dir linkinside.file]] \
	[file normalize [file join dir.dir linkinside.file]]
} {1}
test filesystem-1.6 {link normalisation} {hasLinks} {
    string equal [file normalize [file join dir.dir linkinside.file]] \
	[file normalize [file join dir.link inside.file]]
} {0}
test filesystem-1.7 {link normalisation} {hasLinks unix} {
    testPathEqual [file normalize [file join dir.link linkinside.file foo]] \
	[file normalize [file join dir.dir inside.file foo]]
} {1}
test filesystem-1.8 {link normalisation} {hasLinks} {
    string equal [file normalize [file join dir.dir linkinside.filefoo]] \
	[file normalize [file join dir.link inside.filefoo]]
} {0}
test filesystem-1.9 {link normalisation} {unix hasLinks} {
    file delete -force dir.link

    file link dir.link [file nativename dir.dir]
    testPathEqual [file normalize [file join dir.dir linkinside.file foo]] \
	[file normalize [file join dir.link inside.file foo]]
} {1}
test filesystem-1.10 {link normalisation: double link} {unix hasLinks} {
    file link dir2.link dir.link
    testPathEqual [file normalize [file join dir.dir linkinside.file foo]] \
	[file normalize [file join dir2.link inside.file foo]]
} {1}
makeDirectory dir2.file
test filesystem-1.11 {link normalisation: double link, back in tree} {unix hasLinks} {
    file link [file join dir2.file dir2.link] [file join .. dir2.link]
    testPathEqual [file normalize [file join dir.dir linkinside.file foo]] \
	[file normalize [file join dir2.file dir2.link inside.file foo]]
} {1}
test filesystem-1.12 {file new native path} {} {
    for {set i 0} {$i < 10} {incr i} {
	foreach f [lsort [glob -nocomplain -type l *]] {
	    catch {file readlink $f}
	}
    }
    # If we reach here we've succeeded. We used to crash above.







|



|



|



|







|




|

>



|




|





|







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
} {0}
test filesystem-1.1 {link normalisation} {hasLinks} {
   string equal [file normalize dir.dir] [file normalize dir.link]
} {0}
test filesystem-1.2 {link normalisation} {hasLinks unix} {
    testPathEqual [file normalize [file join gorp.file foo]] \
	[file normalize [file join link.file foo]]
} ok
test filesystem-1.3 {link normalisation} {hasLinks} {
    testPathEqual [file normalize [file join dir.dir foo]] \
	[file normalize [file join dir.link foo]]
} ok
test filesystem-1.4 {link normalisation} {hasLinks} {
    testPathEqual [file normalize [file join dir.dir inside.file]] \
	[file normalize [file join dir.link inside.file]]
} ok
test filesystem-1.5 {link normalisation} {hasLinks} {
    testPathEqual [file normalize [file join dir.dir linkinside.file]] \
	[file normalize [file join dir.dir linkinside.file]]
} ok
test filesystem-1.6 {link normalisation} {hasLinks} {
    string equal [file normalize [file join dir.dir linkinside.file]] \
	[file normalize [file join dir.link inside.file]]
} {0}
test filesystem-1.7 {link normalisation} {hasLinks unix} {
    testPathEqual [file normalize [file join dir.link linkinside.file foo]] \
	[file normalize [file join dir.dir inside.file foo]]
} ok
test filesystem-1.8 {link normalisation} {hasLinks} {
    string equal [file normalize [file join dir.dir linkinside.filefoo]] \
	[file normalize [file join dir.link inside.filefoo]]
} {0}
test filesystem-1.9 {link normalisation} -setup {
    file delete -force dir.link
} -constraints {unix hasLinks} -body {
    file link dir.link [file nativename dir.dir]
    testPathEqual [file normalize [file join dir.dir linkinside.file foo]] \
	[file normalize [file join dir.link inside.file foo]]
} -result ok
test filesystem-1.10 {link normalisation: double link} {unix hasLinks} {
    file link dir2.link dir.link
    testPathEqual [file normalize [file join dir.dir linkinside.file foo]] \
	[file normalize [file join dir2.link inside.file foo]]
} ok
makeDirectory dir2.file
test filesystem-1.11 {link normalisation: double link, back in tree} {unix hasLinks} {
    file link [file join dir2.file dir2.link] [file join .. dir2.link]
    testPathEqual [file normalize [file join dir.dir linkinside.file foo]] \
	[file normalize [file join dir2.file dir2.link inside.file foo]]
} ok
test filesystem-1.12 {file new native path} {} {
    for {set i 0} {$i < 10} {incr i} {
	foreach f [lsort [glob -nocomplain -type l *]] {
	    catch {file readlink $f}
	}
    }
    # If we reach here we've succeeded. We used to crash above.
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
} "${drive}:/a"
test filesystem-1.25 {file normalisation} {win unusedDrive} {
    file normalize ${drive}:/./.././../../a
} "${drive}:/a"
test filesystem-1.25.1 {file normalisation} {win unusedDrive} {
    file normalize ${drive}:/./.././..\\..\\a\\bb
} "${drive}:/a/bb"
test filesystem-1.26 {link normalisation: link and ..} {hasLinks} {
    file delete -force dir2.link

    set dir [file join dir2 foo bar]
    file mkdir $dir
    file link dir2.link [file join dir2 foo bar]
    set res [list [file normalize [file join dir2 foo x]] \
	    [file normalize [file join dir2.link .. x]]]
    testPathEqual [lindex $res 0] [lindex $res 1]
} 1
test filesystem-1.27 {file normalisation: up and down with ..} {
    set dir [file join dir2 foo bar]
    file mkdir $dir
    set dir2 [file join dir2 .. dir2 foo .. foo bar]
    set res [list [file normalize $dir] [file normalize $dir2]]
    set res2 [list [file exists $dir] [file exists $dir2]]
    if {![string equal [lindex $res 0] [lindex $res 1]]} {
	set res "exists: $res2, $res not equal"
    } else {
	set res "ok: $res2"
    }
} {ok: 1 1}
test filesystem-1.28 {link normalisation: link with .. and ..} {hasLinks} {
    file delete -force dir2.link

    set dir [file join dir2 foo bar]
    file mkdir $dir
    set to [file join dir2 .. dir2 foo .. foo bar]
    file link dir2.link $to
    set res [list [file normalize [file join dir2 foo x]] \
	    [file normalize [file join dir2.link .. x]]]
    testPathEqual [lindex $res 0] [lindex $res 1]
} 1
test filesystem-1.29 {link normalisation: link with ..} {hasLinks} {
    file delete -force dir2.link

    set dir [file join dir2 foo bar]
    file mkdir $dir
    set to [file join dir2 .. dir2 foo .. foo bar]
    file link dir2.link $to
    set res [file normalize [file join dir2.link x yyy z]]
    if {[string match *..* $res]} {
	return "$res must not contain '..'"
    }
    return "ok"
} {ok}
test filesystem-1.29.1 {link normalisation with two consecutive links} {hasLinks} {
    testPathEqual [file normalize [file join dir.link dirinside.link abc]] \
	[file normalize [file join dir.dir dirinside.dir abc]]
} {1}
file delete -force dir2.file
file delete -force dir2.link
file delete -force link.file dir.link
file delete -force dir2
file delete -force [file join dir.dir dirinside.link]
removeFile [file join dir.dir inside.file]
removeDirectory [file join dir.dir dirinside.dir]







|

>



|
|
<
|




|
|
<
<
<
<
<
|
|

>




|
|
<
|
|

>









|



|







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
} "${drive}:/a"
test filesystem-1.25 {file normalisation} {win unusedDrive} {
    file normalize ${drive}:/./.././../../a
} "${drive}:/a"
test filesystem-1.25.1 {file normalisation} {win unusedDrive} {
    file normalize ${drive}:/./.././..\\..\\a\\bb
} "${drive}:/a/bb"
test filesystem-1.26 {link normalisation: link and ..} -setup {
    file delete -force dir2.link
} -constraints {hasLinks} -body {
    set dir [file join dir2 foo bar]
    file mkdir $dir
    file link dir2.link [file join dir2 foo bar]
    testPathEqual [file normalize [file join dir2 foo x]] \
	    [file normalize [file join dir2.link .. x]]

} -result ok
test filesystem-1.27 {file normalisation: up and down with ..} {
    set dir [file join dir2 foo bar]
    file mkdir $dir
    set dir2 [file join dir2 .. dir2 foo .. foo bar]
    list [testPathEqual [file normalize $dir] [file normalize $dir2]] \
	[file exists $dir] [file exists $dir2]





} {ok 1 1}
test filesystem-1.28 {link normalisation: link with .. and ..} -setup {
    file delete -force dir2.link
} -constraints {hasLinks} -body {
    set dir [file join dir2 foo bar]
    file mkdir $dir
    set to [file join dir2 .. dir2 foo .. foo bar]
    file link dir2.link $to
    testPathEqual [file normalize [file join dir2 foo x]] \
	    [file normalize [file join dir2.link .. x]]

} -result ok
test filesystem-1.29 {link normalisation: link with ..} -setup {
    file delete -force dir2.link
} -constraints {hasLinks} -body {
    set dir [file join dir2 foo bar]
    file mkdir $dir
    set to [file join dir2 .. dir2 foo .. foo bar]
    file link dir2.link $to
    set res [file normalize [file join dir2.link x yyy z]]
    if {[string match *..* $res]} {
	return "$res must not contain '..'"
    }
    return "ok"
} -result {ok}
test filesystem-1.29.1 {link normalisation with two consecutive links} {hasLinks} {
    testPathEqual [file normalize [file join dir.link dirinside.link abc]] \
	[file normalize [file join dir.dir dirinside.dir abc]]
} ok
file delete -force dir2.file
file delete -force dir2.link
file delete -force link.file dir.link
file delete -force dir2
file delete -force [file join dir.dir dirinside.link]
removeFile [file join dir.dir inside.file]
removeDirectory [file join dir.dir dirinside.dir]
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
	regexp {C:/bar$} $res res
    }
    set res
} {C:/bar}
if {[testConstraint testsetplatform]} {
    testsetplatform $platform
}
test filesystem-1.34 {file normalisation with '/./'} {
    set res [file normalize /foo/bar/anc/./.tml]
    if {[string first "/./" $res] != -1} {
	set res "normalization of /foo/bar/anc/./.tml is: $res"
    } else {
	set res "ok"
    }
    set res
} {ok}
test filesystem-1.35 {file normalisation with '/./'} {
    set res [file normalize /ffo/bar/anc/./foo/.tml]
    if {[string first "/./" $res] != -1 || ([regsub -all "foo" $res "" reg] == 2)} {


	set res "normalization of /ffo/bar/anc/./foo/.tml is: $res"
    } else {
	set res "ok"
    }
    set res
} {ok}
test filesystem-1.36 {file normalisation with '/./'} {
    set res [file normalize /foo/bar/anc/././asdasd/.tml]
    if {[string first "/./" $res] != -1 || ([regsub -all "asdasd" $res "" reg] == 2) } {


	set res "normalization of /foo/bar/anc/././asdasd/.tml is: $res"
    } else {
	set res "ok"
    }
    set res
} {ok}
test filesystem-1.37 {file normalisation with '/./'} {
    set fname "/abc/./def/./ghi/./asda/.././.././asd/x/../../../../....."
    set res [file norm $fname]
    if {[string first "//" $res] != -1} {
	set res "normalization of $fname is: $res"
    } else {
	set res "ok"
    }
    set res
} {ok}
test filesystem-1.38 {file normalisation with volume relative} \

  {win moreThanOneDrive} {
    set path "[string range [lindex $drives 0] 0 1]foo"
    set dir [pwd]
    cd [lindex $drives 1]
    set res [file norm $path]

    cd $dir
    set res
} "[lindex $drives 0]foo"
test filesystem-1.39 {file normalisation with volume relative} {win} {


    set drv C:/
    set dir [lindex [glob -type d -dir $drv *] 0]
    set old [pwd]
    cd $dir
    set res [file norm [string range $drv 0 1]]

    cd $old
    if {[string index $res end] eq "/"} {
        set res "Bad normalized path: $res"
    } else {
        set res "ok"
    }
} {ok}
test filesystem-1.40 {file normalisation with repeated separators} {
    set a [file norm foo////bar]
    set b [file norm foo/bar]
    if {![string equal $a $b]} {
        set res "Paths should be equal: $a , $b"
    } else {
        set res "ok"
    }
} {ok}
test filesystem-1.41 {file normalisation with repeated separators} {win} {
    set a [file norm foo\\\\\\bar]
    set b [file norm foo/bar]
    if {![string equal $a $b]} {
        set res "Paths should be equal: $a , $b"
    } else {
        set res "ok"
    }
} {ok}
test filesystem-1.42 {file normalisation .. beyond root (Bug 1379287)} {
    set a [file norm /xxx/..]
    set b [file norm /]
    if {![string equal $a $b]} {
        set res "Paths should be equal: $a , $b"
    } else {
        set res "ok"
    }
} {ok}
test filesystem-1.42.1 {file normalisation .. beyond root (Bug 1379287)} {
    set a [file norm /xxx/../]
    set b [file norm /]
    if {![string equal $a $b]} {
        set res "Paths should be equal: $a , $b"
    } else {
        set res "ok"
    }
} {ok}
test filesystem-1.43 {file normalisation .. beyond root (Bug 1379287)} {
    set a [file norm /xxx/foo/../..]
    set b [file norm /]
    if {![string equal $a $b]} {
        set res "Paths should be equal: $a , $b"
    } else {
        set res "ok"
    }
} {ok}
test filesystem-1.43.1 {file normalisation .. beyond root (Bug 1379287)} {
    set a [file norm /xxx/foo/../../]
    set b [file norm /]
    if {![string equal $a $b]} {
        set res "Paths should be equal: $a , $b"
    } else {
        set res "ok"
    }
} {ok}
test filesystem-1.44 {file normalisation .. beyond root (Bug 1379287)} {
    set a [file norm /xxx/foo/../../bar]
    set b [file norm /bar]
    if {![string equal $a $b]} {
        set res "Paths should be equal: $a , $b"
    } else {
        set res "ok"
    }
} {ok}
test filesystem-1.45 {file normalisation .. beyond root (Bug 1379287)} {
    set a [file norm /xxx/../../bar]
    set b [file norm /bar]
    if {![string equal $a $b]} {
        set res "Paths should be equal: $a , $b"
    } else {
        set res "ok"
    }
} {ok}
test filesystem-1.46 {file normalisation .. beyond root (Bug 1379287)} {
    set a [file norm /xxx/../bar]
    set b [file norm /bar]
    if {![string equal $a $b]} {
        set res "Paths should be equal: $a , $b"
    } else {
        set res "ok"
    }
} {ok}
test filesystem-1.47 {file normalisation .. beyond root (Bug 1379287)} {
    set a [file norm /..]
    set b [file norm /]
    if {![string equal $a $b]} {
        set res "Paths should be equal: $a , $b"
    } else {
        set res "ok"
    }
} {ok}
test filesystem-1.48 {file normalisation .. beyond root (Bug 1379287)} {
    set a [file norm /../]
    set b [file norm /]
    if {![string equal $a $b]} {
        set res "Paths should be equal: $a , $b"
    } else {
        set res "ok"
    }
} {ok}
test filesystem-1.49 {file normalisation .. beyond root (Bug 1379287)} {
    set a [file norm /.]
    set b [file norm /]
    if {![string equal $a $b]} {
        set res "Paths should be equal: $a , $b"
    } else {
        set res "ok"
    }
} {ok}
test filesystem-1.50 {file normalisation .. beyond root (Bug 1379287)} {
    set a [file norm /./]
    set b [file norm /]
    if {![string equal $a $b]} {
        set res "Paths should be equal: $a , $b"
    } else {
        set res "ok"
    }
} {ok}
test filesystem-1.51 {file normalisation .. beyond root (Bug 1379287)} {
    set a [file norm /../..]
    set b [file norm /]
    if {![string equal $a $b]} {
        set res "Paths should be equal: $a , $b"
    } else {
        set res "ok"
    }
} {ok}
test filesystem-1.51.1 {file normalisation .. beyond root (Bug 1379287)} {
    set a [file norm /../../]
    set b [file norm /]
    if {![string equal $a $b]} {
        set res "Paths should be equal: $a , $b"
    } else {
        set res "ok"
    }
} {ok}

test filesystem-2.0 {new native path} {unix} {
   foreach f [lsort [glob -nocomplain /usr/bin/c*]] {
       catch {file readlink $f}
   }
   # If we reach here we've succeeded. We used to crash above.
   expr 1
} {1}

# Make sure the testfilesystem hasn't been registered.
if {[testConstraint testfilesystem]} {
    while {![catch {testfilesystem 0}]} {}
}

test filesystem-3.1 {Tcl_FSRegister & Tcl_FSUnregister} testfilesystem {







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

|
<
<
<
<
<
|
<
|
>
|

<

|
>

<
|
|
>
>

|
<
<
|
>

<
<
<
|
<
<

|
<
<
<
<
<
|
<

|
<
<
<
<
<
|
<

|
<
<
<
<
<
|
<

|
<
<
<
<
<
|
<

|
<
<
<
<
<
|
<

|
<
<
<
<
<
|
<

|
<
<
<
<
<
|
<

|
<
<
<
<
<
|
<

|
<
<
<
<
<
|
<

|
<
<
<
<
<
|
<

|
<
<
<
<
<
|
<

|
<
<
<
<
<
|
<

|
<
<
<
<
<
|
<

|
<
<
<
<
<
|
<

|
<
<
<
<
<
|
<






|
|







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
	regexp {C:/bar$} $res res
    }
    set res
} {C:/bar}
if {[testConstraint testsetplatform]} {
    testsetplatform $platform
}
test filesystem-1.34 {file normalisation with '/./'} -body {
    file normalize /foo/bar/anc/./.tml





} -match regexp -result {^(?:(?!/\./).)*$}

test filesystem-1.35a {file normalisation with '/./'} -body {
    file normalize /ffo/bar/anc/./foo/.tml

} -match regexp -result {^(?:(?!/\./).)*$}
test filesystem-1.35b {file normalisation with '/./'} {
    llength [regexp -all foo [file normalize /ffo/bar/anc/./foo/.tml]]


} 1


test filesystem-1.36a {file normalisation with '/./'} -body {
    file normalize /foo/bar/anc/././asdasd/.tml

} -match regexp -result {^(?:(?!/\./).)*$}
test filesystem-1.36b {file normalisation with '/./'} {
    llength [regexp -all asdasd [file normalize /foo/bar/anc/././asdasd/.tml]]


} 1


test filesystem-1.37 {file normalisation with '/./'} -body {
    set fname "/abc/./def/./ghi/./asda/.././.././asd/x/../../../../....."
    file norm $fname





} -match regexp -result {^(?:[^/]|/(?:[^/]|$))+$}

test filesystem-1.38 {file normalisation with volume relative} -setup {
    set dir [pwd]
} -constraints {win moreThanOneDrive} -body {
    set path "[string range [lindex $drives 0] 0 1]foo"

    cd [lindex $drives 1]
    file norm $path
} -cleanup {
    cd $dir

} -result "[lindex $drives 0]foo"
test filesystem-1.39 {file normalisation with volume relative} -setup {
    set old [pwd]
} -constraints {win} -body {
    set drv C:/
    cd [lindex [glob -type d -dir $drv *] 0]


    file norm [string range $drv 0 1]
} -cleanup {
    cd $old



} -match glob -result {*[^/]}


test filesystem-1.40 {file normalisation with repeated separators} {
    testPathEqual [file norm foo////bar] [file norm foo/bar]





} ok

test filesystem-1.41 {file normalisation with repeated separators} {win} {
    testPathEqual [file norm foo\\\\\\bar] [file norm foo/bar]





} ok

test filesystem-1.42 {file normalisation .. beyond root (Bug 1379287)} {
    testPathEqual [file norm /xxx/..] [file norm /]





} ok

test filesystem-1.42.1 {file normalisation .. beyond root (Bug 1379287)} {
    testPathEqual [file norm /xxx/../] [file norm /]





} ok

test filesystem-1.43 {file normalisation .. beyond root (Bug 1379287)} {
    testPathEqual [file norm /xxx/foo/../..] [file norm /]





} ok

test filesystem-1.43.1 {file normalisation .. beyond root (Bug 1379287)} {
    testPathEqual [file norm /xxx/foo/../../] [file norm /]





} ok

test filesystem-1.44 {file normalisation .. beyond root (Bug 1379287)} {
    testPathEqual [file norm /xxx/foo/../../bar] [file norm /bar]





} ok

test filesystem-1.45 {file normalisation .. beyond root (Bug 1379287)} {
    testPathEqual [file norm /xxx/../../bar] [file norm /bar]





} ok

test filesystem-1.46 {file normalisation .. beyond root (Bug 1379287)} {
    testPathEqual [file norm /xxx/../bar] [file norm /bar]





} ok

test filesystem-1.47 {file normalisation .. beyond root (Bug 1379287)} {
    testPathEqual [file norm /..] [file norm /]





} ok

test filesystem-1.48 {file normalisation .. beyond root (Bug 1379287)} {
    testPathEqual [file norm /../] [file norm /]





} ok

test filesystem-1.49 {file normalisation .. beyond root (Bug 1379287)} {
    testPathEqual [file norm /.] [file norm /]





} ok

test filesystem-1.50 {file normalisation .. beyond root (Bug 1379287)} {
    testPathEqual [file norm /./] [file norm /]





} ok

test filesystem-1.51 {file normalisation .. beyond root (Bug 1379287)} {
    testPathEqual [file norm /../..] [file norm /]





} ok

test filesystem-1.51.1 {file normalisation .. beyond root (Bug 1379287)} {
    testPathEqual [file norm /../../] [file norm /]





} ok


test filesystem-2.0 {new native path} {unix} {
   foreach f [lsort [glob -nocomplain /usr/bin/c*]] {
       catch {file readlink $f}
   }
   # If we reach here we've succeeded. We used to crash above.
   return ok
} ok

# Make sure the testfilesystem hasn't been registered.
if {[testConstraint testfilesystem]} {
    while {![catch {testfilesystem 0}]} {}
}

test filesystem-3.1 {Tcl_FSRegister & Tcl_FSUnregister} testfilesystem {
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
} {native}

test filesystem-4.0 {testfilesystem} -constraints testfilesystem -body {
    testfilesystem 1
    set filesystemReport {}
    file exists foo
    testfilesystem 0
    set filesystemReport
} -match glob -result {*{access foo}}
test filesystem-4.1 {testfilesystem} -constraints testfilesystem -body {
    testfilesystem 1
    set filesystemReport {}
    catch {file stat foo bar}
    testfilesystem 0
    set filesystemReport
} -match glob -result {*{stat foo}}
test filesystem-4.2 {testfilesystem} -constraints testfilesystem -body {
    testfilesystem 1
    set filesystemReport {}
    catch {file lstat foo bar}
    testfilesystem 0
    set filesystemReport
} -match glob -result {*{lstat foo}}
test filesystem-4.3 {testfilesystem} -constraints testfilesystem -body {
    testfilesystem 1
    set filesystemReport {}
    catch {glob *}
    testfilesystem 0
    set filesystemReport
} -match glob -result {*{matchindirectory *}*}

test filesystem-5.1 {cache and ~} -constraints testfilesystem -setup {
    set orig $::env(HOME)
} -body {
    set ::env(HOME) /foo/bar/blah
    set testdir ~







|






|






|






|







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
} {native}

test filesystem-4.0 {testfilesystem} -constraints testfilesystem -body {
    testfilesystem 1
    set filesystemReport {}
    file exists foo
    testfilesystem 0
    return $filesystemReport
} -match glob -result {*{access foo}}
test filesystem-4.1 {testfilesystem} -constraints testfilesystem -body {
    testfilesystem 1
    set filesystemReport {}
    catch {file stat foo bar}
    testfilesystem 0
    return $filesystemReport
} -match glob -result {*{stat foo}}
test filesystem-4.2 {testfilesystem} -constraints testfilesystem -body {
    testfilesystem 1
    set filesystemReport {}
    catch {file lstat foo bar}
    testfilesystem 0
    return $filesystemReport
} -match glob -result {*{lstat foo}}
test filesystem-4.3 {testfilesystem} -constraints testfilesystem -body {
    testfilesystem 1
    set filesystemReport {}
    catch {glob *}
    testfilesystem 0
    return $filesystemReport
} -match glob -result {*{matchindirectory *}*}

test filesystem-5.1 {cache and ~} -constraints testfilesystem -setup {
    set orig $::env(HOME)
} -body {
    set ::env(HOME) /foo/bar/blah
    set testdir ~
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
    file delete -force tilde
    cd $origdir
} -result {0 0 0 0 1}

# ----------------------------------------------------------------------

cleanupTests
unset -nocomplain drive
}
namespace delete ::tcl::test::fileSystem
return

# Local Variables:
# mode: tcl
# End:







|







917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
    file delete -force tilde
    cd $origdir
} -result {0 0 0 0 1}

# ----------------------------------------------------------------------

cleanupTests
unset -nocomplain drive drives
}
namespace delete ::tcl::test::fileSystem
return

# Local Variables:
# mode: tcl
# End:

Changes to tests/http.test.

47
48
49
50
51
52
53

54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
if {![file exists $httpdFile]} {
    makeFile "" $httpdFile
    file delete $httpdFile
    file copy $origFile $httpdFile
    set removeHttpd 1
}


if {[info commands testthread] == "testthread" && [file exists $httpdFile]} {
    set httpthread [testthread create "
	source [list $httpdFile]
	testthread wait
    "]
    testthread send $httpthread [list set port $port]
    testthread send $httpthread [list set bindata $bindata]
    testthread send $httpthread {httpd_init $port}
    puts "Running httpd in thread $httpthread"
} else {
    if {![file exists $httpdFile]} {
	puts "Cannot read $httpdFile script, http test skipped"
	unset port
	return
    }







>
|
|
|
<
<
|
|
|







47
48
49
50
51
52
53
54
55
56
57


58
59
60
61
62
63
64
65
66
67
if {![file exists $httpdFile]} {
    makeFile "" $httpdFile
    file delete $httpdFile
    file copy $origFile $httpdFile
    set removeHttpd 1
}

catch {package require Thread 2.6}
if {[catch {package present Thread}] == 0 && [file exists $httpdFile]} {
    set httpthread [thread::create -preserved]
    thread::send $httpthread [list source $httpdFile]


    thread::send $httpthread [list set port $port]
    thread::send $httpthread [list set bindata $bindata]
    thread::send $httpthread {httpd_init $port}
    puts "Running httpd in thread $httpthread"
} else {
    if {![file exists $httpdFile]} {
	puts "Cannot read $httpdFile script, http test skipped"
	unset port
	return
    }
361
362
363
364
365
366
367


























368
369
370
371
372
373
374
    set token [http::geturl $url -headers {X-Check 1} -timeout 2000]
    array set m [http::meta $token]
    lsort [array names m]
} -cleanup {
    http::cleanup $token
    unset -nocomplain m token
} -result {Content-Length Content-Type Date X-Check}



























test http-4.1 {http::Event} -body {
    set token [http::geturl $url -keepalive 0]
    upvar #0 $token data
    array set meta $data(meta)
    expr {($data(totalsize) == $meta(Content-Length))}
} -cleanup {







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







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
    set token [http::geturl $url -headers {X-Check 1} -timeout 2000]
    array set m [http::meta $token]
    lsort [array names m]
} -cleanup {
    http::cleanup $token
    unset -nocomplain m token
} -result {Content-Length Content-Type Date X-Check}
test http-3.27 {http::geturl: -headers override -type} -body {
    set token [http::geturl $url/headers -type "text/plain" -query dummy \
	    -headers [list "Content-Type" "text/plain;charset=utf-8"]]
    http::data $token
} -cleanup {
    http::cleanup $token
} -match regexp -result {(?n)Accept \*/\*
Host .*
User-Agent .*
Connection close
Content-Type {text/plain;charset=utf-8}
Accept-Encoding .*
Content-Length 5}
test http-3.28 {http::geturl: -headers override -type default} -body {
    set token [http::geturl $url/headers -query dummy \
	    -headers [list "Content-Type" "text/plain;charset=utf-8"]]
    http::data $token
} -cleanup {
    http::cleanup $token
} -match regexp -result {(?n)Accept \*/\*
Host .*
User-Agent .*
Connection close
Content-Type {text/plain;charset=utf-8}
Accept-Encoding .*
Content-Length 5}

test http-4.1 {http::Event} -body {
    set token [http::geturl $url -keepalive 0]
    upvar #0 $token data
    array set meta $data(meta)
    expr {($data(totalsize) == $meta(Content-Length))}
} -cleanup {
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602

# cleanup
catch {unset url}
catch {unset badurl}
catch {unset port}
catch {unset data}
if {[info exists httpthread]} {
    testthread send -async $httpthread {
	testthread exit
    }
} else {
    close $listen
}

if {[info exists removeHttpd]} {
    removeFile $httpdFile
}







|
<
<







611
612
613
614
615
616
617
618


619
620
621
622
623
624
625

# cleanup
catch {unset url}
catch {unset badurl}
catch {unset port}
catch {unset data}
if {[info exists httpthread]} {
    thread::release $httpthread


} else {
    close $listen
}

if {[info exists removeHttpd]} {
    removeFile $httpdFile
}

Changes to tests/httpd.

171
172
173
174
175
176
177








178
179
180
181
182
183
184
	    set html "$bindata[info hostname]:$port$data(url)"
	    set type application/octet-stream
	}
	*post* {
	    set html "Got [string length $data(query)] bytes"
	    set type text/plain
	}








	default {
	    set type text/html

	    set html "<html><head><title>HTTP/1.0 TEST</title></head><body>
<h1>Hello, World!</h1>
<h2>$data(proto) $data(url)</h2>
"







>
>
>
>
>
>
>
>







171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
	    set html "$bindata[info hostname]:$port$data(url)"
	    set type application/octet-stream
	}
	*post* {
	    set html "Got [string length $data(query)] bytes"
	    set type text/plain
	}
	*headers* {
	    set html ""
	    set type text/plain
	    foreach {key value} $data(meta) {
		append html [list $key $value] "\n"
	    }
	    set html [string trim $html]
	}
	default {
	    set type text/html

	    set html "<html><head><title>HTTP/1.0 TEST</title></head><body>
<h1>Hello, World!</h1>
<h2>$data(proto) $data(url)</h2>
"

Changes to tests/indexObj.test.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

17
18
19
20
21
22
23
24
# This file is a Tcl script to test out the the procedures in file
# tkIndexObj.c, which implement indexed table lookups.  The tests here
# are organized in the standard fashion for Tcl tests.
#
# Copyright (c) 1997 Sun Microsystems, Inc.
# Copyright (c) 1998-1999 by Scriptics Corporation.
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import -force ::tcltest::*
}

testConstraint testindexobj [llength [info commands testindexobj]]


test indexObj-1.1 {exact match} testindexobj {
    testindexobj 1 1 xyz abc def xyz alm
} {2}
test indexObj-1.2 {exact match} testindexobj {
    testindexobj 1 1 abc abc def xyz alm
} {0}
test indexObj-1.3 {exact match} testindexobj {

|
|




|
|


|




>
|







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
# This file is a Tcl script to test out the the procedures in file
# tkIndexObj.c, which implement indexed table lookups.  The tests here are
# organized in the standard fashion for Tcl tests.
#
# Copyright (c) 1997 Sun Microsystems, Inc.
# Copyright (c) 1998-1999 by Scriptics Corporation.
#
# See the file "license.terms" for information on usage and redistribution of
# this file, and for a DISCLAIMER OF ALL WARRANTIES.

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest 2
    namespace import -force ::tcltest::*
}

testConstraint testindexobj [llength [info commands testindexobj]]
testConstraint testparseargs [llength [info commands testparseargs]]

test indexObj-1.1 {exact match} testindexobj {
    testindexobj 1 1 xyz abc def xyz alm
} {2}
test indexObj-1.2 {exact match} testindexobj {
    testindexobj 1 1 abc abc def xyz alm
} {0}
test indexObj-1.3 {exact match} testindexobj {
124
125
126
127
128
129
130

























131
132
133
134
135
136
137
} "wrong # args: should be \"testgetindexfromobjstruct c 1\""
test indexObj-6.4 {Tcl_GetIndexFromObjStruct} testindexobj {
    set x c
    testgetindexfromobjstruct $x 1
    testgetindexfromobjstruct $x 1
} "wrong # args: should be \"testgetindexfromobjstruct c 1\""


























# cleanup
::tcltest::cleanupTests
return

# Local Variables:
# mode: tcl
# End:







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







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
} "wrong # args: should be \"testgetindexfromobjstruct c 1\""
test indexObj-6.4 {Tcl_GetIndexFromObjStruct} testindexobj {
    set x c
    testgetindexfromobjstruct $x 1
    testgetindexfromobjstruct $x 1
} "wrong # args: should be \"testgetindexfromobjstruct c 1\""

test indexObj-7.1 {Tcl_ParseArgsObjv} testparseargs {
    testparseargs
} {0 1 testparseargs}
test indexObj-7.2 {Tcl_ParseArgsObjv} testparseargs {
    testparseargs -bool
} {1 1 testparseargs}
test indexObj-7.3 {Tcl_ParseArgsObjv} testparseargs {
    testparseargs -bool bar
} {1 2 {testparseargs bar}}
test indexObj-7.4 {Tcl_ParseArgsObjv} testparseargs {
    testparseargs bar
} {0 2 {testparseargs bar}}
test indexObj-7.5 {Tcl_ParseArgsObjv} -constraints testparseargs -body {
    testparseargs -help
} -returnCodes error -result {Command-specific options:
 -bool: booltest
 --:    Marks the end of the options
 -help: Print summary of command-line options and abort}
test indexObj-7.6 {Tcl_ParseArgsObjv} testparseargs {
    testparseargs -- -bool -help
} {0 3 {testparseargs -bool -help}}
test indexObj-7.7 {Tcl_ParseArgsObjv memory management} testparseargs {
    testparseargs 1 2 3 4 5 6 7 8 9 0 -bool 1 2 3 4 5 6 7 8 9 0
} {1 21 {testparseargs 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0}}

# cleanup
::tcltest::cleanupTests
return

# Local Variables:
# mode: tcl
# End:

Changes to tests/info.test.

211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
} -result {procedure "t1" doesn't have an argument "x"}
test info-6.9 {info default option} -returnCodes error -setup {
    catch {unset a}
} -cleanup {unset a} -body {
    set a(0) 88
    proc t1 {a b} {}
    info default t1 a a
} -returnCodes error -result {couldn't store default value in variable "a"}
test info-6.10 {info default option} -setup {
    catch {unset a}
} -cleanup {unset a} -body {
    set a(0) 88
    proc t1 {{a 18} b} {}
    info default t1 a a
} -returnCodes error -result {couldn't store default value in variable "a"}
test info-6.11 {info default option} {
    catch {namespace delete test_ns_info2}
    namespace eval test_ns_info2 {
        namespace import ::test_ns_info1::*
        list [info default p x foo] $foo [info default q y bar] $bar
    }
} {0 {} 1 27}







|






|







211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
} -result {procedure "t1" doesn't have an argument "x"}
test info-6.9 {info default option} -returnCodes error -setup {
    catch {unset a}
} -cleanup {unset a} -body {
    set a(0) 88
    proc t1 {a b} {}
    info default t1 a a
} -returnCodes error -result {can't set "a": variable is array}
test info-6.10 {info default option} -setup {
    catch {unset a}
} -cleanup {unset a} -body {
    set a(0) 88
    proc t1 {{a 18} b} {}
    info default t1 a a
} -returnCodes error -result {can't set "a": variable is array}
test info-6.11 {info default option} {
    catch {namespace delete test_ns_info2}
    namespace eval test_ns_info2 {
        namespace import ::test_ns_info1::*
        list [info default p x foo] $foo [info default q y bar] $bar
    }
} {0 {} 1 27}
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
test info-30.46 {TIP 280 for compiled [subst]} {
    unset -nocomplain a
    set a(1825) YES;  set a(1824) 1824; set a(1826) 1826
    subst {$a([dict get [info frame 0] line])} ; # 1825
} YES
test info-30.47 {TIP 280 for compiled [subst]} {
    unset -nocomplain a
    set a(\n1831) YES;  set a(\n1830) 1830; set a(\n1832) 1832 
    subst {$a(
[dict get [info frame 0] line])} ; # 1831
} YES
unset -nocomplain a

test info-30.48 {Bug 2850901} testevalex {
    testevalex {return -level 0 [format %s {}







|







1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
test info-30.46 {TIP 280 for compiled [subst]} {
    unset -nocomplain a
    set a(1825) YES;  set a(1824) 1824; set a(1826) 1826
    subst {$a([dict get [info frame 0] line])} ; # 1825
} YES
test info-30.47 {TIP 280 for compiled [subst]} {
    unset -nocomplain a
    set a(\n1831) YES;  set a(\n1830) 1830; set a(\n1832) 1832
    subst {$a(
[dict get [info frame 0] line])} ; # 1831
} YES
unset -nocomplain a

test info-30.48 {Bug 2850901} testevalex {
    testevalex {return -level 0 [format %s {}

Changes to tests/init.test.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# Functionality covered: this file contains a collection of tests for the auto
# loading and namespaces.
#
# Sourcing this file into Tcl runs the tests and generates output for errors.
# No output means no errors were found.
#
# Copyright (c) 1997 Sun Microsystems, Inc.
# Copyright (c) 1998-1999 by Scriptics Corporation.
#
# See the file "license.terms" for information on usage and redistribution of
# this file, and for a DISCLAIMER OF ALL WARRANTIES.

if {"::tcltest" ni [namespace children]} {
    package require tcltest 2
    namespace import -force ::tcltest::*
}

# Clear out any namespaces called test_ns_*
catch {namespace delete {*}[namespace children :: test_ns_*]}

# Six cases - white box testing













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# Functionality covered: this file contains a collection of tests for the auto
# loading and namespaces.
#
# Sourcing this file into Tcl runs the tests and generates output for errors.
# No output means no errors were found.
#
# Copyright (c) 1997 Sun Microsystems, Inc.
# Copyright (c) 1998-1999 by Scriptics Corporation.
#
# See the file "license.terms" for information on usage and redistribution of
# this file, and for a DISCLAIMER OF ALL WARRANTIES.

if {"::tcltest" ni [namespace children]} {
    package require tcltest 2.3.3
    namespace import -force ::tcltest::*
}

# Clear out any namespaces called test_ns_*
catch {namespace delete {*}[namespace children :: test_ns_*]}

# Six cases - white box testing

Changes to tests/interp.test.

13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
if {"::tcltest" ni [namespace children]} {
    package require tcltest 2.1
    namespace import -force ::tcltest::*
}

testConstraint testinterpdelete [llength [info commands testinterpdelete]]

set hidden_cmds {cd encoding exec exit fconfigure glob load open pwd socket source tcl:file:atime tcl:file:attributes tcl:file:copy tcl:file:delete tcl:file:dirname tcl:file:executable tcl:file:exists tcl:file:extension tcl:file:isdirectory tcl:file:isfile tcl:file:link tcl:file:lstat tcl:file:mkdir tcl:file:mtime tcl:file:nativename tcl:file:normalize tcl:file:owned tcl:file:readable tcl:file:readlink tcl:file:rename tcl:file:rootname tcl:file:size tcl:file:stat tcl:file:tail tcl:file:tempfile tcl:file:type tcl:file:volumes tcl:file:writable unload}

foreach i [interp slaves] {
  interp delete $i
}

# Part 0: Check out options for interp command
test interp-1.1 {options for interp command} -returnCodes error -body {







|







13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
if {"::tcltest" ni [namespace children]} {
    package require tcltest 2.1
    namespace import -force ::tcltest::*
}

testConstraint testinterpdelete [llength [info commands testinterpdelete]]

set hidden_cmds {cd encoding exec exit fconfigure file glob load open pwd socket source tcl:file:atime tcl:file:attributes tcl:file:copy tcl:file:delete tcl:file:dirname tcl:file:executable tcl:file:exists tcl:file:extension tcl:file:isdirectory tcl:file:isfile tcl:file:link tcl:file:lstat tcl:file:mkdir tcl:file:mtime tcl:file:nativename tcl:file:normalize tcl:file:owned tcl:file:readable tcl:file:readlink tcl:file:rename tcl:file:rootname tcl:file:size tcl:file:stat tcl:file:tail tcl:file:tempfile tcl:file:type tcl:file:volumes tcl:file:writable unload}

foreach i [interp slaves] {
  interp delete $i
}

# Part 0: Check out options for interp command
test interp-1.1 {options for interp command} -returnCodes error -body {
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
} -cleanup {
    rename setx {}
    interp delete a
} -result {x
    invoked from within
"a 1"}


# part 15: testing file sharing
test interp-15.1 {testing file sharing} {
    catch {interp delete z}
    interp create z
    z eval close stdout
    list [catch {z eval puts hello} msg] $msg
} {1 {can not find channel named "stdout"}}







<







580
581
582
583
584
585
586

587
588
589
590
591
592
593
} -cleanup {
    rename setx {}
    interp delete a
} -result {x
    invoked from within
"a 1"}


# part 15: testing file sharing
test interp-15.1 {testing file sharing} {
    catch {interp delete z}
    interp create z
    z eval close stdout
    list [catch {z eval puts hello} msg] $msg
} {1 {can not find channel named "stdout"}}
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
    removeFile file-15.8
} -result 0

#
# Torture tests for interpreter deletion order
#
proc kill {} {interp delete xxx}

test interp-15.9 {testing deletion order} {
    catch {interp delete xxx}
    interp create xxx
    xxx alias kill kill
    list [catch {xxx eval kill} msg] $msg
} {0 {}}
test interp-16.1 {testing deletion order} {
    catch {interp delete xxx}







<
|







660
661
662
663
664
665
666

667
668
669
670
671
672
673
674
    removeFile file-15.8
} -result 0

#
# Torture tests for interpreter deletion order
#
proc kill {} {interp delete xxx}

test interp-16.0 {testing deletion order} {
    catch {interp delete xxx}
    interp create xxx
    xxx alias kill kill
    list [catch {xxx eval kill} msg] $msg
} {0 {}}
test interp-16.1 {testing deletion order} {
    catch {interp delete xxx}
3493
3494
3495
3496
3497
3498
3499







3500
3501
3502
3503
3504
3505
3506
test interp-35.22 {interp time limits normalize milliseconds} -body {
    set i [interp create]
    interp limit $i time -seconds 1 -millis 1500
    list [$i limit time -seconds] [$i limit time -millis]
} -cleanup {
    interp delete $i
} -result {2 500}








test interp-36.1 {interp bgerror syntax} -body {
    interp bgerror
} -returnCodes error -result {wrong # args: should be "interp bgerror path ?cmdPrefix?"}
test interp-36.2 {interp bgerror syntax} -body { 
    interp bgerror x y z
} -returnCodes error -result {wrong # args: should be "interp bgerror path ?cmdPrefix?"}







>
>
>
>
>
>
>







3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
test interp-35.22 {interp time limits normalize milliseconds} -body {
    set i [interp create]
    interp limit $i time -seconds 1 -millis 1500
    list [$i limit time -seconds] [$i limit time -millis]
} -cleanup {
    interp delete $i
} -result {2 500}
# Bug 3398794
test interp-35.23 {interp command limits can't touch current interp} -body {
    interp limit {} commands -value 10
} -returnCodes error -result {limits on current interpreter inaccessible}
test interp-35.24 {interp time limits can't touch current interp} -body {
    interp limit {} time -seconds 2
} -returnCodes error -result {limits on current interpreter inaccessible}

test interp-36.1 {interp bgerror syntax} -body {
    interp bgerror
} -returnCodes error -result {wrong # args: should be "interp bgerror path ?cmdPrefix?"}
test interp-36.2 {interp bgerror syntax} -body { 
    interp bgerror x y z
} -returnCodes error -result {wrong # args: should be "interp bgerror path ?cmdPrefix?"}
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
    interp debug {} -frames
} -returnCodes error -result {bad debug option "-frames": must be -frame}
test interp-38.8 {interp debug basic setup} -body {
    interp debug {} -frame 0 bogus
} -returnCodes {
    error
} -result {wrong # args: should be "interp debug path ?-frame ?bool??"}


# cleanup
unset -nocomplain hidden_cmds
foreach i [interp slaves] {
    interp delete $i
}
::tcltest::cleanupTests
return

# Local Variables:
# mode: tcl
# fill-column: 78
# End:







<













3611
3612
3613
3614
3615
3616
3617

3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
    interp debug {} -frames
} -returnCodes error -result {bad debug option "-frames": must be -frame}
test interp-38.8 {interp debug basic setup} -body {
    interp debug {} -frame 0 bogus
} -returnCodes {
    error
} -result {wrong # args: should be "interp debug path ?-frame ?bool??"}


# cleanup
unset -nocomplain hidden_cmds
foreach i [interp slaves] {
    interp delete $i
}
::tcltest::cleanupTests
return

# Local Variables:
# mode: tcl
# fill-column: 78
# End:

Changes to tests/io.test.

33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
testConstraint exec             [llength [info commands exec]]
testConstraint openpipe         1
testConstraint fileevent        [llength [info commands fileevent]]
testConstraint fcopy            [llength [info commands fcopy]]
testConstraint testfevent       [llength [info commands testfevent]]
testConstraint testchannelevent [llength [info commands testchannelevent]]
testConstraint testmainthread   [llength [info commands testmainthread]]
testConstraint testthread       [llength [info commands testthread]]

# You need a *very* special environment to do some tests.  In
# particular, many file systems do not support large-files...
testConstraint largefileSupport 0

# some tests can only be run is umask is 2
# if "umask" cannot be run, the tests will be skipped.







|







33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
testConstraint exec             [llength [info commands exec]]
testConstraint openpipe         1
testConstraint fileevent        [llength [info commands fileevent]]
testConstraint fcopy            [llength [info commands fcopy]]
testConstraint testfevent       [llength [info commands testfevent]]
testConstraint testchannelevent [llength [info commands testchannelevent]]
testConstraint testmainthread   [llength [info commands testmainthread]]
testConstraint thread [expr {0 == [catch {package require Thread 2.6}]}]

# You need a *very* special environment to do some tests.  In
# particular, many file systems do not support large-files...
testConstraint largefileSupport 0

# some tests can only be run is umask is 2
# if "umask" cannot be run, the tests will be skipped.
7431
7432
7433
7434
7435
7436
7437
7438
7439
7440
7441
7442
7443
7444
7445
} {1 {gets {normal message from pipe} gets {} catch {error message from pipe}}}

test io-59.1 {Thread reference of channels} {testmainthread testchannel} {
    # TIP #10
    # More complicated tests (like that the reference changes as a
    # channel is moved from thread to thread) can be done only in the
    # extension which fully implements the moving of channels between
    # threads, i.e. 'Threads'. Or we have to extend [testthread] as well.

    set f [open $path(longfile) r]
    set result [testchannel mthread $f]
    close $f
    string equal $result [testmainthread]
} {1}








|







7431
7432
7433
7434
7435
7436
7437
7438
7439
7440
7441
7442
7443
7444
7445
} {1 {gets {normal message from pipe} gets {} catch {error message from pipe}}}

test io-59.1 {Thread reference of channels} {testmainthread testchannel} {
    # TIP #10
    # More complicated tests (like that the reference changes as a
    # channel is moved from thread to thread) can be done only in the
    # extension which fully implements the moving of channels between
    # threads, i.e. 'Threads'.

    set f [open $path(longfile) r]
    set result [testchannel mthread $f]
    close $f
    string equal $result [testmainthread]
} {1}

7523
7524
7525
7526
7527
7528
7529
7530
7531
7532
7533
7534
7535
7536
7537
7538
7539
7540
7541
7542
7543
7544
7545
7546
7547
7548
7549
7550
7551
7552
7553
7554
7555
7556
7557
7558

7559
7560
7561
7562
7563
7564
7565
7566
7567
7568
7569
7570
7571
7572
7573

    removeFile cutsplice

    set res
} {0 1 0}


# Duplicate of code in "thread.test". Find a better way of doing this
# without duplication. Maybe placement into a proc which transforms to
# nop after the first call, and placement of its defintion in a
# central location.

if {[testConstraint testthread]} {
    testthread errorproc ThreadError

    proc ThreadError {id info} {
	global threadError
	set threadError $info
    }

    proc ThreadNullError {id info} {
	# ignore
    }
}

test io-70.1 {Transfer channel} {testchannel testthread} {
    set f [makeFile {... dummy ...} cutsplice]
    set c [open $f r]

    set     res {}
    lappend res [catch {seek $c 0 start}]
    testchannel cut $c
    lappend res [catch {seek $c 0 start}]

    set tid [testthread create]
    testthread send $tid [list set c $c]

    lappend res [testthread send $tid {
	testchannel splice $c
	set res [catch {seek $c 0 start}]
	close $c
	set res
    }]

    tcltest::threadReap
    removeFile cutsplice

    set res
} {0 1 0}

# ### ### ### ######### ######### #########








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








|
|
>
|






|







7523
7524
7525
7526
7527
7528
7529


















7530
7531
7532
7533
7534
7535
7536
7537
7538
7539
7540
7541
7542
7543
7544
7545
7546
7547
7548
7549
7550
7551
7552
7553
7554
7555
7556

    removeFile cutsplice

    set res
} {0 1 0}




















test io-70.1 {Transfer channel} {testchannel thread} {
    set f [makeFile {... dummy ...} cutsplice]
    set c [open $f r]

    set     res {}
    lappend res [catch {seek $c 0 start}]
    testchannel cut $c
    lappend res [catch {seek $c 0 start}]

    set tid [thread::create -preserved]
    thread::send $tid [list set c $c]
    thread::send $tid {load {} Tcltest}
    lappend res [thread::send $tid {
	testchannel splice $c
	set res [catch {seek $c 0 start}]
	close $c
	set res
    }]

    thread::release $tid
    removeFile cutsplice

    set res
} {0 1 0}

# ### ### ### ######### ######### #########

Changes to tests/ioCmd.test.

17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
    package require tcltest 2
    namespace import -force ::tcltest::*
}

# Custom constraints used in this file
testConstraint fcopy		[llength [info commands fcopy]]
testConstraint testchannel	[llength [info commands testchannel]]
testConstraint testthread	[llength [info commands testthread]]

#----------------------------------------------------------------------

test iocmd-1.1 {puts command} {
   list [catch {puts} msg] $msg
} {1 {wrong # args: should be "puts ?-nonewline? ?channelId? string"}}
test iocmd-1.2 {puts command} {







|







17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
    package require tcltest 2
    namespace import -force ::tcltest::*
}

# Custom constraints used in this file
testConstraint fcopy		[llength [info commands fcopy]]
testConstraint testchannel	[llength [info commands testchannel]]
testConstraint thread [expr {0 == [catch {package require Thread 2.6}]}]

#----------------------------------------------------------------------

test iocmd-1.1 {puts command} {
   list [catch {puts} msg] $msg
} {1 {wrong # args: should be "puts ?-nonewline? ?channelId? string"}}
test iocmd-1.2 {puts command} {
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
    interp eval $ida [list testchannel cut    $chan]
    interp eval $idb [list testchannel splice $chan]

    # Run access from interpreter B, this will give us a synchronous
    # response.

    interp eval $idb [list set chan $chan]
    interp eval $idb [list set mid $tcltest::mainThread]
    set res [interp eval $idb {
	# wait a bit, give the main thread the time to start its event
	# loop to wait for the response from B
	after 2000
	catch { puts $chan shoo } res
	set res
    }]







<







1987
1988
1989
1990
1991
1992
1993

1994
1995
1996
1997
1998
1999
2000
    interp eval $ida [list testchannel cut    $chan]
    interp eval $idb [list testchannel splice $chan]

    # Run access from interpreter B, this will give us a synchronous
    # response.

    interp eval $idb [list set chan $chan]

    set res [interp eval $idb {
	# wait a bit, give the main thread the time to start its event
	# loop to wait for the response from B
	after 2000
	catch { puts $chan shoo } res
	set res
    }]
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
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
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
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
2581
2582
2583
2584
2585
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
2617
2618
2619
2620
2621
2622
2623
2624
2625
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
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
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
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
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497


3498

3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529













3530
3531
3532
3533

3534

3535
3536
3537
3538
3539
3540
3541
3542
3543

3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567

3568
3569
3570
3571
3572
3573
3574
3575
3576
3577
# ### ### ### ######### ######### #########
## Testing the reflected channel (Thread forwarding).
#
## The id numbers refer to the original test without thread
## forwarding, and gaps due to tests not applicable to forwarding are
## left to keep this asociation.

# Duplicate of code in "thread.test". Find a better way of doing this
# without duplication. Maybe placement into a proc which transforms to
# nop after the first call, and placement of its defintion in a
# central location.

if {[testConstraint testthread]} {
    testthread errorproc ThreadError

    proc ThreadError {id info} {
	global threadError
	set threadError $info
    }
    proc ThreadNullError {id info} {
	# ignore
    }
}

# ### ### ### ######### ######### #########
## Helper command. Runs a script in a separate thread and returns the
## result. A channel is transfered into the thread as well, and list of
## configuation variables

proc inthread {chan script args} {
    # Test thread.

    set tid [testthread create]


    # Init thread configuration.
    # - Listed variables
    # - Id of main thread
    # - A number of helper commands

    foreach v $args {
	upvar 1 $v x
	testthread send $tid [list set $v $x]
    }

    testthread send $tid [list set mid $tcltest::mainThread]
    testthread send $tid {
	proc note {item} {global notes; lappend notes $item}
	proc notes {} {global notes; return $notes}
	proc noteOpts opts {global notes; lappend notes [dict merge {
	    -code !?! -level !?! -errorcode !?! -errorline !?! -errorinfo !?!
	} $opts]}
    }
    testthread send $tid [list proc s {} [list uplevel 1 $script]]; # (*)

    # Transfer channel (cut/splice aka detach/attach)

    testchannel cut $chan
    testthread send $tid [list testchannel splice $chan]

    # Run test script, also run local event loop!
    # The local event loop waits for the result to come back.
    # It is also necessary for the execution of forwarded channel
    # operations.

    set ::tres ""
    testthread send -async $tid {
	after 500
	catch {s} res; # This runs the script, 's' was defined at (*)
	testthread send -async $mid [list set ::tres $res]
    }
    vwait ::tres
    # Remove test thread, and return the captured result.

    tcltest::threadReap
    return $::tres
}

# ### ### ### ######### ######### #########

# ### ### ### ######### ######### #########

test iocmd.tf-22.2 {chan finalize, for close} -match glob -body {
    set res {}
    proc foo {args} {track; oninit; return {}}
    note [set c [chan create {r w} foo]]
    note [inthread $c {
	close $c
	# Close the deleted the channel.
	file channels rc*
    } c]
    # Channel destruction does not kill handler command!
    note [info command foo]
    rename foo {}
    set res
} -constraints {testchannel testthread} -result {{initialize rc* {read write}} rc* {finalize rc*} {} foo}
test iocmd.tf-22.3 {chan finalize, for close, error, close error} -match glob -body {
    set res {}
    proc foo {args} {track; oninit; return -code error 5}
    note [set c [chan create {r w} foo]]
    notes [inthread $c {
	note [catch {close $c} msg]; note $msg
	# Channel is gone despite error.
	note [file channels rc*]
	notes
    } c]
    rename foo {}
    set res
} -constraints {testchannel testthread} -result {{initialize rc* {read write}} rc* {finalize rc*} 1 5 {}}
test iocmd.tf-22.4 {chan finalize, for close, error, close errror} -match glob -body {
    set res {}
    proc foo {args} {track; oninit; error FOO}
    note [set c [chan create {r w} foo]]
    notes [inthread $c {
	note [catch {close $c} msg]; note $msg
	notes
    } c]
    rename foo {}
    set res
} -constraints {testchannel testthread} -result {{initialize rc* {read write}} rc* {finalize rc*} 1 FOO}
test iocmd.tf-22.5 {chan finalize, for close, arbitrary result} -match glob -body {
    set res {}
    proc foo {args} {track; oninit; return SOMETHING}
    note [set c [chan create {r w} foo]]
    notes [inthread $c {
	note [catch {close $c} msg]; note $msg
	notes
    } c]
    rename foo {}
    set res
} -constraints {testchannel testthread} -result {{initialize rc* {read write}} rc* {finalize rc*} 0 {}}
test iocmd.tf-22.6 {chan finalize, for close, break, close error} -match glob -body {
    set res {}
    proc foo {args} {track; oninit; return -code 3}
    note [set c [chan create {r w} foo]]
    notes [inthread $c {
	note [catch {close $c} msg]; note $msg
	notes
    } c]
    rename foo {}
    set res
} -result {{initialize rc* {read write}} rc* {finalize rc*} 1 *bad code*} \
    -constraints {testchannel testthread}
test iocmd.tf-22.7 {chan finalize, for close, continue, close error} -match glob -body {
    set res {}
    proc foo {args} {track; oninit; return -code 4}
    note [set c [chan create {r w} foo]]
    notes [inthread $c {
	note [catch {close $c} msg]; note $msg
	notes
    } c]
    rename foo {}
    set res
} -result {{initialize rc* {read write}} rc* {finalize rc*} 1 *bad code*} \
    -constraints {testchannel testthread}
test iocmd.tf-22.8 {chan finalize, for close, custom code, close error} -match glob -body {
    set res {}
    proc foo {args} {track; oninit; return -code 777 BANG}
    note [set c [chan create {r w} foo]]
    notes [inthread $c {
	note [catch {close $c} msg]; note $msg
	notes
    } c]
    rename foo {}
    set res
} -result {{initialize rc* {read write}} rc* {finalize rc*} 1 *bad code*} \
    -constraints {testchannel testthread}
test iocmd.tf-22.9 {chan finalize, for close, ignore level, close error} -match glob -body {
    set res {}
    proc foo {args} {track; oninit; return -level 5 -code 777 BANG}
    note [set c [chan create {r w} foo]]
    notes [inthread $c {
	note [catch {close $c} msg opt]; note $msg; noteOpts $opt
	notes
    } c]
    rename foo {}
    set res
} -result {{initialize rc* {read write}} rc* {finalize rc*} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "finalize"*}} \
    -constraints {testchannel testthread}

# --- === *** ###########################
# method read

test iocmd.tf-23.1 {chan read, regular data return} -match glob -body {
    set res {}
    proc foo {args} {
	oninit; onfinal; track
	return snarf
    }
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [read $c 10]
	close $c
	notes
    } c]
    rename foo {}
    set res
} -constraints {testchannel testthread} -result {{read rc* 4096} {read rc* 4096} snarfsnarf}
test iocmd.tf-23.2 {chan read, bad data return, to much} -match glob -body {
    set res {}
    proc foo {args} {
	oninit; onfinal; track
	return [string repeat snarf 1000]
    }
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {[read $c 2]} msg]; note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -constraints {testchannel testthread} -result {{read rc* 4096} 1 {read delivered more than requested}}
test iocmd.tf-23.3 {chan read, for non-readable channel} -match glob -body {
    set res {}
    proc foo {args} {
	oninit; onfinal; track; note MUST_NOT_HAPPEN
    }
    set c [chan create {w} foo]
    notes [inthread $c {
	note [catch {[read $c 2]} msg]; note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -constraints {testchannel testthread} -result {1 {channel "rc*" wasn't opened for reading}}
test iocmd.tf-23.4 {chan read, error return} -match glob -body {
    set res {}
    proc foo {args} {
	oninit; onfinal; track
	return -code error BOOM!
    }
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {read $c 2} msg]; note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{read rc* 4096} 1 BOOM!} \
    -constraints {testchannel testthread}
test iocmd.tf-23.5 {chan read, break return is error} -match glob -body {
    set res {}
    proc foo {args} {
	oninit; onfinal; track
	return -code break BOOM!
    }
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {read $c 2} msg]; note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{read rc* 4096} 1 *bad code*} \
    -constraints {testchannel testthread}
test iocmd.tf-23.6 {chan read, continue return is error} -match glob -body {
    set res {}
    proc foo {args} {
	oninit; onfinal; track
	return -code continue BOOM!
    }
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {read $c 2} msg]; note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{read rc* 4096} 1 *bad code*} \
    -constraints {testchannel testthread}
test iocmd.tf-23.7 {chan read, custom return is error} -match glob -body {
    set res {}
    proc foo {args} {
	oninit; onfinal; track
	return -code 777 BOOM!
    }
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {read $c 2} msg]; note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{read rc* 4096} 1 *bad code*} \
    -constraints {testchannel testthread}
test iocmd.tf-23.8 {chan read, level is squashed} -match glob -body {
    set res {}
    proc foo {args} {
	oninit; onfinal; track
	return -level 55 -code 777 BOOM!
    }
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {read $c 2} msg opt]; note $msg; noteOpts $opt
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{read rc* 4096} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "read"*}} \
    -constraints {testchannel testthread}
test iocmd.tf-23.9 {chan read, no data means eof} -match glob -setup {
    set res {}
    proc foo {args} {
	oninit; onfinal; track
	return ""
    }
    set c [chan create {r w} foo]
} -body {
    notes [inthread $c {
	note [read $c 2]
	note [eof $c]
	close $c
	notes
    } c]
    set res
} -cleanup {
    rename foo {}
    unset res
} -result {{read rc* 4096} {} 1} \
    -constraints {testchannel testthread}
test iocmd.tf-23.10 {chan read, EAGAIN means no data, yet no eof either} -match glob -setup {
    set res {}
    proc foo {args} {
	oninit; onfinal; track
	error EAGAIN
    }
    set c [chan create {r w} foo]
} -body {
    notes [inthread $c {
	note [read $c 2]
	note [eof $c]
	close $c
	notes
    } c]
    set res
} -cleanup {
    rename foo {}
    unset res
} -result {{read rc* 4096} {} 0} \
    -constraints {testchannel testthread}

# --- === *** ###########################
# method write

test iocmd.tf-24.1 {chan write, regular write} -match glob -body {
    set res {}
    proc foo {args} {
	oninit; onfinal; track
	set     written [string length [lindex $args 2]]
	note   $written
	return $written
    }
    set c [chan create {r w} foo]
    inthread $c {
	puts -nonewline $c snarf; flush $c
	close $c
    } c
    rename foo {}
    set res
} -constraints {testchannel testthread} -result {{write rc* snarf} 5}
test iocmd.tf-24.2 {chan write, ack partial writes} -match glob -body {
    set res {}
    proc foo {args} {
	oninit; onfinal; track
	set     written [string length [lindex $args 2]]
	if {$written > 10} {set written [expr {$written / 2}]}
	note   $written
	return $written
    }
    set c [chan create {r w} foo]
    inthread $c {
	puts -nonewline $c snarfsnarfsnarf; flush $c
	close $c
    } c
    rename foo {}
    set res
} -constraints {testchannel testthread} -result {{write rc* snarfsnarfsnarf} 7 {write rc* arfsnarf} 8}
test iocmd.tf-24.3 {chan write, failed write} -match glob -body {
    set res {}
    proc foo {args} {oninit; onfinal; track; note -1; return -1}
    set c [chan create {r w} foo]
    inthread $c {
	puts -nonewline $c snarfsnarfsnarf; flush $c
	close $c
    } c
    rename foo {}
    set res
} -constraints {testchannel testthread} -result {{write rc* snarfsnarfsnarf} -1}
test iocmd.tf-24.4 {chan write, non-writable channel} -match glob -body {
    set res {}
    proc foo {args} {oninit; onfinal; track; note MUST_NOT_HAPPEN; return}
    set c [chan create {r} foo]
    notes [inthread $c {
	note [catch {puts -nonewline $c snarfsnarfsnarf; flush $c} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -constraints {testchannel testthread} -result {1 {channel "rc*" wasn't opened for writing}}
test iocmd.tf-24.5 {chan write, bad result, more written than data} -match glob -body {
    set res {}
    proc foo {args} {oninit; onfinal; track; return 10000}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {puts -nonewline $c snarf; flush $c} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -constraints {testchannel testthread} -result {{write rc* snarf} 1 {write wrote more than requested}}
test iocmd.tf-24.6 {chan write, zero writes} -match glob -body {
    set res {}
    proc foo {args} {oninit; onfinal; track; return 0}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {puts -nonewline $c snarf; flush $c} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -constraints {testchannel testthread} -result {{write rc* snarf} 1 {write wrote more than requested}}
test iocmd.tf-24.7 {chan write, failed write, error return} -match glob -body {
    set res {}
    proc foo {args} {oninit; onfinal; track; return -code error BOOM!}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {puts -nonewline $c snarfsnarfsnarf; flush $c} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{write rc* snarfsnarfsnarf} 1 BOOM!} \
    -constraints {testchannel testthread}
test iocmd.tf-24.8 {chan write, failed write, error return} -match glob -body {
    set res {}
    proc foo {args} {oninit; onfinal; track; error BOOM!}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {puts -nonewline $c snarfsnarfsnarf; flush $c} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{write rc* snarfsnarfsnarf} 1 BOOM!} \
    -constraints {testchannel testthread}
test iocmd.tf-24.9 {chan write, failed write, break return is error} -match glob -body {
    set res {}
    proc foo {args} {oninit; onfinal; track; return -code break BOOM!}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {puts -nonewline $c snarfsnarfsnarf; flush $c} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{write rc* snarfsnarfsnarf} 1 *bad code*} \
    -constraints {testchannel testthread}
test iocmd.tf-24.10 {chan write, failed write, continue return is error} -match glob -body {
    set res {}
    proc foo {args} {oninit; onfinal; track; return -code continue BOOM!}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {puts -nonewline $c snarfsnarfsnarf; flush $c} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{write rc* snarfsnarfsnarf} 1 *bad code*} \
    -constraints {testchannel testthread}
test iocmd.tf-24.11 {chan write, failed write, custom return is error} -match glob -body {
    set res {}
    proc foo {args} {oninit; onfinal; track; return -code 777 BOOM!}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {puts -nonewline $c snarfsnarfsnarf; flush $c} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{write rc* snarfsnarfsnarf} 1 *bad code*} \
    -constraints {testchannel testthread}
test iocmd.tf-24.12 {chan write, failed write, non-numeric return is error} -match glob -body {
    set res {}
    proc foo {args} {oninit; onfinal; track; return BANG}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {puts -nonewline $c snarfsnarfsnarf; flush $c} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{write rc* snarfsnarfsnarf} 1 {expected integer but got "BANG"}} \
    -constraints {testchannel testthread}
test iocmd.tf-24.13 {chan write, failed write, level is ignored} -match glob -body {
    set res {}
    proc foo {args} {oninit; onfinal; track; return -level 55 -code 777 BOOM!}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {puts -nonewline $c snarfsnarfsnarf; flush $c} msg opt]
	note $msg
	noteOpts $opt
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{write rc* snarfsnarfsnarf} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "write"*}} \
    -constraints {testchannel testthread}
test iocmd.tf-24.14 {chan write, no EAGAIN means that writing is allowed at this time, bug 2936225} -match glob -setup {
    set res {}
    proc foo {args} {
	oninit; onfinal; track
	return 3
    }
    set c [chan create {r w} foo]
} -body {
    notes [inthread $c {
	note [puts -nonewline $c ABC ; flush $c]
	close $c
	notes
    } c]
    set res
} -cleanup {
    rename foo {}
    unset res
} -result {{write rc* ABC} {}} \
    -constraints {testchannel testthread}
test iocmd.tf-24.15 {chan write, EAGAIN means that writing is not allowed at this time, bug 2936225} -match glob -setup {
    set res {}
    proc foo {args} {
	oninit; onfinal; track
	# Note: The EAGAIN signals that the channel cannot accept
	# write requests right now, this in turn causes the IO core to
	# request the generation of writable events (see expected
	# result below, and compare to case 24.14 above).
	error EAGAIN
    }
    set c [chan create {r w} foo]
} -body {
    notes [inthread $c {
	note [puts -nonewline $c ABC ; flush $c]
	close $c
	notes
    } c]
    set res
} -cleanup {


    rename foo {}
    unset res
} -result {{write rc* ABC} {watch rc* write} {}} \
    -constraints {testchannel testthread}

































# --- === *** ###########################
# method cgetall

test iocmd.tf-25.1 {chan configure, cgetall, standard options} -match glob -body {
    set res {}
    proc foo {args} {oninit; onfinal; track; note MUST_NOT_HAPPEN; return}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [fconfigure $c]
	close $c
	notes
    } c]
    rename foo {}
    set res
} -constraints {testchannel testthread} \
    -result {{-blocking 1 -buffering full -buffersize 4096 -encoding * -eofchar {{} {}} -translation {auto *}}}
test iocmd.tf-25.2 {chan configure, cgetall, no options} -match glob -body {
    set res {}
    proc foo {args} {oninit cget cgetall; onfinal; track; return ""}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [fconfigure $c]
	close $c
	notes
    } c]
    rename foo {}
    set res
} -constraints {testchannel testthread} \
    -result {{cgetall rc*} {-blocking 1 -buffering full -buffersize 4096 -encoding * -eofchar {{} {}} -translation {auto *}}}
test iocmd.tf-25.3 {chan configure, cgetall, regular result} -match glob -body {
    set res {}
    proc foo {args} {
	oninit cget cgetall; onfinal; track
	return "-bar foo -snarf x"
    }
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [fconfigure $c]
	close $c
	notes
    } c]
    rename foo {}
    set res
} -constraints {testchannel testthread} \
    -result {{cgetall rc*} {-blocking 1 -buffering full -buffersize 4096 -encoding * -eofchar {{} {}} -translation {auto *} -bar foo -snarf x}}
test iocmd.tf-25.4 {chan configure, cgetall, bad result, list of uneven length} -match glob -body {
    set res {}
    proc foo {args} {
	oninit cget cgetall; onfinal; track
	return "-bar"
    }
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {fconfigure $c} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -constraints {testchannel testthread} -result {{cgetall rc*} 1 {Expected list with even number of elements, got 1 element instead}}
test iocmd.tf-25.5 {chan configure, cgetall, bad result, not a list} -match glob -body {
    set res {}
    proc foo {args} {
	oninit cget cgetall; onfinal; track
	return "\{"
    }
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {fconfigure $c} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -constraints {testchannel testthread} -result {{cgetall rc*} 1 {unmatched open brace in list}}
test iocmd.tf-25.6 {chan configure, cgetall, error return} -match glob -body {
    set res {}
    proc foo {args} {
	oninit cget cgetall; onfinal; track
	return -code error BOOM!
    }
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {fconfigure $c} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -constraints {testchannel testthread} -result {{cgetall rc*} 1 BOOM!}
test iocmd.tf-25.7 {chan configure, cgetall, break return is error} -match glob -body {
    set res {}
    proc foo {args} {
	oninit cget cgetall; onfinal; track
	return -code break BOOM!
    }
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {fconfigure $c} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{cgetall rc*} 1 *bad code*} \
    -constraints {testchannel testthread}
test iocmd.tf-25.8 {chan configure, cgetall, continue return is error} -match glob -body {
    set res {}
    proc foo {args} {
	oninit cget cgetall; onfinal; track
	return -code continue BOOM!
    }
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {fconfigure $c} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{cgetall rc*} 1 *bad code*} \
    -constraints {testchannel testthread}
test iocmd.tf-25.9 {chan configure, cgetall, custom return is error} -match glob -body {
    set res {}
    proc foo {args} {
	oninit cget cgetall; onfinal; track
	return -code 777 BOOM!
    }
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {fconfigure $c} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{cgetall rc*} 1 *bad code*} \
    -constraints {testchannel testthread}
test iocmd.tf-25.10 {chan configure, cgetall, level is ignored} -match glob -body {
    set res {}
    proc foo {args} {
	oninit cget cgetall; onfinal; track
	return -level 55 -code 777 BANG
    }
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {fconfigure $c} msg opt]
	note $msg
	noteOpts $opt
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{cgetall rc*} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "cgetall"*}} \
    -constraints {testchannel testthread}

# --- === *** ###########################
# method configure

test iocmd.tf-26.1 {chan configure, set standard option} -match glob -body {
    set res {}
    proc foo {args} {
	oninit configure; onfinal; track; note MUST_NOT_HAPPEN; return
    }
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [fconfigure $c -translation lf]
	close $c
	notes
    } c]
    rename foo {}
    set res
} -constraints {testchannel testthread} -result {{}}
test iocmd.tf-26.2 {chan configure, set option, error return} -match glob -body {
    set res {}
    proc foo {args} {
	oninit configure; onfinal; track
	return -code error BOOM!
    }
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {fconfigure $c -rc-foo bar} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -constraints {testchannel testthread} -result {{configure rc* -rc-foo bar} 1 BOOM!}
test iocmd.tf-26.3 {chan configure, set option, ok return} -match glob -body {
    set res {}
    proc foo {args} {oninit configure; onfinal; track; return}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [fconfigure $c -rc-foo bar]
	close $c
	notes
    } c]
    rename foo {}
    set res
} -constraints {testchannel testthread} -result {{configure rc* -rc-foo bar} {}}
test iocmd.tf-26.4 {chan configure, set option, break return is error} -match glob -body {
    set res {}
    proc foo {args} {
	oninit configure; onfinal; track
	return -code break BOOM!
    }
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {fconfigure $c -rc-foo bar} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{configure rc* -rc-foo bar} 1 *bad code*} \
    -constraints {testchannel testthread}
test iocmd.tf-26.5 {chan configure, set option, continue return is error} -match glob -body {
    set res {}
    proc foo {args} {
	oninit configure; onfinal; track
	return -code continue BOOM!
    }
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {fconfigure $c -rc-foo bar} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{configure rc* -rc-foo bar} 1 *bad code*} \
    -constraints {testchannel testthread}
test iocmd.tf-26.6 {chan configure, set option, custom return is error} -match glob -body {
    set res {}
    proc foo {args} {
	oninit configure; onfinal; track
	return -code 444 BOOM!
    }
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {fconfigure $c -rc-foo bar} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{configure rc* -rc-foo bar} 1 *bad code*} \
    -constraints {testchannel testthread}
test iocmd.tf-26.7 {chan configure, set option, level is ignored} -match glob -body {
    set res {}
    proc foo {args} {
	oninit configure; onfinal; track
	return -level 55 -code 444 BANG
    }
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {fconfigure $c -rc-foo bar} msg opt]
	note $msg
	noteOpts $opt
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{configure rc* -rc-foo bar} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "configure"*}} \
    -constraints {testchannel testthread}

# --- === *** ###########################
# method cget

test iocmd.tf-27.1 {chan configure, get option, ok return} -match glob -body {
    set res {}
    proc foo {args} {oninit cget cgetall; onfinal; track; return foo}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [fconfigure $c -rc-foo]
	close $c
	notes
    } c]
    rename foo {}
    set res
} -constraints {testchannel testthread} -result {{cget rc* -rc-foo} foo}
test iocmd.tf-27.2 {chan configure, get option, error return} -match glob -body {
    set res {}
    proc foo {args} {
	oninit cget cgetall; onfinal; track
	return -code error BOOM!
    }
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {fconfigure $c -rc-foo} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -constraints {testchannel testthread} -result {{cget rc* -rc-foo} 1 BOOM!}
test iocmd.tf-27.3 {chan configure, get option, break return is error} -match glob -body {
    set res {}
    proc foo {args} {
	oninit cget cgetall; onfinal; track
	return -code error BOOM!
    }
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {fconfigure $c -rc-foo} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{cget rc* -rc-foo} 1 BOOM!} \
    -constraints {testchannel testthread}
test iocmd.tf-27.4 {chan configure, get option, continue return is error} -match glob -body {
    set res {}
    proc foo {args} {
	oninit cget cgetall; onfinal; track
	return -code continue BOOM!
    }
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {fconfigure $c -rc-foo} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{cget rc* -rc-foo} 1 *bad code*} \
    -constraints {testchannel testthread}
test iocmd.tf-27.5 {chan configure, get option, custom return is error} -match glob -body {
    set res {}
    proc foo {args} {
	oninit cget cgetall; onfinal; track
	return -code 333 BOOM!
    }
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {fconfigure $c -rc-foo} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{cget rc* -rc-foo} 1 *bad code*} \
    -constraints {testchannel testthread}
test iocmd.tf-27.6 {chan configure, get option, level is ignored} -match glob -body {
    set res {}
    proc foo {args} {
	oninit cget cgetall; onfinal; track
	return -level 77 -code 333 BANG
    }
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {fconfigure $c -rc-foo} msg opt]
	note $msg
	noteOpts $opt
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{cget rc* -rc-foo} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "cget"*}} \
    -constraints {testchannel testthread}

# --- === *** ###########################
# method seek

test iocmd.tf-28.1 {chan tell, not supported by handler} -match glob -body {
    set res {}
    proc foo {args} {oninit; onfinal; track; note MUST_NOT_HAPPEN; return}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [tell $c]
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {-1} \
    -constraints {testchannel testthread}
test iocmd.tf-28.2 {chan tell, error return} -match glob -body {
    set res {}
    proc foo {args} {oninit seek; onfinal; track; return -code error BOOM!}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {tell $c} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{seek rc* 0 current} 1 BOOM!} \
    -constraints {testchannel testthread}
test iocmd.tf-28.3 {chan tell, break return is error} -match glob -body {
    set res {}
    proc foo {args} {oninit seek; onfinal; track; return -code break BOOM!}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {tell $c} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{seek rc* 0 current} 1 *bad code*} \
    -constraints {testchannel testthread}
test iocmd.tf-28.4 {chan tell, continue return is error} -match glob -body {
    set res {}
    proc foo {args} {oninit seek; onfinal; track; return -code continue BOOM!}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {tell $c} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{seek rc* 0 current} 1 *bad code*} \
    -constraints {testchannel testthread}
test iocmd.tf-28.5 {chan tell, custom return is error} -match glob -body {
    set res {}
    proc foo {args} {oninit seek; onfinal; track; return -code 222 BOOM!}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {tell $c} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{seek rc* 0 current} 1 *bad code*} \
    -constraints {testchannel testthread}
test iocmd.tf-28.6 {chan tell, level is ignored} -match glob -body {
    set res {}
    proc foo {args} {oninit seek; onfinal; track; return -level 11 -code 222 BANG}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {tell $c} msg opt]
	note $msg
	noteOpts $opt
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{seek rc* 0 current} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "seek"*}} \
    -constraints {testchannel testthread}
test iocmd.tf-28.7 {chan tell, regular return} -match glob -body {
    set res {}
    proc foo {args} {oninit seek; onfinal; track; return 88}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [tell $c]
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{seek rc* 0 current} 88} \
    -constraints {testchannel testthread}
test iocmd.tf-28.8 {chan tell, negative return} -match glob -body {
    set res {}
    proc foo {args} {oninit seek; onfinal; track; return -1}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {tell $c} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{seek rc* 0 current} 1 {Tried to seek before origin}} \
    -constraints {testchannel testthread}
test iocmd.tf-28.9 {chan tell, string return} -match glob -body {
    set res {}
    proc foo {args} {oninit seek; onfinal; track; return BOGUS}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {tell $c} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{seek rc* 0 current} 1 {expected integer but got "BOGUS"}} \
    -constraints {testchannel testthread}
test iocmd.tf-28.10 {chan seek, not supported by handler} -match glob -body {
    set res {}
    proc foo {args} {oninit; onfinal; track; note MUST_NOT_HAPPEN; return}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {seek $c 0 start} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {1 {error during seek on "rc*": invalid argument}} \
    -constraints {testchannel testthread}
test iocmd.tf-28.11 {chan seek, error return} -match glob -body {
    set res {}
    proc foo {args} {oninit seek; onfinal; track; return -code error BOOM!}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {seek $c 0 start} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{seek rc* 0 start} 1 BOOM!} \
    -constraints {testchannel testthread}
test iocmd.tf-28.12 {chan seek, break return is error} -match glob -body {
    set res {}
    proc foo {args} {oninit seek; onfinal; track; return -code break BOOM!}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {seek $c 0 start} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{seek rc* 0 start} 1 *bad code*} \
    -constraints {testchannel testthread}
test iocmd.tf-28.13 {chan seek, continue return is error} -match glob -body {
    set res {}
    proc foo {args} {oninit seek; onfinal; track; return -code continue BOOM!}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {seek $c 0 start} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{seek rc* 0 start} 1 *bad code*} \
    -constraints {testchannel testthread}
test iocmd.tf-28.14 {chan seek, custom return is error} -match glob -body {
    set res {}
    proc foo {args} {oninit seek; onfinal; track; return -code 99 BOOM!}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {seek $c 0 start} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{seek rc* 0 start} 1 *bad code*} \
    -constraints {testchannel testthread}
test iocmd.tf-28.15 {chan seek, level is ignored} -match glob -body {
    set res {}
    proc foo {args} {oninit seek; onfinal; track; return -level 33 -code 99 BANG}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {seek $c 0 start} msg opt]
	note $msg
	noteOpts $opt
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{seek rc* 0 start} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "seek"*}} \
    -constraints {testchannel testthread}
test iocmd.tf-28.16 {chan seek, bogus return, negative location} -match glob -body {
    set res {}
    proc foo {args} {oninit seek; onfinal; track; return -45}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {seek $c 0 start} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{seek rc* 0 start} 1 {Tried to seek before origin}} \
    -constraints {testchannel testthread}
test iocmd.tf-28.17 {chan seek, bogus return, string return} -match glob -body {
    set res {}
    proc foo {args} {oninit seek; onfinal; track; return BOGUS}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {seek $c 0 start} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{seek rc* 0 start} 1 {expected integer but got "BOGUS"}} \
    -constraints {testchannel testthread}
test iocmd.tf-28.18 {chan seek, ok result} -match glob -body {
    set res {}
    proc foo {args} {oninit seek; onfinal; track; return 23}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [seek $c 0 current]
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{seek rc* 0 current} {}} \
    -constraints {testchannel testthread}
foreach {testname code} {
    iocmd.tf-28.19.0 start
    iocmd.tf-28.19.1 current
    iocmd.tf-28.19.2 end
} {
    test $testname "chan seek, base conversion, $code" -match glob -body {
	set res {}
	proc foo {args} {oninit seek; onfinal; track; return 0}
	set c [chan create {r w} foo]
	notes [inthread $c {
	    note [seek $c 0 $code]
	    close $c
	    notes
	} c code]
	rename foo {}
	set res
    } -result [list [list seek rc* 0 $code] {}] \
	-constraints {testchannel testthread}
}

# --- === *** ###########################
# method blocking

test iocmd.tf-29.1 {chan blocking, no handler support} -match glob -body {
    set res {}
    proc foo {args} {oninit; onfinal; track; note MUST_NOT_HAPPEN; return}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [fconfigure $c -blocking]
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {1} \
    -constraints {testchannel testthread}
test iocmd.tf-29.2 {chan blocking, no handler support} -match glob -body {
    set res {}
    proc foo {args} {oninit; onfinal; track; note MUST_NOT_HAPPEN; return}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [fconfigure $c -blocking 0]
	note [fconfigure $c -blocking]
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{} 0} \
    -constraints {testchannel testthread}
test iocmd.tf-29.3 {chan blocking, retrieval, handler support} -match glob -body {
    set res {}
    proc foo {args} {oninit blocking; onfinal; track; note MUST_NOT_HAPPEN; return}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [fconfigure $c -blocking]
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {1} \
    -constraints {testchannel testthread}
test iocmd.tf-29.4 {chan blocking, resetting, handler support} -match glob -body {
    set res {}
    proc foo {args} {oninit blocking; onfinal; track; return}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [fconfigure $c -blocking 0]
	note [fconfigure $c -blocking]
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{blocking rc* 0} {} 0} \
    -constraints {testchannel testthread}
test iocmd.tf-29.5 {chan blocking, setting, handler support} -match glob -body {
    set res {}
    proc foo {args} {oninit blocking; onfinal; track; return}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [fconfigure $c -blocking 1]
	note [fconfigure $c -blocking]
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{blocking rc* 1} {} 1} \
    -constraints {testchannel testthread}
test iocmd.tf-29.6 {chan blocking, error return} -match glob -body {
    set res {}
    proc foo {args} {oninit blocking; onfinal; track; error BOOM!}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {fconfigure $c -blocking 0} msg]
	note $msg
	# Catch the close. It changes blocking mode internally, and runs into the error result.
	catch {close $c}
	notes
    } c]
    rename foo {}
    set res
} -result {{blocking rc* 0} 1 BOOM!} \
    -constraints {testchannel testthread}
test iocmd.tf-29.7 {chan blocking, break return is error} -match glob -body {
    set res {}
    proc foo {args} {oninit blocking; onfinal; track; return -code break BOOM!}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {fconfigure $c -blocking 0} msg]
	note $msg
	catch {close $c}
	notes
    } c]
    rename foo {}
    set res
} -result {{blocking rc* 0} 1 *bad code*} \
    -constraints {testchannel testthread}
test iocmd.tf-29.8 {chan blocking, continue return is error} -match glob -body {
    set res {}
    proc foo {args} {oninit blocking; onfinal; track; return -code continue BOOM!}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {fconfigure $c -blocking 0} msg]
	note $msg
	catch {close $c}
	notes
    } c]
    rename foo {}
    set res
} -result {{blocking rc* 0} 1 *bad code*} \
    -constraints {testchannel testthread}
test iocmd.tf-29.9 {chan blocking, custom return is error} -match glob -body {
    set res {}
    proc foo {args} {oninit blocking; onfinal; track; return -code 44 BOOM!}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {fconfigure $c -blocking 0} msg]
	note $msg
	catch {close $c}
	notes
    } c]
    rename foo {}
    set res
} -result {{blocking rc* 0} 1 *bad code*} \
    -constraints {testchannel testthread}
test iocmd.tf-29.10 {chan blocking, level is ignored} -match glob -body {
    set res {}
    proc foo {args} {oninit blocking; onfinal; track; return -level 99 -code 44 BANG}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {fconfigure $c -blocking 0} msg opt]
	note $msg
	noteOpts $opt
	catch {close $c}
	notes
    } c]
    rename foo {}
    set res
} -result {{blocking rc* 0} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "blocking"*}} \
    -constraints {testchannel testthread}
test iocmd.tf-29.11 {chan blocking, regular return ok, value ignored} -match glob -body {
    set res {}
    proc foo {args} {oninit blocking; onfinal; track; return BOGUS}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {fconfigure $c -blocking 0} msg]
	note $msg
	catch {close $c}
	notes
    } c]
    rename foo {}
    set res
} -result {{blocking rc* 0} 0 {}} \
    -constraints {testchannel testthread}

# --- === *** ###########################
# method watch

test iocmd.tf-30.1 {chan watch, read interest, some return} -match glob -body {
    set res {}
    proc foo {args} {oninit; onfinal; track; return IGNORED}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [fileevent $c readable {set tick $tick}]
	close $c		;# 2nd watch, interest zero.
	notes
    } c]
    rename foo {}
    set res
} -constraints {testchannel testthread} -result {{watch rc* read} {watch rc* {}} {}}
test iocmd.tf-30.2 {chan watch, write interest, error return} -match glob -body {
    set res {}
    proc foo {args} {oninit; onfinal; track; return -code error BOOM!_IGNORED}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [fileevent $c writable {set tick $tick}]
	note [fileevent $c writable {}]
	close $c
	notes
    } c]
    rename foo {}
    set res
} -constraints {testchannel testthread} -result {{watch rc* write} {watch rc* {}} {} {}}
test iocmd.tf-30.3 {chan watch, accumulated interests} -match glob -body {
    set res {}
    proc foo {args} {oninit; onfinal; track; return}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [fileevent $c writable {set tick $tick}]
	note [fileevent $c readable {set tick $tick}]
	note [fileevent $c writable {}]
	note [fileevent $c readable {}]
	close $c
	notes
    } c]
    rename foo {}
    set res
} -constraints {testchannel testthread} \
    -result {{watch rc* write} {watch rc* {read write}} {watch rc* read} {watch rc* {}} {} {} {} {}}
test iocmd.tf-30.4 {chan watch, unchanged interest not forwarded} -match glob -body {
    set res {}
    proc foo {args} {oninit; onfinal; track; return}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [fileevent $c writable {set tick $tick}]
	note [fileevent $c readable {set tick $tick}] ;# Script is changing,
	note [fileevent $c readable {set tock $tock}] ;# interest does not.
	close $c	;# 3rd and 4th watch, removing the event handlers.
	notes
    } c]
    rename foo {}
    set res
} -constraints {testchannel testthread} \
    -result {{watch rc* write} {watch rc* {read write}} {watch rc* write} {watch rc* {}} {} {} {}}

# --- === *** ###########################
# postevent
# Not possible from a thread not containing the command handler.
# Check that this is rejected.

test iocmd.tf-31.8 {chan postevent, bad input} -match glob -body {
    set res {}
    proc foo {args} {oninit; onfinal; track; return}
    set c [chan create {r w} foo]
    notes [inthread $c {
	catch {chan postevent $c r} msg
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -constraints {testchannel testthread} \
    -result {{can not find reflected channel named "rc*"}}

# --- === *** ###########################
# 'Pull the rug' tests. Create channel in a thread A, move to other
# thread B, destroy the origin thread (A) before or during access from
# B. Must not crash, must return proper errors.

test iocmd.tf-32.0 {origin thread of moved channel gone} -match glob -body {

    #puts <<$tcltest::mainThread>>main
    set tida [testthread create];#puts <<$tida>>


    set tidb [testthread create];#puts <<$tidb>>


    # Set up channel in thread
    testthread send $tida $helperscript
    set chan [testthread send $tida {
	proc foo {args} {oninit seek; onfinal; track; return}
	set chan [chan create {r w} foo]
	fconfigure $chan -buffering none
	set chan
    }]

    # Move channel to 2nd thread.
    testthread send $tida [list testchannel cut    $chan]
    testthread send $tidb [list testchannel splice $chan]

    # Kill origin thread, then access channel from 2nd thread.
    testthread send -async $tida {testthread exit}
    after 100

    set     res {}
    lappend res [catch {testthread send $tidb [list puts  $chan shoo]} msg] $msg

    lappend res [catch {testthread send $tidb [list tell  $chan]}      msg] $msg
    lappend res [catch {testthread send $tidb [list seek  $chan 1]}    msg] $msg
    lappend res [catch {testthread send $tidb [list gets  $chan]}      msg] $msg
    lappend res [catch {testthread send $tidb [list close $chan]}      msg] $msg
    tcltest::threadReap
    set res

} -constraints {testchannel testthread} \
    -result {1 {Owner lost} 1 {Owner lost} 1 {Owner lost} 1 {Owner lost} 1 {Owner lost}}














test iocmd.tf-32.1 {origin thread of moved channel destroyed during access} -match glob -body {

    #puts <<$tcltest::mainThread>>main
    set tida [testthread create];#puts <<$tida>>

    set tidb [testthread create];#puts <<$tidb>>


    # Set up channel in thread
    set chan [testthread send $tida $helperscript]
    set chan [testthread send $tida {
	proc foo {args} {
	    oninit; onfinal; track;
	    # destroy thread during channel access
	    testthread exit
	    return}

	set chan [chan create {r w} foo]
	fconfigure $chan -buffering none
	set chan
    }]

    # Move channel to 2nd thread.
    testthread send $tida [list testchannel cut    $chan]
    testthread send $tidb [list testchannel splice $chan]

    # Run access from thread B, wait for response from A (A is not
    # using event loop at this point, so the event pile up in the
    # queue.

    testthread send $tidb [list set chan $chan]
    testthread send $tidb [list set mid $tcltest::mainThread]
    testthread send -async $tidb {
	# wait a bit, give the main thread the time to start its event
	# loop to wait for the response from B
	after 2000
	catch { puts $chan shoo } res
	testthread send -async $mid [list set ::res $res]
    }
    vwait ::res


    tcltest::threadReap
    set res
} -constraints {testchannel testthread} \
    -result {Owner lost}

# ### ### ### ######### ######### #########

# ### ### ### ######### ######### #########

rename track {}







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








|
>








|
|
>
|
|






|




|







|


|




|




















|












|










|










|











|











|











|











|


















|














|













|















|















|















|















|















|



















|



















|



















|
















|










|












|












|












|













|













|













|













|













|













|














|


















|



















>
>



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















|












|















|
















|















|















|
















|
















|
















|

















|

















|















|











|
















|
















|
















|

















|















|















|
















|
















|
















|

















|
















|













|













|













|













|














|












|













|













|













|













|













|













|













|














|













|













|












|

















|

















|













|












|













|













|














|













|













|













|














|













|















|












|














|














|



















|










|
>
>
|
>


|
|







|
|


|
<


|

|
|
|
|
|


|


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



|
>
|
>


|
|



|
<
>






|
|





|
|
|




|



>
|

|







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
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
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
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
2581
2582
2583
2584
2585
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
2617
2618
2619
2620
2621
2622
2623
2624
2625
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
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
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
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
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535

3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568
3569
3570
3571
3572
3573
3574
3575
3576
3577

3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
# ### ### ### ######### ######### #########
## Testing the reflected channel (Thread forwarding).
#
## The id numbers refer to the original test without thread
## forwarding, and gaps due to tests not applicable to forwarding are
## left to keep this asociation.


















# ### ### ### ######### ######### #########
## Helper command. Runs a script in a separate thread and returns the
## result. A channel is transfered into the thread as well, and list of
## configuation variables

proc inthread {chan script args} {
    # Test thread.

    set tid [thread::create -preserved]
    thread::send $tid {load {} Tcltest}

    # Init thread configuration.
    # - Listed variables
    # - Id of main thread
    # - A number of helper commands

    foreach v $args {
	upvar 1 $v x
	thread::send $tid [list set $v $x]

    }
    thread::send $tid [list set mid [thread::id]]
    thread::send $tid {
	proc note {item} {global notes; lappend notes $item}
	proc notes {} {global notes; return $notes}
	proc noteOpts opts {global notes; lappend notes [dict merge {
	    -code !?! -level !?! -errorcode !?! -errorline !?! -errorinfo !?!
	} $opts]}
    }
    thread::send $tid [list proc s {} [list uplevel 1 $script]]; # (*)

    # Transfer channel (cut/splice aka detach/attach)

    testchannel cut $chan
    thread::send $tid [list testchannel splice $chan]

    # Run test script, also run local event loop!
    # The local event loop waits for the result to come back.
    # It is also necessary for the execution of forwarded channel
    # operations.

    set ::tres ""
    thread::send -async $tid {
	after 500
	catch {s} res; # This runs the script, 's' was defined at (*)
	thread::send -async $mid [list set ::tres $res]
    }
    vwait ::tres
    # Remove test thread, and return the captured result.

    thread::release $tid
    return $::tres
}

# ### ### ### ######### ######### #########

# ### ### ### ######### ######### #########

test iocmd.tf-22.2 {chan finalize, for close} -match glob -body {
    set res {}
    proc foo {args} {track; oninit; return {}}
    note [set c [chan create {r w} foo]]
    note [inthread $c {
	close $c
	# Close the deleted the channel.
	file channels rc*
    } c]
    # Channel destruction does not kill handler command!
    note [info command foo]
    rename foo {}
    set res
} -constraints {testchannel thread} -result {{initialize rc* {read write}} rc* {finalize rc*} {} foo}
test iocmd.tf-22.3 {chan finalize, for close, error, close error} -match glob -body {
    set res {}
    proc foo {args} {track; oninit; return -code error 5}
    note [set c [chan create {r w} foo]]
    notes [inthread $c {
	note [catch {close $c} msg]; note $msg
	# Channel is gone despite error.
	note [file channels rc*]
	notes
    } c]
    rename foo {}
    set res
} -constraints {testchannel thread} -result {{initialize rc* {read write}} rc* {finalize rc*} 1 5 {}}
test iocmd.tf-22.4 {chan finalize, for close, error, close errror} -match glob -body {
    set res {}
    proc foo {args} {track; oninit; error FOO}
    note [set c [chan create {r w} foo]]
    notes [inthread $c {
	note [catch {close $c} msg]; note $msg
	notes
    } c]
    rename foo {}
    set res
} -constraints {testchannel thread} -result {{initialize rc* {read write}} rc* {finalize rc*} 1 FOO}
test iocmd.tf-22.5 {chan finalize, for close, arbitrary result} -match glob -body {
    set res {}
    proc foo {args} {track; oninit; return SOMETHING}
    note [set c [chan create {r w} foo]]
    notes [inthread $c {
	note [catch {close $c} msg]; note $msg
	notes
    } c]
    rename foo {}
    set res
} -constraints {testchannel thread} -result {{initialize rc* {read write}} rc* {finalize rc*} 0 {}}
test iocmd.tf-22.6 {chan finalize, for close, break, close error} -match glob -body {
    set res {}
    proc foo {args} {track; oninit; return -code 3}
    note [set c [chan create {r w} foo]]
    notes [inthread $c {
	note [catch {close $c} msg]; note $msg
	notes
    } c]
    rename foo {}
    set res
} -result {{initialize rc* {read write}} rc* {finalize rc*} 1 *bad code*} \
    -constraints {testchannel thread}
test iocmd.tf-22.7 {chan finalize, for close, continue, close error} -match glob -body {
    set res {}
    proc foo {args} {track; oninit; return -code 4}
    note [set c [chan create {r w} foo]]
    notes [inthread $c {
	note [catch {close $c} msg]; note $msg
	notes
    } c]
    rename foo {}
    set res
} -result {{initialize rc* {read write}} rc* {finalize rc*} 1 *bad code*} \
    -constraints {testchannel thread}
test iocmd.tf-22.8 {chan finalize, for close, custom code, close error} -match glob -body {
    set res {}
    proc foo {args} {track; oninit; return -code 777 BANG}
    note [set c [chan create {r w} foo]]
    notes [inthread $c {
	note [catch {close $c} msg]; note $msg
	notes
    } c]
    rename foo {}
    set res
} -result {{initialize rc* {read write}} rc* {finalize rc*} 1 *bad code*} \
    -constraints {testchannel thread}
test iocmd.tf-22.9 {chan finalize, for close, ignore level, close error} -match glob -body {
    set res {}
    proc foo {args} {track; oninit; return -level 5 -code 777 BANG}
    note [set c [chan create {r w} foo]]
    notes [inthread $c {
	note [catch {close $c} msg opt]; note $msg; noteOpts $opt
	notes
    } c]
    rename foo {}
    set res
} -result {{initialize rc* {read write}} rc* {finalize rc*} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "finalize"*}} \
    -constraints {testchannel thread}

# --- === *** ###########################
# method read

test iocmd.tf-23.1 {chan read, regular data return} -match glob -body {
    set res {}
    proc foo {args} {
	oninit; onfinal; track
	return snarf
    }
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [read $c 10]
	close $c
	notes
    } c]
    rename foo {}
    set res
} -constraints {testchannel thread} -result {{read rc* 4096} {read rc* 4096} snarfsnarf}
test iocmd.tf-23.2 {chan read, bad data return, to much} -match glob -body {
    set res {}
    proc foo {args} {
	oninit; onfinal; track
	return [string repeat snarf 1000]
    }
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {[read $c 2]} msg]; note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -constraints {testchannel thread} -result {{read rc* 4096} 1 {read delivered more than requested}}
test iocmd.tf-23.3 {chan read, for non-readable channel} -match glob -body {
    set res {}
    proc foo {args} {
	oninit; onfinal; track; note MUST_NOT_HAPPEN
    }
    set c [chan create {w} foo]
    notes [inthread $c {
	note [catch {[read $c 2]} msg]; note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -constraints {testchannel thread} -result {1 {channel "rc*" wasn't opened for reading}}
test iocmd.tf-23.4 {chan read, error return} -match glob -body {
    set res {}
    proc foo {args} {
	oninit; onfinal; track
	return -code error BOOM!
    }
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {read $c 2} msg]; note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{read rc* 4096} 1 BOOM!} \
    -constraints {testchannel thread}
test iocmd.tf-23.5 {chan read, break return is error} -match glob -body {
    set res {}
    proc foo {args} {
	oninit; onfinal; track
	return -code break BOOM!
    }
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {read $c 2} msg]; note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{read rc* 4096} 1 *bad code*} \
    -constraints {testchannel thread}
test iocmd.tf-23.6 {chan read, continue return is error} -match glob -body {
    set res {}
    proc foo {args} {
	oninit; onfinal; track
	return -code continue BOOM!
    }
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {read $c 2} msg]; note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{read rc* 4096} 1 *bad code*} \
    -constraints {testchannel thread}
test iocmd.tf-23.7 {chan read, custom return is error} -match glob -body {
    set res {}
    proc foo {args} {
	oninit; onfinal; track
	return -code 777 BOOM!
    }
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {read $c 2} msg]; note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{read rc* 4096} 1 *bad code*} \
    -constraints {testchannel thread}
test iocmd.tf-23.8 {chan read, level is squashed} -match glob -body {
    set res {}
    proc foo {args} {
	oninit; onfinal; track
	return -level 55 -code 777 BOOM!
    }
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {read $c 2} msg opt]; note $msg; noteOpts $opt
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{read rc* 4096} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "read"*}} \
    -constraints {testchannel thread}
test iocmd.tf-23.9 {chan read, no data means eof} -match glob -setup {
    set res {}
    proc foo {args} {
	oninit; onfinal; track
	return ""
    }
    set c [chan create {r w} foo]
} -body {
    notes [inthread $c {
	note [read $c 2]
	note [eof $c]
	close $c
	notes
    } c]
    set res
} -cleanup {
    rename foo {}
    unset res
} -result {{read rc* 4096} {} 1} \
    -constraints {testchannel thread}
test iocmd.tf-23.10 {chan read, EAGAIN means no data, yet no eof either} -match glob -setup {
    set res {}
    proc foo {args} {
	oninit; onfinal; track
	error EAGAIN
    }
    set c [chan create {r w} foo]
} -body {
    notes [inthread $c {
	note [read $c 2]
	note [eof $c]
	close $c
	notes
    } c]
    set res
} -cleanup {
    rename foo {}
    unset res
} -result {{read rc* 4096} {} 0} \
    -constraints {testchannel thread}

# --- === *** ###########################
# method write

test iocmd.tf-24.1 {chan write, regular write} -match glob -body {
    set res {}
    proc foo {args} {
	oninit; onfinal; track
	set     written [string length [lindex $args 2]]
	note   $written
	return $written
    }
    set c [chan create {r w} foo]
    inthread $c {
	puts -nonewline $c snarf; flush $c
	close $c
    } c
    rename foo {}
    set res
} -constraints {testchannel thread} -result {{write rc* snarf} 5}
test iocmd.tf-24.2 {chan write, ack partial writes} -match glob -body {
    set res {}
    proc foo {args} {
	oninit; onfinal; track
	set     written [string length [lindex $args 2]]
	if {$written > 10} {set written [expr {$written / 2}]}
	note   $written
	return $written
    }
    set c [chan create {r w} foo]
    inthread $c {
	puts -nonewline $c snarfsnarfsnarf; flush $c
	close $c
    } c
    rename foo {}
    set res
} -constraints {testchannel thread} -result {{write rc* snarfsnarfsnarf} 7 {write rc* arfsnarf} 8}
test iocmd.tf-24.3 {chan write, failed write} -match glob -body {
    set res {}
    proc foo {args} {oninit; onfinal; track; note -1; return -1}
    set c [chan create {r w} foo]
    inthread $c {
	puts -nonewline $c snarfsnarfsnarf; flush $c
	close $c
    } c
    rename foo {}
    set res
} -constraints {testchannel thread} -result {{write rc* snarfsnarfsnarf} -1}
test iocmd.tf-24.4 {chan write, non-writable channel} -match glob -body {
    set res {}
    proc foo {args} {oninit; onfinal; track; note MUST_NOT_HAPPEN; return}
    set c [chan create {r} foo]
    notes [inthread $c {
	note [catch {puts -nonewline $c snarfsnarfsnarf; flush $c} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -constraints {testchannel thread} -result {1 {channel "rc*" wasn't opened for writing}}
test iocmd.tf-24.5 {chan write, bad result, more written than data} -match glob -body {
    set res {}
    proc foo {args} {oninit; onfinal; track; return 10000}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {puts -nonewline $c snarf; flush $c} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -constraints {testchannel thread} -result {{write rc* snarf} 1 {write wrote more than requested}}
test iocmd.tf-24.6 {chan write, zero writes} -match glob -body {
    set res {}
    proc foo {args} {oninit; onfinal; track; return 0}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {puts -nonewline $c snarf; flush $c} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -constraints {testchannel thread} -result {{write rc* snarf} 1 {write wrote more than requested}}
test iocmd.tf-24.7 {chan write, failed write, error return} -match glob -body {
    set res {}
    proc foo {args} {oninit; onfinal; track; return -code error BOOM!}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {puts -nonewline $c snarfsnarfsnarf; flush $c} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{write rc* snarfsnarfsnarf} 1 BOOM!} \
    -constraints {testchannel thread}
test iocmd.tf-24.8 {chan write, failed write, error return} -match glob -body {
    set res {}
    proc foo {args} {oninit; onfinal; track; error BOOM!}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {puts -nonewline $c snarfsnarfsnarf; flush $c} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{write rc* snarfsnarfsnarf} 1 BOOM!} \
    -constraints {testchannel thread}
test iocmd.tf-24.9 {chan write, failed write, break return is error} -match glob -body {
    set res {}
    proc foo {args} {oninit; onfinal; track; return -code break BOOM!}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {puts -nonewline $c snarfsnarfsnarf; flush $c} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{write rc* snarfsnarfsnarf} 1 *bad code*} \
    -constraints {testchannel thread}
test iocmd.tf-24.10 {chan write, failed write, continue return is error} -match glob -body {
    set res {}
    proc foo {args} {oninit; onfinal; track; return -code continue BOOM!}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {puts -nonewline $c snarfsnarfsnarf; flush $c} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{write rc* snarfsnarfsnarf} 1 *bad code*} \
    -constraints {testchannel thread}
test iocmd.tf-24.11 {chan write, failed write, custom return is error} -match glob -body {
    set res {}
    proc foo {args} {oninit; onfinal; track; return -code 777 BOOM!}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {puts -nonewline $c snarfsnarfsnarf; flush $c} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{write rc* snarfsnarfsnarf} 1 *bad code*} \
    -constraints {testchannel thread}
test iocmd.tf-24.12 {chan write, failed write, non-numeric return is error} -match glob -body {
    set res {}
    proc foo {args} {oninit; onfinal; track; return BANG}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {puts -nonewline $c snarfsnarfsnarf; flush $c} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{write rc* snarfsnarfsnarf} 1 {expected integer but got "BANG"}} \
    -constraints {testchannel thread}
test iocmd.tf-24.13 {chan write, failed write, level is ignored} -match glob -body {
    set res {}
    proc foo {args} {oninit; onfinal; track; return -level 55 -code 777 BOOM!}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {puts -nonewline $c snarfsnarfsnarf; flush $c} msg opt]
	note $msg
	noteOpts $opt
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{write rc* snarfsnarfsnarf} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "write"*}} \
    -constraints {testchannel thread}
test iocmd.tf-24.14 {chan write, no EAGAIN means that writing is allowed at this time, bug 2936225} -match glob -setup {
    set res {}
    proc foo {args} {
	oninit; onfinal; track
	return 3
    }
    set c [chan create {r w} foo]
} -body {
    notes [inthread $c {
	note [puts -nonewline $c ABC ; flush $c]
	close $c
	notes
    } c]
    set res
} -cleanup {
    rename foo {}
    unset res
} -result {{write rc* ABC} {}} \
    -constraints {testchannel thread}
test iocmd.tf-24.15 {chan write, EAGAIN means that writing is not allowed at this time, bug 2936225} -match glob -setup {
    set res {}
    proc foo {args} {
	oninit; onfinal; track
	# Note: The EAGAIN signals that the channel cannot accept
	# write requests right now, this in turn causes the IO core to
	# request the generation of writable events (see expected
	# result below, and compare to case 24.14 above).
	error EAGAIN
    }
    set c [chan create {r w} foo]
} -body {
    notes [inthread $c {
	note [puts -nonewline $c ABC ; flush $c]
	close $c
	notes
    } c]
    set res
} -cleanup {
    proc foo {args} {onfinal; set ::done-24.15 1; return 3}
    vwait done-24.15
    rename foo {}
    unset res
} -result {{write rc* ABC} {watch rc* write} {}} \
    -constraints {testchannel thread}

test iocmd.tf-24.16 {chan write, note the background flush setup by close due to the EAGAIN leaving data in buffers.} -match glob -setup {
    set res {}
    proc foo {args} {
	oninit; onfinal; track
	# Note: The EAGAIN signals that the channel cannot accept
	# write requests right now, this in turn causes the IO core to
	# request the generation of writable events (see expected
	# result below, and compare to case 24.14 above).
	error EAGAIN
    }
    set c [chan create {r w} foo]
} -body {
    notes [inthread $c {
	note [puts -nonewline $c ABC ; flush $c]
	close $c
	notes
    } c]
    # Replace handler with all-tracking one which doesn't error.
    # This will tell us if a write-due-flush is there.
    proc foo {args} { onfinal; note BG ; track ; set ::endbody-24.16 1}
    # Flush (sic!) the event-queue to capture the write from a
    # BG-flush.
    vwait endbody-24.16
    set res
} -cleanup {
    proc foo {args} {onfinal; set ::done-24.16 1; return 3}
    vwait done-24.16
    rename foo {}
    unset res
} -result {{write rc* ABC} {watch rc* write} {} BG {write rc* ABC}} \
    -constraints {testchannel thread}

# --- === *** ###########################
# method cgetall

test iocmd.tf-25.1 {chan configure, cgetall, standard options} -match glob -body {
    set res {}
    proc foo {args} {oninit; onfinal; track; note MUST_NOT_HAPPEN; return}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [fconfigure $c]
	close $c
	notes
    } c]
    rename foo {}
    set res
} -constraints {testchannel thread} \
    -result {{-blocking 1 -buffering full -buffersize 4096 -encoding * -eofchar {{} {}} -translation {auto *}}}
test iocmd.tf-25.2 {chan configure, cgetall, no options} -match glob -body {
    set res {}
    proc foo {args} {oninit cget cgetall; onfinal; track; return ""}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [fconfigure $c]
	close $c
	notes
    } c]
    rename foo {}
    set res
} -constraints {testchannel thread} \
    -result {{cgetall rc*} {-blocking 1 -buffering full -buffersize 4096 -encoding * -eofchar {{} {}} -translation {auto *}}}
test iocmd.tf-25.3 {chan configure, cgetall, regular result} -match glob -body {
    set res {}
    proc foo {args} {
	oninit cget cgetall; onfinal; track
	return "-bar foo -snarf x"
    }
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [fconfigure $c]
	close $c
	notes
    } c]
    rename foo {}
    set res
} -constraints {testchannel thread} \
    -result {{cgetall rc*} {-blocking 1 -buffering full -buffersize 4096 -encoding * -eofchar {{} {}} -translation {auto *} -bar foo -snarf x}}
test iocmd.tf-25.4 {chan configure, cgetall, bad result, list of uneven length} -match glob -body {
    set res {}
    proc foo {args} {
	oninit cget cgetall; onfinal; track
	return "-bar"
    }
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {fconfigure $c} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -constraints {testchannel thread} -result {{cgetall rc*} 1 {Expected list with even number of elements, got 1 element instead}}
test iocmd.tf-25.5 {chan configure, cgetall, bad result, not a list} -match glob -body {
    set res {}
    proc foo {args} {
	oninit cget cgetall; onfinal; track
	return "\{"
    }
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {fconfigure $c} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -constraints {testchannel thread} -result {{cgetall rc*} 1 {unmatched open brace in list}}
test iocmd.tf-25.6 {chan configure, cgetall, error return} -match glob -body {
    set res {}
    proc foo {args} {
	oninit cget cgetall; onfinal; track
	return -code error BOOM!
    }
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {fconfigure $c} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -constraints {testchannel thread} -result {{cgetall rc*} 1 BOOM!}
test iocmd.tf-25.7 {chan configure, cgetall, break return is error} -match glob -body {
    set res {}
    proc foo {args} {
	oninit cget cgetall; onfinal; track
	return -code break BOOM!
    }
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {fconfigure $c} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{cgetall rc*} 1 *bad code*} \
    -constraints {testchannel thread}
test iocmd.tf-25.8 {chan configure, cgetall, continue return is error} -match glob -body {
    set res {}
    proc foo {args} {
	oninit cget cgetall; onfinal; track
	return -code continue BOOM!
    }
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {fconfigure $c} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{cgetall rc*} 1 *bad code*} \
    -constraints {testchannel thread}
test iocmd.tf-25.9 {chan configure, cgetall, custom return is error} -match glob -body {
    set res {}
    proc foo {args} {
	oninit cget cgetall; onfinal; track
	return -code 777 BOOM!
    }
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {fconfigure $c} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{cgetall rc*} 1 *bad code*} \
    -constraints {testchannel thread}
test iocmd.tf-25.10 {chan configure, cgetall, level is ignored} -match glob -body {
    set res {}
    proc foo {args} {
	oninit cget cgetall; onfinal; track
	return -level 55 -code 777 BANG
    }
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {fconfigure $c} msg opt]
	note $msg
	noteOpts $opt
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{cgetall rc*} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "cgetall"*}} \
    -constraints {testchannel thread}

# --- === *** ###########################
# method configure

test iocmd.tf-26.1 {chan configure, set standard option} -match glob -body {
    set res {}
    proc foo {args} {
	oninit configure; onfinal; track; note MUST_NOT_HAPPEN; return
    }
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [fconfigure $c -translation lf]
	close $c
	notes
    } c]
    rename foo {}
    set res
} -constraints {testchannel thread} -result {{}}
test iocmd.tf-26.2 {chan configure, set option, error return} -match glob -body {
    set res {}
    proc foo {args} {
	oninit configure; onfinal; track
	return -code error BOOM!
    }
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {fconfigure $c -rc-foo bar} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -constraints {testchannel thread} -result {{configure rc* -rc-foo bar} 1 BOOM!}
test iocmd.tf-26.3 {chan configure, set option, ok return} -match glob -body {
    set res {}
    proc foo {args} {oninit configure; onfinal; track; return}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [fconfigure $c -rc-foo bar]
	close $c
	notes
    } c]
    rename foo {}
    set res
} -constraints {testchannel thread} -result {{configure rc* -rc-foo bar} {}}
test iocmd.tf-26.4 {chan configure, set option, break return is error} -match glob -body {
    set res {}
    proc foo {args} {
	oninit configure; onfinal; track
	return -code break BOOM!
    }
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {fconfigure $c -rc-foo bar} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{configure rc* -rc-foo bar} 1 *bad code*} \
    -constraints {testchannel thread}
test iocmd.tf-26.5 {chan configure, set option, continue return is error} -match glob -body {
    set res {}
    proc foo {args} {
	oninit configure; onfinal; track
	return -code continue BOOM!
    }
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {fconfigure $c -rc-foo bar} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{configure rc* -rc-foo bar} 1 *bad code*} \
    -constraints {testchannel thread}
test iocmd.tf-26.6 {chan configure, set option, custom return is error} -match glob -body {
    set res {}
    proc foo {args} {
	oninit configure; onfinal; track
	return -code 444 BOOM!
    }
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {fconfigure $c -rc-foo bar} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{configure rc* -rc-foo bar} 1 *bad code*} \
    -constraints {testchannel thread}
test iocmd.tf-26.7 {chan configure, set option, level is ignored} -match glob -body {
    set res {}
    proc foo {args} {
	oninit configure; onfinal; track
	return -level 55 -code 444 BANG
    }
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {fconfigure $c -rc-foo bar} msg opt]
	note $msg
	noteOpts $opt
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{configure rc* -rc-foo bar} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "configure"*}} \
    -constraints {testchannel thread}

# --- === *** ###########################
# method cget

test iocmd.tf-27.1 {chan configure, get option, ok return} -match glob -body {
    set res {}
    proc foo {args} {oninit cget cgetall; onfinal; track; return foo}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [fconfigure $c -rc-foo]
	close $c
	notes
    } c]
    rename foo {}
    set res
} -constraints {testchannel thread} -result {{cget rc* -rc-foo} foo}
test iocmd.tf-27.2 {chan configure, get option, error return} -match glob -body {
    set res {}
    proc foo {args} {
	oninit cget cgetall; onfinal; track
	return -code error BOOM!
    }
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {fconfigure $c -rc-foo} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -constraints {testchannel thread} -result {{cget rc* -rc-foo} 1 BOOM!}
test iocmd.tf-27.3 {chan configure, get option, break return is error} -match glob -body {
    set res {}
    proc foo {args} {
	oninit cget cgetall; onfinal; track
	return -code error BOOM!
    }
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {fconfigure $c -rc-foo} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{cget rc* -rc-foo} 1 BOOM!} \
    -constraints {testchannel thread}
test iocmd.tf-27.4 {chan configure, get option, continue return is error} -match glob -body {
    set res {}
    proc foo {args} {
	oninit cget cgetall; onfinal; track
	return -code continue BOOM!
    }
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {fconfigure $c -rc-foo} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{cget rc* -rc-foo} 1 *bad code*} \
    -constraints {testchannel thread}
test iocmd.tf-27.5 {chan configure, get option, custom return is error} -match glob -body {
    set res {}
    proc foo {args} {
	oninit cget cgetall; onfinal; track
	return -code 333 BOOM!
    }
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {fconfigure $c -rc-foo} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{cget rc* -rc-foo} 1 *bad code*} \
    -constraints {testchannel thread}
test iocmd.tf-27.6 {chan configure, get option, level is ignored} -match glob -body {
    set res {}
    proc foo {args} {
	oninit cget cgetall; onfinal; track
	return -level 77 -code 333 BANG
    }
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {fconfigure $c -rc-foo} msg opt]
	note $msg
	noteOpts $opt
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{cget rc* -rc-foo} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "cget"*}} \
    -constraints {testchannel thread}

# --- === *** ###########################
# method seek

test iocmd.tf-28.1 {chan tell, not supported by handler} -match glob -body {
    set res {}
    proc foo {args} {oninit; onfinal; track; note MUST_NOT_HAPPEN; return}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [tell $c]
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {-1} \
    -constraints {testchannel thread}
test iocmd.tf-28.2 {chan tell, error return} -match glob -body {
    set res {}
    proc foo {args} {oninit seek; onfinal; track; return -code error BOOM!}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {tell $c} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{seek rc* 0 current} 1 BOOM!} \
    -constraints {testchannel thread}
test iocmd.tf-28.3 {chan tell, break return is error} -match glob -body {
    set res {}
    proc foo {args} {oninit seek; onfinal; track; return -code break BOOM!}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {tell $c} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{seek rc* 0 current} 1 *bad code*} \
    -constraints {testchannel thread}
test iocmd.tf-28.4 {chan tell, continue return is error} -match glob -body {
    set res {}
    proc foo {args} {oninit seek; onfinal; track; return -code continue BOOM!}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {tell $c} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{seek rc* 0 current} 1 *bad code*} \
    -constraints {testchannel thread}
test iocmd.tf-28.5 {chan tell, custom return is error} -match glob -body {
    set res {}
    proc foo {args} {oninit seek; onfinal; track; return -code 222 BOOM!}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {tell $c} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{seek rc* 0 current} 1 *bad code*} \
    -constraints {testchannel thread}
test iocmd.tf-28.6 {chan tell, level is ignored} -match glob -body {
    set res {}
    proc foo {args} {oninit seek; onfinal; track; return -level 11 -code 222 BANG}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {tell $c} msg opt]
	note $msg
	noteOpts $opt
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{seek rc* 0 current} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "seek"*}} \
    -constraints {testchannel thread}
test iocmd.tf-28.7 {chan tell, regular return} -match glob -body {
    set res {}
    proc foo {args} {oninit seek; onfinal; track; return 88}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [tell $c]
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{seek rc* 0 current} 88} \
    -constraints {testchannel thread}
test iocmd.tf-28.8 {chan tell, negative return} -match glob -body {
    set res {}
    proc foo {args} {oninit seek; onfinal; track; return -1}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {tell $c} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{seek rc* 0 current} 1 {Tried to seek before origin}} \
    -constraints {testchannel thread}
test iocmd.tf-28.9 {chan tell, string return} -match glob -body {
    set res {}
    proc foo {args} {oninit seek; onfinal; track; return BOGUS}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {tell $c} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{seek rc* 0 current} 1 {expected integer but got "BOGUS"}} \
    -constraints {testchannel thread}
test iocmd.tf-28.10 {chan seek, not supported by handler} -match glob -body {
    set res {}
    proc foo {args} {oninit; onfinal; track; note MUST_NOT_HAPPEN; return}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {seek $c 0 start} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {1 {error during seek on "rc*": invalid argument}} \
    -constraints {testchannel thread}
test iocmd.tf-28.11 {chan seek, error return} -match glob -body {
    set res {}
    proc foo {args} {oninit seek; onfinal; track; return -code error BOOM!}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {seek $c 0 start} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{seek rc* 0 start} 1 BOOM!} \
    -constraints {testchannel thread}
test iocmd.tf-28.12 {chan seek, break return is error} -match glob -body {
    set res {}
    proc foo {args} {oninit seek; onfinal; track; return -code break BOOM!}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {seek $c 0 start} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{seek rc* 0 start} 1 *bad code*} \
    -constraints {testchannel thread}
test iocmd.tf-28.13 {chan seek, continue return is error} -match glob -body {
    set res {}
    proc foo {args} {oninit seek; onfinal; track; return -code continue BOOM!}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {seek $c 0 start} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{seek rc* 0 start} 1 *bad code*} \
    -constraints {testchannel thread}
test iocmd.tf-28.14 {chan seek, custom return is error} -match glob -body {
    set res {}
    proc foo {args} {oninit seek; onfinal; track; return -code 99 BOOM!}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {seek $c 0 start} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{seek rc* 0 start} 1 *bad code*} \
    -constraints {testchannel thread}
test iocmd.tf-28.15 {chan seek, level is ignored} -match glob -body {
    set res {}
    proc foo {args} {oninit seek; onfinal; track; return -level 33 -code 99 BANG}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {seek $c 0 start} msg opt]
	note $msg
	noteOpts $opt
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{seek rc* 0 start} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "seek"*}} \
    -constraints {testchannel thread}
test iocmd.tf-28.16 {chan seek, bogus return, negative location} -match glob -body {
    set res {}
    proc foo {args} {oninit seek; onfinal; track; return -45}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {seek $c 0 start} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{seek rc* 0 start} 1 {Tried to seek before origin}} \
    -constraints {testchannel thread}
test iocmd.tf-28.17 {chan seek, bogus return, string return} -match glob -body {
    set res {}
    proc foo {args} {oninit seek; onfinal; track; return BOGUS}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {seek $c 0 start} msg]
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{seek rc* 0 start} 1 {expected integer but got "BOGUS"}} \
    -constraints {testchannel thread}
test iocmd.tf-28.18 {chan seek, ok result} -match glob -body {
    set res {}
    proc foo {args} {oninit seek; onfinal; track; return 23}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [seek $c 0 current]
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{seek rc* 0 current} {}} \
    -constraints {testchannel thread}
foreach {testname code} {
    iocmd.tf-28.19.0 start
    iocmd.tf-28.19.1 current
    iocmd.tf-28.19.2 end
} {
    test $testname "chan seek, base conversion, $code" -match glob -body {
	set res {}
	proc foo {args} {oninit seek; onfinal; track; return 0}
	set c [chan create {r w} foo]
	notes [inthread $c {
	    note [seek $c 0 $code]
	    close $c
	    notes
	} c code]
	rename foo {}
	set res
    } -result [list [list seek rc* 0 $code] {}] \
	-constraints {testchannel thread}
}

# --- === *** ###########################
# method blocking

test iocmd.tf-29.1 {chan blocking, no handler support} -match glob -body {
    set res {}
    proc foo {args} {oninit; onfinal; track; note MUST_NOT_HAPPEN; return}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [fconfigure $c -blocking]
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {1} \
    -constraints {testchannel thread}
test iocmd.tf-29.2 {chan blocking, no handler support} -match glob -body {
    set res {}
    proc foo {args} {oninit; onfinal; track; note MUST_NOT_HAPPEN; return}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [fconfigure $c -blocking 0]
	note [fconfigure $c -blocking]
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{} 0} \
    -constraints {testchannel thread}
test iocmd.tf-29.3 {chan blocking, retrieval, handler support} -match glob -body {
    set res {}
    proc foo {args} {oninit blocking; onfinal; track; note MUST_NOT_HAPPEN; return}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [fconfigure $c -blocking]
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {1} \
    -constraints {testchannel thread}
test iocmd.tf-29.4 {chan blocking, resetting, handler support} -match glob -body {
    set res {}
    proc foo {args} {oninit blocking; onfinal; track; return}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [fconfigure $c -blocking 0]
	note [fconfigure $c -blocking]
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{blocking rc* 0} {} 0} \
    -constraints {testchannel thread}
test iocmd.tf-29.5 {chan blocking, setting, handler support} -match glob -body {
    set res {}
    proc foo {args} {oninit blocking; onfinal; track; return}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [fconfigure $c -blocking 1]
	note [fconfigure $c -blocking]
	close $c
	notes
    } c]
    rename foo {}
    set res
} -result {{blocking rc* 1} {} 1} \
    -constraints {testchannel thread}
test iocmd.tf-29.6 {chan blocking, error return} -match glob -body {
    set res {}
    proc foo {args} {oninit blocking; onfinal; track; error BOOM!}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {fconfigure $c -blocking 0} msg]
	note $msg
	# Catch the close. It changes blocking mode internally, and runs into the error result.
	catch {close $c}
	notes
    } c]
    rename foo {}
    set res
} -result {{blocking rc* 0} 1 BOOM!} \
    -constraints {testchannel thread}
test iocmd.tf-29.7 {chan blocking, break return is error} -match glob -body {
    set res {}
    proc foo {args} {oninit blocking; onfinal; track; return -code break BOOM!}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {fconfigure $c -blocking 0} msg]
	note $msg
	catch {close $c}
	notes
    } c]
    rename foo {}
    set res
} -result {{blocking rc* 0} 1 *bad code*} \
    -constraints {testchannel thread}
test iocmd.tf-29.8 {chan blocking, continue return is error} -match glob -body {
    set res {}
    proc foo {args} {oninit blocking; onfinal; track; return -code continue BOOM!}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {fconfigure $c -blocking 0} msg]
	note $msg
	catch {close $c}
	notes
    } c]
    rename foo {}
    set res
} -result {{blocking rc* 0} 1 *bad code*} \
    -constraints {testchannel thread}
test iocmd.tf-29.9 {chan blocking, custom return is error} -match glob -body {
    set res {}
    proc foo {args} {oninit blocking; onfinal; track; return -code 44 BOOM!}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {fconfigure $c -blocking 0} msg]
	note $msg
	catch {close $c}
	notes
    } c]
    rename foo {}
    set res
} -result {{blocking rc* 0} 1 *bad code*} \
    -constraints {testchannel thread}
test iocmd.tf-29.10 {chan blocking, level is ignored} -match glob -body {
    set res {}
    proc foo {args} {oninit blocking; onfinal; track; return -level 99 -code 44 BANG}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {fconfigure $c -blocking 0} msg opt]
	note $msg
	noteOpts $opt
	catch {close $c}
	notes
    } c]
    rename foo {}
    set res
} -result {{blocking rc* 0} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "blocking"*}} \
    -constraints {testchannel thread}
test iocmd.tf-29.11 {chan blocking, regular return ok, value ignored} -match glob -body {
    set res {}
    proc foo {args} {oninit blocking; onfinal; track; return BOGUS}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [catch {fconfigure $c -blocking 0} msg]
	note $msg
	catch {close $c}
	notes
    } c]
    rename foo {}
    set res
} -result {{blocking rc* 0} 0 {}} \
    -constraints {testchannel thread}

# --- === *** ###########################
# method watch

test iocmd.tf-30.1 {chan watch, read interest, some return} -match glob -body {
    set res {}
    proc foo {args} {oninit; onfinal; track; return IGNORED}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [fileevent $c readable {set tick $tick}]
	close $c		;# 2nd watch, interest zero.
	notes
    } c]
    rename foo {}
    set res
} -constraints {testchannel thread} -result {{watch rc* read} {watch rc* {}} {}}
test iocmd.tf-30.2 {chan watch, write interest, error return} -match glob -body {
    set res {}
    proc foo {args} {oninit; onfinal; track; return -code error BOOM!_IGNORED}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [fileevent $c writable {set tick $tick}]
	note [fileevent $c writable {}]
	close $c
	notes
    } c]
    rename foo {}
    set res
} -constraints {testchannel thread} -result {{watch rc* write} {watch rc* {}} {} {}}
test iocmd.tf-30.3 {chan watch, accumulated interests} -match glob -body {
    set res {}
    proc foo {args} {oninit; onfinal; track; return}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [fileevent $c writable {set tick $tick}]
	note [fileevent $c readable {set tick $tick}]
	note [fileevent $c writable {}]
	note [fileevent $c readable {}]
	close $c
	notes
    } c]
    rename foo {}
    set res
} -constraints {testchannel thread} \
    -result {{watch rc* write} {watch rc* {read write}} {watch rc* read} {watch rc* {}} {} {} {} {}}
test iocmd.tf-30.4 {chan watch, unchanged interest not forwarded} -match glob -body {
    set res {}
    proc foo {args} {oninit; onfinal; track; return}
    set c [chan create {r w} foo]
    notes [inthread $c {
	note [fileevent $c writable {set tick $tick}]
	note [fileevent $c readable {set tick $tick}] ;# Script is changing,
	note [fileevent $c readable {set tock $tock}] ;# interest does not.
	close $c	;# 3rd and 4th watch, removing the event handlers.
	notes
    } c]
    rename foo {}
    set res
} -constraints {testchannel thread} \
    -result {{watch rc* write} {watch rc* {read write}} {watch rc* write} {watch rc* {}} {} {} {}}

# --- === *** ###########################
# postevent
# Not possible from a thread not containing the command handler.
# Check that this is rejected.

test iocmd.tf-31.8 {chan postevent, bad input} -match glob -body {
    set res {}
    proc foo {args} {oninit; onfinal; track; return}
    set c [chan create {r w} foo]
    notes [inthread $c {
	catch {chan postevent $c r} msg
	note $msg
	close $c
	notes
    } c]
    rename foo {}
    set res
} -constraints {testchannel thread} \
    -result {{can not find reflected channel named "rc*"}}

# --- === *** ###########################
# 'Pull the rug' tests. Create channel in a thread A, move to other
# thread B, destroy the origin thread (A) before or during access from
# B. Must not crash, must return proper errors.

test iocmd.tf-32.0 {origin thread of moved channel gone} -match glob -body {

    #puts <<$tcltest::mainThread>>main
    set tida [thread::create -preserved];#puts <<$tida>>
    thread::send $tida {load {} Tcltest}

    set tidb [thread::create -preserved];#puts <<$tidb>>
    thread::send $tidb {load {} Tcltest}

    # Set up channel in thread
    thread::send $tida $helperscript
    set chan [thread::send $tida {
	proc foo {args} {oninit seek; onfinal; track; return}
	set chan [chan create {r w} foo]
	fconfigure $chan -buffering none
	set chan
    }]

    # Move channel to 2nd thread.
    thread::send $tida [list testchannel cut $chan]
    thread::send $tidb [list testchannel splice $chan]

    # Kill origin thread, then access channel from 2nd thread.
    thread::release $tida


    set     res {}
    lappend res [catch {thread::send $tidb [list puts  $chan shoo]} msg] $msg

    lappend res [catch {thread::send $tidb [list tell  $chan]}      msg] $msg
    lappend res [catch {thread::send $tidb [list seek  $chan 1]}    msg] $msg
    lappend res [catch {thread::send $tidb [list gets  $chan]}      msg] $msg
    lappend res [catch {thread::send $tidb [list close $chan]}      msg] $msg
    thread::release $tidb
    set res

} -constraints {testchannel thread} \
    -result {1 {Owner lost} 1 {Owner lost} 1 {Owner lost} 1 {Owner lost} 1 {Owner lost}}


# The test iocmd.tf-32.1 unavoidably exhibits a memory leak.  We are testing
# the ability of the reflected channel system to react to the situation where
# the thread in which the driver routines runs exits during driver operations.
# In this case, thread exit handlers signal back to the owner thread so that the 
# channel operation does not hang.  There's no way to test this without actually
# exiting a thread in mid-operation, and that action is unavoidably leaky (which
# is why [thread::exit] is advised against).
#
# Use constraints to skip this test while valgrinding so this expected leak
# doesn't prevent a finding of "leak-free".
#
testConstraint notValgrind [expr {![testConstraint valgrind]}]
test iocmd.tf-32.1 {origin thread of moved channel destroyed during access} -match glob -body {

    #puts <<$tcltest::mainThread>>main
    set tida [thread::create -preserved];#puts <<$tida>>
    thread::send $tida {load {} Tcltest}
    set tidb [thread::create -preserved];#puts <<$tidb>>
    thread::send $tidb {load {} Tcltest}

    # Set up channel in thread
    thread::send $tida $helperscript
    set chan [thread::send $tida {
	proc foo {args} {
	    oninit; onfinal; track;
	    # destroy thread during channel access
	    thread::exit

	    }
	set chan [chan create {r w} foo]
	fconfigure $chan -buffering none
	set chan
    }]

    # Move channel to 2nd thread.
    thread::send $tida [list testchannel cut    $chan]
    thread::send $tidb [list testchannel splice $chan]

    # Run access from thread B, wait for response from A (A is not
    # using event loop at this point, so the event pile up in the
    # queue.

    thread::send $tidb [list set chan $chan]
    thread::send $tidb [list set mid [thread::id]]
    thread::send -async $tidb {
	# wait a bit, give the main thread the time to start its event
	# loop to wait for the response from B
	after 2000
	catch { puts $chan shoo } res
	thread::send -async $mid [list set ::res $res]
    }
    vwait ::res

    catch {thread::release $tida}
    thread::release $tidb
    set res
} -constraints {testchannel thread notValgrind} \
    -result {Owner lost}

# ### ### ### ######### ######### #########

# ### ### ### ######### ######### #########

rename track {}

Changes to tests/ioTrans.test.

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest 2
    namespace import -force ::tcltest::*
}

# Custom constraints used in this file
testConstraint testchannel [llength [info commands testchannel]]
testConstraint testthread  [llength [info commands testthread]]

# testchannel cut|splice  Both needed to test the reflection in threads.
# testthread  send 

#----------------------------------------------------------------------

# ### ### ### ######### ######### #########
## Testing the reflected transformation.

# Helper commands to record the arguments to handler methods.  Stored in a







|


|







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest 2
    namespace import -force ::tcltest::*
}

# Custom constraints used in this file
testConstraint testchannel [llength [info commands testchannel]]
testConstraint thread [expr {0 == [catch {package require Thread 2.6}]}]

# testchannel cut|splice  Both needed to test the reflection in threads.
# thread::send

#----------------------------------------------------------------------

# ### ### ### ######### ######### #########
## Testing the reflected transformation.

# Helper commands to record the arguments to handler methods.  Stored in a
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
} -match glob -result {*returned bad method "BOGUS": must be clear, drain, finalize, flush, initialize, limit?, read, or write}
test iortrans-2.14 {chan push, initialize failed, bad result, mode/handler mismatch} -body {
    proc foo {args} {return {initialize finalize}}
    chan push [tempchan] foo
} -returnCodes error -cleanup {
    tempdone
    rename foo {}
} -match glob -result {*makes the channel inacessible}
# iortrans-2.15 event/watch methods elimimated, removed these tests.
# iortrans-2.16
test iortrans-2.17 {chan push, initialize failed, bad result, drain/read mismatch} -body {
    proc foo {args} {return {initialize finalize drain write}}
    chan push [tempchan] foo
} -returnCodes error -cleanup {
    tempdone







|







203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
} -match glob -result {*returned bad method "BOGUS": must be clear, drain, finalize, flush, initialize, limit?, read, or write}
test iortrans-2.14 {chan push, initialize failed, bad result, mode/handler mismatch} -body {
    proc foo {args} {return {initialize finalize}}
    chan push [tempchan] foo
} -returnCodes error -cleanup {
    tempdone
    rename foo {}
} -match glob -result {*makes the channel inaccessible}
# iortrans-2.15 event/watch methods elimimated, removed these tests.
# iortrans-2.16
test iortrans-2.17 {chan push, initialize failed, bad result, drain/read mismatch} -body {
    proc foo {args} {return {initialize finalize drain write}}
    chan push [tempchan] foo
} -returnCodes error -cleanup {
    tempdone
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
# ### ### ### ######### ######### #########
## Testing the reflected channel (Thread forwarding).
#
## The id numbers refer to the original test without thread forwarding, and
## gaps due to tests not applicable to forwarding are left to keep this
## association.

# Duplicate of code in "thread.test", and "ioCmd.test". Find a better way of
# doing this without duplication. Maybe placement into a proc which transforms
# to nop after the first call, and placement of its defintion in a central
# location.

if {[testConstraint testthread]} {
    testthread errorproc ThreadError
    proc ThreadError {id info} {
	global threadError
	set threadError $info
    }
    proc ThreadNullError {id info} {
	# ignore
    }
}

# ### ### ### ######### ######### #########
## Helper command. Runs a script in a separate thread and returns the result.
## A channel is transfered into the thread as well, and a list of configuation
## variables

proc inthread {chan script args} {
    # Test thread.
    set tid [testthread create]


    # Init thread configuration.
    # - Listed variables
    # - Id of main thread
    # - A number of helper commands

    foreach v $args {
	upvar 1 $v x
	testthread send $tid [list set $v $x]
    }
    testthread send $tid [list set mid $tcltest::mainThread]
    testthread send $tid {
	proc notes {} {
	    return $::notes
	}
	proc noteOpts opts {
	    lappend ::notes [dict merge {
		-code !?! -level !?! -errorcode !?! -errorline !?!
		-errorinfo !?! -errorstack !?!
	    } $opts]
	}
    }
    testthread send $tid [list proc s {} [list uplevel 1 $script]]; # (*)

    # Transfer channel (cut/splice aka detach/attach)

    testchannel cut $chan
    testthread send $tid [list testchannel splice $chan]

    # Run test script, also run local event loop!  The local event loop waits
    # for the result to come back.  It is also necessary for the execution of
    # forwarded channel operations.

    set ::tres ""
    testthread send -async $tid {
	after 50
	catch {s} res;	# This runs the script, 's' was defined at (*)
	testthread send -async $mid [list set ::tres $res]
    }
    vwait ::tres
    # Remove test thread, and return the captured result.

    tcltest::threadReap
    return $::tres
}

# ### ### ### ######### ######### #########

test iortrans.tf-3.2 {chan finalize, for close} -setup {
    set res {}
} -constraints {testchannel testthread} -match glob -body {
    proc foo {args} {
	lappend ::res $args
	handle.initialize
	return {}
    }
    lappend res [set c [chan push [tempchan] foo]]
    lappend res [inthread $c {
	close $c
	# Close the deleted the channel.
	file channels rt*
    } c]
    # Channel destruction does not kill handler command!
    lappend res [info command foo]
} -cleanup {
    rename foo {}
} -result {{initialize rt* {read write}} file* {finalize rt*} {} foo}
test iortrans.tf-3.3 {chan finalize, for close, error, close error} -setup {
    set res {}
} -constraints {testchannel testthread} -match glob -body {
    proc foo {args} {
	lappend ::res $args
	handle.initialize
	return -code error 5
    }
    lappend res [set c [chan push [tempchan] foo]]
    lappend res {*}[inthread $c {
	lappend notes [catch {close $c} msg] $msg
	# Channel is gone despite error.
	lappend notes [file channels rt*]
	notes
    } c]
} -cleanup {
    rename foo {}
} -result {{initialize rt* {read write}} file* {finalize rt*} 1 5 {}}
test iortrans.tf-3.4 {chan finalize, for close, error, close errror} -setup {
    set res {}
} -constraints {testchannel testthread} -body {
    proc foo {args} {
	lappend ::res $args
	handle.initialize
	error FOO
    }
    lappend res [set c [chan push [tempchan] foo]]
    lappend res {*}[inthread $c {
	lappend notes [catch {close $c} msg] $msg
	notes
    } c]
} -match glob -cleanup {
    rename foo {}
} -result {{initialize rt* {read write}} file* {finalize rt*} 1 FOO}
test iortrans.tf-3.5 {chan finalize, for close, arbitrary result} -setup {
    set res {}
} -constraints {testchannel testthread} -match glob -body {
    proc foo {args} {
	lappend ::res $args
	handle.initialize
	return SOMETHING
    }
    lappend res [set c [chan push [tempchan] foo]]
    lappend res {*}[inthread $c {
	lappend notes [catch {close $c} msg] $msg
	notes
    } c]
} -cleanup {
    rename foo {}
} -result {{initialize rt* {read write}} file* {finalize rt*} 0 {}}
test iortrans.tf-3.6 {chan finalize, for close, break, close error} -setup {
    set res {}
} -constraints {testchannel testthread} -match glob -body {
    proc foo {args} {
	lappend ::res $args
	handle.initialize
	return -code 3
    }
    lappend res [set c [chan push [tempchan] foo]]
    lappend res {*}[inthread $c {
	lappend notes [catch {close $c} msg] $msg
	notes
    } c]
} -cleanup {
    rename foo {}
} -result {{initialize rt* {read write}} file* {finalize rt*} 1 *bad code*}
test iortrans.tf-3.7 {chan finalize, for close, continue, close error} -setup {
    set res {}
} -constraints {testchannel testthread} -match glob -body {
    proc foo {args} {
	lappend ::res $args
	handle.initialize
	return -code 4
    }
    lappend res [set c [chan push [tempchan] foo]]
    lappend res {*}[inthread $c {
	lappend notes [catch {close $c} msg] $msg
	notes
    } c]
} -cleanup {
    rename foo {}
} -result {{initialize rt* {read write}} file* {finalize rt*} 1 *bad code*}
test iortrans.tf-3.8 {chan finalize, for close, custom code, close error} -setup {
    set res {}
} -constraints {testchannel testthread} -match glob -body {
    proc foo {args} {
	lappend ::res $args
	handle.initialize
	return -code 777 BANG
    }
    lappend res [set c [chan push [tempchan] foo]]
    lappend res {*}[inthread $c {
	lappend notes [catch {close $c} msg] $msg
	notes
    } c]
} -cleanup {
    rename foo {}
} -result {{initialize rt* {read write}} file* {finalize rt*} 1 *bad code*}
test iortrans.tf-3.9 {chan finalize, for close, ignore level, close error} -setup {
    set res {}
} -constraints {testchannel testthread} -match glob -body {
    proc foo {args} {
	lappend ::res $args
	handle.initialize
	return -level 5 -code 777 BANG
    }
    lappend res [set c [chan push [tempchan] foo]]
    lappend res {*}[inthread $c {
	lappend notes [catch {close $c} msg opt] $msg
	noteOpts $opt
	notes
    } c]
} -cleanup {
    rename foo {}
} -result {{initialize rt* {read write}} file* {finalize rt*} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "finalize"*}}

# --- === *** ###########################
# method read

test iortrans.tf-4.1 {chan read, transform call and return} -setup {
    set res {}
} -constraints {testchannel testthread} -body {
    proc foo {args} {
	handle.initialize
	handle.finalize
	lappend ::res $args
	return snarf
    }
    set c [chan push [tempchan] foo]
    lappend res {*}[inthread $c {
	lappend notes [read $c 10]
	close $c
	notes
    } c]
} -cleanup {
    tempdone
    rename foo {}
} -match glob -result {{read rt* {test data
}} snarf}
test iortrans.tf-4.2 {chan read, for non-readable channel} -setup {
    set res {}
} -constraints {testchannel testthread} -body {
    proc foo {args} {
	handle.initialize
	handle.finalize
	lappend ::res $args MUST_NOT_HAPPEN
    }
    set c [chan push [tempchan w] foo]
    lappend res {*}[inthread $c {
	lappend notes [catch {[read $c 2]} msg] $msg
	close $c
	notes
    } c]
} -cleanup {
    tempdone
    rename foo {}
} -match glob -result {1 {channel "file*" wasn't opened for reading}}
test iortrans.tf-4.3 {chan read, error return} -setup {
    set res {}
} -constraints {testchannel testthread} -body {
    proc foo {args} {
	handle.initialize
	handle.finalize
	lappend ::res $args
	return -code error BOOM!
    }
    set c [chan push [tempchan] foo]
    lappend res {*}[inthread $c {
	lappend notes [catch {read $c 2} msg] $msg
	close $c
	notes
    } c]
} -cleanup {
    tempdone
    rename foo {}
} -match glob -result {{read rt* {test data
}} 1 BOOM!}
test iortrans.tf-4.4 {chan read, break return is error} -setup {
    set res {}
} -constraints {testchannel testthread} -body {
    proc foo {args} {
	handle.initialize
	handle.finalize
	lappend ::res $args
	return -code break BOOM!
    }
    set c [chan push [tempchan] foo]
    lappend res {*}[inthread $c {
	lappend notes [catch {read $c 2} msg] $msg
	close $c
	notes
    } c]
} -cleanup {
    tempdone
    rename foo {}
} -match glob -result {{read rt* {test data
}} 1 *bad code*}
test iortrans.tf-4.5 {chan read, continue return is error} -setup {
    set res {}
} -constraints {testchannel testthread} -body {
    proc foo {args} {
	handle.initialize
	handle.finalize
	lappend ::res $args
	return -code continue BOOM!
    }
    set c [chan push [tempchan] foo]
    lappend res {*}[inthread $c {
	lappend notes [catch {read $c 2} msg] $msg
	close $c
	notes
    } c]
} -cleanup {
    tempdone
    rename foo {}
} -match glob -result {{read rt* {test data
}} 1 *bad code*}
test iortrans.tf-4.6 {chan read, custom return is error} -setup {
    set res {}
} -constraints {testchannel testthread} -body {
    proc foo {args} {
	handle.initialize
	handle.finalize
	lappend ::res $args
	return -code 777 BOOM!
    }
    set c [chan push [tempchan] foo]
    lappend res {*}[inthread $c {
	lappend notes [catch {read $c 2} msg] $msg
	close $c
	notes
    } c]
} -cleanup {
    tempdone
    rename foo {}
} -match glob -result {{read rt* {test data
}} 1 *bad code*}
test iortrans.tf-4.7 {chan read, level is squashed} -setup {
    set res {}
} -constraints {testchannel testthread} -body {
    proc foo {args} {
	handle.initialize
	handle.finalize
	lappend ::res $args
	return -level 55 -code 777 BOOM!
    }
    set c [chan push [tempchan] foo]







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







|
>








|

|
|










|




|






|


|




|







|


















|

















|















|















|















|















|















|




















|



















|

















|



















|



















|



















|



















|







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
# ### ### ### ######### ######### #########
## Testing the reflected channel (Thread forwarding).
#
## The id numbers refer to the original test without thread forwarding, and
## gaps due to tests not applicable to forwarding are left to keep this
## association.

















# ### ### ### ######### ######### #########
## Helper command. Runs a script in a separate thread and returns the result.
## A channel is transfered into the thread as well, and a list of configuation
## variables

proc inthread {chan script args} {
    # Test thread.
    set tid [thread::create -preserved]
    thread::send $tid {load {} Tcltest}

    # Init thread configuration.
    # - Listed variables
    # - Id of main thread
    # - A number of helper commands

    foreach v $args {
	upvar 1 $v x
	thread::send $tid [list set $v $x]
    }
    thread::send $tid [list set mid [thread::id]]
    thread::send $tid {
	proc notes {} {
	    return $::notes
	}
	proc noteOpts opts {
	    lappend ::notes [dict merge {
		-code !?! -level !?! -errorcode !?! -errorline !?!
		-errorinfo !?! -errorstack !?!
	    } $opts]
	}
    }
    thread::send $tid [list proc s {} [list uplevel 1 $script]]; # (*)

    # Transfer channel (cut/splice aka detach/attach)

    testchannel cut $chan
    thread::send $tid [list testchannel splice $chan]

    # Run test script, also run local event loop!  The local event loop waits
    # for the result to come back.  It is also necessary for the execution of
    # forwarded channel operations.

    set ::tres ""
    thread::send -async $tid {	
	after 50
	catch {s} res;	# This runs the script, 's' was defined at (*)
	thread::send -async $mid [list set ::tres $res]
    }
    vwait ::tres
    # Remove test thread, and return the captured result.

    thread::release $tid
    return $::tres
}

# ### ### ### ######### ######### #########

test iortrans.tf-3.2 {chan finalize, for close} -setup {
    set res {}
} -constraints {testchannel thread} -match glob -body {
    proc foo {args} {
	lappend ::res $args
	handle.initialize
	return {}
    }
    lappend res [set c [chan push [tempchan] foo]]
    lappend res [inthread $c {
	close $c
	# Close the deleted the channel.
	file channels rt*
    } c]
    # Channel destruction does not kill handler command!
    lappend res [info command foo]
} -cleanup {
    rename foo {}
} -result {{initialize rt* {read write}} file* {finalize rt*} {} foo}
test iortrans.tf-3.3 {chan finalize, for close, error, close error} -setup {
    set res {}
} -constraints {testchannel thread} -match glob -body {
    proc foo {args} {
	lappend ::res $args
	handle.initialize
	return -code error 5
    }
    lappend res [set c [chan push [tempchan] foo]]
    lappend res {*}[inthread $c {
	lappend notes [catch {close $c} msg] $msg
	# Channel is gone despite error.
	lappend notes [file channels rt*]
	notes
    } c]
} -cleanup {
    rename foo {}
} -result {{initialize rt* {read write}} file* {finalize rt*} 1 5 {}}
test iortrans.tf-3.4 {chan finalize, for close, error, close errror} -setup {
    set res {}
} -constraints {testchannel thread} -body {
    proc foo {args} {
	lappend ::res $args
	handle.initialize
	error FOO
    }
    lappend res [set c [chan push [tempchan] foo]]
    lappend res {*}[inthread $c {
	lappend notes [catch {close $c} msg] $msg
	notes
    } c]
} -match glob -cleanup {
    rename foo {}
} -result {{initialize rt* {read write}} file* {finalize rt*} 1 FOO}
test iortrans.tf-3.5 {chan finalize, for close, arbitrary result} -setup {
    set res {}
} -constraints {testchannel thread} -match glob -body {
    proc foo {args} {
	lappend ::res $args
	handle.initialize
	return SOMETHING
    }
    lappend res [set c [chan push [tempchan] foo]]
    lappend res {*}[inthread $c {
	lappend notes [catch {close $c} msg] $msg
	notes
    } c]
} -cleanup {
    rename foo {}
} -result {{initialize rt* {read write}} file* {finalize rt*} 0 {}}
test iortrans.tf-3.6 {chan finalize, for close, break, close error} -setup {
    set res {}
} -constraints {testchannel thread} -match glob -body {
    proc foo {args} {
	lappend ::res $args
	handle.initialize
	return -code 3
    }
    lappend res [set c [chan push [tempchan] foo]]
    lappend res {*}[inthread $c {
	lappend notes [catch {close $c} msg] $msg
	notes
    } c]
} -cleanup {
    rename foo {}
} -result {{initialize rt* {read write}} file* {finalize rt*} 1 *bad code*}
test iortrans.tf-3.7 {chan finalize, for close, continue, close error} -setup {
    set res {}
} -constraints {testchannel thread} -match glob -body {
    proc foo {args} {
	lappend ::res $args
	handle.initialize
	return -code 4
    }
    lappend res [set c [chan push [tempchan] foo]]
    lappend res {*}[inthread $c {
	lappend notes [catch {close $c} msg] $msg
	notes
    } c]
} -cleanup {
    rename foo {}
} -result {{initialize rt* {read write}} file* {finalize rt*} 1 *bad code*}
test iortrans.tf-3.8 {chan finalize, for close, custom code, close error} -setup {
    set res {}
} -constraints {testchannel thread} -match glob -body {
    proc foo {args} {
	lappend ::res $args
	handle.initialize
	return -code 777 BANG
    }
    lappend res [set c [chan push [tempchan] foo]]
    lappend res {*}[inthread $c {
	lappend notes [catch {close $c} msg] $msg
	notes
    } c]
} -cleanup {
    rename foo {}
} -result {{initialize rt* {read write}} file* {finalize rt*} 1 *bad code*}
test iortrans.tf-3.9 {chan finalize, for close, ignore level, close error} -setup {
    set res {}
} -constraints {testchannel thread} -match glob -body {
    proc foo {args} {
	lappend ::res $args
	handle.initialize
	return -level 5 -code 777 BANG
    }
    lappend res [set c [chan push [tempchan] foo]]
    lappend res {*}[inthread $c {
	lappend notes [catch {close $c} msg opt] $msg
	noteOpts $opt
	notes
    } c]
} -cleanup {
    rename foo {}
} -result {{initialize rt* {read write}} file* {finalize rt*} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "finalize"*}}

# --- === *** ###########################
# method read

test iortrans.tf-4.1 {chan read, transform call and return} -setup {
    set res {}
} -constraints {testchannel thread} -body {
    proc foo {args} {
	handle.initialize
	handle.finalize
	lappend ::res $args
	return snarf
    }
    set c [chan push [tempchan] foo]
    lappend res {*}[inthread $c {
	lappend notes [read $c 10]
	close $c
	notes
    } c]
} -cleanup {
    tempdone
    rename foo {}
} -match glob -result {{read rt* {test data
}} snarf}
test iortrans.tf-4.2 {chan read, for non-readable channel} -setup {
    set res {}
} -constraints {testchannel thread} -body {
    proc foo {args} {
	handle.initialize
	handle.finalize
	lappend ::res $args MUST_NOT_HAPPEN
    }
    set c [chan push [tempchan w] foo]
    lappend res {*}[inthread $c {
	lappend notes [catch {[read $c 2]} msg] $msg
	close $c
	notes
    } c]
} -cleanup {
    tempdone
    rename foo {}
} -match glob -result {1 {channel "file*" wasn't opened for reading}}
test iortrans.tf-4.3 {chan read, error return} -setup {
    set res {}
} -constraints {testchannel thread} -body {
    proc foo {args} {
	handle.initialize
	handle.finalize
	lappend ::res $args
	return -code error BOOM!
    }
    set c [chan push [tempchan] foo]
    lappend res {*}[inthread $c {
	lappend notes [catch {read $c 2} msg] $msg
	close $c
	notes
    } c]
} -cleanup {
    tempdone
    rename foo {}
} -match glob -result {{read rt* {test data
}} 1 BOOM!}
test iortrans.tf-4.4 {chan read, break return is error} -setup {
    set res {}
} -constraints {testchannel thread} -body {
    proc foo {args} {
	handle.initialize
	handle.finalize
	lappend ::res $args
	return -code break BOOM!
    }
    set c [chan push [tempchan] foo]
    lappend res {*}[inthread $c {
	lappend notes [catch {read $c 2} msg] $msg
	close $c
	notes
    } c]
} -cleanup {
    tempdone
    rename foo {}
} -match glob -result {{read rt* {test data
}} 1 *bad code*}
test iortrans.tf-4.5 {chan read, continue return is error} -setup {
    set res {}
} -constraints {testchannel thread} -body {
    proc foo {args} {
	handle.initialize
	handle.finalize
	lappend ::res $args
	return -code continue BOOM!
    }
    set c [chan push [tempchan] foo]
    lappend res {*}[inthread $c {
	lappend notes [catch {read $c 2} msg] $msg
	close $c
	notes
    } c]
} -cleanup {
    tempdone
    rename foo {}
} -match glob -result {{read rt* {test data
}} 1 *bad code*}
test iortrans.tf-4.6 {chan read, custom return is error} -setup {
    set res {}
} -constraints {testchannel thread} -body {
    proc foo {args} {
	handle.initialize
	handle.finalize
	lappend ::res $args
	return -code 777 BOOM!
    }
    set c [chan push [tempchan] foo]
    lappend res {*}[inthread $c {
	lappend notes [catch {read $c 2} msg] $msg
	close $c
	notes
    } c]
} -cleanup {
    tempdone
    rename foo {}
} -match glob -result {{read rt* {test data
}} 1 *bad code*}
test iortrans.tf-4.7 {chan read, level is squashed} -setup {
    set res {}
} -constraints {testchannel thread} -body {
    proc foo {args} {
	handle.initialize
	handle.finalize
	lappend ::res $args
	return -level 55 -code 777 BOOM!
    }
    set c [chan push [tempchan] foo]
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
}} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "read"*}}

# --- === *** ###########################
# method write

test iortrans.tf-5.1 {chan write, regular write} -setup {
    set res {}
} -constraints {testchannel testthread} -match glob -body {
    proc foo {args} {
	handle.initialize
	handle.finalize
	lappend ::res $args
	return transformresult
    }
    set c [chan push [tempchan] foo]
    inthread $c {
	puts -nonewline $c snarf
	flush $c
	close $c
    } c
    lappend res [tempview]
} -cleanup {
    tempdone
    rename foo {}
} -result {{write rt* snarf} transformresult}
test iortrans.tf-5.2 {chan write, no write is ok, no change to file} -setup {
    set res {}
} -constraints {testchannel testthread} -match glob -body {
    proc foo {args} {
	handle.initialize
	handle.finalize
	lappend ::res $args
	return
    }
    set c [chan push [tempchan] foo]
    inthread $c {
	puts -nonewline $c snarfsnarfsnarf
	flush $c
	close $c
    } c
    lappend res [tempview];	# This has to show the original data, as nothing was written
} -cleanup {
    tempdone
    rename foo {}
} -result {{write rt* snarfsnarfsnarf} {test data}}
test iortrans.tf-5.3 {chan write, failed write} -setup {
    set res {}
} -constraints {testchannel testthread} -match glob -body {
    proc foo {args} {
	handle.initialize
	handle.finalize
	lappend ::res $args
	return -code error FAIL!
    }
    set c [chan push [tempchan] foo]
    lappend res {*}[inthread $c {
	puts -nonewline $c snarfsnarfsnarf
	lappend notes [catch {flush $c} msg] $msg
	close $c
	notes
    } c]
} -cleanup {
    tempdone
    rename foo {}
} -result {{write rt* snarfsnarfsnarf} 1 FAIL!}
test iortrans.tf-5.4 {chan write, non-writable channel} -setup {
    set res {}
} -constraints {testchannel testthread} -match glob -body {
    proc foo {args} {
	handle.initialize
	handle.finalize
	lappend ::res $args MUST_NOT_HAPPEN
	return
    }
    set c [chan push [tempchan r] foo]







|



















|



















|



















|







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
}} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline 1 -errorinfo *bad code*subcommand "read"*}}

# --- === *** ###########################
# method write

test iortrans.tf-5.1 {chan write, regular write} -setup {
    set res {}
} -constraints {testchannel thread} -match glob -body {
    proc foo {args} {
	handle.initialize
	handle.finalize
	lappend ::res $args
	return transformresult
    }
    set c [chan push [tempchan] foo]
    inthread $c {
	puts -nonewline $c snarf
	flush $c
	close $c
    } c
    lappend res [tempview]
} -cleanup {
    tempdone
    rename foo {}
} -result {{write rt* snarf} transformresult}
test iortrans.tf-5.2 {chan write, no write is ok, no change to file} -setup {
    set res {}
} -constraints {testchannel thread} -match glob -body {
    proc foo {args} {
	handle.initialize
	handle.finalize
	lappend ::res $args
	return
    }
    set c [chan push [tempchan] foo]
    inthread $c {
	puts -nonewline $c snarfsnarfsnarf
	flush $c
	close $c
    } c
    lappend res [tempview];	# This has to show the original data, as nothing was written
} -cleanup {
    tempdone
    rename foo {}
} -result {{write rt* snarfsnarfsnarf} {test data}}
test iortrans.tf-5.3 {chan write, failed write} -setup {
    set res {}
} -constraints {testchannel thread} -match glob -body {
    proc foo {args} {
	handle.initialize
	handle.finalize
	lappend ::res $args
	return -code error FAIL!
    }
    set c [chan push [tempchan] foo]
    lappend res {*}[inthread $c {
	puts -nonewline $c snarfsnarfsnarf
	lappend notes [catch {flush $c} msg] $msg
	close $c
	notes
    } c]
} -cleanup {
    tempdone
    rename foo {}
} -result {{write rt* snarfsnarfsnarf} 1 FAIL!}
test iortrans.tf-5.4 {chan write, non-writable channel} -setup {
    set res {}
} -constraints {testchannel thread} -match glob -body {
    proc foo {args} {
	handle.initialize
	handle.finalize
	lappend ::res $args MUST_NOT_HAPPEN
	return
    }
    set c [chan push [tempchan r] foo]
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
    } c]
} -cleanup {
    tempdone
    rename foo {}
} -result {1 {channel "file*" wasn't opened for writing}}
test iortrans.tf-5.5 {chan write, failed write, error return} -setup {
    set res {}
} -constraints {testchannel testthread} -match glob -body {
    proc foo {args} {
	handle.initialize
	handle.finalize
	lappend ::res $args
	return -code error BOOM!
    }
    set c [chan push [tempchan] foo]







|







1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
    } c]
} -cleanup {
    tempdone
    rename foo {}
} -result {1 {channel "file*" wasn't opened for writing}}
test iortrans.tf-5.5 {chan write, failed write, error return} -setup {
    set res {}
} -constraints {testchannel thread} -match glob -body {
    proc foo {args} {
	handle.initialize
	handle.finalize
	lappend ::res $args
	return -code error BOOM!
    }
    set c [chan push [tempchan] foo]
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
    } c]
} -cleanup {
    tempdone
    rename foo {}
} -result {{write rt* snarfsnarfsnarf} 1 BOOM!}
test iortrans.tf-5.6 {chan write, failed write, error return} -setup {
    set res {}
} -constraints {testchannel testthread} -match glob -body {
    proc foo {args} {
	handle.initialize
	handle.finalize
	lappend ::res $args
	error BOOM!
    }
    set c [chan push [tempchan] foo]







|







1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
    } c]
} -cleanup {
    tempdone
    rename foo {}
} -result {{write rt* snarfsnarfsnarf} 1 BOOM!}
test iortrans.tf-5.6 {chan write, failed write, error return} -setup {
    set res {}
} -constraints {testchannel thread} -match glob -body {
    proc foo {args} {
	handle.initialize
	handle.finalize
	lappend ::res $args
	error BOOM!
    }
    set c [chan push [tempchan] foo]
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
    } c]
} -cleanup {
    tempdone
    rename foo {}
} -result {{write rt* snarfsnarfsnarf} 1 BOOM!}
test iortrans.tf-5.7 {chan write, failed write, break return is error} -setup {
    set res {}
} -constraints {testchannel testthread} -match glob -body {
    proc foo {args} {
	handle.initialize
	handle.finalize
	lappend ::res $args
	return -code break BOOM!
    }
    set c [chan push [tempchan] foo]







|







1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
    } c]
} -cleanup {
    tempdone
    rename foo {}
} -result {{write rt* snarfsnarfsnarf} 1 BOOM!}
test iortrans.tf-5.7 {chan write, failed write, break return is error} -setup {
    set res {}
} -constraints {testchannel thread} -match glob -body {
    proc foo {args} {
	handle.initialize
	handle.finalize
	lappend ::res $args
	return -code break BOOM!
    }
    set c [chan push [tempchan] foo]
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
    } c]
} -cleanup {
    tempdone
    rename foo {}
} -result {{write rt* snarfsnarfsnarf} 1 *bad code*}
test iortrans.tf-5.8 {chan write, failed write, continue return is error} -setup {
    set res {}
} -constraints {testchannel testthread} -match glob -body {
    proc foo {args} {
	handle.initialize
	handle.finalize
	lappend ::res $args
	return -code continue BOOM!
    }
    set c [chan push [tempchan] foo]
    lappend res {*}[inthread $c {
	lappend notes [catch {
	    puts -nonewline $c snarfsnarfsnarf
	    flush $c
	} msg] $msg
	close $c
	notes
    } c]
} -cleanup {
    rename foo {}
} -result {{write rt* snarfsnarfsnarf} 1 *bad code*}
test iortrans.tf-5.9 {chan write, failed write, custom return is error} -setup {
    set res {}
} -constraints {testchannel testthread} -body {
    proc foo {args} {
	handle.initialize
	handle.finalize
	lappend ::res $args
	return -code 777 BOOM!
    }
    set c [chan push [tempchan] foo]







|




















|







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
    } c]
} -cleanup {
    tempdone
    rename foo {}
} -result {{write rt* snarfsnarfsnarf} 1 *bad code*}
test iortrans.tf-5.8 {chan write, failed write, continue return is error} -setup {
    set res {}
} -constraints {testchannel thread} -match glob -body {
    proc foo {args} {
	handle.initialize
	handle.finalize
	lappend ::res $args
	return -code continue BOOM!
    }
    set c [chan push [tempchan] foo]
    lappend res {*}[inthread $c {
	lappend notes [catch {
	    puts -nonewline $c snarfsnarfsnarf
	    flush $c
	} msg] $msg
	close $c
	notes
    } c]
} -cleanup {
    rename foo {}
} -result {{write rt* snarfsnarfsnarf} 1 *bad code*}
test iortrans.tf-5.9 {chan write, failed write, custom return is error} -setup {
    set res {}
} -constraints {testchannel thread} -body {
    proc foo {args} {
	handle.initialize
	handle.finalize
	lappend ::res $args
	return -code 777 BOOM!
    }
    set c [chan push [tempchan] foo]
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
    } c]
} -cleanup {
    tempdone
    rename foo {}
} -match glob -result {{write rt* snarfsnarfsnarf} 1 *bad code*}
test iortrans.tf-5.10 {chan write, failed write, level is ignored} -setup {
    set res {}
} -constraints {testchannel testthread} -match glob -body {
    proc foo {args} {
	handle.initialize
	handle.finalize
	lappend ::res $args
	return -level 55 -code 777 BOOM!
    }
    set c [chan push [tempchan] foo]







|







1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
    } c]
} -cleanup {
    tempdone
    rename foo {}
} -match glob -result {{write rt* snarfsnarfsnarf} 1 *bad code*}
test iortrans.tf-5.10 {chan write, failed write, level is ignored} -setup {
    set res {}
} -constraints {testchannel thread} -match glob -body {
    proc foo {args} {
	handle.initialize
	handle.finalize
	lappend ::res $args
	return -level 55 -code 777 BOOM!
    }
    set c [chan push [tempchan] foo]
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
} -result {{write rt* snarfsnarfsnarf} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline * -errorinfo *bad code*subcommand "write"*}}

# --- === *** ###########################
# method limit?, drain (via read)

test iortrans.tf-6.1 {chan read, read limits} -setup {
    set res {}
} -constraints {testchannel testthread} -match glob -body {
    proc foo {args} {
	handle.initialize limit?
	handle.finalize
	lappend ::res $args
	handle.read
	return 6
    }
    set c [chan push [tempchan] foo]
    lappend res {*}[inthread $c {
	lappend notes [read $c 10]
	close $c
	notes
    } c]
} -cleanup {
    tempdone
    rename foo {}
} -result {{limit? rt*} {read rt* {test d}} {limit? rt*} {read rt* {ata
}} {limit? rt*} @@}
test iortrans.tf-6.2 {chan read, read transform drain on eof} -setup {
    set res {}
} -constraints {testchannel testthread} -match glob -body {
    proc foo {args} {
	handle.initialize drain
	handle.finalize
	lappend ::res $args
	handle.read
	handle.drain
	return







|




















|







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
} -result {{write rt* snarfsnarfsnarf} 1 *bad code* {-code 1 -level 0 -errorcode NONE -errorline * -errorinfo *bad code*subcommand "write"*}}

# --- === *** ###########################
# method limit?, drain (via read)

test iortrans.tf-6.1 {chan read, read limits} -setup {
    set res {}
} -constraints {testchannel thread} -match glob -body {
    proc foo {args} {
	handle.initialize limit?
	handle.finalize
	lappend ::res $args
	handle.read
	return 6
    }
    set c [chan push [tempchan] foo]
    lappend res {*}[inthread $c {
	lappend notes [read $c 10]
	close $c
	notes
    } c]
} -cleanup {
    tempdone
    rename foo {}
} -result {{limit? rt*} {read rt* {test d}} {limit? rt*} {read rt* {ata
}} {limit? rt*} @@}
test iortrans.tf-6.2 {chan read, read transform drain on eof} -setup {
    set res {}
} -constraints {testchannel thread} -match glob -body {
    proc foo {args} {
	handle.initialize drain
	handle.finalize
	lappend ::res $args
	handle.read
	handle.drain
	return
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
}} {drain rt*} @<> {}}

# --- === *** ###########################
# method clear (via puts, seek)

test iortrans.tf-7.1 {chan write, write clears read buffers} -setup {
    set res {}
} -constraints {testchannel testthread} -match glob -body {
    proc foo {args} {
	handle.initialize clear
	handle.finalize
	lappend ::res $args
	handle.clear
	return transformresult
    }
    set c [chan push [tempchan] foo]
    inthread $c {
	puts -nonewline $c snarf
	flush $c
	close $c
    } c
    return $res
} -cleanup {
    tempdone
    rename foo {}
} -result {{clear rt*} {write rt* snarf}}
test iortrans.tf-7.2 {seek clears read buffers} -setup {
    set res {}
} -constraints {testchannel testthread} -match glob -body {
    proc foo {args} {
	handle.initialize clear
	handle.finalize
	lappend ::res $args
	return
    }
    set c [chan push [tempchan] foo]
    inthread $c {
	seek $c 2
	close $c
    } c
    return $res
} -cleanup {
    tempdone
    rename foo {}
} -result {{clear rt*}}
test iortrans.tf-7.3 {clear, any result is ignored} -setup {
    set res {}
} -constraints {testchannel testthread} -match glob -body {
    proc foo {args} {
	handle.initialize clear
	handle.finalize
	lappend ::res $args
	return -code error "X"
    }
    set c [chan push [tempchan] foo]







|




















|


















|







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
}} {drain rt*} @<> {}}

# --- === *** ###########################
# method clear (via puts, seek)

test iortrans.tf-7.1 {chan write, write clears read buffers} -setup {
    set res {}
} -constraints {testchannel thread} -match glob -body {
    proc foo {args} {
	handle.initialize clear
	handle.finalize
	lappend ::res $args
	handle.clear
	return transformresult
    }
    set c [chan push [tempchan] foo]
    inthread $c {
	puts -nonewline $c snarf
	flush $c
	close $c
    } c
    return $res
} -cleanup {
    tempdone
    rename foo {}
} -result {{clear rt*} {write rt* snarf}}
test iortrans.tf-7.2 {seek clears read buffers} -setup {
    set res {}
} -constraints {testchannel thread} -match glob -body {
    proc foo {args} {
	handle.initialize clear
	handle.finalize
	lappend ::res $args
	return
    }
    set c [chan push [tempchan] foo]
    inthread $c {
	seek $c 2
	close $c
    } c
    return $res
} -cleanup {
    tempdone
    rename foo {}
} -result {{clear rt*}}
test iortrans.tf-7.3 {clear, any result is ignored} -setup {
    set res {}
} -constraints {testchannel thread} -match glob -body {
    proc foo {args} {
	handle.initialize clear
	handle.finalize
	lappend ::res $args
	return -code error "X"
    }
    set c [chan push [tempchan] foo]
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
} -result {{clear rt*}}

# --- === *** ###########################
# method flush (via seek, close)

test iortrans.tf-8.1 {seek flushes write buffers, ignores data} -setup {
    set res {}
} -constraints {testchannel testthread} -match glob -body {
    proc foo {args} {
	handle.initialize flush
	handle.finalize
	lappend ::res $args
	return X
    }
    set c [chan push [tempchan] foo]







|







1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
} -result {{clear rt*}}

# --- === *** ###########################
# method flush (via seek, close)

test iortrans.tf-8.1 {seek flushes write buffers, ignores data} -setup {
    set res {}
} -constraints {testchannel thread} -match glob -body {
    proc foo {args} {
	handle.initialize flush
	handle.finalize
	lappend ::res $args
	return X
    }
    set c [chan push [tempchan] foo]
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
    lappend res [tempview]
} -cleanup {
    tempdone
    rename foo {}
} -result {{flush rt*} {flush rt*} | {} | {teXt data}}
test iortrans.tf-8.2 {close flushes write buffers, writes data} -setup {
    set res {}
} -constraints {testchannel testthread} -match glob -body {
    proc foo {args} {
	handle.initialize flush
	lappend ::res $args
	handle.finalize
	return .flushed.
    }
    set c [chan push [tempchan] foo]







|







1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
    lappend res [tempview]
} -cleanup {
    tempdone
    rename foo {}
} -result {{flush rt*} {flush rt*} | {} | {teXt data}}
test iortrans.tf-8.2 {close flushes write buffers, writes data} -setup {
    set res {}
} -constraints {testchannel thread} -match glob -body {
    proc foo {args} {
	handle.initialize flush
	lappend ::res $args
	handle.finalize
	return .flushed.
    }
    set c [chan push [tempchan] foo]
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
# --- === *** ###########################
# 'Pull the rug' tests. Create channel in a thread A, move to other thread B,
# destroy the origin thread (A) before or during access from B. Must not
# crash, must return proper errors.

test iortrans.tf-11.0 {origin thread of moved transform gone} -setup {
    #puts <<$tcltest::mainThread>>main
    set tida [testthread create];	#puts <<$tida>>

    set tidb [testthread create];	#puts <<$tidb>>

} -constraints {testchannel testthread} -match glob -body {
    # Set up channel in thread
    testthread send $tida $helperscript

    set chan [testthread send $tida {
	proc foo {args} {
	    handle.initialize clear drain flush limit? read write
	    handle.finalize
	    lappend ::res $args
	    return
	}
	set chan [chan push [tempchan] foo]
	fconfigure $chan -buffering none
	set chan
    }]

    # Move channel to 2nd thread, transform goes with it.
    testthread send $tida [list testchannel cut $chan]
    testthread send $tidb [list testchannel splice $chan]

    # Kill origin thread, then access channel from 2nd thread.
    testthread send -async $tida {testthread exit}
    after 50
    set res {}
    lappend res [catch {testthread send $tidb [list puts $chan shoo]} msg] $msg
    lappend res [catch {testthread send $tidb [list tell $chan]} msg] $msg
    lappend res [catch {testthread send $tidb [list seek $chan 1]} msg] $msg
    lappend res [catch {testthread send $tidb [list gets $chan]} msg] $msg
    lappend res [catch {testthread send $tidb [list close $chan]} msg] $msg
    # The 'tell' is ok, as it passed through the transform to the base
    # channel without invoking the transform handler.
} -cleanup {
    tcltest::threadReap
    tempdone

} -result {1 {Owner lost} 0 0 1 {Owner lost} 1 {Owner lost} 1 {Owner lost}}



test iortrans.tf-11.1 {origin thread of moved transform destroyed during access} -setup {
    #puts <<$tcltest::mainThread>>main
    set tida [testthread create];	#puts <<$tida>>

    set tidb [testthread create];	#puts <<$tidb>>

} -constraints {testchannel testthread} -match glob -body {
    # Set up channel in thread
    set chan [testthread send $tida $helperscript]

    set chan [testthread send $tida {
	proc foo {args} {
	    handle.initialize clear drain flush limit? read write
	    handle.finalize
	    lappend ::res $args
	    # destroy thread during channel access
	    testthread exit
	    return
	}
	set chan [chan push [tempchan] foo]
	fconfigure $chan -buffering none
	set chan
    }]

    # Move channel to 2nd thread, transform goes with it.
    testthread send $tida [list testchannel cut $chan]
    testthread send $tidb [list testchannel splice $chan]

    # Run access from thread B, wait for response from A (A is not using event
    # loop at this point, so the event pile up in the queue.
    testthread send $tidb [list set chan $chan]
    testthread send $tidb [list set mid $tcltest::mainThread]
    testthread send -async $tidb {
	# Wait a bit, give the main thread the time to start its event loop to
	# wait for the response from B
	after 50
	catch { puts $chan shoo } res
	catch { close $chan }
	testthread send -async $mid [list set ::res $res]
    }
    vwait ::res
    return $res
} -cleanup {
    tcltest::threadReap
    tempdone

} -result {Owner lost}

# ### ### ### ######### ######### #########

cleanupTests
return







|
>
|
>
|

|
>
|










>

|
|
>

|
|

|
|
|
|
|



<
|
>

>
>
>


|
>
|
>
|

|
>
|





|
<





>

|
|
>


|
|
|





|


|

<
|
>






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
# --- === *** ###########################
# 'Pull the rug' tests. Create channel in a thread A, move to other thread B,
# destroy the origin thread (A) before or during access from B. Must not
# crash, must return proper errors.

test iortrans.tf-11.0 {origin thread of moved transform gone} -setup {
    #puts <<$tcltest::mainThread>>main
    set tida [thread::create -preserved];	#puts <<$tida>>
    thread::send $tida {load {} Tcltest}
    set tidb [thread::create -preserved];	#puts <<$tida>>
    thread::send $tidb {load {} Tcltest}
} -constraints {testchannel thread} -match glob -body {
    # Set up channel in thread
    thread::send $tida $helperscript
    thread::send $tidb $helperscript
    set chan [thread::send $tida {
	proc foo {args} {
	    handle.initialize clear drain flush limit? read write
	    handle.finalize
	    lappend ::res $args
	    return
	}
	set chan [chan push [tempchan] foo]
	fconfigure $chan -buffering none
	set chan
    }]

    # Move channel to 2nd thread, transform goes with it.
    thread::send $tida [list testchannel cut $chan]
    thread::send $tidb [list testchannel splice $chan]

    # Kill origin thread, then access channel from 2nd thread.
    thread::release -wait $tida

    set res {}
    lappend res [catch {thread::send $tidb [list puts $chan shoo]} msg] $msg
    lappend res [catch {thread::send $tidb [list tell $chan]} msg] $msg
    lappend res [catch {thread::send $tidb [list seek $chan 1]} msg] $msg
    lappend res [catch {thread::send $tidb [list gets $chan]} msg] $msg
    lappend res [catch {thread::send $tidb [list close $chan]} msg] $msg
    # The 'tell' is ok, as it passed through the transform to the base
    # channel without invoking the transform handler.
} -cleanup {

    thread::send $tidb tempdone
    thread::release $tidb
} -result {1 {Owner lost} 0 0 1 {Owner lost} 1 {Owner lost} 1 {Owner lost}}

testConstraint notValgrind [expr {![testConstraint valgrind]}]

test iortrans.tf-11.1 {origin thread of moved transform destroyed during access} -setup {
    #puts <<$tcltest::mainThread>>main
    set tida [thread::create -preserved];	#puts <<$tida>>
    thread::send $tida {load {} Tcltest}
    set tidb [thread::create -preserved];	#puts <<$tidb>>
    thread::send $tidb {load {} Tcltest}
} -constraints {testchannel thread notValgrind} -match glob -body {
    # Set up channel in thread
    thread::send $tida $helperscript
    thread::send $tidb $helperscript
    set chan [thread::send $tida {
	proc foo {args} {
	    handle.initialize clear drain flush limit? read write
	    handle.finalize
	    lappend ::res $args
	    # destroy thread during channel access
	    thread::exit

	}
	set chan [chan push [tempchan] foo]
	fconfigure $chan -buffering none
	set chan
    }]

    # Move channel to 2nd thread, transform goes with it.
    thread::send $tida [list testchannel cut $chan]
    thread::send $tidb [list testchannel splice $chan]

    # Run access from thread B, wait for response from A (A is not using event
    # loop at this point, so the event pile up in the queue.
    thread::send $tidb [list set chan $chan]
    thread::send $tidb [list set mid [thread::id]]
    thread::send -async $tidb {
	# Wait a bit, give the main thread the time to start its event loop to
	# wait for the response from B
	after 50
	catch { puts $chan shoo } res
	catch { close $chan }
	thread::send -async $mid [list set ::res $res]
    }
    vwait ::res
    set res
} -cleanup {

    thread::send $tidb tempdone
    thread::release $tidb
} -result {Owner lost}

# ### ### ### ######### ######### #########

cleanupTests
return

Changes to tests/join.test.

33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
    list [catch join msg] $msg $errorCode
} {1 {wrong # args: should be "join list ?joinString?"} {TCL WRONGARGS}}
test join-2.2 {join errors} {
    list [catch {join a b c} msg] $msg $errorCode
} {1 {wrong # args: should be "join list ?joinString?"} {TCL WRONGARGS}}
test join-2.3 {join errors} {
    list [catch {join "a \{ c" 111} msg] $msg $errorCode
} {1 {unmatched open brace in list} {TCL VALUE LIST}}

test join-3.1 {joinString is binary ok} {
  string length [join {a b c} a\0b]
} 9
test join-3.2 {join is binary ok} {
  string length [join "a\0b a\0b a\0b"]
} 11







|







33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
    list [catch join msg] $msg $errorCode
} {1 {wrong # args: should be "join list ?joinString?"} {TCL WRONGARGS}}
test join-2.2 {join errors} {
    list [catch {join a b c} msg] $msg $errorCode
} {1 {wrong # args: should be "join list ?joinString?"} {TCL WRONGARGS}}
test join-2.3 {join errors} {
    list [catch {join "a \{ c" 111} msg] $msg $errorCode
} {1 {unmatched open brace in list} {TCL VALUE LIST BRACE}}

test join-3.1 {joinString is binary ok} {
  string length [join {a b c} a\0b]
} 9
test join-3.2 {join is binary ok} {
  string length [join "a\0b a\0b a\0b"]
} 11

Changes to tests/list.test.

120
121
122
123
124
125
126




127
128
129
130
	set last [expr $last-1]
    }
    return [concat $result $list]
}
test list-3.1 {SetListFromAny and lrange/concat results} {
    slowsort {fred julie alex carol bill annie}
} {alex annie bill carol fred julie}





# cleanup
::tcltest::cleanupTests
return







>
>
>
>




120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
	set last [expr $last-1]
    }
    return [concat $result $list]
}
test list-3.1 {SetListFromAny and lrange/concat results} {
    slowsort {fred julie alex carol bill annie}
} {alex annie bill carol fred julie}

test list-4.1 {Bug 3173086} {
    string is list "{[list \\\\\}]}"
} 1

# cleanup
::tcltest::cleanupTests
return

Changes to tests/lrepeat.test.

59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
    -body {
	lrepeat 0 a b c
    }
    -result {}
}
test lrepeat-1.8 {Do not build enormous lists - Bug 2130992} -body {
     lrepeat 0x10000000 a b c d e f g h
} -returnCodes error -result {too many elements in result list}

## Okay
test lrepeat-2.1 {normal cases} {
    lrepeat 10 a
} {a a a a a a a a a a}
test lrepeat-2.2 {normal cases} {
    lrepeat 3 [lrepeat 3 0]







|







59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
    -body {
	lrepeat 0 a b c
    }
    -result {}
}
test lrepeat-1.8 {Do not build enormous lists - Bug 2130992} -body {
     lrepeat 0x10000000 a b c d e f g h
} -returnCodes error -match glob -result *

## Okay
test lrepeat-2.1 {normal cases} {
    lrepeat 10 a
} {a a a a a a a a a a}
test lrepeat-2.2 {normal cases} {
    lrepeat 3 [lrepeat 3 0]

Changes to tests/mathop.test.

1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
        lappend res [TestOp $op 5.0 1]
        lappend exp "can't use floating-point value as operand of \"$op\" ARITH DOMAIN {floating-point value}"
        lappend res [TestOp $op 1 5.0]
        lappend exp "can't use floating-point value as operand of \"$op\" ARITH DOMAIN {floating-point value}"
    }
    foreach op {in ni} {
        lappend res [TestOp $op 5 "a b \{ c"]
        lappend exp "unmatched open brace in list TCL VALUE LIST"
    }
    lappend res [TestOp % 5 0]
    lappend exp "divide by zero ARITH DIVZERO {divide by zero}"
    lappend res [TestOp % 9838923468297346238478737647637375 0]
    lappend exp "divide by zero ARITH DIVZERO {divide by zero}"
    lappend res [TestOp / 5 0]
    lappend exp "divide by zero ARITH DIVZERO {divide by zero}"







|







1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
        lappend res [TestOp $op 5.0 1]
        lappend exp "can't use floating-point value as operand of \"$op\" ARITH DOMAIN {floating-point value}"
        lappend res [TestOp $op 1 5.0]
        lappend exp "can't use floating-point value as operand of \"$op\" ARITH DOMAIN {floating-point value}"
    }
    foreach op {in ni} {
        lappend res [TestOp $op 5 "a b \{ c"]
        lappend exp "unmatched open brace in list TCL VALUE LIST BRACE"
    }
    lappend res [TestOp % 5 0]
    lappend exp "divide by zero ARITH DIVZERO {divide by zero}"
    lappend res [TestOp % 9838923468297346238478737647637375 0]
    lappend exp "divide by zero ARITH DIVZERO {divide by zero}"
    lappend res [TestOp / 5 0]
    lappend exp "divide by zero ARITH DIVZERO {divide by zero}"

Changes to tests/namespace.test.

2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
    interp create slave
    slave eval namespace eval demo namespace path ::
    interp delete slave
} {}
test namespace-51.17 {resolution epoch handling: Bug 2898722} -setup {
    set result {}
    catch {namespace delete ::a}
} -constraints knownBug -body {
    namespace eval ::a {
	proc c {} {lappend ::result A}
	c
	namespace eval b {
	    variable d c
	    lappend ::result [catch { $d }]
	}







|







2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
    interp create slave
    slave eval namespace eval demo namespace path ::
    interp delete slave
} {}
test namespace-51.17 {resolution epoch handling: Bug 2898722} -setup {
    set result {}
    catch {namespace delete ::a}
} -body {
    namespace eval ::a {
	proc c {} {lappend ::result A}
	c
	namespace eval b {
	    variable d c
	    lappend ::result [catch { $d }]
	}
2513
2514
2515
2516
2517
2518
2519
















2520
2521
2522
2523
2524
2525
2526
	$d;[format %c 99]
    }
} -cleanup {
    namespace delete ::a
    catch {rename ::c {}}
    unset result
} -result {A 1 . A A . B B . B B . B B . B B . G G}

















# TIP 181 - namespace unknown tests
test namespace-52.1 {unknown: default handler ::unknown} {
    set result [list [namespace eval foobar { namespace unknown }]]
    lappend result [namespace eval :: { namespace unknown }]
    namespace delete foobar
    set result







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







2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
	$d;[format %c 99]
    }
} -cleanup {
    namespace delete ::a
    catch {rename ::c {}}
    unset result
} -result {A 1 . A A . B B . B B . B B . B B . G G}
test namespace-51.18 {Bug 3185407} -setup {
    namespace eval ::test_ns_1 {}
} -body {
    namespace eval ::test_ns_1 {
	variable result {}
	namespace eval ns {proc foo {} {}}
	namespace eval ns2 {proc foo {} {}}
	namespace path {ns ns2}
	variable x foo
	lappend result [namespace which $x]
	proc foo {} {}
	lappend result [namespace which $x]
    }
} -cleanup {
    namespace delete ::test_ns_1
} -result {::test_ns_1::ns::foo ::test_ns_1::foo}

# TIP 181 - namespace unknown tests
test namespace-52.1 {unknown: default handler ::unknown} {
    set result [list [namespace eval foobar { namespace unknown }]]
    lappend result [namespace eval :: { namespace unknown }]
    namespace delete foobar
    set result

Changes to tests/oo.test.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# This file contains a collection of tests for Tcl's built-in object system.
# Sourcing this file into Tcl runs the tests and generates output for errors.
# No output means no errors were found.
#
# Copyright (c) 2006-2008 Donal K. Fellows
#
# See the file "license.terms" for information on usage and redistribution of
# this file, and for a DISCLAIMER OF ALL WARRANTIES.

package require -exact TclOO 0.6.2 ;# Must match value in generic/tclOO.h
package require tcltest 2
if {"::tcltest" in [namespace children]} {
    namespace import -force ::tcltest::*
}

testConstraint memory [llength [info commands memory]]
if {[testConstraint memory]} {




|




|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# This file contains a collection of tests for Tcl's built-in object system.
# Sourcing this file into Tcl runs the tests and generates output for errors.
# No output means no errors were found.
#
# Copyright (c) 2006-2011 Donal K. Fellows
#
# See the file "license.terms" for information on usage and redistribution of
# this file, and for a DISCLAIMER OF ALL WARRANTIES.

package require -exact TclOO 0.6.3 ;# Must match value in generic/tclOO.h
package require tcltest 2
if {"::tcltest" in [namespace children]} {
    namespace import -force ::tcltest::*
}

testConstraint memory [llength [info commands memory]]
if {[testConstraint memory]} {
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
	    uplevel 1 $script
	    set tmp $end
	    set end [getbytes]
	}
	return [expr {$end - $tmp}]
    }
}

proc initInterpreter name {
    $name eval [list package ifneeded TclOO [package provide TclOO] \
		    [package ifneeded TclOO [package provide TclOO]]]
}

test oo-0.1 {basic test of OO's ability to clean up its initial state} {
    interp create t
    initInterpreter t
    t eval {
	package require TclOO
    }
    interp delete t
} {}
test oo-0.2 {basic test of OO's ability to clean up its initial state} {
    set i [interp create]
    initInterpreter $i
    interp eval $i {
	package require TclOO
	namespace delete ::
    }

} {}
test oo-0.3 {basic test of OO's ability to clean up its initial state} -body {
    leaktest {
	[oo::object new] destroy
    }
} -constraints memory -result 0
test oo-0.4 {basic test of OO's ability to clean up its initial state} -body {







<
<
<
<
<



<







<




>







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
	    uplevel 1 $script
	    set tmp $end
	    set end [getbytes]
	}
	return [expr {$end - $tmp}]
    }
}






test oo-0.1 {basic test of OO's ability to clean up its initial state} {
    interp create t

    t eval {
	package require TclOO
    }
    interp delete t
} {}
test oo-0.2 {basic test of OO's ability to clean up its initial state} {
    set i [interp create]

    interp eval $i {
	package require TclOO
	namespace delete ::
    }
    interp delete $i
} {}
test oo-0.3 {basic test of OO's ability to clean up its initial state} -body {
    leaktest {
	[oo::object new] destroy
    }
} -constraints memory -result 0
test oo-0.4 {basic test of OO's ability to clean up its initial state} -body {
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
	interp create foo
	foo eval {oo::object new}
	interp delete foo
    }
} 0
test oo-0.6 {cleaning the core class pair; way #1} -setup {
    interp create t
    initInterpreter t
} -body {
    t eval {
	package require TclOO
	namespace path oo
	list [catch {class destroy} m] $m [catch {object destroy} m] $m
    }
} -cleanup {
    interp delete t
} -result {0 {} 1 {invalid command name "object"}}
test oo-0.7 {cleaning the core class pair; way #2} -setup {
    interp create t
    initInterpreter t
} -body {
    t eval {
	package require TclOO
	namespace path oo
	list [catch {object destroy} m] $m [catch {class destroy} m] $m
    }
} -cleanup {







<











<







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
	interp create foo
	foo eval {oo::object new}
	interp delete foo
    }
} 0
test oo-0.6 {cleaning the core class pair; way #1} -setup {
    interp create t

} -body {
    t eval {
	package require TclOO
	namespace path oo
	list [catch {class destroy} m] $m [catch {object destroy} m] $m
    }
} -cleanup {
    interp delete t
} -result {0 {} 1 {invalid command name "object"}}
test oo-0.7 {cleaning the core class pair; way #2} -setup {
    interp create t

} -body {
    t eval {
	package require TclOO
	namespace path oo
	list [catch {object destroy} m] $m [catch {class destroy} m] $m
    }
} -cleanup {
102
103
104
105
106
107
108




109
110
111
112
113
114
115
	    variable v 0
	}
    }
    leaktest {[foo new] destroy}
} -cleanup {
    foo destroy
} -result 0





test oo-1.1 {basic test of OO functionality: no classes} {
    set result {}
    lappend result [oo::object create foo]
    lappend result [oo::objdefine foo {
	method bar args {
	    global result







>
>
>
>







94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
	    variable v 0
	}
    }
    leaktest {[foo new] destroy}
} -cleanup {
    foo destroy
} -result 0
test oo-0.9 {various types of presence of the TclOO package} {
    list [lsearch -nocase -all -inline [package names] tcloo] \
	[package present TclOO] [package versions TclOO]
} [list TclOO $::oo::version $::oo::version]

test oo-1.1 {basic test of OO functionality: no classes} {
    set result {}
    lappend result [oo::object create foo]
    lappend result [oo::objdefine foo {
	method bar args {
	    global result
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
    info commands ::AGlobalName
} -result {}

test oo-2.1 {basic test of OO functionality: constructor} -setup {
    # This is a bit complex because it needs to run in a sub-interp as
    # we're modifying the root object class's constructor
    interp create subinterp
    initInterpreter subinterp
    subinterp eval {
	package require TclOO
    }
} -body {
    subinterp eval {
	oo::define oo::object constructor {} {
	    lappend ::result [info level 0]







<







264
265
266
267
268
269
270

271
272
273
274
275
276
277
    info commands ::AGlobalName
} -result {}

test oo-2.1 {basic test of OO functionality: constructor} -setup {
    # This is a bit complex because it needs to run in a sub-interp as
    # we're modifying the root object class's constructor
    interp create subinterp

    subinterp eval {
	package require TclOO
    }
} -body {
    subinterp eval {
	oo::define oo::object constructor {} {
	    lappend ::result [info level 0]
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
    foo destroy
} -result good

test oo-3.1 {basic test of OO functionality: destructor} -setup {
    # This is a bit complex because it needs to run in a sub-interp as we're
    # modifying the root object class's constructor
    interp create subinterp
    initInterpreter subinterp
    subinterp eval {
	package require TclOO
    }
} -body {
    subinterp eval {
	oo::define oo::object destructor {
	    lappend ::result died
	}
	lappend result 1 [oo::object create foo]
	lappend result 2 [rename foo {}]
	oo::define oo::object destructor {}
	return $result
    }
} -cleanup {
    interp delete subinterp
} -result {1 ::foo died 2 {}}
test oo-3.2 {basic test of OO functionality: destructor} -setup {
    # This is a bit complex because it needs to run in a sub-interp as
    # we're modifying the root object class's constructor
    interp create subinterp
    initInterpreter subinterp
    subinterp eval {
	package require TclOO
    }
} -body {
    subinterp eval {
	oo::define oo::object destructor {
	    lappend ::result died







<




















<







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
    foo destroy
} -result good

test oo-3.1 {basic test of OO functionality: destructor} -setup {
    # This is a bit complex because it needs to run in a sub-interp as we're
    # modifying the root object class's constructor
    interp create subinterp

    subinterp eval {
	package require TclOO
    }
} -body {
    subinterp eval {
	oo::define oo::object destructor {
	    lappend ::result died
	}
	lappend result 1 [oo::object create foo]
	lappend result 2 [rename foo {}]
	oo::define oo::object destructor {}
	return $result
    }
} -cleanup {
    interp delete subinterp
} -result {1 ::foo died 2 {}}
test oo-3.2 {basic test of OO functionality: destructor} -setup {
    # This is a bit complex because it needs to run in a sub-interp as
    # we're modifying the root object class's constructor
    interp create subinterp

    subinterp eval {
	package require TclOO
    }
} -body {
    subinterp eval {
	oo::define oo::object destructor {
	    lappend ::result died
751
752
753
754
755
756
757














































































































































758
759
760
761
762
763
764
	}
	forward ns curns
    }
    expr {[[fooClass new] ns] ne [[fooClass new] ns]}
} -cleanup {
    fooClass destroy
} -result 1















































































































































test oo-7.1 {OO: inheritance 101} -setup {
    oo::class create superClass
    oo::class create subClass
    subClass create instance
} -body {
    oo::define superClass method doit x {lappend ::result $x}







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







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
	}
	forward ns curns
    }
    expr {[[fooClass new] ns] ne [[fooClass new] ns]}
} -cleanup {
    fooClass destroy
} -result 1
test oo-6.8 {Bug 3400658: forwarding and wrongargs rewriting} -setup {
    oo::class create fooClass
} -body {
    oo::define fooClass {
	forward test my handler
	method handler {a b c} {}
    }
    fooClass create ::foo
    foo test
} -returnCodes error -cleanup {
    fooClass destroy
} -result {wrong # args: should be "foo test a b c"}
test oo-6.9 {Bug 3400658: forwarding and wrongargs rewriting} -setup {
    oo::class create fooClass
} -body {
    oo::define fooClass {
	forward test my handler
	method handler {a b c} {list $a,$b,$c}
    }
    fooClass create ::foo
    foo test 1 2 3
} -cleanup {
    fooClass destroy
} -result 1,2,3
test oo-6.10 {Bug 3400658: forwarding and wrongargs rewriting} -setup {
    oo::class create fooClass
} -body {
    oo::define fooClass {
	forward test my handler
	method handler {a b c} {list $a,$b,$c}
    }
    fooClass create ::foo
    foo test 1 2
} -returnCodes error -cleanup {
    fooClass destroy
} -result {wrong # args: should be "foo test a b c"}
test oo-6.11 {Bug 3400658: forwarding and wrongargs rewriting} -setup {
    oo::object create foo
} -body {
    oo::objdefine foo {
	forward test my handler
	method handler {a b c} {}
    }
    foo test
} -returnCodes error -cleanup {
    foo destroy
} -result {wrong # args: should be "foo test a b c"}
test oo-6.12 {Bug 3400658: forwarding and wrongargs rewriting} -setup {
    oo::object create foo
} -body {
    oo::objdefine foo {
	forward test my handler
	method handler {a b c} {list $a,$b,$c}
    }
    foo test 1 2 3
} -cleanup {
    foo destroy
} -result 1,2,3
test oo-6.13 {Bug 3400658: forwarding and wrongargs rewriting} -setup {
    oo::object create foo
} -body {
    oo::objdefine foo {
	forward test my handler
	method handler {a b c} {list $a,$b,$c}
    }
    foo test 1 2
} -returnCodes error -cleanup {
    foo destroy
} -result {wrong # args: should be "foo test a b c"}
test oo-6.14 {Bug 3400658: forwarding and wrongargs rewriting - multistep} -setup {
    oo::class create fooClass
} -body {
    oo::define fooClass {
	forward test my handler1 p
	forward handler1 my handler q
	method handler {a b c} {}
    }
    fooClass create ::foo
    foo test
} -returnCodes error -cleanup {
    fooClass destroy
} -result {wrong # args: should be "foo test c"}
test oo-6.15 {Bug 3400658: forwarding and wrongargs rewriting - multistep} -setup {
    oo::class create fooClass
} -body {
    oo::define fooClass {
	forward test my handler1 p
	forward handler1 my handler q
	method handler {a b c} {list $a,$b,$c}
    }
    fooClass create ::foo
    foo test 1
} -cleanup {
    fooClass destroy
} -result q,p,1
test oo-6.16 {Bug 3400658: forwarding and wrongargs rewriting - via alias} -setup {
    oo::class create fooClass
} -body {
    oo::define fooClass {
	forward test handler1 foo bar
	forward handler2 my handler x
	method handler {a b c d} {list $a,$b,$c,$d}
	export eval
    }
    fooClass create ::foo
    foo eval {
	interp alias {} [namespace current]::handler1 \
	    {} [namespace current]::my handler2
    }
    foo test 1 2 3
} -returnCodes error -cleanup {
    fooClass destroy
} -result {wrong # args: should be "foo test d"}
test oo-6.17 {Bug 3400658: forwarding and wrongargs rewriting - via ensemble} -setup {
    oo::class create fooClass
} -body {
    oo::define fooClass {
	forward test handler1 foo bar boo
	forward handler2 my handler
	method handler {a b c d} {list $a,$b,$c,$d}
	export eval
    }
    fooClass create ::foo
    foo eval {
	namespace ensemble create \
	    -command [namespace current]::handler1 -parameters {p q} \
	    -map [list boo [list [namespace current]::my handler2]]
    }
    foo test 1 2 3
} -returnCodes error -cleanup {
    fooClass destroy
} -result {wrong # args: should be "foo test c d"}
test oo-6.18 {Bug 3408830: more forwarding cases} -setup {
    oo::class create fooClass
} -body {
    oo::define fooClass {
	forward len  string length
    }
    [fooClass create foo] len a b
} -returnCodes error -cleanup {
    fooClass destroy
} -result {wrong # args: should be "::foo len string"}

test oo-7.1 {OO: inheritance 101} -setup {
    oo::class create superClass
    oo::class create subClass
    subClass create instance
} -body {
    oo::define superClass method doit x {lappend ::result $x}
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
    info object
} -returnCodes 1 -result "wrong \# args: should be \"info object subcommand ?arg ...?\""
test oo-16.2 {OO: object introspection} -body {
    info object class NOTANOBJECT
} -returnCodes 1 -result {NOTANOBJECT does not refer to an object}
test oo-16.3 {OO: object introspection} -body {
    info object gorp oo::object
} -returnCodes 1 -result {unknown or ambiguous subcommand "gorp": must be class, definition, filters, forward, isa, methods, methodtype, mixins, namespace, variables, or vars}
test oo-16.4 {OO: object introspection} -setup {
    oo::class create meta { superclass oo::class }
    [meta create instance1] create instance2
} -body {
    list [list [info object class oo::object] \
	      [info object class oo::class] \
	      [info object class meta] \







|







1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
    info object
} -returnCodes 1 -result "wrong \# args: should be \"info object subcommand ?arg ...?\""
test oo-16.2 {OO: object introspection} -body {
    info object class NOTANOBJECT
} -returnCodes 1 -result {NOTANOBJECT does not refer to an object}
test oo-16.3 {OO: object introspection} -body {
    info object gorp oo::object
} -returnCodes 1 -result {unknown or ambiguous subcommand "gorp": must be call, class, definition, filters, forward, isa, methods, methodtype, mixins, namespace, variables, or vars}
test oo-16.4 {OO: object introspection} -setup {
    oo::class create meta { superclass oo::class }
    [meta create instance1] create instance2
} -body {
    list [list [info object class oo::object] \
	      [info object class oo::class] \
	      [info object class meta] \
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
} -body {
    info class superclass foo
} -returnCodes 1 -cleanup {
    foo destroy
} -result {"foo" is not a class}
test oo-17.4 {OO: class introspection} -body {
    info class gorp oo::object
} -returnCodes 1 -result {unknown or ambiguous subcommand "gorp": must be constructor, definition, destructor, filters, forward, instances, methods, methodtype, mixins, subclasses, superclasses, or variables}
test oo-17.5 {OO: class introspection} -setup {
    oo::class create testClass
} -body {
    testClass create foo
    testClass create bar
    testClass create spong
    lsort [info class instances testClass]







|







1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
} -body {
    info class superclass foo
} -returnCodes 1 -cleanup {
    foo destroy
} -result {"foo" is not a class}
test oo-17.4 {OO: class introspection} -body {
    info class gorp oo::object
} -returnCodes 1 -result {unknown or ambiguous subcommand "gorp": must be call, constructor, definition, destructor, filters, forward, instances, methods, methodtype, mixins, subclasses, superclasses, or variables}
test oo-17.5 {OO: class introspection} -setup {
    oo::class create testClass
} -body {
    testClass create foo
    testClass create bar
    testClass create spong
    lsort [info class instances testClass]

Added tests/ooNext2.test.













































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
# This file contains a collection of tests for Tcl's built-in object system.
# Sourcing this file into Tcl runs the tests and generates output for errors.
# No output means no errors were found.
#
# Copyright (c) 2006-2008 Donal K. Fellows
#
# See the file "license.terms" for information on usage and redistribution of
# this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: oo.test,v 1.59 2011/01/18 16:10:48 dkf Exp $

package require -exact TclOO 0.6.3 ;# Must match value in configure.in
if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest 2
    namespace import -force ::tcltest::*
}

testConstraint memory [llength [info commands memory]]
if {[testConstraint memory]} {
    proc getbytes {} {
	set lines [split [memory info] \n]
	return [lindex $lines 3 3]
    }
    proc leaktest {script {iterations 3}} {
	set end [getbytes]
	for {set i 0} {$i < $iterations} {incr i} {
	    uplevel 1 $script
	    set tmp $end
	    set end [getbytes]
	}
	return [expr {$end - $tmp}]
    }
}

test oo-nextto-1.1 {basic nextto functionality} -setup {
    oo::class create root
} -body {
    oo::class create A {
	superclass root
	method x args {
	    lappend ::result ==A== $args
	}
    }
    oo::class create B {
	superclass A
	method x args {
	    lappend ::result ==B== $args
	    nextto A B -> A {*}$args
	}
    }
    oo::class create C {
	superclass A
	method x args {
	    lappend ::result ==C== $args
	    nextto A C -> A {*}$args
	}
    }
    oo::class create D {
	superclass B C
	method x args {
	    lappend ::result ==D== $args
	    next foo
	    nextto C bar
	}
    }
    set ::result {}
    [D new] x
    return $::result
} -cleanup {
    root destroy
} -result {==D== {} ==B== foo ==A== {B -> A foo} ==C== bar ==A== {C -> A bar}}
test oo-nextto-1.2 {basic nextto functionality} -setup {
    oo::class create root
} -body {
    oo::class create A {
	superclass root
	method x args {
	    lappend ::result ==A== $args
	}
    }
    oo::class create B {
	superclass A
	method x args {
	    lappend ::result ==B== $args
	    nextto A B -> A {*}$args
	}
    }
    oo::class create C {
	superclass A
	method x args {
	    lappend ::result ==C== $args
	    nextto A C -> A {*}$args
	}
    }
    oo::class create D {
	superclass B C
	method x args {
	    lappend ::result ==D== $args
	    nextto B foo {*}$args
	    nextto C bar {*}$args
	}
    }
    set ::result {}
    [D new] x 123
    return $::result
} -cleanup {
    root destroy
} -result {==D== 123 ==B== {foo 123} ==A== {B -> A foo 123} ==C== {bar 123} ==A== {C -> A bar 123}}
test oo-nextto-1.3 {basic nextto functionality: constructors} -setup {
    oo::class create root
} -body {
    oo::class create A {
	superclass root
	variable result
	constructor {a c} {
	    lappend result ==A== a=$a,c=$c
	}
    }
    oo::class create B {
	superclass root
	variable result
	constructor {b} {
	    lappend result ==B== b=$b
	}
    }
    oo::class create C {
	superclass A B
	variable result
	constructor {p q r} {
	    lappend result ==C== p=$p,q=$q,r=$r
	    # Route arguments to superclasses, in non-trival pattern
	    nextto B $q
	    nextto A $p $r
	}
	method result {} {return $result}
    }
    [C new x y z] result
} -cleanup {
    root destroy
} -result {==C== p=x,q=y,r=z ==B== b=y ==A== a=x,c=z}
test oo-nextto-1.4 {basic nextto functionality: destructors} -setup {
    oo::class create root {destructor return}
} -body {
    oo::class create A {
	superclass root
	destructor {
	    lappend ::result ==A==
	    next
	}
    }
    oo::class create B {
	superclass root
	destructor {
	    lappend ::result ==B==
	    next
	}
    }
    oo::class create C {
	superclass A B
	destructor {
	    lappend ::result ==C==
	    lappend ::result |
	    nextto B
	    lappend ::result |
	    nextto A
	    lappend ::result |
	    next
	}
    }
    set ::result ""
    [C new] destroy
    return $::result
} -cleanup {
    root destroy
} -result {==C== | ==B== | ==A== ==B== | ==A== ==B==}

test oo-nextto-2.1 {errors in nextto} -setup {
    oo::class create root
} -body {
    oo::class create A {
	superclass root
	method x y {error $y}
    }
    oo::class create B {
	superclass A
	method x y {nextto A $y}
    }
    [B new] x boom
} -cleanup {
    root destroy
} -result boom -returnCodes error
test oo-nextto-2.2 {errors in nextto} -setup {
    oo::class create root
} -body {
    oo::class create A {
	superclass root
	method x y {error $y}
    }
    oo::class create B {
	superclass root
	method x y {nextto A $y}
    }
    [B new] x boom
} -returnCodes error -cleanup {
    root destroy
} -result {method has no non-filter implementation by "A"}
test oo-nextto-2.3 {errors in nextto} -setup {
    oo::class create root
} -body {
    oo::class create A {
	superclass root
	method x y {nextto $y}
    }
    oo::class create B {
	superclass A
	method x y {nextto A $y}
    }
    [B new] x B
} -returnCodes error -cleanup {
    root destroy
} -result {method implementation by "B" not reachable from here}
test oo-nextto-2.4 {errors in nextto} -setup {
    oo::class create root
} -body {
    oo::class create A {
	superclass root
	method x y {nextto $y}
    }
    oo::class create B {
	superclass A
	method x y {nextto}
    }
    [B new] x B
} -returnCodes error -cleanup {
    root destroy
} -result {wrong # args: should be "nextto class ?arg...?"}
test oo-nextto-2.5 {errors in nextto} -setup {
    oo::class create root
} -body {
    oo::class create A {
	superclass root
	method x y {nextto $y}
    }
    oo::class create B {
	superclass A
	method x y {nextto $y $y $y}
    }
    [B new] x A
} -cleanup {
    root destroy
} -result {wrong # args: should be "nextto A y"} -returnCodes error
test oo-nextto-2.6 {errors in nextto} -setup {
    oo::class create root
} -body {
    oo::class create A {
	superclass root
	method x y {nextto $y}
    }
    oo::class create B {
	superclass A
	method x y {nextto $y $y $y}
    }
    [B new] x [root create notAClass]
} -cleanup {
    root destroy
} -result {"::notAClass" is not a class} -returnCodes error
test oo-nextto-2.7 {errors in nextto} -setup {
    oo::class create root
} -body {
    oo::class create A {
	superclass root
	method x y {nextto $y}
    }
    oo::class create B {
	superclass A
	filter Y
	method Y args {next {*}$args}
    }
    oo::class create C {
	superclass B
	method x y {nextto $y $y $y}
    }
    [C new] x B
} -returnCodes error -cleanup {
    root destroy
} -result {method has no non-filter implementation by "B"}

test oo-call-1.1 {object call introspection} -setup {
    oo::class create root
} -body {
    oo::class create ::A {
	superclass root
	method x {} {}
    }
    A create y
    info object call y x
} -cleanup {
    root destroy
} -result {{method x ::A method}}
test oo-call-1.2 {object call introspection} -setup {
    oo::class create root
} -body {
    oo::class create ::A {
	superclass root
	method x {} {}
    }
    oo::class create ::B {
	superclass A
	method x {} {}
    }
    B create y
    info object call y x
} -cleanup {
    root destroy
} -result {{method x ::B method} {method x ::A method}}
test oo-call-1.3 {object call introspection} -setup {
    oo::class create root
} -body {
    oo::class create ::A {
	superclass root
	method x {} {}
    }
    A create y
    oo::objdefine y method x {} {}
    info object call y x
} -cleanup {
    root destroy
} -result {{method x object method} {method x ::A method}}
test oo-call-1.4 {object object call introspection - unknown} -setup {
    oo::class create root
} -body {
    oo::class create ::A {
	superclass root
	method x {} {}
    }
    A create y
    info object call y z
} -cleanup {
    root destroy
} -result {{unknown unknown ::oo::object {core method: "unknown"}}}
test oo-call-1.5 {object call introspection - filters} -setup {
    oo::class create root
} -body {
    oo::class create ::A {
	superclass root
	method x {} {}
	method y {} {}
	filter y
    }
    A create y
    info object call y x
} -cleanup {
    root destroy
} -result {{filter y ::A method} {method x ::A method}}
test oo-call-1.6 {object call introspection - filters} -setup {
    oo::class create root
} -body {
    oo::class create ::A {
	superclass root
	method x {} {}
	method y {} {}
	filter y
    }
    oo::class create ::B {
	superclass A
	method x {} {}
    }
    B create y
    info object call y x
} -cleanup {
    root destroy
} -result {{filter y ::A method} {method x ::B method} {method x ::A method}}
test oo-call-1.7 {object call introspection - filters} -setup {
    oo::class create root
} -body {
    oo::class create ::A {
	superclass root
	method x {} {}
	method y {} {}
	filter y
    }
    oo::class create ::B {
	superclass A
	method x {} {}
	method y {} {}
    }
    B create y
    info object call y x
} -cleanup {
    root destroy
} -result {{filter y ::B method} {filter y ::A method} {method x ::B method} {method x ::A method}}
test oo-call-1.8 {object call introspection - filters} -setup {
    oo::class create root
} -body {
    oo::class create ::A {
	superclass root
	method x {} {}
	method y {} {}
	filter y
    }
    oo::class create ::B {
	superclass A
	method x {} {}
	method y {} {}
	method z {} {}
	filter z
    }
    B create y
    info object call y x
} -cleanup {
    root destroy
} -result {{filter z ::B method} {filter y ::B method} {filter y ::A method} {method x ::B method} {method x ::A method}}
test oo-call-1.9 {object call introspection - filters} -setup {
    oo::class create root
} -body {
    oo::class create ::A {
	superclass root
	method x {} {}
	method y {} {}
	filter y
    }
    oo::class create ::B {
	superclass A
	method x {} {}
	method y {} {}
	method z {} {}
	filter z
    }
    B create y
    info object call y y
} -cleanup {
    root destroy
} -result {{filter z ::B method} {filter y ::B method} {filter y ::A method} {method y ::B method} {method y ::A method}}
test oo-call-1.10 {object call introspection - filters + unknown} -setup {
    oo::class create root
} -body {
    oo::class create ::A {
	superclass root
	method y {} {}
	filter y
    }
    oo::class create ::B {
	superclass A
	method y {} {}
	method unknown {} {}
    }
    B create y
    info object call y x
} -cleanup {
    root destroy
} -result {{filter y ::B method} {filter y ::A method} {unknown unknown ::B method} {unknown unknown ::oo::object {core method: "unknown"}}}
test oo-call-1.11 {object call introspection - filters + unknown} -setup {
    oo::class create root
} -body {
    oo::class create ::A {
	superclass root
	method y {} {}
	filter y
    }
    A create y
    oo::objdefine y method unknown {} {}
    info object call y x
} -cleanup {
    root destroy
} -result {{filter y ::A method} {unknown unknown object method} {unknown unknown ::oo::object {core method: "unknown"}}}
test oo-call-1.12 {object call introspection - filters + unknown} -setup {
    oo::class create root
} -body {
    oo::class create ::A {
	superclass root
	method y {} {}
    }
    A create y
    oo::objdefine y {
	method unknown {} {}
	filter y
    }
    info object call y x
} -cleanup {
    root destroy
} -result {{filter y ::A method} {unknown unknown object method} {unknown unknown ::oo::object {core method: "unknown"}}}
test oo-call-1.13 {object call introspection - filters + unknown} -setup {
    oo::class create root
} -body {
    oo::class create ::A {
	superclass root
	method y {} {}
    }
    A create y
    oo::objdefine y {
	method unknown {} {}
	method x {} {}
	filter y
    }
    info object call y x
} -cleanup {
    root destroy
} -result {{filter y ::A method} {method x object method}}
test oo-call-1.14 {object call introspection - errors} -body {
    info object call
} -returnCodes error -result {wrong # args: should be "info object call objName methodName"}
test oo-call-1.15 {object call introspection - errors} -body {
    info object call a
} -returnCodes error -result {wrong # args: should be "info object call objName methodName"}
test oo-call-1.16 {object call introspection - errors} -body {
    info object call a b c
} -returnCodes error -result {wrong # args: should be "info object call objName methodName"}
test oo-call-1.17 {object call introspection - errors} -body {
    info object call notanobject x
} -returnCodes error -result {notanobject does not refer to an object}
test oo-call-1.18 {object call introspection - memory leaks} -body {
    leaktest {
	info object call oo::object destroy
    }
} -constraints memory -result 0
test oo-call-1.19 {object call introspection - memory leaks} -setup {
    oo::class create leaktester { method foo {} {dummy} }
} -body {
    leaktest {
	set lt [leaktester new]
	oo::objdefine $lt method foobar {} {dummy}
	list [info object call $lt destroy] \
	    [info object call $lt foo] \
	    [info object call $lt bar] \
	    [info object call $lt foobar] \
	    [$lt destroy]
    }
} -cleanup {
    leaktester destroy
} -constraints memory -result 0

test oo-call-2.1 {class call introspection} -setup {
    oo::class create root
} -body {
    oo::class create ::A {
	superclass root
	method x {} {}
    }
    info class call A x
} -cleanup {
    root destroy
} -result {{method x ::A method}}
test oo-call-2.2 {class call introspection} -setup {
    oo::class create root
} -body {
    oo::class create ::A {
	superclass root
	method x {} {}
    }
    oo::class create ::B {
	superclass A
	method x {} {}
    }
    list [info class call A x] [info class call B x]
} -cleanup {
    root destroy
} -result {{{method x ::A method}} {{method x ::B method} {method x ::A method}}}
test oo-call-2.3 {class call introspection} -setup {
    oo::class create root
} -body {
    oo::class create ::A {
	superclass root
	method x {} {}
    }
    oo::class create ::B {
	superclass A
	method x {} {}
    }
    oo::class create ::C {
	superclass A
	method x {} {}
    }
    oo::class create ::D {
	superclass C B
	method x {} {}
    }
    info class call D x
} -cleanup {
    root destroy
} -result {{method x ::D method} {method x ::C method} {method x ::B method} {method x ::A method}}
test oo-call-2.4 {class call introspection - mixin} -setup {
    oo::class create root
} -body {
    oo::class create ::A {
	superclass root
	method x {} {}
    }
    oo::class create ::B {
	superclass A
	method x {} {}
    }
    oo::class create ::C {
	superclass A
	method x {} {}
    }
    oo::class create ::D {
	superclass C
	mixin B
	method x {} {}
    }
    info class call D x
} -cleanup {
    root destroy
} -result {{method x ::B method} {method x ::D method} {method x ::C method} {method x ::A method}}
test oo-call-2.5 {class call introspection - mixin + filter} -setup {
    oo::class create root
} -body {
    oo::class create ::A {
	superclass root
	method x {} {}
    }
    oo::class create ::B {
	superclass A
	method x {} {}
	method y {} {}
	filter y
    }
    oo::class create ::C {
	superclass A
	method x {} {}
	method y {} {}
    }
    oo::class create ::D {
	superclass C
	mixin B
	method x {} {}
    }
    info class call D x
} -cleanup {
    root destroy
} -result {{filter y ::B method} {filter y ::C method} {method x ::B method} {method x ::D method} {method x ::C method} {method x ::A method}}
test oo-call-2.6 {class call introspection - mixin + filter + unknown} -setup {
    oo::class create root
} -body {
    oo::class create ::A {
	superclass root
	method x {} {}
	method unknown {} {}
    }
    oo::class create ::B {
	superclass A
	method x {} {}
	method y {} {}
	filter y
    }
    oo::class create ::C {
	superclass A
	method x {} {}
	method y {} {}
    }
    oo::class create ::D {
	superclass C
	mixin B
	method x {} {}
	method unknown {} {}
    }
    info class call D z
} -cleanup {
    root destroy
} -result {{filter y ::B method} {filter y ::C method} {unknown unknown ::D method} {unknown unknown ::A method} {unknown unknown ::oo::object {core method: "unknown"}}}
test oo-call-2.7 {class call introspection - mixin + filter + unknown} -setup {
    oo::class create root
} -body {
    oo::class create ::A {
	superclass root
	method x {} {}
    }
    oo::class create ::B {
	superclass A
	method x {} {}
	filter x
    }
    info class call B x
} -cleanup {
    root destroy
} -result {{filter x ::B method} {filter x ::A method} {method x ::B method} {method x ::A method}}
test oo-call-2.8 {class call introspection - errors} -body {
    info class call
} -returnCodes error -result {wrong # args: should be "info class call className methodName"}
test oo-call-2.9 {class call introspection - errors} -body {
    info class call a
} -returnCodes error -result {wrong # args: should be "info class call className methodName"}
test oo-call-2.10 {class call introspection - errors} -body {
    info class call a b c
} -returnCodes error -result {wrong # args: should be "info class call className methodName"}
test oo-call-2.11 {class call introspection - errors} -body {
    info class call notaclass x
} -returnCodes error -result {notaclass does not refer to an object}
test oo-call-2.12 {class call introspection - errors} -setup {
    oo::class create root
} -body {
    root create notaclass
    info class call notaclass x
} -returnCodes error -cleanup {
    root destroy
} -result {"notaclass" is not a class}
test oo-call-2.13 {class call introspection - memory leaks} -body {
    leaktest {
	info class call oo::class destroy
    }
} -constraints memory -result 0
test oo-call-2.14 {class call introspection - memory leaks} -body {
    leaktest {
	oo::class create leaktester { method foo {} {dummy} }
	[leaktester new] destroy
	list [info class call leaktester destroy] \
	    [info class call leaktester foo] \
	    [info class call leaktester bar] \
	    [leaktester destroy]
    }
} -constraints memory -result 0

test oo-call-3.1 {current call introspection} -setup {
    oo::class create root
} -body {
    oo::class create A {
	superclass root
	method x {} {lappend ::result [self call]}
    }
    oo::class create B {
	superclass A
	method x {} {lappend ::result [self call];next}
    }
    B create y
    oo::objdefine y method x {} {lappend ::result [self call];next}
    set ::result {}
    y x
} -cleanup {
    root destroy
} -result {{{{method x object method} {method x ::B method} {method x ::A method}} 0} {{{method x object method} {method x ::B method} {method x ::A method}} 1} {{{method x object method} {method x ::B method} {method x ::A method}} 2}}
test oo-call-3.2 {current call introspection} -setup {
    oo::class create root
} -constraints memory -body {
    oo::class create A {
	superclass root
	method x {} {self call}
    }
    oo::class create B {
	superclass A
	method x {} {self call;next}
    }
    B create y
    oo::objdefine y method x {} {self call;next}
    leaktest {
	y x
    }
} -cleanup {
    root destroy
} -result 0
test oo-call-3.3 {current call introspection: in constructors} -setup {
    oo::class create root
} -body {
    oo::class create A {
	superclass root
	constructor {} {lappend ::result [self call]}
    }
    oo::class create B {
	superclass A
	constructor {} {lappend ::result [self call]; next}
    }
    set ::result {}
    [B new] destroy
    return $::result
} -cleanup {
    root destroy
} -result {{{{method <constructor> ::B method} {method <constructor> ::A method}} 0} {{{method <constructor> ::B method} {method <constructor> ::A method}} 1}}
test oo-call-3.4 {current call introspection: in destructors} -setup {
    oo::class create root
} -body {
    oo::class create A {
	superclass root
	destructor {lappend ::result [self call]}
    }
    oo::class create B {
	superclass A
	destructor {lappend ::result [self call]; next}
    }
    set ::result {}
    [B new] destroy
    return $::result
} -cleanup {
    root destroy
} -result {{{{method <destructor> ::B method} {method <destructor> ::A method}} 0} {{{method <destructor> ::B method} {method <destructor> ::A method}} 1}}

cleanupTests
return

# Local Variables:
# mode: tcl
# End:

Changes to tests/package.test.

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Copyright (c) 1998-1999 by Scriptics Corporation.
# Copyright (c) 2011 Donal K. Fellows
#
# See the file "license.terms" for information on usage and redistribution of
# this file, and for a DISCLAIMER OF ALL WARRANTIES.

if {"::tcltest" ni [namespace children]} {
    package require tcltest 2
    namespace import -force ::tcltest::*
}

# Do all this in a slave interp to avoid garbaging the package list
set i [interp create]
tcltest::loadIntoSlaveInterpreter $i {*}$argv
interp eval $i {







|







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Copyright (c) 1998-1999 by Scriptics Corporation.
# Copyright (c) 2011 Donal K. Fellows
#
# See the file "license.terms" for information on usage and redistribution of
# this file, and for a DISCLAIMER OF ALL WARRANTIES.

if {"::tcltest" ni [namespace children]} {
    package require tcltest 2.3.3
    namespace import -force ::tcltest::*
}

# Do all this in a slave interp to avoid garbaging the package list
set i [interp create]
tcltest::loadIntoSlaveInterpreter $i {*}$argv
interp eval $i {
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
    } $vs
    test package-10.$n {package vcompare} {
	package vcompare $r $p
    } $vc
    incr n
}

test package-11.0 {package vcompare at 32bit boundary} {
    package vcompare [expr {1<<31}] [expr {(1<<31)-1}]
} 1

# Note: It is correct that the result of the very first test, i.e. "5.0 5.0a0"
# is 1, i.e. that version 5.0a0 satisfies a 5.0 requirement.

# The requirement "5.0" internally translates first to "5.0-6", and then to







|







1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
    } $vs
    test package-10.$n {package vcompare} {
	package vcompare $r $p
    } $vc
    incr n
}

test package-11.0.0 {package vcompare at 32bit boundary} {
    package vcompare [expr {1<<31}] [expr {(1<<31)-1}]
} 1

# Note: It is correct that the result of the very first test, i.e. "5.0 5.0a0"
# is 1, i.e. that version 5.0a0 satisfies a 5.0 requirement.

# The requirement "5.0" internally translates first to "5.0-6", and then to

Changes to tests/parse.test.

229
230
231
232
233
234
235






236
237
238
239
240
241
242
} {- \{*\}\\\n\ foo\ bar 3 simple {{*}} 1 text * 0 simple foo 1 text foo 0 simple bar 1 text bar 0 {}}
test parse-5.28 {Tcl_ParseCommand: {*} parsing, expanded literals} testparser {
    testparser {{*}{a b}} 0
} {- {{*}{a b}} 2 simple a 1 text a 0 simple b 1 text b 0 {}}
test parse-5.29 {Tcl_ParseCommand: {*} parsing, expanded literals, naked backslashes} testparser {
    testparser {{*}{a \n b}} 0
} {- {{*}{a \n b}} 1 expand {{*}{a \n b}} 1 text {a \n b} 0 {}}







test parse-6.1 {ParseTokens procedure, empty word} testparser {
    testparser {""} 0
} {- {""} 1 simple {""} 1 text {} 0 {}}
test parse-6.2 {ParseTokens procedure, simple range} testparser {
    testparser {"abc$x.e"} 0
} {- {"abc$x.e"} 1 word {"abc$x.e"} 4 text abc 0 variable {$x} 1 text x 0 text .e 0 {}}







>
>
>
>
>
>







229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
} {- \{*\}\\\n\ foo\ bar 3 simple {{*}} 1 text * 0 simple foo 1 text foo 0 simple bar 1 text bar 0 {}}
test parse-5.28 {Tcl_ParseCommand: {*} parsing, expanded literals} testparser {
    testparser {{*}{a b}} 0
} {- {{*}{a b}} 2 simple a 1 text a 0 simple b 1 text b 0 {}}
test parse-5.29 {Tcl_ParseCommand: {*} parsing, expanded literals, naked backslashes} testparser {
    testparser {{*}{a \n b}} 0
} {- {{*}{a \n b}} 1 expand {{*}{a \n b}} 1 text {a \n b} 0 {}}
test parse-5.30 {Tcl_ParseCommand: {*} parsing, expanded literals} testparser {
    testparser {{*}"a b"} 0
} {- {{*}"a b"} 2 simple a 1 text a 0 simple b 1 text b 0 {}}
test parse-5.31 {Tcl_ParseCommand: {*} parsing, expanded literals, naked backslashes} testparser {
    testparser {{*}"a \n b"} 0
} {- {{*}"a \n b"} 1 expand {{*}"a \n b"} 3 text {a } 0 backslash {\n} 0 text { b} 0 {}}

test parse-6.1 {ParseTokens procedure, empty word} testparser {
    testparser {""} 0
} {- {""} 1 simple {""} 1 text {} 0 {}}
test parse-6.2 {ParseTokens procedure, simple range} testparser {
    testparser {"abc$x.e"} 0
} {- {"abc$x.e"} 1 word {"abc$x.e"} 4 text abc 0 variable {$x} 1 text x 0 text .e 0 {}}

Changes to tests/parseExpr.test.

992
993
994
995
996
997
998


































































999
1000
1001
1002
    expr {123456789012345678901234567890*[abcdefghijklmnopqrstuvwxyz"}
} -returnCodes error -result {missing close-bracket
in expression "...012345678901234567890*[abcdefghijklmnopqrstuv..."}
test parseExpr-21.63 {error message} -body {
    expr "123456789012345678901234567890*\[\{abcdefghijklmnopqrstuvwxyz]"
} -returnCodes error -result "missing close-brace
in expression \"...12345678901234567890*\[\{abcdefghijklmnopqrstuv...\""



































































# cleanup
::tcltest::cleanupTests
return







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




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
    expr {123456789012345678901234567890*[abcdefghijklmnopqrstuvwxyz"}
} -returnCodes error -result {missing close-bracket
in expression "...012345678901234567890*[abcdefghijklmnopqrstuv..."}
test parseExpr-21.63 {error message} -body {
    expr "123456789012345678901234567890*\[\{abcdefghijklmnopqrstuvwxyz]"
} -returnCodes error -result "missing close-brace
in expression \"...12345678901234567890*\[\{abcdefghijklmnopqrstuv...\""

test parseExpr-22.1 {Bug 3401704} -constraints testexprparser -body {
    testexprparser 2a() 1
} -result {- {} 0 subexpr 2 1 text 2 0 {}}
test parseExpr-22.2 {Bug 3401704} -constraints testexprparser -body {
    testexprparser nana() 3
} -result {- {} 0 subexpr nan 1 text nan 0 {}}
test parseExpr-22.3 {Bug 3401704} -constraints testexprparser -body {
    testexprparser 2a() -1
} -result {- {} 0 subexpr 2a() 1 operator 2a 0 {}}
test parseExpr-22.4 {Bug 3401704} -constraints testexprparser -body {
    testexprparser nana() -1
} -result {- {} 0 subexpr nana() 1 operator nana 0 {}}
test parseExpr-22.5 {Bug 3401704} -constraints testexprparser -body {
    testexprparser nan9() -1
} -result {- {} 0 subexpr nan9() 1 operator nan9 0 {}}
test parseExpr-22.6 {Bug 3401704} -constraints testexprparser -body {
    testexprparser 2_() -1
} -result {- {} 0 subexpr 2_() 1 operator 2_ 0 {}}
test parseExpr-22.7 {Bug 3401704} -constraints testexprparser -body {
    testexprparser nan_() -1
} -result {- {} 0 subexpr nan_() 1 operator nan_ 0 {}}
test parseExpr-22.8 {Bug 3401704} -constraints testexprparser -body {
    catch {testexprparser nan!() -1} m o
    dict get $o -errorcode
} -result {TCL PARSE EXPR MISSING}
test parseExpr-22.9 {Bug 3401704} -constraints testexprparser -body {
    testexprparser 1e3_() -1
} -result {- {} 0 subexpr 1e3_() 1 operator 1e3_ 0 {}}
test parseExpr-22.10 {Bug 3401704} -constraints testexprparser -body {
    catch {testexprparser 1.3_() -1} m o
    dict get $o -errorcode
} -result {TCL PARSE EXPR BADCHAR}
test parseExpr-22.11 {Bug 3401704} -constraints testexprparser -body {
    catch {testexprparser 1e-3_() -1} m o
    dict get $o -errorcode
} -result {TCL PARSE EXPR BADCHAR}
test parseExpr-22.12 {Bug 3401704} -constraints testexprparser -body {
    catch {testexprparser naneq() -1} m o
    dict get $o -errorcode
} -result {TCL PARSE EXPR EMPTY}
test parseExpr-22.13 {Bug 3401704} -constraints testexprparser -body {
    testexprparser naner() -1
} -result {- {} 0 subexpr naner() 1 operator naner 0 {}}

test parseExpr-22.14 {Bug 3401704} -constraints testexprparser -body {
    catch {testexprparser 08 -1} m o
    dict get $o -errorcode
} -result {TCL PARSE EXPR BADNUMBER OCTAL}
test parseExpr-22.15 {Bug 3401704} -constraints testexprparser -body {
    catch {testexprparser 0o8 -1} m o
    dict get $o -errorcode
} -result {TCL PARSE EXPR BADNUMBER OCTAL}
test parseExpr-22.16 {Bug 3401704} -constraints testexprparser -body {
    catch {testexprparser 0o08 -1} m o
    dict get $o -errorcode
} -result {TCL PARSE EXPR BADNUMBER OCTAL}
test parseExpr-22.17 {Bug 3401704} -constraints testexprparser -body {
    catch {testexprparser 0b2 -1} m o
    dict get $o -errorcode
} -result {TCL PARSE EXPR BADNUMBER BINARY}
test parseExpr-22.18 {Bug 3401704} -constraints testexprparser -body {
    catch {testexprparser 0b02 -1} m o
    dict get $o -errorcode
} -result {TCL PARSE EXPR BADNUMBER BINARY}


# cleanup
::tcltest::cleanupTests
return

Changes to tests/proc.test.

182
183
184
185
186
187
188





189
190
191
192
193
194
195
    proc p {x} {info commands 3m}
    p
} -returnCodes error -result {wrong # args: should be "p x"}
test proc-3.6 {TclObjInterpProc, proper quoting of proc name, Bug 942757} -body {
    proc {a b  c} {x} {info commands 3m}
    {a b  c}
} -returnCodes error -result {wrong # args: should be "{a b  c} x"}






catch {namespace delete {*}[namespace children :: test_ns_*]}
catch {rename p ""}
catch {rename {} ""}
catch {rename {a b  c} {}}
catch {unset msg}








>
>
>
>
>







182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
    proc p {x} {info commands 3m}
    p
} -returnCodes error -result {wrong # args: should be "p x"}
test proc-3.6 {TclObjInterpProc, proper quoting of proc name, Bug 942757} -body {
    proc {a b  c} {x} {info commands 3m}
    {a b  c}
} -returnCodes error -result {wrong # args: should be "{a b  c} x"}

test proc-3.7 {TclObjInterpProc, wrong num args, Bug 3366265} {
    proc {} {x} {}
    list [catch {{}} msg] $msg
} {1 {wrong # args: should be "{} x"}}

catch {namespace delete {*}[namespace children :: test_ns_*]}
catch {rename p ""}
catch {rename {} ""}
catch {rename {a b  c} {}}
catch {unset msg}

Changes to tests/reg.test.

622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638








639
640
641
642
643
644
645
expectMatch	13.10 MP	"a\\cHb"	"a\bb"	"a\bb"
expectMatch	13.11 LMP	"a\\e"		"a\033"	"a\033"
expectMatch	13.12 P		"a\\fb"		"a\fb"	"a\fb"
expectMatch	13.13 P		"a\\nb"		"a\nb"	"a\nb"
expectMatch	13.14 P		"a\\rb"		"a\rb"	"a\rb"
expectMatch	13.15 P		"a\\tb"		"a\tb"	"a\tb"
expectMatch	13.16 P		"a\\u0008x"	"a\bx"	"a\bx"
expectError	13.17 -		{a\u008x}	EESCAPE
expectMatch	13.18 P		"a\\u00088x"	"a\b8x"	"a\b8x"
expectMatch	13.19 P		"a\\U00000008x"	"a\bx"	"a\bx"
expectError	13.20 -		{a\U0000008x}	EESCAPE
expectMatch	13.21 P		"a\\vb"		"a\vb"	"a\vb"
expectMatch	13.22 MP	"a\\x08x"	"a\bx"	"a\bx"
expectError	13.23 -		{a\xq}		EESCAPE
expectMatch	13.24 MP	"a\\x0008x"	"a\bx"	"a\bx"
expectError	13.25 -		{a\z}		EESCAPE
expectMatch	13.26 MP	"a\\010b"	"a\bb"	"a\bb"










doing 14 "back references"
# ugh
expectMatch	14.1  RP	{a(b*)c\1}	abbcbb	abbcbb	bb
expectMatch	14.2  RP	{a(b*)c\1}	ac	ac	""
expectNomatch	14.3  RP	{a(b*)c\1}	abbcb







|


|



|


>
>
>
>
>
>
>
>







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
expectMatch	13.10 MP	"a\\cHb"	"a\bb"	"a\bb"
expectMatch	13.11 LMP	"a\\e"		"a\033"	"a\033"
expectMatch	13.12 P		"a\\fb"		"a\fb"	"a\fb"
expectMatch	13.13 P		"a\\nb"		"a\nb"	"a\nb"
expectMatch	13.14 P		"a\\rb"		"a\rb"	"a\rb"
expectMatch	13.15 P		"a\\tb"		"a\tb"	"a\tb"
expectMatch	13.16 P		"a\\u0008x"	"a\bx"	"a\bx"
expectMatch	13.17 P		{a\u008x}	"a\bx"	"a\bx"
expectMatch	13.18 P		"a\\u00088x"	"a\b8x"	"a\b8x"
expectMatch	13.19 P		"a\\U00000008x"	"a\bx"	"a\bx"
expectMatch	13.20 P		{a\U0000008x}	"a\bx"	"a\bx"
expectMatch	13.21 P		"a\\vb"		"a\vb"	"a\vb"
expectMatch	13.22 MP	"a\\x08x"	"a\bx"	"a\bx"
expectError	13.23 -		{a\xq}		EESCAPE
expectMatch	13.24 MP	"a\\x08x"	"a\bx"	"a\bx"
expectError	13.25 -		{a\z}		EESCAPE
expectMatch	13.26 MP	"a\\010b"	"a\bb"	"a\bb"
expectMatch	13.27 P		"a\\U00001234x"	"a\u1234x"	"a\u1234x"
expectMatch	13.28 P		{a\U00001234x}	"a\u1234x"	"a\u1234x"
expectMatch	13.29 P		"a\\U0001234x"	"a\u1234x"	"a\u1234x"
expectMatch	13.30 P		{a\U0001234x}	"a\u1234x"	"a\u1234x"
expectMatch	13.31 P		"a\\U000012345x"	"a\u12345x"	"a\u12345x"
expectMatch	13.32 P		{a\U000012345x}	"a\u12345x"	"a\u12345x"
expectMatch	13.33 P		"a\\U1000000x"	"a\ufffd0x"	"a\ufffd0x"
expectMatch	13.34 P		{a\U1000000x}	"a\ufffd0x"	"a\ufffd0x"


doing 14 "back references"
# ugh
expectMatch	14.1  RP	{a(b*)c\1}	abbcbb	abbcbb	bb
expectMatch	14.2  RP	{a(b*)c\1}	ac	ac	""
expectNomatch	14.3  RP	{a(b*)c\1}	abbcb
678
679
680
681
682
683
684

685
686
687
688
689
690
691
	"abbbbbbbbbbbc" abbbbbbbbbbbc b b b b b b b b b b
# but we're fussy about border cases -- guys who want octal should use the zero
expectError	15.9  -	{a((((((((((b\10))))))))))c}	ESUBREG
# BREs don't have octal, EREs don't have backrefs
expectMatch	15.10 MP	"a\\12b"	"a\nb"	"a\nb"
expectError	15.11 b		{a\12b}		ESUBREG
expectMatch	15.12 eAS	{a\12b}		a12b	a12b



doing 16 "expanded syntax"
expectMatch	16.1 xP		"a b c"		"abc"	"abc"
expectMatch	16.2 xP		"a b #oops\nc\td"	"abcd"	"abcd"
expectMatch	16.3 x		"a\\ b\\\tc"	"a b\tc"	"a b\tc"
expectMatch	16.4 xP		"a b\\#c"	"ab#c"	"ab#c"







>







686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
	"abbbbbbbbbbbc" abbbbbbbbbbbc b b b b b b b b b b
# but we're fussy about border cases -- guys who want octal should use the zero
expectError	15.9  -	{a((((((((((b\10))))))))))c}	ESUBREG
# BREs don't have octal, EREs don't have backrefs
expectMatch	15.10 MP	"a\\12b"	"a\nb"	"a\nb"
expectError	15.11 b		{a\12b}		ESUBREG
expectMatch	15.12 eAS	{a\12b}		a12b	a12b
expectMatch	15.13 MP	{a\701b}	a\u00381b	a\u00381b


doing 16 "expanded syntax"
expectMatch	16.1 xP		"a b c"		"abc"	"abc"
expectMatch	16.2 xP		"a b #oops\nc\td"	"abcd"	"abcd"
expectMatch	16.3 x		"a\\ b\\\tc"	"a b\tc"	"a b\tc"
expectMatch	16.4 xP		"a b\\#c"	"ab#c"	"ab#c"

Changes to tests/safe.test.

537
538
539
540
541
542
543
















544
545
546
547
548
549
550
test safe-12.7 {glob is restricted} -setup {
    set i [safe::interpCreate]
} -body {
    $i eval glob *
} -cleanup {
    safe::interpDelete $i
} -match glob -result *

















set ::auto_path $saveAutoPath
# cleanup
::tcltest::cleanupTests
return

# Local Variables:







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







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
test safe-12.7 {glob is restricted} -setup {
    set i [safe::interpCreate]
} -body {
    $i eval glob *
} -cleanup {
    safe::interpDelete $i
} -match glob -result *

test safe-13.1 {safe file ensemble does not surprise code} -setup {
    set i [interp create -safe]
} -body {
    set result [expr {"file" in [interp hidden $i]}]
    lappend result [interp eval $i {tcl::file::split a/b/c}]
    lappend result [catch {interp eval $i {tcl::file::isdirectory .}}]
    lappend result [interp invokehidden $i file split a/b/c]
    lappend result [catch {interp eval $i {file split a/b/c}} msg] $msg
    lappend result [catch {interp invokehidden $i file isdirectory .}]
    interp expose $i file
    lappend result [catch {interp eval $i {file split a/b/c}} msg] $msg
    lappend result [catch {interp eval $i {file isdirectory .}} msg] $msg
} -cleanup {
    interp delete $i
} -result {1 {a b c} 1 {a b c} 1 {invalid command name "file"} 1 0 {a b c} 1 {invalid command name "::tcl::file::isdirectory"}}

set ::auto_path $saveAutoPath
# cleanup
::tcltest::cleanupTests
return

# Local Variables:

Changes to tests/scan.test.

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
    set x {}
    set y {}
    catch {unset z}; array set z {}
    set result [list [catch {scan {abc def ghi} {%s%s%s} x z y} msg] \
	    $msg $x $y]
    unset z
    set result
} {1 {couldn't set variable "z"} abc ghi}
test scan-4.61 {Tcl_ScanObjCmd, set errors} {
    set x {}
    catch {unset y}; array set y {}
    catch {unset z}; array set z {}
    set result [list [catch {scan {abc def ghi} {%s%s%s} x z y} msg] \
	    $msg $x]
    unset y
    unset z
    set result
} {1 {couldn't set variable "z"couldn't set variable "y"} abc}

# procedure that returns the range of integers

proc int_range {} {
    for { set MIN_INT 1 } { int($MIN_INT) > 0 } {} {
	set MIN_INT [expr { $MIN_INT << 1 }]
    }







|









|







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
    set x {}
    set y {}
    catch {unset z}; array set z {}
    set result [list [catch {scan {abc def ghi} {%s%s%s} x z y} msg] \
	    $msg $x $y]
    unset z
    set result
} {1 {can't set "z": variable is array} abc ghi}
test scan-4.61 {Tcl_ScanObjCmd, set errors} {
    set x {}
    catch {unset y}; array set y {}
    catch {unset z}; array set z {}
    set result [list [catch {scan {abc def ghi} {%s%s%s} x z y} msg] \
	    $msg $x]
    unset y
    unset z
    set result
} {1 {can't set "z": variable is array} abc}

# procedure that returns the range of integers

proc int_range {} {
    for { set MIN_INT 1 } { int($MIN_INT) > 0 } {} {
	set MIN_INT [expr { $MIN_INT << 1 }]
    }
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
    set a {}; set b {}; set c {}; set d {}
    list [scan "1 2" "%d %d %d %d" a b c d] $a $b $c $d
} {2 1 2 {} {}}
test scan-8.12 {error conditions} {
    catch {unset a}
    set a(0) 44
    list [catch {scan 44 %d a} msg] $msg
} {1 {couldn't set variable "a"}}
test scan-8.13 {error conditions} {
    catch {unset a}
    set a(0) 44
    list [catch {scan 44 %c a} msg] $msg
} {1 {couldn't set variable "a"}}
test scan-8.14 {error conditions} {
    catch {unset a}
    set a(0) 44
    list [catch {scan 44 %s a} msg] $msg
} {1 {couldn't set variable "a"}}
test scan-8.15 {error conditions} {
    catch {unset a}
    set a(0) 44
    list [catch {scan 44 %f a} msg] $msg
} {1 {couldn't set variable "a"}}
test scan-8.16 {error conditions} {
    catch {unset a}
    set a(0) 44
    list [catch {scan 44 %f a} msg] $msg
} {1 {couldn't set variable "a"}}
catch {unset a}
test scan-8.17 {error conditions} {
    list [catch {scan 44 %2c a} msg] $msg
} {1 {field width may not be specified in %c conversion}}
test scan-8.18 {error conditions} {
    list [catch {scan abc {%[} x} msg] $msg
} {1 {unmatched [ in format string}}







|




|




|




|




|







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
    set a {}; set b {}; set c {}; set d {}
    list [scan "1 2" "%d %d %d %d" a b c d] $a $b $c $d
} {2 1 2 {} {}}
test scan-8.12 {error conditions} {
    catch {unset a}
    set a(0) 44
    list [catch {scan 44 %d a} msg] $msg
} {1 {can't set "a": variable is array}}
test scan-8.13 {error conditions} {
    catch {unset a}
    set a(0) 44
    list [catch {scan 44 %c a} msg] $msg
} {1 {can't set "a": variable is array}}
test scan-8.14 {error conditions} {
    catch {unset a}
    set a(0) 44
    list [catch {scan 44 %s a} msg] $msg
} {1 {can't set "a": variable is array}}
test scan-8.15 {error conditions} {
    catch {unset a}
    set a(0) 44
    list [catch {scan 44 %f a} msg] $msg
} {1 {can't set "a": variable is array}}
test scan-8.16 {error conditions} {
    catch {unset a}
    set a(0) 44
    list [catch {scan 44 %f a} msg] $msg
} {1 {can't set "a": variable is array}}
catch {unset a}
test scan-8.17 {error conditions} {
    list [catch {scan 44 %2c a} msg] $msg
} {1 {field width may not be specified in %c conversion}}
test scan-8.18 {error conditions} {
    list [catch {scan abc {%[} x} msg] $msg
} {1 {unmatched [ in format string}}
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
    }
}

testConstraint ieeeFloatingPoint [testIEEE]

# scan infinities - not working

test scan-14.1 {infinity} ieeeFloatingPoint {
    scan Inf %g d
    set d
} Inf
test scan-14.2 {infinity} ieeeFloatingPoint {
    scan -Inf %g d
    set d
} -Inf

# TODO - also need to scan NaN's

# cleanup
::tcltest::cleanupTests
return

# Local Variables:
# mode: tcl
# End:







|



|













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
    }
}

testConstraint ieeeFloatingPoint [testIEEE]

# scan infinities - not working

test scan-14.1 {infinity} {
    scan Inf %g d
    set d
} Inf
test scan-14.2 {infinity} {
    scan -Inf %g d
    set d
} -Inf

# TODO - also need to scan NaN's

# cleanup
::tcltest::cleanupTests
return

# Local Variables:
# mode: tcl
# End:

Changes to tests/socket.test.

59
60
61
62
63
64
65
66
67
68
69
70
71
72


















73
74
75
76
77
78
79
# server (via exec) on platforms that support this, on the local host,
# listening at port 2048. If all fails, a message is printed and the tests
# using the remote server are not performed.

package require tcltest 2
namespace import -force ::tcltest::*

# Some tests require the testthread and exec commands
testConstraint testthread [llength [info commands testthread]]
testConstraint exec [llength [info commands exec]]

# Produce a random port number in the Dynamic/Private range
# from 49152 through 65535.
proc randport {} { expr {int(rand()*16383+49152)} }



















# If remoteServerIP or remoteServerPort are not set, check in the environment
# variables for externally set values.
#

if {![info exists remoteServerIP]} {
    if {[info exists env(remoteServerIP)]} {







|
|





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







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
# server (via exec) on platforms that support this, on the local host,
# listening at port 2048. If all fails, a message is printed and the tests
# using the remote server are not performed.

package require tcltest 2
namespace import -force ::tcltest::*

# Some tests require the Thread package or exec command
testConstraint thread [expr {0 == [catch {package require Thread 2.6}]}]
testConstraint exec [llength [info commands exec]]

# Produce a random port number in the Dynamic/Private range
# from 49152 through 65535.
proc randport {} { expr {int(rand()*16383+49152)} }

# Test the latency of tcp connections over the loopback interface. Some OSes
# (e.g. NetBSD) seem to use the Nagle algorithm and delayed ACKs, so it takes
# up to 200ms for a packet sent to localhost to arrive. We're measuring this
# here, so that OSes that don't have this problem can run the tests at full
# speed.
set server [socket -server {apply {{s a p} {set ::s1 $s}}} 0]
set s2 [socket localhost [lindex [fconfigure $server -sockname] 2]]
vwait s1; close $server
fconfigure $s1 -buffering line
fconfigure $s2 -buffering line
set t1 [clock milliseconds]
puts $s2 test1; gets $s1
puts $s2 test2; gets $s1
close $s1; close $s2
set t2 [clock milliseconds]
set latency [expr {($t2-$t1)*2}]; # doubled as a safety margin
unset t1 t2 s1 s2 server

# If remoteServerIP or remoteServerPort are not set, check in the environment
# variables for externally set values.
#

if {![info exists remoteServerIP]} {
    if {[info exists env(remoteServerIP)]} {
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
if 0 {
    # activate this to time the tests
    proc test {args} {
        set name [lindex $args 0]
        puts "[lindex [time {uplevel [linsert $args 0 tcltest::test]}] 0] @@@ $name"
    }
}


















foreach {af localhost} {
    any 127.0.0.1
    inet 127.0.0.1
    inet6 ::1
} {
    set ::tcl::unsupported::socketAF $af
    # Check if the family is supported and set the constraint accordingly
    testConstraint supported_$af [expr {![catch {socket -server foo 0} sock]}]
    catch {close $sock}
    
#
# Check if we're supposed to do tests against the remote server
#

set doTestsWithRemoteServer 1
if {![info exists remoteServerIP]} {
    set remoteServerIP $localhost







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







<
<
<
<







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
if 0 {
    # activate this to time the tests
    proc test {args} {
        set name [lindex $args 0]
        puts "[lindex [time {uplevel [linsert $args 0 tcltest::test]}] 0] @@@ $name"
    }
}

foreach {af localhost} {
    inet 127.0.0.1
    inet6 ::1
} {
    # Check if the family is supported and set the constraint accordingly
    testConstraint supported_$af [expr {![catch {socket -server foo -myaddr $localhost 0} sock]}]
    catch {close $sock}
}
testConstraint supported_any [expr {[testConstraint supported_inet] || [testConstraint supported_inet6]}]

set sock [socket -server foo -myaddr localhost 0]
set sockname [fconfigure $sock -sockname]
close $sock
testConstraint localhost_v4 [expr {"127.0.0.1" in $sockname}]
testConstraint localhost_v6 [expr {"::1" in $sockname}]


foreach {af localhost} {
    any 127.0.0.1
    inet 127.0.0.1
    inet6 ::1
} {
    set ::tcl::unsupported::socketAF $af




#
# Check if we're supposed to do tests against the remote server
#

set doTestsWithRemoteServer 1
if {![info exists remoteServerIP]} {
    set remoteServerIP $localhost
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
    vwait x
    fconfigure $sock -blocking 0
    set result a:[gets $sock]
    lappend result b:[gets $sock]
    fconfigure $sock -blocking 1
    puts $s2 two
    flush $s2
    after idle {set x 1}
    vwait x
    fconfigure $sock -blocking 0
    lappend result c:[gets $sock]
} -cleanup {
    fconfigure $sock -blocking 1
    close $s2
    close $s







|







611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
    vwait x
    fconfigure $sock -blocking 0
    set result a:[gets $sock]
    lappend result b:[gets $sock]
    fconfigure $sock -blocking 1
    puts $s2 two
    flush $s2
    after $latency {set x 1}; # NetBSD fails here if we do [after idle]
    vwait x
    fconfigure $sock -blocking 0
    lappend result c:[gets $sock]
} -cleanup {
    fconfigure $sock -blocking 1
    close $s2
    close $s
796
797
798
799
800
801
802


















803
804
805
806
807
808
809
    after cancel $timer
    close $s
    return $x
} -cleanup {
    interp bgerror {} $handler
} -result {divide by zero}



















test socket_$af-7.1 {testing socket specific options} -setup {
    file delete $path(script)
    set f [open $path(script) w]
    puts $f {
	set ss [socket -server accept 0]
	proc accept args {
	    global x







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







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
    after cancel $timer
    close $s
    return $x
} -cleanup {
    interp bgerror {} $handler
} -result {divide by zero}

test socket_$af-6.2 {
    readable fileevent on server socket
} -setup {
    set sock [socket -server dummy 0]
} -constraints [list socket supported_$af] -body {
    fileevent $sock readable dummy
} -cleanup {
    close $sock
} -returnCodes 1 -result "channel is not readable"

test socket_$af-6.3 {writable fileevent on server socket} -setup {
    set sock [socket -server dummy 0]
} -constraints [list socket supported_$af] -body {
    fileevent $sock writable dummy
} -cleanup {
    close $sock
} -returnCodes 1 -result "channel is not writable"

test socket_$af-7.1 {testing socket specific options} -setup {
    file delete $path(script)
    set f [open $path(script) w]
    puts $f {
	set ss [socket -server accept 0]
	proc accept args {
	    global x
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
    gets $p listen
    set f [socket $localhost $listen]
    fconfigure $f -buffering full -blocking 0
    fileevent $f readable [list getdata $f]
    # If the socket is still open after 5 seconds, the script1 process must
    # have inherited the accepted socket.
    set failed 0
    after 5000 set failed 1
    proc getdata { file } {
	# Read handler on the client socket.
	global x
	global failed
	set status [catch {read $file} data]
	if {$status != 0} {
	    set x {read failed, error was $data}







|







1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
    gets $p listen
    set f [socket $localhost $listen]
    fconfigure $f -buffering full -blocking 0
    fileevent $f readable [list getdata $f]
    # If the socket is still open after 5 seconds, the script1 process must
    # have inherited the accepted socket.
    set failed 0
    set after [after 5000 [list set failed 1]]
    proc getdata { file } {
	# Read handler on the client socket.
	global x
	global failed
	set status [catch {read $file} data]
	if {$status != 0} {
	    set x {read failed, error was $data}
1615
1616
1617
1618
1619
1620
1621

1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
	    catch { close $file }
	}
	return
    }
    vwait x
    return $x
} -cleanup {

    catch {close $p}
} -result {accepted socket was not inherited}

test socket_$af-13.1 {Testing use of shared socket between two threads} -setup {
    threadReap
    set path(script) [makeFile [string map [list @localhost@ $localhost] {
        set f [socket -server accept -myaddr @localhost@ 0]
        set listen [lindex [fconfigure $f -sockname] 2]
        proc accept {s a p} {
            fileevent $s readable [list echo $s]
            fconfigure $s -buffering line
        }
        proc echo {s} {







>



|
|
|







1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
	    catch { close $file }
	}
	return
    }
    vwait x
    return $x
} -cleanup {
    after cancel $after
    catch {close $p}
} -result {accepted socket was not inherited}

test socket_$af-13.1 {Testing use of shared socket between two threads} -body {
    # create a thread
    set serverthread [thread::create -preserved [string map [list @localhost@ $localhost] {
        set f [socket -server accept -myaddr @localhost@ 0]
        set listen [lindex [fconfigure $f -sockname] 2]
        proc accept {s a p} {
            fileevent $s readable [list echo $s]
            fconfigure $s -buffering line
        }
        proc echo {s} {
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
                 incr i
                 puts $s $l
             }
        }
        set i 0
        vwait x
        close $f
        # thread cleans itself up.
        testthread exit
    }] script]
} -constraints [list socket supported_$af testthread] -body {
    # create a thread
    set serverthread [testthread create [list source $path(script) ] ]
    update
    set port [testthread send $serverthread {set listen}]
    update
    set s [socket $localhost $port]
    fconfigure $s -buffering line
    catch {
        puts $s "hello"
        gets $s result
    }
    close $s
    update
    append result " " [threadReap]
} -cleanup {
    removeFile script
} -result {hello 1}

# ----------------------------------------------------------------------

removeFile script1
removeFile script2

# cleanup
if {$remoteProcChan ne ""} {
    catch {sendCommand exit}
}
catch {close $commandSocket}
catch {close $remoteProcChan}
}





























































































































::tcltest::cleanupTests
flush stdout
return

# Local Variables:
# mode: tcl
# fill-column: 78
# End:







<
<
|
<
<
<
<
|
<







|
|
<
<
|













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








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
                 incr i
                 puts $s $l
             }
        }
        set i 0
        vwait x
        close $f


    }]]




    set port [thread::send $serverthread {set listen}]

    set s [socket $localhost $port]
    fconfigure $s -buffering line
    catch {
        puts $s "hello"
        gets $s result
    }
    close $s
    thread::release $serverthread
    append result " " [llength [thread::names]]


} -result {hello 1} -constraints [list socket supported_$af thread] 

# ----------------------------------------------------------------------

removeFile script1
removeFile script2

# cleanup
if {$remoteProcChan ne ""} {
    catch {sendCommand exit}
}
catch {close $commandSocket}
catch {close $remoteProcChan}
}
unset ::tcl::unsupported::socketAF
test socket-14.0 {[socket -async] when server only listens on IPv4} \
    -constraints [list socket supported_any localhost_v4] \
    -setup {
        proc accept {s a p} {
            global x
            puts $s bye
            close $s
            set x ok
        }
        set server [socket -server accept -myaddr 127.0.0.1 0]
        set port [lindex [fconfigure $server -sockname] 2]
    } -body {
        set client [socket -async localhost $port]
        set after [after 1000 {set x [fconfigure $client -error]}]
        vwait x
        set x
    } -cleanup {
        after cancel $after
        close $server
        close $client
        unset x
    } -result ok
test socket-14.1 {[socket -async] fileevent while still connecting} \
    -constraints [list socket supported_any] \
    -setup {
        proc accept {s a p} {
            global x
            puts $s bye
            close $s
	    lappend x ok
        }
        set server [socket -server accept -myaddr localhost 0]
        set port [lindex [fconfigure $server -sockname] 2]
        set x ""
    } -body {
        set client [socket -async localhost $port]
        fileevent $client writable {
            lappend x [fconfigure $client -error]
	    fileevent $client writable {}
        }
        set after [after 1000 {lappend x timeout}]
        while {[llength $x] < 2 && "timeout" ni $x} {
            vwait x
        }
        lsort $x; # we only want to see both events, the order doesn't matter
    } -cleanup {
        after cancel $after
        close $server
        close $client
        unset x
    } -result {{} ok}
test socket-14.2 {[socket -async] fileevent connection refused} \
    -constraints [list socket supported_any] \
    -body {
        set client [socket -async localhost [randport]]
        fileevent $client writable {set x [fconfigure $client -error]}
        set after [after 1000 {set x timeout}]
        vwait x
        if {$x eq "timeout"} {
            append x ": [fconfigure $client -error]"
        }
        set x
    } -cleanup {
        after cancel $after
        close $client
        unset x
    } -result "connection refused"
test socket-14.3 {[socket -async] when server only listens on IPv6} \
    -constraints [list socket supported_any localhost_v6] \
    -setup {
        proc accept {s a p} {
            global x
            puts $s bye
            close $s
            set x ok
        }
        set server [socket -server accept -myaddr ::1 0]
        set port [lindex [fconfigure $server -sockname] 2]
    } -body {
        set client [socket -async localhost $port]
        set after [after 1000 {set x [fconfigure $client -error]}]
        vwait x
        set x
    } -cleanup {
        after cancel $after
        close $server
        close $client
        unset x
    } -result ok
test socket-14.4 {[socket -async] and both, readdable and writable fileevents} \
    -constraints [list socket supported_any] \
    -setup {
        proc accept {s a p} {
            puts $s bye
            close $s
        }
        set server [socket -server accept -myaddr localhost 0]
        set port [lindex [fconfigure $server -sockname] 2]
        set x ""
    } -body {
        set client [socket -async localhost $port]
        fileevent $client writable {
            lappend x [fconfigure $client -error]
            fileevent $client writable {}
        }
        fileevent $client readable {lappend x [gets $client]}
        set after [after 1000 {lappend x timeout}]
        while {[llength $x] < 2 && "timeout" ni $x} {
            vwait x
        }
        lsort $x
    } -cleanup {
        after cancel $after
        close $client
        close $server
    } -result {{} bye}
test socket-14.5 {[socket -async] which fails before any connect() can be made} \
    -constraints [list socket supported_any] \
    -body {
        # address from rfc5737
        socket -async -myaddr 192.0.2.42 127.0.0.1 [randport]
    } \
    -returnCodes 1 \
    -result {couldn't open socket: cannot assign requested address}
::tcltest::cleanupTests
flush stdout
return

# Local Variables:
# mode: tcl
# fill-column: 78
# End:

Changes to tests/string.test.

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
    set result ""
    set numbers [list 1.0 +1.0 ++1.0 +-1.0 -+1.0 -1.0 --1.0 "- +1.0"]
    foreach num $numbers {
	lappend result [string is double -strict $num]
    }
    set result
} {1 1 0 0 0 1 0 0}
test string-6.92 {string is double, 32-bit overflow} {
    # Bug 718878
    set x 0x100000000
    list [string is integer -failindex var $x] $var
} {0 -1}
test string-6.93 {string is double, 32-bit overflow} {
    # Bug 718878
    set x 0x100000000
    append x ""
    list [string is integer -failindex var $x] $var
} {0 -1}
test string-6.94 {string is double, 32-bit overflow} {
    # Bug 718878
    set x 0x100000000
    list [string is integer -failindex var [expr {$x}]] $var
} {0 -1}
test string-6.95 {string is wideinteger, true} {
    string is wideinteger +1234567890
} 1







|




|





|







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
    set result ""
    set numbers [list 1.0 +1.0 ++1.0 +-1.0 -+1.0 -1.0 --1.0 "- +1.0"]
    foreach num $numbers {
	lappend result [string is double -strict $num]
    }
    set result
} {1 1 0 0 0 1 0 0}
test string-6.92 {string is integer, 32-bit overflow} {
    # Bug 718878
    set x 0x100000000
    list [string is integer -failindex var $x] $var
} {0 -1}
test string-6.93 {string is integer, 32-bit overflow} {
    # Bug 718878
    set x 0x100000000
    append x ""
    list [string is integer -failindex var $x] $var
} {0 -1}
test string-6.94 {string is integer, 32-bit overflow} {
    # Bug 718878
    set x 0x100000000
    list [string is integer -failindex var [expr {$x}]] $var
} {0 -1}
test string-6.95 {string is wideinteger, true} {
    string is wideinteger +1234567890
} 1
1614
1615
1616
1617
1618
1619
1620
















1621
1622
1623
1624
1625
1626
1627
    string reverse $x
} \udead\ubeef
test string-24.11 {string reverse command - corner case} {
    set x \ubeef
    set y \udead
    string reverse $x$y
} \udead\ubeef

















test string-25.1 {string is list} {
    string is list {a b c}
} 1
test string-25.2 {string is list} {
    string is list "a \{b c"
} 0







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







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
    string reverse $x
} \udead\ubeef
test string-24.11 {string reverse command - corner case} {
    set x \ubeef
    set y \udead
    string reverse $x$y
} \udead\ubeef
test string-24.12 {string reverse command - corner case} {
    set x \ubeef
    set y \udead
    string is ascii [string reverse $x$y]
} 0
test string-24.13 {string reverse command - pure Unicode string} {
    string reverse [string range \ubeef\udead\ubeef\udead\ubeef\udead 1 5]
} \udead\ubeef\udead\ubeef\udead
test string-24.14 {string reverse command - pure bytearray} {
    binary scan [string reverse [binary format H* 010203]] H* x
    set x
} 030201
test string-24.15 {string reverse command - pure bytearray} {
    binary scan [tcl::string::reverse [binary format H* 010203]] H* x
    set x
} 030201

test string-25.1 {string is list} {
    string is list {a b c}
} 1
test string-25.2 {string is list} {
    string is list "a \{b c"
} 0

Changes to tests/thread.test.

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
    package require tcltest
    namespace import -force ::tcltest::*
}

# Some tests require the testthread command

testConstraint testthread [expr {[info commands testthread] != {}}]














if {[testConstraint testthread]} {
    testthread errorproc ThreadError

    proc ThreadError {id info} {
	global threadId threadError
	set threadId $id
	set threadError $info
    }

    proc ThreadNullError {id info} {
	# ignore
    }
}

















test thread-1.1 {Tcl_ThreadObjCmd: no args} {testthread} {
    list [catch {testthread} msg] $msg
} {1 {wrong # args: should be "testthread option ?arg ...?"}}
test thread-1.2 {Tcl_ThreadObjCmd: bad option} {testthread} {
    list [catch {testthread foo} msg] $msg
} {1 {bad option "foo": must be cancel, create, event, exit, id, join, names, send, wait, or errorproc}}
test thread-1.3 {Tcl_ThreadObjCmd: initial thread list} {testthread} {
    list [threadReap] [llength [testthread names]]
} {1 1}
test thread-1.4 {Tcl_ThreadObjCmd: thread create } {testthread} {
    threadReap
    set serverthread [testthread create]
    update
    set numthreads [llength [testthread names]]
    threadReap
    set numthreads
} {2}
test thread-1.5 {Tcl_ThreadObjCmd: thread create one shot} {testthread} {
    threadReap
    testthread create {set x 5}
    foreach try {0 1 2 4 5 6} {
	# Try various ways to yield
	update
	after 10
	set l [llength [testthread names]]
	if {$l == 1} {
	    break
	}
    }
    threadReap
    set l
} {1}
test thread-1.6 {Tcl_ThreadObjCmd: thread exit} {testthread} {
    threadReap
    testthread create {testthread exit}
    update
    after 10
    set result [llength [testthread names]]
    threadReap
    set result
} {1}
test thread-1.7 {Tcl_ThreadObjCmd: thread id args} {testthread} {
    set x [catch {testthread id x} msg]
    list $x $msg
} {1 {wrong # args: should be "testthread id"}}
test thread-1.8 {Tcl_ThreadObjCmd: thread id} {testthread} {
    string compare [testthread id] $::tcltest::mainThread
} {0}
test thread-1.9 {Tcl_ThreadObjCmd: thread names args} {testthread} {
    set x [catch {testthread names x} msg]
    list $x $msg
} {1 {wrong # args: should be "testthread names"}}
test thread-1.10 {Tcl_ThreadObjCmd: thread id} {testthread} {
    string compare [testthread names] $::tcltest::mainThread
} {0}
test thread-1.11 {Tcl_ThreadObjCmd: send args} {testthread} {
    set x [catch {testthread send} msg]
    list $x $msg
} {1 {wrong # args: should be "testthread send ?-async? id script"}}
test thread-1.12 {Tcl_ThreadObjCmd: send nonint} {testthread} {
    set x [catch {testthread send abc command} msg]
    list $x $msg
} {1 {expected integer but got "abc"}}
test thread-1.13 {Tcl_ThreadObjCmd: send args} {testthread} {
    threadReap
    set serverthread [testthread create]
    set five [testthread send $serverthread {set x 5}]
    threadReap
    set five
} 5
test thread-1.14 {Tcl_ThreadObjCmd: send bad id} {testthread} {
    set tid [expr $::tcltest::mainThread + 10]
    set x [catch {testthread send $tid {set x 5}} msg]
    list $x $msg
} {1 {invalid thread id}}
test thread-1.15 {Tcl_ThreadObjCmd: wait} {testthread} {
    threadReap
    set serverthread [testthread create {set z 5 ; testthread wait}]
    set five [testthread send $serverthread {set z}]
    threadReap
    set five
} 5
test thread-1.16 {Tcl_ThreadObjCmd: errorproc args} {testthread} {
    set x [catch {testthread errorproc foo bar} msg]
    list $x $msg
} {1 {wrong # args: should be "testthread errorproc proc"}}
test thread-1.17 {Tcl_ThreadObjCmd: errorproc change} {testthread} {
    testthread errorproc foo
    testthread errorproc ThreadError
} {}

# The tests above also cover:
# TclCreateThread, except when pthread_create fails
# NewThread, safe and regular
# ThreadErrorProc, except for printing to standard error

test thread-2.1 {ListUpdateInner and ListRemove} {testthread} {
    threadReap
    catch {unset tid}
    foreach t {0 1 2} {
	upvar #0 t$t tid
	set tid [testthread create]
    }


    threadReap


} 1

test thread-3.1 {TclThreadList} {testthread} {
    threadReap
    catch {unset tid}
    set len [llength [testthread names]]
    set l1  {}
    foreach t {0 1 2} {
	lappend l1 [testthread create]
    }
    set l2 [testthread names]
    list $l1 $l2
    set c [string compare \
	    [lsort -integer [concat $::tcltest::mainThread $l1]] \
	    [lsort -integer $l2]]
    threadReap

    list $len $c
} {1 0}

test thread-4.1 {TclThreadSend to self} {testthread} {
    catch {unset x}
    testthread send [testthread id] {
	set x 4
    }
    set x
} {4}
test thread-4.2 {TclThreadSend -async} {testthread} {
    threadReap
    set len [llength [testthread names]]
    set serverthread [testthread create]
    testthread send -async $serverthread {
	after 1000
	testthread exit
    }
    set two [llength [testthread names]]
    after 1500 {set done 1}
    vwait done
    threadReap
    list $len [llength [testthread names]] $two
} {1 1 2}
test thread-4.3 {TclThreadSend preserve errorInfo} {testthread} {
    threadReap
    set len [llength [testthread names]]
    set serverthread [testthread create]
    set x [catch {testthread send $serverthread {set undef}} msg]
    set savedErrorInfo $::errorInfo
    threadReap
    list $len $x $msg $savedErrorInfo
} {1 1 {can't read "undef": no such variable} {can't read "undef": no such variable
    while executing
"set undef"
    invoked from within
"testthread send $serverthread {set undef}"}}
test thread-4.4 {TclThreadSend preserve code} {testthread} {
    threadReap
    set len [llength [testthread names]]
    set serverthread [testthread create]
    set ::errorInfo {}
    set x [catch {testthread send $serverthread {set ::errorInfo {}; break}} msg]
    set savedErrorInfo $::errorInfo
    threadReap
    list $len $x $msg $savedErrorInfo
} {1 3 {} {}}
test thread-4.5 {TclThreadSend preserve errorCode} {testthread} {
    threadReap
    set ::tcltest::mainThread [testthread names]
    set serverthread [testthread create]
    set x [catch {testthread send $serverthread {error ERR INFO CODE}} msg]
    set savedErrorCode $::errorCode
    threadReap
    list $x $msg $savedErrorCode
} {1 ERR CODE}


test thread-5.0 {Joining threads} {testthread} {
    threadReap
    set serverthread [testthread create -joinable]
    testthread send -async $serverthread {after 1000 ; testthread exit}
    set res [testthread join $serverthread]
    threadReap
    set res
} {0}
test thread-5.1 {Joining threads after the fact} {testthread} {
    threadReap
    set serverthread [testthread create -joinable]
    testthread send -async $serverthread {testthread exit}
    after 2000
    set res [testthread join $serverthread]
    threadReap
    set res
} {0}
test thread-5.2 {Try to join a detached thread} {testthread} {
    threadReap
    set serverthread [testthread create]
    testthread send -async $serverthread {after 1000 ; testthread exit}
    catch {set res [testthread join $serverthread]} msg
    threadReap


    lrange $msg 0 2
} {cannot join thread}

test thread-6.1 {freeing very large object trees in a thread} testthread {
    # conceptual duplicate of obj-32.1
    threadReap
    set serverthread [testthread create -joinable]
    testthread send -async $serverthread {
	set x {}
	for {set i 0} {$i<100000} {incr i} {
	    set x [list $x {}]
	}
	unset x
	testthread exit
    }
    catch {set res [testthread join $serverthread]} msg
    threadReap
    set res
} {0}

# TIP #285: Script cancellation support
test thread-7.1 {cancel: args} {testthread} {
    set x [catch {testthread cancel} msg]
    list $x $msg
} {1 {wrong # args: should be "testthread cancel ?-unwind? id ?result?"}}
test thread-7.2 {cancel: nonint} {testthread} {
    set x [catch {testthread cancel abc} msg]
    list $x $msg
} {1 {expected integer but got "abc"}}
test thread-7.3 {cancel: bad id} {testthread} {
    set tid [expr $::tcltest::mainThread + 10]
    set x [catch {testthread cancel $tid} msg]
    list $x $msg
} {1 {invalid thread id}}
test thread-7.4 {cancel: pure bytecode loop} {testthread} {
    threadReap
    unset -nocomplain ::threadError ::threadId ::threadIdStarted
    set serverthread [testthread create -joinable {







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




<
|
<
<
<




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







|
|
|
|
<
|
<
|
|


|
<
|




|




<


|
|
<


<
|
<






|






|









|
<
|
|
|



|



|
<
|
|
|
















|
<



|

>
>
|
>
>


|
<

|


|

|
<
|
<
|
|
>



|

|




|
<
|
|
|
|
<

|
|

<
|

|
<
|
|
|

|





|
|
<
|
|

|

|


|
<
<
|
|

|




|
<
|
|
|
<
<

|
<
|
|

|
<
<

|
<
|
|
|
|
>
>



|

<
|
|





<

<
|
<
|











|







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
    package require tcltest
    namespace import -force ::tcltest::*
}

# Some tests require the testthread command

testConstraint testthread [expr {[info commands testthread] != {}}]
testConstraint thread [expr {0 == [catch {package require Thread 2.6}]}]

testConstraint notValgrind [expr {![testConstraint valgrind]}]

proc ThreadError {id info} {
    global threadId threadError
    set threadId $id
    set threadError $info
}

if {[testConstraint thread]} {
    thread::errorproc ThreadError
}

if {[testConstraint testthread]} {
    testthread errorproc ThreadError


    set mainThread [testthread id]




    proc ThreadNullError {id info} {
	# ignore
    }

    proc threadReap {} {
	testthread errorproc ThreadNullError
	while {[llength [testthread names]] > 1} {
	    foreach tid [testthread names] {
		if {$tid != [testthread id]} {
		    catch {
			testthread send -async $tid {testthread exit}
		    }
		}
	    }
	    after 1
	}
	testthread errorproc ThreadError
	return [llength [testthread names]]
    }
}

test thread-1.1 {Tcl_ThreadObjCmd: no args} {testthread} {
    list [catch {testthread} msg] $msg
} {1 {wrong # args: should be "testthread option ?arg ...?"}}
test thread-1.2 {Tcl_ThreadObjCmd: bad option} {testthread} {
    list [catch {testthread foo} msg] $msg
} {1 {bad option "foo": must be cancel, create, event, exit, id, join, names, send, wait, or errorproc}}
test thread-1.3 {Tcl_ThreadObjCmd: initial thread list} {thread} {
    llength [thread::names]
} 1
test thread-1.4 {Tcl_ThreadObjCmd: thread create } {thread} {

    set serverthread [thread::create -preserved]

    set numthreads [llength [thread::names]]
    thread::release $serverthread
    set numthreads
} {2}
test thread-1.5 {Tcl_ThreadObjCmd: thread create one shot} {thread} {

    thread::create {set x 5}
    foreach try {0 1 2 4 5 6} {
	# Try various ways to yield
	update
	after 10
	set l [llength [thread::names]]
	if {$l == 1} {
	    break
	}
    }

    set l
} {1}
test thread-1.6 {Tcl_ThreadObjCmd: thread exit} {thread} {
    thread::create {{*}{}}

    update
    after 10

    llength [thread::names]

} {1}
test thread-1.7 {Tcl_ThreadObjCmd: thread id args} {testthread} {
    set x [catch {testthread id x} msg]
    list $x $msg
} {1 {wrong # args: should be "testthread id"}}
test thread-1.8 {Tcl_ThreadObjCmd: thread id} {testthread} {
    string compare [testthread id] $mainThread
} {0}
test thread-1.9 {Tcl_ThreadObjCmd: thread names args} {testthread} {
    set x [catch {testthread names x} msg]
    list $x $msg
} {1 {wrong # args: should be "testthread names"}}
test thread-1.10 {Tcl_ThreadObjCmd: thread id} {testthread} {
    string compare [testthread names] $mainThread
} {0}
test thread-1.11 {Tcl_ThreadObjCmd: send args} {testthread} {
    set x [catch {testthread send} msg]
    list $x $msg
} {1 {wrong # args: should be "testthread send ?-async? id script"}}
test thread-1.12 {Tcl_ThreadObjCmd: send nonint} {testthread} {
    set x [catch {testthread send abc command} msg]
    list $x $msg
} {1 {expected integer but got "abc"}}
test thread-1.13 {Tcl_ThreadObjCmd: send args} {thread} {

    set serverthread [thread::create -preserved]
    set five [thread::send $serverthread {set x 5}]
    thread::release $serverthread
    set five
} 5
test thread-1.14 {Tcl_ThreadObjCmd: send bad id} {testthread} {
    set tid [expr $mainThread + 10]
    set x [catch {testthread send $tid {set x 5}} msg]
    list $x $msg
} {1 {invalid thread id}}
test thread-1.15 {Tcl_ThreadObjCmd: wait} {thread} {

    set serverthread [thread::create -preserved {set z 5 ; thread::wait}]
    set five [thread::send $serverthread {set z}]
    thread::release $serverthread
    set five
} 5
test thread-1.16 {Tcl_ThreadObjCmd: errorproc args} {testthread} {
    set x [catch {testthread errorproc foo bar} msg]
    list $x $msg
} {1 {wrong # args: should be "testthread errorproc proc"}}
test thread-1.17 {Tcl_ThreadObjCmd: errorproc change} {testthread} {
    testthread errorproc foo
    testthread errorproc ThreadError
} {}

# The tests above also cover:
# TclCreateThread, except when pthread_create fails
# NewThread, safe and regular
# ThreadErrorProc, except for printing to standard error

test thread-2.1 {ListUpdateInner and ListRemove} {thread} {

    catch {unset tid}
    foreach t {0 1 2} {
	upvar #0 t$t tid
	set tid [thread::create -preserved]
    }
    foreach t {0 1 2} {
	upvar #0 t$t tid
	thread::release $tid
    }
    llength [thread::names]
} 1

test thread-3.1 {TclThreadList} {thread} {

    catch {unset tid}
    set len [llength [thread::names]]
    set l1  {}
    foreach t {0 1 2} {
	lappend l1 [thread::create -preserved]
    }
    set l2 [thread::names]

    set c [string compare [lsort [concat [thread::id] $l1]] [lsort $l2]]

    foreach t $l1 {
	thread::release $t
    }
    list $len $c
} {1 0}

test thread-4.1 {TclThreadSend to self} {thread} {
    catch {unset x}
    thread::send [thread::id] {
	set x 4
    }
    set x
} {4}
test thread-4.2 {TclThreadSend -async} {thread} {

    set len [llength [thread::names]]
    set serverthread [thread::create -preserved]
    thread::send -async $serverthread {
	after 1 {thread::release}

    }
    set two [llength [thread::names]]
    after 100 {set done 1}
    vwait done

    list $len [llength [thread::names]] $two
} {1 1 2}
test thread-4.3 {TclThreadSend preserve errorInfo} {thread} {

    set len [llength [thread::names]]
    set serverthread [thread::create -preserved]
    set x [catch {thread::send $serverthread {set undef}} msg]
    set savedErrorInfo $::errorInfo
    thread::release $serverthread
    list $len $x $msg $savedErrorInfo
} {1 1 {can't read "undef": no such variable} {can't read "undef": no such variable
    while executing
"set undef"
    invoked from within
"thread::send $serverthread {set undef}"}}
test thread-4.4 {TclThreadSend preserve code} {thread} {

    set len [llength [thread::names]]
    set serverthread [thread::create -preserved]
    set ::errorInfo {}
    set x [catch {thread::send $serverthread {set ::errorInfo {}; break}} msg]
    set savedErrorInfo $::errorInfo
    thread::release $serverthread
    list $len $x $msg $savedErrorInfo
} {1 3 {} {}}
test thread-4.5 {TclThreadSend preserve errorCode} {thread} {


    set serverthread [thread::create]
    set x [catch {thread::send $serverthread {error ERR INFO CODE}} msg]
    set savedErrorCode $::errorCode
    thread::release $serverthread
    list $x $msg $savedErrorCode
} {1 ERR CODE}


test thread-5.0 {Joining threads} {thread} {

    set serverthread [thread::create -joinable -preserved]
    thread::send -async $serverthread {after 1000 ; thread::release}
    thread::join $serverthread


} {0}
test thread-5.1 {Joining threads after the fact} {thread} {

    set serverthread [thread::create -joinable -preserved]
    thread::send -async $serverthread {thread::release}
    after 2000
    thread::join $serverthread


} {0}
test thread-5.2 {Try to join a detached thread} {thread} {

    set serverthread [thread::create -preserved]
    thread::send -async $serverthread {after 1000 ; thread::release}
    catch {set res [thread::join $serverthread]} msg
    while {[llength [thread::names]] > 1} {
	after 20
    }
    lrange $msg 0 2
} {cannot join thread}

test thread-6.1 {freeing very large object trees in a thread} thread {
    # conceptual duplicate of obj-32.1

    set serverthread [thread::create -preserved]
    thread::send -async $serverthread {
	set x {}
	for {set i 0} {$i<100000} {incr i} {
	    set x [list $x {}]
	}
	unset x

    }

    thread::release -wait $serverthread

} 0

# TIP #285: Script cancellation support
test thread-7.1 {cancel: args} {testthread} {
    set x [catch {testthread cancel} msg]
    list $x $msg
} {1 {wrong # args: should be "testthread cancel ?-unwind? id ?result?"}}
test thread-7.2 {cancel: nonint} {testthread} {
    set x [catch {testthread cancel abc} msg]
    list $x $msg
} {1 {expected integer but got "abc"}}
test thread-7.3 {cancel: bad id} {testthread} {
    set tid [expr $mainThread + 10]
    set x [catch {testthread cancel $tid} msg]
    list $x $msg
} {1 {invalid thread id}}
test thread-7.4 {cancel: pure bytecode loop} {testthread} {
    threadReap
    unset -nocomplain ::threadError ::threadId ::threadIdStarted
    set serverthread [testthread create -joinable {
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
    list $res [expr {[info exists ::threadIdStarted] ? \
		  $::threadIdStarted == $serverthread : 0}] \
	      [expr {[info exists ::threadId] ? \
		  $::threadId == $serverthread : 0}] \
	      [expr {[info exists ::threadError] ? \
		  [lindex [split $::threadError \n] 0] : "" }]
} {{} 1 1 {eval unwound}}
test thread-7.24 {cancel: nested catch inside pure bytecode loop} {testthread} {
    threadReap
    unset -nocomplain ::threadError ::threadId ::threadIdStarted
    set serverthread [testthread create -joinable {
	proc foobar {} {
	    while {1} {
		if {![info exists foo]} then {
		    # signal the primary thread that we are ready







|







870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
    list $res [expr {[info exists ::threadIdStarted] ? \
		  $::threadIdStarted == $serverthread : 0}] \
	      [expr {[info exists ::threadId] ? \
		  $::threadId == $serverthread : 0}] \
	      [expr {[info exists ::threadError] ? \
		  [lindex [split $::threadError \n] 0] : "" }]
} {{} 1 1 {eval unwound}}
test thread-7.24 {cancel: nested catch inside pure bytecode loop} {notValgrind testthread} {
    threadReap
    unset -nocomplain ::threadError ::threadId ::threadIdStarted
    set serverthread [testthread create -joinable {
	proc foobar {} {
	    while {1} {
		if {![info exists foo]} then {
		    # signal the primary thread that we are ready
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
    list $res [expr {[info exists ::threadIdStarted] ? \
		  $::threadIdStarted == $serverthread : 0}] \
	      [expr {[info exists ::threadId] ? \
		  $::threadId == $serverthread : 0}] \
	      [expr {[info exists ::threadError] ? \
		  [lindex [split $::threadError \n] 0] : "" }]
} {{} 1 0 {}}
test thread-7.25 {cancel: nested catch inside pure inside-command loop} {testthread} {
    threadReap
    unset -nocomplain ::threadError ::threadId ::threadIdStarted
    set serverthread [testthread create -joinable {
	proc foobar {} {
	    set catch catch
	    set while while
	    $while {1} {







|







912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
    list $res [expr {[info exists ::threadIdStarted] ? \
		  $::threadIdStarted == $serverthread : 0}] \
	      [expr {[info exists ::threadId] ? \
		  $::threadId == $serverthread : 0}] \
	      [expr {[info exists ::threadError] ? \
		  [lindex [split $::threadError \n] 0] : "" }]
} {{} 1 0 {}}
test thread-7.25 {cancel: nested catch inside pure inside-command loop} {notValgrind testthread} {
    threadReap
    unset -nocomplain ::threadError ::threadId ::threadIdStarted
    set serverthread [testthread create -joinable {
	proc foobar {} {
	    set catch catch
	    set while while
	    $while {1} {
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
    list $res [expr {[info exists ::threadIdStarted] ? \
		  $::threadIdStarted == $serverthread : 0}] \
	      [expr {[info exists ::threadId] ? \
		  $::threadId == $serverthread : 0}] \
	      [expr {[info exists ::threadError] ? \
		  [lindex [split $::threadError \n] 0] : "" }]
} {{} 1 0 {}}
test thread-7.26 {cancel: send async cancel bad interp path} {testthread} {
    threadReap
    unset -nocomplain ::threadError ::threadId ::threadIdStarted
    set serverthread [testthread create -joinable {

	proc foobar {} {
	    while {1} {
		if {![info exists foo]} then {
		    # signal the primary thread that we are ready
		    # to be canceled now (we are running).
		    testthread send [testthread id -main] \
			    [list set ::threadIdStarted [testthread id]]
		    set foo 1
		}
		update
	    }
	}
	foobar
    }]
    # wait for other thread to signal "ready to cancel"
    vwait ::threadIdStarted; after 1000
    catch {testthread send $serverthread {interp cancel -- bad}} msg

    threadReap
    list [expr {[info exists ::threadIdStarted] ? \
		  $::threadIdStarted == $serverthread : 0}] \
		  $msg
} {1 {could not find interpreter "bad"}}
test thread-7.27 {cancel: send async cancel -- switch} {testthread} {
    threadReap
    unset -nocomplain ::threadError ::threadId ::threadIdStarted







|
<
|
|
>





|
|






|


|
>
|







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
    list $res [expr {[info exists ::threadIdStarted] ? \
		  $::threadIdStarted == $serverthread : 0}] \
	      [expr {[info exists ::threadId] ? \
		  $::threadId == $serverthread : 0}] \
	      [expr {[info exists ::threadError] ? \
		  [lindex [split $::threadError \n] 0] : "" }]
} {{} 1 0 {}}
test thread-7.26 {cancel: send async cancel bad interp path} {thread} {

    unset -nocomplain ::threadIdStarted
    set serverthread [thread::create -preserved \
	[string map [list MAIN [thread::id]] {
	proc foobar {} {
	    while {1} {
		if {![info exists foo]} then {
		    # signal the primary thread that we are ready
		    # to be canceled now (we are running).
		    thread::send MAIN \
			    [list set ::threadIdStarted [thread::id]]
		    set foo 1
		}
		update
	    }
	}
	foobar
    }]]
    # wait for other thread to signal "ready to cancel"
    vwait ::threadIdStarted; after 1000
    catch {thread::send $serverthread {interp cancel -- bad}} msg
    thread::send -async $serverthread {interp cancel -unwind}
    thread::release -wait $serverthread
    list [expr {[info exists ::threadIdStarted] ? \
		  $::threadIdStarted == $serverthread : 0}] \
		  $msg
} {1 {could not find interpreter "bad"}}
test thread-7.27 {cancel: send async cancel -- switch} {testthread} {
    threadReap
    unset -nocomplain ::threadError ::threadId ::threadIdStarted
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
    list $res [expr {[info exists ::threadIdStarted] ? \
		  $::threadIdStarted == $serverthread : 0}] \
	      [expr {[info exists ::threadId] ? \
		  $::threadId == $serverthread : 0}] \
	      [expr {[info exists ::threadError] ? \
		  [lindex [split $::threadError \n] 0] : "" }]
} {{} 1 1 {eval canceled}}
test thread-7.28 {cancel: send async cancel nested catch inside pure bytecode loop} {testthread} {
    threadReap
    unset -nocomplain ::threadError ::threadId ::threadIdStarted
    set serverthread [testthread create -joinable {
	proc foobar {} {
	    while {1} {
		if {![info exists foo]} then {
		    # signal the primary thread that we are ready







|







1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
    list $res [expr {[info exists ::threadIdStarted] ? \
		  $::threadIdStarted == $serverthread : 0}] \
	      [expr {[info exists ::threadId] ? \
		  $::threadId == $serverthread : 0}] \
	      [expr {[info exists ::threadError] ? \
		  [lindex [split $::threadError \n] 0] : "" }]
} {{} 1 1 {eval canceled}}
test thread-7.28 {cancel: send async cancel nested catch inside pure bytecode loop} {notValgrind testthread} {
    threadReap
    unset -nocomplain ::threadError ::threadId ::threadIdStarted
    set serverthread [testthread create -joinable {
	proc foobar {} {
	    while {1} {
		if {![info exists foo]} then {
		    # signal the primary thread that we are ready
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
    list $res [expr {[info exists ::threadIdStarted] ? \
		  $::threadIdStarted == $serverthread : 0}] \
	      [expr {[info exists ::threadId] ? \
		  $::threadId == $serverthread : 0}] \
	      [expr {[info exists ::threadError] ? \
		  [lindex [split $::threadError \n] 0] : "" }]
} {{} 1 0 {}}
test thread-7.29 {cancel: send async cancel nested catch pure inside-command loop} {testthread} {
    threadReap
    unset -nocomplain ::threadError ::threadId ::threadIdStarted
    set serverthread [testthread create -joinable {
	proc foobar {} {
	    set catch catch
	    set while while
	    $while {1} {







|







1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
    list $res [expr {[info exists ::threadIdStarted] ? \
		  $::threadIdStarted == $serverthread : 0}] \
	      [expr {[info exists ::threadId] ? \
		  $::threadId == $serverthread : 0}] \
	      [expr {[info exists ::threadError] ? \
		  [lindex [split $::threadError \n] 0] : "" }]
} {{} 1 0 {}}
test thread-7.29 {cancel: send async cancel nested catch pure inside-command loop} {notValgrind testthread} {
    threadReap
    unset -nocomplain ::threadError ::threadId ::threadIdStarted
    set serverthread [testthread create -joinable {
	proc foobar {} {
	    set catch catch
	    set while while
	    $while {1} {
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
    list $res [expr {[info exists ::threadIdStarted] ? \
		  $::threadIdStarted == $serverthread : 0}] \
	      [expr {[info exists ::threadId] ? \
		  $::threadId == $serverthread : 0}] \
	      [expr {[info exists ::threadError] ? \
		  [lindex [split $::threadError \n] 0] : "" }]
} {{} 1 0 {}}
test thread-7.30 {cancel: send async testthread cancel nested catch inside pure bytecode loop} {testthread} {
    threadReap
    unset -nocomplain ::threadError ::threadId ::threadIdStarted
    set serverthread [testthread create -joinable {
	proc foobar {} {
	    while {1} {
		if {![info exists foo]} then {
		    # signal the primary thread that we are ready







|







1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
    list $res [expr {[info exists ::threadIdStarted] ? \
		  $::threadIdStarted == $serverthread : 0}] \
	      [expr {[info exists ::threadId] ? \
		  $::threadId == $serverthread : 0}] \
	      [expr {[info exists ::threadError] ? \
		  [lindex [split $::threadError \n] 0] : "" }]
} {{} 1 0 {}}
test thread-7.30 {cancel: send async testthread cancel nested catch inside pure bytecode loop} {notValgrind testthread} {
    threadReap
    unset -nocomplain ::threadError ::threadId ::threadIdStarted
    set serverthread [testthread create -joinable {
	proc foobar {} {
	    while {1} {
		if {![info exists foo]} then {
		    # signal the primary thread that we are ready
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
    list $res [expr {[info exists ::threadIdStarted] ? \
		  $::threadIdStarted == $serverthread : 0}] \
	      [expr {[info exists ::threadId] ? \
		  $::threadId == $serverthread : 0}] \
	      [expr {[info exists ::threadError] ? \
		  [lindex [split $::threadError \n] 0] : "" }]
} {{} 1 0 {}}
test thread-7.31 {cancel: send async testthread cancel nested catch pure inside-command loop} {testthread} {
    threadReap
    unset -nocomplain ::threadError ::threadId ::threadIdStarted
    set serverthread [testthread create -joinable {
	proc foobar {} {
	    set catch catch
	    set while while
	    $while {1} {







|







1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
    list $res [expr {[info exists ::threadIdStarted] ? \
		  $::threadIdStarted == $serverthread : 0}] \
	      [expr {[info exists ::threadId] ? \
		  $::threadId == $serverthread : 0}] \
	      [expr {[info exists ::threadError] ? \
		  [lindex [split $::threadError \n] 0] : "" }]
} {{} 1 0 {}}
test thread-7.31 {cancel: send async testthread cancel nested catch pure inside-command loop} {notValgrind testthread} {
    threadReap
    unset -nocomplain ::threadError ::threadId ::threadIdStarted
    set serverthread [testthread create -joinable {
	proc foobar {} {
	    set catch catch
	    set while while
	    $while {1} {

Changes to tests/unixNotfy.test.

16
17
18
19
20
21
22
23

24
25
26
27
28
29
30

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest 2
    namespace import -force ::tcltest::*
}

# When run in a Tk shell, these tests hang.
testConstraint noTk       [expr {![info exists tk_version]}]

testConstraint testthread [expr {[info commands testthread] != {}}]
# Darwin always uses a threaded notifier
testConstraint unthreaded [expr {
    (![info exist tcl_platform(threaded)] || !$tcl_platform(threaded))
    && $tcl_platform(os) ne "Darwin"
}]








|
>







16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest 2
    namespace import -force ::tcltest::*
}

# When run in a Tk shell, these tests hang.
testConstraint noTk [expr {0 != [catch {package present Tk}]}]
testConstraint thread [expr {0 == [catch {package require Thread 2.6}]}]
testConstraint testthread [expr {[info commands testthread] != {}}]
# Darwin always uses a threaded notifier
testConstraint unthreaded [expr {
    (![info exist tcl_platform(threaded)] || !$tcl_platform(threaded))
    && $tcl_platform(os) ne "Darwin"
}]

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
    catch { close $f1 }
    catch { close $f2 }
    catch { removeFile foo }
    catch { removeFile foo2 }
}

test unixNotfy-2.1 {Tcl_DeleteFileHandler} \
    -constraints {noTk unix testthread} \
    -body {
	update
	set f [open [makeFile "" foo] w]
	fileevent $f writable {set x 1}
	vwait x
	close $f
   	testthread create "testthread send [testthread id] {set x ok}"
	vwait x
	threadReap
	set x
    } \
    -result {ok} \
    -cleanup {
	catch { close $f }
	catch { removeFile foo }
    }
test unixNotfy-2.2 {Tcl_DeleteFileHandler} \
    -constraints {noTk unix testthread} \
    -body {
	update
	set f1 [open [makeFile "" foo] w]
	set f2 [open [makeFile "" foo2] w]
	fileevent $f1 writable {set x 1}
	fileevent $f2 writable {set y 1}
	vwait x
	close $f1
	vwait y
	close $f2
   	testthread create "testthread send [testthread id] {set x ok}"
	vwait x
	threadReap
	set x
    } \
    -result {ok} \
    -cleanup { 
	catch { close $f1 }
	catch { close $f2 }
	catch { removeFile foo }
	catch { removeFile foo2 }
    }

# cleanup
::tcltest::cleanupTests
return







|






|

<








|










|

<













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
    catch { close $f1 }
    catch { close $f2 }
    catch { removeFile foo }
    catch { removeFile foo2 }
}

test unixNotfy-2.1 {Tcl_DeleteFileHandler} \
    -constraints {noTk unix thread} \
    -body {
	update
	set f [open [makeFile "" foo] w]
	fileevent $f writable {set x 1}
	vwait x
	close $f
   	thread::create "thread::send [thread::id] {set x ok}"
	vwait x

	set x
    } \
    -result {ok} \
    -cleanup {
	catch { close $f }
	catch { removeFile foo }
    }
test unixNotfy-2.2 {Tcl_DeleteFileHandler} \
    -constraints {noTk unix thread} \
    -body {
	update
	set f1 [open [makeFile "" foo] w]
	set f2 [open [makeFile "" foo2] w]
	fileevent $f1 writable {set x 1}
	fileevent $f2 writable {set y 1}
	vwait x
	close $f1
	vwait y
	close $f2
   	thread::create "thread::send [thread::id] {set x ok}"
	vwait x

	set x
    } \
    -result {ok} \
    -cleanup { 
	catch { close $f1 }
	catch { close $f2 }
	catch { removeFile foo }
	catch { removeFile foo2 }
    }

# cleanup
::tcltest::cleanupTests
return

Changes to tests/utf.test.

23
24
25
26
27
28
29
30



31
32
33
34
35
36
37
38
39
} [bytestring "\xc0\x80"]
test utf-1.3 {Tcl_UniCharToUtf: 2 byte sequences} {
    set x "\xe0"
} [bytestring "\xc3\xa0"]
test utf-1.4 {Tcl_UniCharToUtf: 3 byte sequences} {
    set x "\u4e4e"
} [bytestring "\xe4\xb9\x8e"]
test utf-1.5 {Tcl_UniCharToUtf: negative Tcl_UniChar} {



    string length [format %c -1]
} 1

test utf-2.1 {Tcl_UtfToUniChar: low ascii} {
    string length "abc"
} {3}
test utf-2.2 {Tcl_UtfToUniChar: naked trail bytes} {
    string length [bytestring "\x82\x83\x84"]
} {3}







|
>
>
>
|
|







23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
} [bytestring "\xc0\x80"]
test utf-1.3 {Tcl_UniCharToUtf: 2 byte sequences} {
    set x "\xe0"
} [bytestring "\xc3\xa0"]
test utf-1.4 {Tcl_UniCharToUtf: 3 byte sequences} {
    set x "\u4e4e"
} [bytestring "\xe4\xb9\x8e"]
test utf-1.5 {Tcl_UniCharToUtf: overflowed Tcl_UniChar} {
    format %c 0x110000
} [bytestring "\xef\xbf\xbd"]
test utf-1.6 {Tcl_UniCharToUtf: negative Tcl_UniChar} {
    format %c -1
} [bytestring "\xef\xbf\xbd"]

test utf-2.1 {Tcl_UtfToUniChar: low ascii} {
    string length "abc"
} {3}
test utf-2.2 {Tcl_UtfToUniChar: naked trail bytes} {
    string length [bytestring "\x82\x83\x84"]
} {3}
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179












180
181
182
183
184
185
186
bsCheck \14	12
bsCheck \141	97
bsCheck b\0	98
bsCheck \x	120
bsCheck \xa	10
bsCheck \xA	10
bsCheck \x41	65
bsCheck \x541	65
bsCheck \u	117
bsCheck \uk	117
bsCheck \u41	65
bsCheck \ua	10
bsCheck \uA	10
bsCheck \340	224
bsCheck \ua1	161
bsCheck \u4e21	20001













test utf-11.1 {Tcl_UtfToUpper} {
    string toupper {}
} {}
test utf-11.2 {Tcl_UtfToUpper} {
    string toupper abc
} ABC







|








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







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
bsCheck \14	12
bsCheck \141	97
bsCheck b\0	98
bsCheck \x	120
bsCheck \xa	10
bsCheck \xA	10
bsCheck \x41	65
bsCheck \x541	84
bsCheck \u	117
bsCheck \uk	117
bsCheck \u41	65
bsCheck \ua	10
bsCheck \uA	10
bsCheck \340	224
bsCheck \ua1	161
bsCheck \u4e21	20001
bsCheck \741	60
bsCheck \U	85
bsCheck \Uk	85
bsCheck \U41	65
bsCheck \Ua	10
bsCheck \UA	10
bsCheck \Ua1	161
bsCheck \U4e21	20001
bsCheck \U004e21	20001
bsCheck \U00004e21	20001
bsCheck \U00110000	65533
bsCheck \Uffffffff	65533

test utf-11.1 {Tcl_UtfToUpper} {
    string toupper {}
} {}
test utf-11.2 {Tcl_UtfToUpper} {
    string toupper abc
} ABC
240
241
242
243
244
245
246
247
248

249
250
251
252
253
254
255
    string toupper !
} !

test utf-16.1 {Tcl_UniCharToLower, negative delta} {
    string tolower aA
} aa
test utf-16.2 {Tcl_UniCharToLower, positive delta} {
    string tolower \u0178\u00ff
} \u00ff\u00ff

test utf-17.1 {Tcl_UniCharToLower, no delta} {
    string tolower !
} !

test utf-18.1 {Tcl_UniCharToTitle, add one for title} {
    string totitle \u01c4
} \u01c5







|
|
>







255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
    string toupper !
} !

test utf-16.1 {Tcl_UniCharToLower, negative delta} {
    string tolower aA
} aa
test utf-16.2 {Tcl_UniCharToLower, positive delta} {
    string tolower \u0178\u00ff\uA78D
} \u00ff\u00ff\u0265

test utf-17.1 {Tcl_UniCharToLower, no delta} {
    string tolower !
} !

test utf-18.1 {Tcl_UniCharToTitle, add one for title} {
    string totitle \u01c4
} \u01c5

Changes to tests/util.test.

171
172
173
174
175
176
177






178
179
180
181
182
183
184
    proc #\{ {} {return #}
    set cmd [list #\{]
    append cmd ""	;# force string rep generation
    set result [eval $cmd]
    rename #\{ {}
    set result
} {#}







test util-4.1 {Tcl_ConcatObj - backslash-space at end of argument} {
    concat a {b\ } c
} {a b\  c}
test util-4.2 {Tcl_ConcatObj - backslash-space at end of argument} {
    concat a {b\   } c
} {a b\  c}







>
>
>
>
>
>







171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
    proc #\{ {} {return #}
    set cmd [list #\{]
    append cmd ""	;# force string rep generation
    set result [eval $cmd]
    rename #\{ {}
    set result
} {#}
test util-3.6 {Tcl_ConvertElement, Bug 3371644} {
    interp create #\\
    interp alias {} x #\\ concat
    interp target {} x ;# Crash if bug not fixed
    interp delete #\\
} {}

test util-4.1 {Tcl_ConcatObj - backslash-space at end of argument} {
    concat a {b\ } c
} {a b\  c}
test util-4.2 {Tcl_ConcatObj - backslash-space at end of argument} {
    concat a {b\   } c
} {a b\  c}
3853
3854
3855
3856
3857
3858
3859





























3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
    9.9999999999999994e+304
test util-16.1.17.306 {8.4 compatible formatting of doubles} \
    {expr 1e306} \
    1e+306
test util-16.1.17.307 {8.4 compatible formatting of doubles} \
    {expr 1e307} \
    9.9999999999999999e+306






























set ::tcl_precision $saved_precision

# cleanup
::tcltest::cleanupTests
return

# Local Variables:
# mode: tcl
# End:







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










3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
    9.9999999999999994e+304
test util-16.1.17.306 {8.4 compatible formatting of doubles} \
    {expr 1e306} \
    1e+306
test util-16.1.17.307 {8.4 compatible formatting of doubles} \
    {expr 1e307} \
    9.9999999999999999e+306

test util-17.1 {bankers' rounding [Bug 3349507]} {ieeeFloatingPoint} {
    set r {}
    foreach {input} {
	0x1ffffffffffffc000
	0x1ffffffffffffc800
	0x1ffffffffffffd000
	0x1ffffffffffffd800
	0x1ffffffffffffe000
	0x1ffffffffffffe800
	0x1fffffffffffff000
	0x1fffffffffffff800
    } {
	binary scan [binary format q [expr double($input)]] wu x
	lappend r [format %#llx $x]
	binary scan [binary format q [expr double(-$input)]] wu x
	lappend r [format %#llx $x]
    }
    set r
} [list {*}{
    0x43fffffffffffffc 0xc3fffffffffffffc 
    0x43fffffffffffffc 0xc3fffffffffffffc
    0x43fffffffffffffd 0xc3fffffffffffffd
    0x43fffffffffffffe 0xc3fffffffffffffe
    0x43fffffffffffffe 0xc3fffffffffffffe
    0x43fffffffffffffe 0xc3fffffffffffffe
    0x43ffffffffffffff 0xc3ffffffffffffff
    0x4400000000000000 0xc400000000000000
}]

set ::tcl_precision $saved_precision

# cleanup
::tcltest::cleanupTests
return

# Local Variables:
# mode: tcl
# End:

Changes to tests/zlib.test.

152
153
154
155
156
157
158

159
160
161
162
163
164
165
    }
    append total --> [file size $file]
} -cleanup {
    close $fout
    close $srv
    removeFile $file
} -result 81920-->81920

test zlib-9.1 "check fcopy with push" -constraints zlib -setup {
    set sfile [makeFile {} testsrc.gz]
    set file [makeFile {} test.gz]
    set f [open $sfile wb]
    puts -nonewline $f [zlib gzip [string repeat a 81920]]
    close $f
} -body {







>







152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
    }
    append total --> [file size $file]
} -cleanup {
    close $fout
    close $srv
    removeFile $file
} -result 81920-->81920

test zlib-9.1 "check fcopy with push" -constraints zlib -setup {
    set sfile [makeFile {} testsrc.gz]
    set file [makeFile {} test.gz]
    set f [open $sfile wb]
    puts -nonewline $f [zlib gzip [string repeat a 81920]]
    close $f
} -body {
565
566
567
568
569
570
571































572
573
574
575
576
577
578
    vwait ::total
    set ::total
} -cleanup {
    close $srv
    rename bgerror {}
    rename zlibRead {}
} -result {error {invalid block type}}
































::tcltest::cleanupTests
return

# Local Variables:
# mode: tcl
# End:







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







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
    vwait ::total
    set ::total
} -cleanup {
    close $srv
    rename bgerror {}
    rename zlibRead {}
} -result {error {invalid block type}}

test zlib-11.1 "Bug #3390073: mis-appled gzip filtering" -setup {
    set file [makeFile {} test.input]
} -constraints zlib -body {
    set f [open $file wb]
    puts -nonewline [zlib push gzip $f] [string repeat "hello" 1000]
    close $f
    set f [open $file rb]
    set d [read $f]
    close $f
    set d [zlib gunzip $d]
    list [regexp -all "hello" $d] [string length [regsub -all "hello" $d {}]]
} -cleanup {
    removeFile $file
} -result {1000 0}
test zlib-11.2 "Bug #3390073: mis-appled gzip filtering" -setup {
    set file [makeFile {} test.input]
} -constraints zlib -body {
    set f [open $file wb]
    puts -nonewline [zlib push gzip $f -header {filename /foo/bar}] \
	[string repeat "hello" 1000]
    close $f
    set f [open $file rb]
    set d [read $f]
    close $f
    set d [zlib gunzip $d -header h]
    list [regexp -all "hello" $d] [dict get $h filename] \
	[string length [regsub -all "hello" $d {}]]
} -cleanup {
    removeFile $file
} -result {1000 /foo/bar 0}

::tcltest::cleanupTests
return

# Local Variables:
# mode: tcl
# End:

Changes to tools/tcl.wse.in.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  Japanese Font Size=10
  Start Gradient=0 0 255
  End Gradient=0 0 0
  Windows Flags=00000000000000010010110000001000
  Log Pathname=%MAINDIR%\INSTALL.LOG
  Message Font=MS Sans Serif
  Font Size=8
  Disk Label=tcl8.6b1
  Disk Filename=setup
  Patch Flags=0000000000000001
  Patch Threshold=85
  Patch Memory=4000
  Variable Name1=_SYS_
  Variable Default1=C:\WINDOWS\SYSTEM
  Variable Flags1=00001000







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  Japanese Font Size=10
  Start Gradient=0 0 255
  End Gradient=0 0 0
  Windows Flags=00000000000000010010110000001000
  Log Pathname=%MAINDIR%\INSTALL.LOG
  Message Font=MS Sans Serif
  Font Size=8
  Disk Label=tcl8.6b2
  Disk Filename=setup
  Patch Flags=0000000000000001
  Patch Threshold=85
  Patch Memory=4000
  Variable Name1=_SYS_
  Variable Default1=C:\WINDOWS\SYSTEM
  Variable Flags1=00001000

Changes to tools/tcltk-man2html-utils.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
##
## Utility functions for Man->HTML converter. Note that these
## functions are specifically intended to work with the format as used
## by Tcl and Tk; they do not cope with arbitrary nroff markup.
##
## Copyright (c) 1995-1997 Roger E. Critchlow Jr
## Copyright (c) 2004-2010 Donal K. Fellows

set ::manual(report-level) 1

proc manerror {msg} {
    global manual
    set name {}
    set subj {}






|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
##
## Utility functions for Man->HTML converter. Note that these
## functions are specifically intended to work with the format as used
## by Tcl and Tk; they do not cope with arbitrary nroff markup.
##
## Copyright (c) 1995-1997 Roger E. Critchlow Jr
## Copyright (c) 2004-2011 Donal K. Fellows

set ::manual(report-level) 1

proc manerror {msg} {
    global manual
    set name {}
    set subj {}
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
}

proc fatal {msg} {
    global manual
    uplevel 1 [list manerror $msg]
    exit 1
}

##
## templating
##
proc indexfile {} {
    if {[info exists ::TARGET] && $::TARGET eq "devsite"} {
	return "index.tml"
    } else {
	return "contents.htm"
    }
}

proc copyright {copyright {level {}}} {
    # We don't actually generate a separate copyright page anymore
    #set page "${level}copyright.htm"
    #return "<A HREF=\"$page\">Copyright</A> &#169; [htmlize-text [lrange $copyright 2 end]]"
    # obfuscate any email addresses that may appear in name
    set who [string map {@ (at)} [lrange $copyright 2 end]]
    return "Copyright &copy; [htmlize-text $who]"
}

proc copyout {copyrights {level {}}} {
    set out "<div class=\"copy\">"
    foreach c $copyrights {
	append out "[copyright $c $level]\n"
    }
    append out "</div>"
    return $out
}

proc CSS {{level ""}} {
    return "<link rel=\"stylesheet\" href=\"${level}$::CSSFILE\" type=\"text/css\" media=\"all\">\n"
}

proc DOCTYPE {} {
    return "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">"
}

proc htmlhead {title header args} {
    set level ""
    if {[lindex $args end] eq "../[indexfile]"} {
	# XXX hack - assume same level for CSS file
	set level "../"
    }
    set out "[DOCTYPE]\n<HTML>\n<HEAD><TITLE>$title</TITLE>\n[CSS $level]</HEAD>\n"







|










>








>








>



>



>







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
}

proc fatal {msg} {
    global manual
    uplevel 1 [list manerror $msg]
    exit 1
}

##
## templating
##
proc indexfile {} {
    if {[info exists ::TARGET] && $::TARGET eq "devsite"} {
	return "index.tml"
    } else {
	return "contents.htm"
    }
}

proc copyright {copyright {level {}}} {
    # We don't actually generate a separate copyright page anymore
    #set page "${level}copyright.htm"
    #return "<A HREF=\"$page\">Copyright</A> &#169; [htmlize-text [lrange $copyright 2 end]]"
    # obfuscate any email addresses that may appear in name
    set who [string map {@ (at)} [lrange $copyright 2 end]]
    return "Copyright &copy; [htmlize-text $who]"
}

proc copyout {copyrights {level {}}} {
    set out "<div class=\"copy\">"
    foreach c $copyrights {
	append out "[copyright $c $level]\n"
    }
    append out "</div>"
    return $out
}

proc CSS {{level ""}} {
    return "<link rel=\"stylesheet\" href=\"${level}$::CSSFILE\" type=\"text/css\" media=\"all\">\n"
}

proc DOCTYPE {} {
    return "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">"
}

proc htmlhead {title header args} {
    set level ""
    if {[lindex $args end] eq "../[indexfile]"} {
	# XXX hack - assume same level for CSS file
	set level "../"
    }
    set out "[DOCTYPE]\n<HTML>\n<HEAD><TITLE>$title</TITLE>\n[CSS $level]</HEAD>\n"
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
		lappend subs "<A HREF=\"${level}$subdir/[indexfile]\">$name</A>"
	    }
	}
	append out "\n<H3>[join $subs { | }]</H3>"
    }
    return $out
}

##
## parsing
##
proc unquote arg {
    return [string map [list \" {}] $arg]
}

proc parse-directive {line codename restname} {
    upvar 1 $codename code $restname rest
    return [regexp {^(\.[.a-zA-Z0-9]*) *(.*)} $line all code rest]
}

proc htmlize-text {text {charmap {}}} {
    # contains some extras for use in nroff->html processing
    # build on the list passed in, if any
    lappend charmap \

	{&}	{&amp;} \
	{\\}	"&#92;" \
	{\e}	"&#92;" \
	{\ }	{&nbsp;} \
	{\|}	{&nbsp;} \
	{\0}	{ } \
	\"	{&quot;} \







|
















>







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
		lappend subs "<A HREF=\"${level}$subdir/[indexfile]\">$name</A>"
	    }
	}
	append out "\n<H3>[join $subs { | }]</H3>"
    }
    return $out
}

##
## parsing
##
proc unquote arg {
    return [string map [list \" {}] $arg]
}

proc parse-directive {line codename restname} {
    upvar 1 $codename code $restname rest
    return [regexp {^(\.[.a-zA-Z0-9]*) *(.*)} $line all code rest]
}

proc htmlize-text {text {charmap {}}} {
    # contains some extras for use in nroff->html processing
    # build on the list passed in, if any
    lappend charmap \
	"&ndash;" "&ndash;" \
	{&}	{&amp;} \
	{\\}	"&#92;" \
	{\e}	"&#92;" \
	{\ }	{&nbsp;} \
	{\|}	{&nbsp;} \
	{\0}	{ } \
	\"	{&quot;} \
139
140
141
142
143
144
145

146
147
148
149
150
151
152
153
154
	    {\(fm}	"&#8242;" \
	    {\(mu}	"&#215;" \
	    {\(mi}	"&#8722;" \
	    {\(->}	"<font size=\"+1\">&#8594;</font>" \
	    {\fP}	{\fR} \
	    {\.}	. \
	    {\(bu}	"&#8226;" \

	    ]
    lappend charmap {\o'o^'} {&ocirc;} ; # o-circumflex in re_syntax.n
    lappend charmap {\-\|\-} --        ; # two hyphens
    lappend charmap {\-} -             ; # a hyphen

    set text [htmlize-text $text $charmap]
    # General quoted entity
    regsub -all {\\N'(\d+)'} $text "\\&#\\1;" text
    while {[string first "\\" $text] >= 0} {







>

<







145
146
147
148
149
150
151
152
153

154
155
156
157
158
159
160
	    {\(fm}	"&#8242;" \
	    {\(mu}	"&#215;" \
	    {\(mi}	"&#8722;" \
	    {\(->}	"<font size=\"+1\">&#8594;</font>" \
	    {\fP}	{\fR} \
	    {\.}	. \
	    {\(bu}	"&#8226;" \
	    {\*(qo}	"&ocirc;" \
	    ]

    lappend charmap {\-\|\-} --        ; # two hyphens
    lappend charmap {\-} -             ; # a hyphen

    set text [htmlize-text $text $charmap]
    # General quoted entity
    regsub -all {\\N'(\d+)'} $text "\\&#\\1;" text
    while {[string first "\\" $text] >= 0} {
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
	}
	# unrecognized
	manerror "uncaught backslash: $text"
	set text [string map [list "\\" "&#92;"] $text]
    }
    return $text
}

##
## pass 2 text input and matching
##
proc open-text {} {
    global manual
    set manual(text-length) [llength $manual(text)]
    set manual(text-pointer) 0
}

proc more-text {} {
    global manual
    return [expr {$manual(text-pointer) < $manual(text-length)}]
}

proc next-text {} {
    global manual
    if {[more-text]} {
	set text [lindex $manual(text) $manual(text-pointer)]
	incr manual(text-pointer)
	return $text
    }
    manerror "read past end of text"
    error "fatal"
}

proc is-a-directive {line} {
    return [string match .* $line]
}

proc split-directive {line opname restname} {
    upvar 1 $opname op $restname rest
    set op [string range $line 0 2]
    set rest [string trim [string range $line 3 end]]
}

proc next-op-is {op restname} {
    global manual
    upvar 1 $restname rest
    if {[more-text]} {
	set text [lindex $manual(text) $manual(text-pointer)]
	if {[string equal -length 3 $text $op]} {
	    set rest [string range $text 4 end]
	    incr manual(text-pointer)
	    return 1
	}
    }
    return 0
}

proc backup-text {n} {
    global manual
    if {$manual(text-pointer)-$n >= 0} {
	incr manual(text-pointer) -$n
    }
}

proc match-text args {
    global manual
    set nargs [llength $args]
    if {$manual(text-pointer) + $nargs > $manual(text-length)} {
	return 0
    }
    set nback 0







>








>




>










>



>





>













>






>







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
	}
	# unrecognized
	manerror "uncaught backslash: $text"
	set text [string map [list "\\" "&#92;"] $text]
    }
    return $text
}

##
## pass 2 text input and matching
##
proc open-text {} {
    global manual
    set manual(text-length) [llength $manual(text)]
    set manual(text-pointer) 0
}

proc more-text {} {
    global manual
    return [expr {$manual(text-pointer) < $manual(text-length)}]
}

proc next-text {} {
    global manual
    if {[more-text]} {
	set text [lindex $manual(text) $manual(text-pointer)]
	incr manual(text-pointer)
	return $text
    }
    manerror "read past end of text"
    error "fatal"
}

proc is-a-directive {line} {
    return [string match .* $line]
}

proc split-directive {line opname restname} {
    upvar 1 $opname op $restname rest
    set op [string range $line 0 2]
    set rest [string trim [string range $line 3 end]]
}

proc next-op-is {op restname} {
    global manual
    upvar 1 $restname rest
    if {[more-text]} {
	set text [lindex $manual(text) $manual(text-pointer)]
	if {[string equal -length 3 $text $op]} {
	    set rest [string range $text 4 end]
	    incr manual(text-pointer)
	    return 1
	}
    }
    return 0
}

proc backup-text {n} {
    global manual
    if {$manual(text-pointer)-$n >= 0} {
	incr manual(text-pointer) -$n
    }
}

proc match-text args {
    global manual
    set nargs [llength $args]
    if {$manual(text-pointer) + $nargs > $manual(text-length)} {
	return 0
    }
    set nback 0
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
	    continue
	}
	backup-text $nback
	return 0
    }
    return 1
}

proc expand-next-text {n} {
    global manual
    return [join [lrange $manual(text) $manual(text-pointer) \
	    [expr {$manual(text-pointer)+$n-1}]] \n\n]
}

##
## pass 2 output
##
proc man-puts {text} {
    global manual
    lappend manual(output-$manual(wing-file)-$manual(name)) $text
}

##
## build hypertext links to tables of contents
##
proc long-toc {text} {
    global manual
    set here M[incr manual(section-toc-n)]
    set manual($manual(name)-id-$text) $here
    set there L[incr manual(long-toc-n)]
    lappend manual(section-toc) \
	    "<DD><A HREF=\"$manual(name).htm#$here\" NAME=\"$there\">$text</A>"
    return "<A NAME=\"$here\">$text</A>"
}

proc option-toc {name class switch} {
    global manual
    # Special case handling, oh we hate it but must do it
    if {[string match "*OPTIONS" $manual(section)]} {
	if {$manual(name) ne "ttk_widget" && ($manual(name) ne "ttk_entry" ||
		![string match validate* $name])} {
	    # link the defined option into the long table of contents







>





>







|












>







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
	    continue
	}
	backup-text $nback
	return 0
    }
    return 1
}

proc expand-next-text {n} {
    global manual
    return [join [lrange $manual(text) $manual(text-pointer) \
	    [expr {$manual(text-pointer)+$n-1}]] \n\n]
}

##
## pass 2 output
##
proc man-puts {text} {
    global manual
    lappend manual(output-$manual(wing-file)-$manual(name)) $text
}

##
## build hypertext links to tables of contents
##
proc long-toc {text} {
    global manual
    set here M[incr manual(section-toc-n)]
    set manual($manual(name)-id-$text) $here
    set there L[incr manual(long-toc-n)]
    lappend manual(section-toc) \
	    "<DD><A HREF=\"$manual(name).htm#$here\" NAME=\"$there\">$text</A>"
    return "<A NAME=\"$here\">$text</A>"
}

proc option-toc {name class switch} {
    global manual
    # Special case handling, oh we hate it but must do it
    if {[string match "*OPTIONS" $manual(section)]} {
	if {$manual(name) ne "ttk_widget" && ($manual(name) ne "ttk_entry" ||
		![string match validate* $name])} {
	    # link the defined option into the long table of contents
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
    set there L[incr manual(long-toc-n)]
    set manual(standard-option-$manual(name)-$first) \
	"<A HREF=\"$manual(name).htm#$here\">$switch, $name, $class</A>"
    lappend manual(section-toc) \
	"<DD><A HREF=\"$manual(name).htm#$here\" NAME=\"$there\">$switch, $name, $class</A>"
    return "<A NAME=\"$here\">$switch</A>"
}

proc std-option-toc {name page} {
    global manual
    if {[info exists manual(standard-option-$page-$name)]} {
	lappend manual(section-toc) <DD>$manual(standard-option-$page-$name)
	return $manual(standard-option-$page-$name)
    }
    manerror "missing reference to \"$name\" in $page.n"
    set here M[incr manual(section-toc-n)]
    set there L[incr manual(long-toc-n)]
    set other M$name
    lappend manual(section-toc) "<DD><A HREF=\"$page.htm#$other\">$name</A>"
    return "<A HREF=\"$page.htm#$other\">$name</A>"
}

##
## process the widget option section
## in widget and options man pages
##
proc output-widget-options {rest} {
    global manual
    man-puts <DL>







>













>







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
    set there L[incr manual(long-toc-n)]
    set manual(standard-option-$manual(name)-$first) \
	"<A HREF=\"$manual(name).htm#$here\">$switch, $name, $class</A>"
    lappend manual(section-toc) \
	"<DD><A HREF=\"$manual(name).htm#$here\" NAME=\"$there\">$switch, $name, $class</A>"
    return "<A NAME=\"$here\">$switch</A>"
}

proc std-option-toc {name page} {
    global manual
    if {[info exists manual(standard-option-$page-$name)]} {
	lappend manual(section-toc) <DD>$manual(standard-option-$page-$name)
	return $manual(standard-option-$page-$name)
    }
    manerror "missing reference to \"$name\" in $page.n"
    set here M[incr manual(section-toc-n)]
    set there L[incr manual(long-toc-n)]
    set other M$name
    lappend manual(section-toc) "<DD><A HREF=\"$page.htm#$other\">$name</A>"
    return "<A HREF=\"$page.htm#$other\">$name</A>"
}

##
## process the widget option section
## in widget and options man pages
##
proc output-widget-options {rest} {
    global manual
    man-puts <DL>
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
		}
	    }
	}
    }
    man-puts </DL>
    lappend manual(section-toc) </DL>
}

##
## process .RS lists
##
proc output-RS-list {} {
    global manual
    if {[next-op-is .IP rest]} {
	output-IP-list .RS .IP $rest







|







425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
		}
	    }
	}
    }
    man-puts </DL>
    lappend manual(section-toc) </DL>
}

##
## process .RS lists
##
proc output-RS-list {} {
    global manual
    if {[next-op-is .IP rest]} {
	output-IP-list .RS .IP $rest
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
	    }
	} else {
	    man-puts $line
	}
    }
    man-puts </DL>
}

##
## process .IP lists which may be plain indents,
## numeric lists, or definition lists
##
proc output-IP-list {context code rest} {
    global manual
    if {![string length $rest]} {







|







469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
	    }
	} else {
	    man-puts $line
	}
    }
    man-puts </DL>
}

##
## process .IP lists which may be plain indents,
## numeric lists, or definition lists
##
proc output-IP-list {context code rest} {
    global manual
    if {![string length $rest]} {
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
	man-puts </DL>
    } else {
	# labelled list, make contents
	if {$context ne ".SH" && $context ne ".SS"} {
	    man-puts <P>
	}
	set dl "<DL class=\"[string tolower $manual(section)]\">"










	man-puts $dl
	lappend manual(section-toc) $dl
	backup-text 1
	set accept_RE 0
	set para {}
	while {[more-text]} {
	    set line [next-text]
	    if {[is-a-directive $line]} {
		split-directive $line code rest
		switch -exact -- $code {
		    .IP {
			if {$accept_RE} {
			    output-IP-list .IP $code $rest
			    continue
			}
			if {$manual(section) eq "ARGUMENTS" || \
				[regexp {^\[\d+\]$} $rest]} {
			    man-puts "$para<DT>$rest<DD>"




			} elseif {"&#8226;" eq $rest} {
			    man-puts "$para<DT><DD>$rest&nbsp;"
			} else {
			    man-puts "$para<DT>[long-toc $rest]<DD>"
			}
		    }
		    .sp - .br - .DS - .CS {
			output-directive $line
		    }







>
>
>
>
>
>
>
>
>
>















|
<

>
>
>
>

|







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
	man-puts </DL>
    } else {
	# labelled list, make contents
	if {$context ne ".SH" && $context ne ".SS"} {
	    man-puts <P>
	}
	set dl "<DL class=\"[string tolower $manual(section)]\">"
	set enddl "</DL>"
	if {$code eq ".IP"} {
	    if {[regexp {^\[[\da-f]+\]|\(?[\da-f]+\)$} $rest]} {
		set dl "<OL class=\"[string tolower $manual(section)]\">"
		set enddl "</OL>"
	    } elseif {"&#8226;" eq $rest} {
		set dl "<UL class=\"[string tolower $manual(section)]\">"
		set enddl "</UL>"
	    }
	}
	man-puts $dl
	lappend manual(section-toc) $dl
	backup-text 1
	set accept_RE 0
	set para {}
	while {[more-text]} {
	    set line [next-text]
	    if {[is-a-directive $line]} {
		split-directive $line code rest
		switch -exact -- $code {
		    .IP {
			if {$accept_RE} {
			    output-IP-list .IP $code $rest
			    continue
			}
			if {$manual(section) eq "ARGUMENTS"} {

			    man-puts "$para<DT>$rest<DD>"
			} elseif {[regexp {^\[([\da-f]+)\]$} $rest -> value]} {
			    man-puts "$para<LI value=\"$value\">"
			} elseif {[regexp {^\(?([\da-f]+)\)$} $rest -> value]} {
			    man-puts "$para<LI value=\"$value\">"
			} elseif {"&#8226;" eq $rest} {
			    man-puts "$para<LI>"
			} else {
			    man-puts "$para<DT>[long-toc $rest]<DD>"
			}
		    }
		    .sp - .br - .DS - .CS {
			output-directive $line
		    }
538
539
540
541
542
543
544
545
546
547
548
549

550
551
552
553
554
555
556
557
558
559
			    # yet another nroff kludge as above
			    man-puts "$para<DT>[long-toc $rest1]"
			    man-puts "<DT>[long-toc $rest2]<DD>"
			    incr accept_RE 1
			} elseif {[match-text @rest .RE]} {
			    # gad, this is getting ridiculous
			    if {!$accept_RE} {
				man-puts "</DL><P>$rest<DL>"
				backup-text 1
				set para {}
				break
			    } else {

				man-puts "<P>$rest"
				incr accept_RE -1
			    }
			} elseif {$accept_RE} {
			    output-directive $line
			} else {
			    backup-text 1
			    break
			}
		    }







|



<
>
|
|
<







570
571
572
573
574
575
576
577
578
579
580

581
582
583

584
585
586
587
588
589
590
			    # yet another nroff kludge as above
			    man-puts "$para<DT>[long-toc $rest1]"
			    man-puts "<DT>[long-toc $rest2]<DD>"
			    incr accept_RE 1
			} elseif {[match-text @rest .RE]} {
			    # gad, this is getting ridiculous
			    if {!$accept_RE} {
				man-puts "$enddl<P>$rest$dl"
				backup-text 1
				set para {}
				break

			    }
			    man-puts "<P>$rest"
			    incr accept_RE -1

			} elseif {$accept_RE} {
			    output-directive $line
			} else {
			    backup-text 1
			    break
			}
		    }
570
571
572
573
574
575
576
577
578
579
580
581
582
583

584
585
586
587
588
589
590
		    }
		}
	    } else {
		man-puts $line
	    }
	    set para <P>
	}
	man-puts "$para</DL>"
	lappend manual(section-toc) </DL>
	if {$accept_RE} {
	    manerror "missing .RE in output-IP-list"
	}
    }
}

##
## handle the NAME section lines
## there's only one line in the NAME section,
## consisting of a comma separated list of names,
## followed by a hyphen and a short description.
##
proc output-name {line} {







|
|





>







601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
		    }
		}
	    } else {
		man-puts $line
	    }
	    set para <P>
	}
	man-puts "$para$enddl"
	lappend manual(section-toc) $enddl
	if {$accept_RE} {
	    manerror "missing .RE in output-IP-list"
	}
    }
}

##
## handle the NAME section lines
## there's only one line in the NAME section,
## consisting of a comma separated list of names,
## followed by a hyphen and a short description.
##
proc output-name {line} {
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
	if {[llength $name] > 1} {
	    manerror "name has a space: {$name}\nfrom: $line"
	}
	lappend manual(wing-toc) $name
	lappend manual(name-$name) $manual(wing-file)/$manual(name)
    }
}

##
## build a cross-reference link if appropriate
##
proc cross-reference {ref} {
    global manual remap_link_target
    global ensemble_commands exclude_refs_map exclude_when_followed_by_map
    set lref [string tolower $ref]

    if {[string match "Tcl_*" $ref] || [string match "Tk_*" $ref]} {





	set lref $ref

    } elseif {$ref eq "Tcl"} {
	set lref $ref
    } elseif {
	[regexp {^[A-Z0-9 ?!]+$} $ref]
	&& [info exists manual($manual(name)-id-$ref)]
    } {
	return "<A HREF=\"#$manual($manual(name)-id-$ref)\">$ref</A>"
    }

    ##
    ## apply a link remapping if available
    ##
    if {[info exists remap_link_target($lref)]} {
	set lref $remap_link_target($lref)

    }
    ##
    ## nothing to reference
    ##
    if {![info exists manual(name-$lref)]} {
	foreach name $ensemble_commands {

	    if {[regexp "^$name \[a-z0-9]*\$" $lref] && \
		    [info exists manual(name-$name)] && \
		    $manual(tail) ne "$name.n"} {



		return "<A HREF=\"../$manual(name-$name).htm\">$ref</A>"
	    }
	}
	if {$lref in {end}} {
	    # no good place to send this tcl token?
	}
	return $ref
    }

    ##
    ## would be a self reference
    ##
    foreach name $manual(name-$lref) {
	if {"$manual(wing-file)/$manual(name)" in $name} {
	    return $ref
	}
    }
    ##
    ## multiple choices for reference
    ##
    if {[llength $manual(name-$lref)] > 1} {
	set tcl_i [lsearch -glob $manual(name-$lref) *TclCmd*]
	set tcl_ref [lindex $manual(name-$lref) $tcl_i]
	set tk_i [lsearch -glob $manual(name-$lref) *TkCmd*]
	set tk_ref [lindex $manual(name-$lref) $tk_i]
	if {$tcl_i >= 0 && $manual(wing-file) eq "TclCmd"
		|| $manual(wing-file) eq "TclLib"} {

	    return "<A HREF=\"../$tcl_ref.htm\">$ref</A>"
	}

	if {$tk_i >= 0 && $manual(wing-file) eq "TkCmd"
		|| $manual(wing-file) eq "TkLib"} {

	    return "<A HREF=\"../$tk_ref.htm\">$ref</A>"
	}
	if {$lref eq "exit" && $manual(tail) eq "tclsh.1" && $tcl_i >= 0} {

	    return "<A HREF=\"../$tcl_ref.htm\">$ref</A>"
	}
	puts stderr "multiple cross reference to $ref in $manual(name-$lref) from $manual(wing-file)/$manual(tail)"
	return $ref
    }
    ##
    ## exceptions, sigh, to the rule
    ##
    if {[info exists exclude_when_followed_by_map($manual(tail))]} {
	upvar 1 tail tail
	set following_word [lindex [regexp -inline {\S+} $tail] 0]
	foreach {this that} $exclude_when_followed_by_map($manual(tail)) {
	    # only a ref if $this is not followed by $that
	    if {$lref eq $this && [string match $that* $following_word]} {
		return $ref
	    }
	}
    }
    if {
	[info exists exclude_refs_map($manual(tail))]
	&& $lref in $exclude_refs_map($manual(tail))
    } {
	return $ref
    }
    ##
    ## return the cross reference
    ##
    return "<A HREF=\"../$manual(name-$lref).htm\">$ref</A>"
}

##
## reference generation errors
##
proc reference-error {msg text} {
    global manual
    puts stderr "$manual(tail): $msg: {$text}"
    return $text
}

##
## insert as many cross references into this text string as are appropriate
##
proc insert-cross-references {text} {
    global manual



    ##
    ## we identify cross references by:
    ##     ``quotation''
    ##    <B>emboldening</B>
    ##    Tcl_ prefix
    ##    Tk_ prefix
    ##	  [a-zA-Z0-9]+ manual entry
    ## and we avoid messing with already anchored text
    ##
    ##
    ## find where each item lives
    ##
    array set offset [list \
	    anchor [string first {<A } $text] \
	    end-anchor [string first {</A>} $text] \
	    quote [string first {``} $text] \
	    end-quote [string first {''} $text] \
	    bold [string first {<B>} $text] \
	    end-bold [string first {</B>} $text] \
	    tcl [string first {Tcl_} $text] \
	    tk [string first {Tk_} $text] \



	    Tcl1 [string first {Tcl manual entry} $text] \
	    Tcl2 [string first {Tcl overview manual entry} $text] \
	    ]
    ##

    ## accumulate a list
    ##
    foreach name [array names offset] {

	if {$offset($name) >= 0} {
	    set invert($offset($name)) $name
	    lappend offsets $offset($name)
	}
    }
    ##
    ## if nothing, then we're done.
    ##
    if {![info exists offsets]} {
	return $text
    }
    ##
    ## sort the offsets
    ##
    set offsets [lsort -integer $offsets]
    ##
    ## see which we want to use
    ##
    switch -exact -- $invert([lindex $offsets 0]) {
	anchor {
	    if {$offset(end-anchor) < 0} {
		return [reference-error {Missing end anchor} $text]
	    }
	    set head [string range $text 0 $offset(end-anchor)]

	    set tail [string range $text [expr {$offset(end-anchor)+1}] end]
	    return $head[insert-cross-references $tail]

	}
	quote {
	    if {$offset(end-quote) < 0} {
		return [reference-error "Missing end quote" $text]
	    }
	    if {$invert([lindex $offsets 1]) eq "tk"} {
		set offsets [lreplace $offsets 1 1]
	    }
	    if {$invert([lindex $offsets 1]) eq "tcl"} {
		set offsets [lreplace $offsets 1 1]
	    }
	    switch -exact -- $invert([lindex $offsets 1]) {
		end-quote {
		    set head [string range $text 0 [expr {$offset(quote)-1}]]
		    set body [string range $text [expr {$offset(quote)+2}] \
			    [expr {$offset(end-quote)-1}]]
		    set tail [string range $text \
			    [expr {$offset(end-quote)+2}] end]
		    return "$head``[cross-reference $body]''[insert-cross-references $tail]"

		}
		bold -
		anchor {
		    set head [string range $text \
			    0 [expr {$offset(end-quote)+1}]]
		    set tail [string range $text \
			    [expr {$offset(end-quote)+2}] end]
		    return "$head[insert-cross-references $tail]"

		}
	    }
	    return [reference-error "Uncaught quote case" $text]
	}
	bold {
	    if {$offset(end-bold) < 0} {
		return $text
	    }
	    if {$invert([lindex $offsets 1]) eq "tk"} {
		set offsets [lreplace $offsets 1 1]
	    }
	    if {$invert([lindex $offsets 1]) eq "tcl"} {
		set offsets [lreplace $offsets 1 1]
	    }
	    switch -exact -- $invert([lindex $offsets 1]) {
		end-bold {

		    set head [string range $text 0 [expr {$offset(bold)-1}]]
		    set body [string range $text [expr {$offset(bold)+3}] \
			    [expr {$offset(end-bold)-1}]]
		    set tail [string range $text \
			    [expr {$offset(end-bold)+4}] end]
		    return "$head<B>[cross-reference $body]</B>[insert-cross-references $tail]"
		}
		anchor {
		    set head [string range $text \
			    0 [expr {$offset(end-bold)+3}]]
		    set tail [string range $text \
			    [expr {$offset(end-bold)+4}] end]

		    return "$head[insert-cross-references $tail]"

		}






	    }

	    return [reference-error "Uncaught bold case" $text]
	}
	tk {
	    set head [string range $text 0 [expr {$offset(tk)-1}]]
	    set tail [string range $text $offset(tk) end]
	    if {![regexp {^(Tk_\w+)(.*)$} $tail all body tail]} {
		return [reference-error "Tk regexp failed" $text]
	    }
	    return $head[cross-reference $body][insert-cross-references $tail]
	}
	tcl {
	    set head [string range $text 0 [expr {$offset(tcl)-1}]]
	    set tail [string range $text $offset(tcl) end]
	    if {![regexp {^(Tcl_\w+)(.*)$} $tail all body tail]} {
		return [reference-error {Tcl regexp failed} $text]
	    }
	    return $head[cross-reference $body][insert-cross-references $tail]
	}
	Tcl1 -
	Tcl2 {









	    set off [lindex $offsets 0]
	    set head [string range $text 0 [expr {$off-1}]]





	    set body Tcl


	    set tail [string range $text [expr {$off+3}] end]
	    return $head[cross-reference $body][insert-cross-references $tail]




	}
	end-anchor -
	end-bold -
	end-quote {
	    return [reference-error "Out of place $invert([lindex $offsets 0])" $text]
	}
    }
}


##
## process formatting directives
##
proc output-directive {line} {
    global manual
    # process format directive
    split-directive $line code rest







>






|
>
|
>
>
>
>
>
|
>




|

|
|
>
|
|
|
|
|
>






>
|
|
|
>
>
>








>



|
|






|
|
<
<
<


>


>


>


|
>


|





|
|

|







|
|






|

>








>





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







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
	if {[llength $name] > 1} {
	    manerror "name has a space: {$name}\nfrom: $line"
	}
	lappend manual(wing-toc) $name
	lappend manual(name-$name) $manual(wing-file)/$manual(name)
    }
}

##
## build a cross-reference link if appropriate
##
proc cross-reference {ref} {
    global manual remap_link_target
    global ensemble_commands exclude_refs_map exclude_when_followed_by_map
    set manname $manual(name)
    set mantail $manual(tail)
    if {[string match "Tcl_*" $ref] || [string match "Tk_*" $ref] || [string match "Ttk_*" $ref] || [string match "Itcl_*" $ref] || [string match "Tdbc_*" $ref]} {
	regexp {^\w+} $ref lref
	##
	## apply a link remapping if available
	##
	if {[info exists remap_link_target($lref)]} {
	    set lref $remap_link_target($lref)
	}
    } elseif {$ref eq "Tcl"} {
	set lref $ref
    } elseif {
	[regexp {^[A-Z0-9 ?!]+$} $ref]
	&& [info exists manual($manname-id-$ref)]
    } {
	return "<A HREF=\"#$manual($manname-id-$ref)\">$ref</A>"
    } else {
	set lref [string tolower $ref]
	##
	## apply a link remapping if available
	##
	if {[info exists remap_link_target($lref)]} {
	    set lref $remap_link_target($lref)
	}
    }
    ##
    ## nothing to reference
    ##
    if {![info exists manual(name-$lref)]} {
	foreach name $ensemble_commands {
	    if {
		[regexp "^$name \[a-z0-9]*\$" $lref] &&
		[info exists manual(name-$name)] &&
		$mantail ne "$name.n" &&
		(![info exists exclude_refs_map($mantail)] ||
		$manual(name-$name) ni $exclude_refs_map($mantail))
	    } {
		return "<A HREF=\"../$manual(name-$name).htm\">$ref</A>"
	    }
	}
	if {$lref in {end}} {
	    # no good place to send this tcl token?
	}
	return $ref
    }
    set manref $manual(name-$lref)
    ##
    ## would be a self reference
    ##
    foreach name $manref {
	if {"$manual(wing-file)/$manname" in $name} {
	    return $ref
	}
    }
    ##
    ## multiple choices for reference
    ##
    if {[llength $manref] > 1} {
	set tcl_i [lsearch -glob $manref *TclCmd*]



	if {$tcl_i >= 0 && $manual(wing-file) eq "TclCmd"
		|| $manual(wing-file) eq "TclLib"} {
	    set tcl_ref [lindex $manref $tcl_i]
	    return "<A HREF=\"../$tcl_ref.htm\">$ref</A>"
	}
	set tk_i [lsearch -glob $manref *TkCmd*]
	if {$tk_i >= 0 && $manual(wing-file) eq "TkCmd"
		|| $manual(wing-file) eq "TkLib"} {
	    set tk_ref [lindex $manref $tk_i]
	    return "<A HREF=\"../$tk_ref.htm\">$ref</A>"
	}
	if {$lref eq "exit" && $mantail eq "tclsh.1" && $tcl_i >= 0} {
	    set tcl_ref [lindex $manref $tcl_i]
	    return "<A HREF=\"../$tcl_ref.htm\">$ref</A>"
	}
	puts stderr "multiple cross reference to $ref in $manref from $manual(wing-file)/$mantail"
	return $ref
    }
    ##
    ## exceptions, sigh, to the rule
    ##
    if {[info exists exclude_when_followed_by_map($mantail)]} {
	upvar 1 text tail
	set following_word [lindex [regexp -inline {\S+} $tail] 0]
	foreach {this that} $exclude_when_followed_by_map($mantail) {
	    # only a ref if $this is not followed by $that
	    if {$lref eq $this && [string match $that* $following_word]} {
		return $ref
	    }
	}
    }
    if {
	[info exists exclude_refs_map($mantail)]
	&& $lref in $exclude_refs_map($mantail)
    } {
	return $ref
    }
    ##
    ## return the cross reference
    ##
    return "<A HREF=\"../$manref.htm\">$ref</A>"
}

##
## reference generation errors
##
proc reference-error {msg text} {
    global manual
    puts stderr "$manual(tail): $msg: {$text}"
    return $text
}

##
## insert as many cross references into this text string as are appropriate
##
proc insert-cross-references {text} {
    global manual
    set result ""

    while 1 {
	##
	## we identify cross references by:
	##     ``quotation''
	##    <B>emboldening</B>
	##    Tcl_ prefix
	##    Tk_ prefix
	##	  [a-zA-Z0-9]+ manual entry
	## and we avoid messing with already anchored text
	##
	##
	## find where each item lives - EXPENSIVE - and accumulate a list
	##
	unset -nocomplain offsets
	foreach {name pattern} {
	    anchor     {<A }	end-anchor {</A>}

	    quote      {``}	end-quote  {''}

	    bold       {<B>}	end-bold   {</B>}
	    c.tcl      {Tcl_}
	    c.tk       {Tk_}
	    c.ttk      {Ttk_}
	    c.tdbc     {Tdbc_}
	    c.itcl     {Itcl_}
	    Tcl1       {Tcl manual entry}
	    Tcl2       {Tcl overview manual entry}


	    url	       {http://}
	} {


	    set o [string first $pattern $text]
	    if {[set offset($name) $o] >= 0} {
		set invert($o) $name
		lappend offsets $o
	    }
	}
	##
	## if nothing, then we're done.
	##
	if {![info exists offsets]} {
	    return [append result $text]
	}
	##
	## sort the offsets
	##
	set offsets [lsort -integer $offsets]
	##
	## see which we want to use
	##
	switch -exact -- $invert([lindex $offsets 0]) {
	    anchor {
		if {$offset(end-anchor) < 0} {
		    return [reference-error {Missing end anchor} $text]
		}
		append result [string range $text 0 $offset(end-anchor)]
		set text [string range $text[set text ""] \
			      [expr {$offset(end-anchor)+1}] end]

		continue
	    }
	    quote {
		if {$offset(end-quote) < 0} {
		    return [reference-error "Missing end quote" $text]
		}
		if {$invert([lindex $offsets 1]) in {tcl tk ttk}} {
		    set offsets [lreplace $offsets 1 1]
		}



		switch -exact -- $invert([lindex $offsets 1]) {
		    end-quote {
			append result [string range $text 0 [expr {$offset(quote)-1}]]
			set body [string range $text [expr {$offset(quote)+2}] \
				      [expr {$offset(end-quote)-1}]]
			set text [string range $text[set text ""] \
				      [expr {$offset(end-quote)+2}] end]
			append result `` [cross-reference $body] ''
			continue
		    }
		    bold - anchor {

			append result [string range $text \
				      0 [expr {$offset(end-quote)+1}]]
			set text [string range $text[set text ""] \
				      [expr {$offset(end-quote)+2}] end]

			continue
		    }
		}
		return [reference-error "Uncaught quote case" $text]
	    }
	    bold {
		if {$offset(end-bold) < 0} {
		    return [append result $text]
		}
		if {[string match "c.*" $invert([lindex $offsets 1])]} {
		    set offsets [lreplace $offsets 1 1]
		}



		switch -exact -- $invert([lindex $offsets 1]) {
		    url - end-bold {
			append result \
			    [string range $text 0 [expr {$offset(bold)-1}]]
			set body [string range $text [expr {$offset(bold)+3}] \
				      [expr {$offset(end-bold)-1}]]
			set text [string range $text[set text ""] \
				      [expr {$offset(end-bold)+4}] end]







			regsub {http://[\w/.]+} $body {<A HREF="&">&</A>} body
			append result <B> [cross-reference $body] </B>
			continue
		    }
		    anchor {
			append result \
			    [string range $text 0 [expr {$offset(end-bold)+3}]]
			set text [string range $text[set text ""] \
				      [expr {$offset(end-bold)+4}] end]
			continue
		    }
		    default {
			return [reference-error "Uncaught bold case" $text]
		    }





		}

	    }
	    c.tk - c.ttk - c.tcl - c.tdbc - c.itcl {

		append result [string range $text 0 \







				   [expr {[lindex $offsets 0]-1}]]
		regexp -indices -start [lindex $offsets 0] {\w+} $text range
		set body [string range $text {*}$range]
		set text [string range $text[set text ""] \
			      [expr {[lindex $range 1]+1}] end]
		append result [cross-reference $body]
		continue
	    }
	    Tcl1 - Tcl2 {
		set off [lindex $offsets 0]
		append result [string range $text 0 [expr {$off-1}]]
		set text [string range $text[set text ""] [expr {$off+3}] end]
		append result [cross-reference Tcl]
		continue
	    }
	    url {
		set off [lindex $offsets 0]
		append result [string range $text 0 [expr {$off-1}]]
		regexp -indices -start $off {http://[\w/.]+} $text range
		set url [string range $text {*}$range]

		append result "<A HREF=\"$url\">" $url "</A>"
		set text [string range $text[set text ""] \
			      [expr {[lindex $range 1]+1}] end]
		continue
	    }
	    end-anchor - end-bold - end-quote {


		return [reference-error "Out of place $invert([lindex $offsets 0])" $text]
	    }
	}
    }
}

##
## process formatting directives
##
proc output-directive {line} {
    global manual
    # process format directive
    split-directive $line code rest
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
	    output-widget-options $rest
	    return
	}
	.IP {
	    output-IP-list .IP .IP $rest
	    return
	}
	.PP {
	    man-puts <P>
	}
	.RS {
	    output-RS-list
	    return
	}
	.RE {
	    manerror "unexpected .RE"
	    return
	}
	.br {
	    man-puts <BR>
	    return
	}
	.DE {
	    manerror "unexpected .DE"
	    return
	}
	.DS {
	    if {[next-op-is .ta rest]} {
		# skip the leading .ta directive if it is there
	    }
	    if {[match-text @stuff .DE]} {
		set td "<td><p class=\"tablecell\">"
		set bodyText [string map [list \n <tr>$td \t $td] \n$stuff]







|






<
<
<
<




<
<
<
<







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
	    output-widget-options $rest
	    return
	}
	.IP {
	    output-IP-list .IP .IP $rest
	    return
	}
	.PP - .sp {
	    man-puts <P>
	}
	.RS {
	    output-RS-list
	    return
	}




	.br {
	    man-puts <BR>
	    return
	}




	.DS {
	    if {[next-op-is .ta rest]} {
		# skip the leading .ta directive if it is there
	    }
	    if {[match-text @stuff .DE]} {
		set td "<td><p class=\"tablecell\">"
		set bodyText [string map [list \n <tr>$td \t $td] \n$stuff]
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
	    if {[match-text @stuff .CE]} {
		man-puts <PRE>$stuff</PRE>
	    } else {
		manerror "unexpected .CS format:\n[expand-next-text 2]"
	    }
	    return
	}
	.CE {
	    manerror "unexpected .CE"
	    return
	}
	.sp {
	    man-puts <P>
	}
	.ta {
	    manerror "ignoring $line"
	}
	.nf {
	    if {[match-text @more .fi]} {
		foreach more [split $more \n] {
		    man-puts $more<BR>
		}
	    } elseif {[match-text .RS @more .RE .fi]} {
		man-puts <DL><DD>







<
<
<
<
<
<
<
<
<
<







1121
1122
1123
1124
1125
1126
1127










1128
1129
1130
1131
1132
1133
1134
	    if {[match-text @stuff .CE]} {
		man-puts <PRE>$stuff</PRE>
	    } else {
		manerror "unexpected .CS format:\n[expand-next-text 2]"
	    }
	    return
	}










	.nf {
	    if {[match-text @more .fi]} {
		foreach more [split $more \n] {
		    man-puts $more<BR>
		}
	    } elseif {[match-text .RS @more .RE .fi]} {
		man-puts <DL><DD>
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
		    man-puts $more<BR>
		}
		man-puts </DL><P>
	    } else {
		manerror "ignoring $line"
	    }
	}
	.fi {
	    manerror "ignoring $line"

	}
	.na -
	.ad -
	.UL -
	.ne {
	    manerror "ignoring $line"
	}
	default {
	    manerror "unrecognized format directive: $line"
	}
    }
}

##
## merge copyright listings
##
proc merge-copyrights {l1 l2} {
    set merge {}
    set re1 {^Copyright +(?:\(c\)|\\\(co|&copy;) +(\w.*?)(?:all rights reserved)?(?:\. )*$}
    set re2 {^(\d+) +(?:by +)?(\w.*)$}         ;# date who







|
|
>

|
<
<
<







>







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
		    man-puts $more<BR>
		}
		man-puts </DL><P>
	    } else {
		manerror "ignoring $line"
	    }
	}
	.RE - .DE - .CE {
	    manerror "unexpected $code"
	    return
	}
	.ta - .fi - .na - .ad - .UL - .ie - .el - .ne {



	    manerror "ignoring $line"
	}
	default {
	    manerror "unrecognized format directive: $line"
	}
    }
}

##
## merge copyright listings
##
proc merge-copyrights {l1 l2} {
    set merge {}
    set re1 {^Copyright +(?:\(c\)|\\\(co|&copy;) +(\w.*?)(?:all rights reserved)?(?:\. )*$}
    set re2 {^(\d+) +(?:by +)?(\w.*)$}         ;# date who
1190
1191
1192
1193
1194
1195
1196
1197


































































































































































































































































































































































1198
1199
1200
1201
1202
1203
1204
	    lappend merge "Copyright &copy; [lindex $list 0] $who"
	} else {
	    lappend merge "Copyright &copy; [lindex $list 0]-[lrange $list end end] $who"
	}
    }
    return [lsort -dictionary $merge]
}



































































































































































































































































































































































proc makedirhier {dir} {
    try {
	if {![file isdirectory $dir]} {
	    file mkdir $dir
	}
    } on error msg {
	return -code error "cannot create directory $dir: $msg"







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







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
	    lappend merge "Copyright &copy; [lindex $list 0] $who"
	} else {
	    lappend merge "Copyright &copy; [lindex $list 0]-[lrange $list end end] $who"
	}
    }
    return [lsort -dictionary $merge]
}

##
## foreach of the man pages in the section specified by
## sectionDescriptor, convert manpages into hypertext in
## the directory specified by outputDir.
##
proc make-manpage-section {outputDir sectionDescriptor} {
    global manual overall_title tcltkdesc verbose
    global excluded_pages forced_index_pages process_first_patterns

    set LQ \u201c
    set RQ \u201d

    lassign $sectionDescriptor \
	manual(wing-glob) \
	manual(wing-name) \
	manual(wing-file) \
	manual(wing-description)
    set manual(wing-copyrights) {}
    makedirhier $outputDir/$manual(wing-file)
    set manual(wing-toc-fp) [open $outputDir/$manual(wing-file)/[indexfile] w]
    # whistle
    puts stderr "scanning section $manual(wing-name)"
    # put the entry for this section into the short table of contents
    puts $manual(short-toc-fp) "<DT><A HREF=\"$manual(wing-file)/[indexfile]\">$manual(wing-name)</A></DT><DD>$manual(wing-description)</DD>"
    # initialize the wing table of contents
    puts $manual(wing-toc-fp) [htmlhead $manual(wing-name) \
	    $manual(wing-name) $overall_title "../[indexfile]"]
    # initialize the short table of contents for this section
    set manual(wing-toc) {}
    # initialize the man directory for this section
    makedirhier $outputDir/$manual(wing-file)
    # initialize the long table of contents for this section
    set manual(long-toc-n) 1
    # get the manual pages for this section
    set manual(pages) [lsort -dictionary [glob -nocomplain $manual(wing-glob)]]
    # Some pages have to go first so that their links override others
    foreach pat $process_first_patterns {
	set n [lsearch -glob $manual(pages) $pat]
	if {$n >= 0} {
	    set f [lindex $manual(pages) $n]
	    puts stderr "shuffling [file tail $f] to front of processing queue"
	    set manual(pages) \
		[linsert [lreplace $manual(pages) $n $n] 0 $f]
	}
    }
    # set manual(pages) [lrange $manual(pages) 0 5]
    foreach manual_page $manual(pages) {
	set manual(page) [file normalize $manual_page]
	# whistle
	if {$verbose} {
	    puts stderr "scanning page $manual(page)"
	} else {
	    puts -nonewline stderr .
	}
	set manual(tail) [file tail $manual(page)]
	set manual(name) [file root $manual(tail)]
	set manual(section) {}
	if {$manual(name) in $excluded_pages} {
	    # obsolete
	    if {!$verbose} {
		puts stderr ""
	    }
	    manerror "discarding $manual(name)"
	    continue
	}
	set manual(infp) [open $manual(page)]
	set manual(text) {}
	set manual(partial-text) {}
	foreach p {.RS .DS .CS .SO} {
	    set manual($p) 0
	}
	set manual(stack) {}
	set manual(section) {}
	set manual(section-toc) {}
	set manual(section-toc-n) 1
	set manual(copyrights) {}
	lappend manual(all-pages) $manual(wing-file)/$manual(tail)
	lappend manual(all-page-domains) $manual(wing-name)
	manreport 100 $manual(name)
	while {[gets $manual(infp) line] >= 0} {
	    manreport 100 $line
	    if {[regexp {^[`'][/\\]} $line]} {
		if {[regexp {Copyright (?:\(c\)|\\\(co).*$} $line copyright]} {
		    lappend manual(copyrights) $copyright
		}
		# comment
		continue
	    }
	    if {"$line" eq {'}} {
		# comment
		continue
	    }
	    if {![parse-directive $line code rest]} {
		addbuffer $line
		continue
	    }
	    switch -exact -- $code {
		.if - .nr - .ti - .in - .ie - .el -
		.ad - .na - .so - .ne - .AS - .VE - .VS - . {
		    # ignore
		    continue
		}
	    }
	    switch -exact -- $code {
		.SH - .SS {
		    flushbuffer
		    if {[llength $rest] == 0} {
			gets $manual(infp) rest
		    }
		    lappend manual(text) "$code [unquote $rest]"
		}
		.TH {
		    flushbuffer
		    lappend manual(text) "$code [unquote $rest]"
		}
		.QW {
		    lassign [regexp -all -inline {\"(?:[^""]+)\"|\S+} $rest] \
			inQuote afterwards
		    addbuffer $LQ [unquote $inQuote] $RQ [unquote $afterwards]
		}
		.PQ {
		    lassign [regexp -all -inline {\"(?:[^""]+)\"|\S+} $rest] \
			inQuote punctuation afterwards
		    addbuffer ( $LQ [unquote $inQuote] $RQ \
			    [unquote $punctuation] ) [unquote $afterwards]
		}
		.QR {
		    lassign [regexp -all -inline {\"(?:[^""]+)\"|\S+} $rest] \
			rangeFrom rangeTo afterwards
		    addbuffer $LQ [unquote $rangeFrom] "&ndash;" \
			    [unquote $rangeTo] $RQ [unquote $afterwards]
		}
		.MT {
		    addbuffer $LQ$RQ
		}
		.HS - .UL - .ta {
		    flushbuffer
		    lappend manual(text) "$code [unquote $rest]"
		}
		.BS - .BE - .br - .fi - .sp - .nf {
		    flushbuffer
		    if {$rest ne ""} {
			if {!$verbose} {
			    puts stderr ""
			}
			manerror "unexpected argument: $line"
		    }
		    lappend manual(text) $code
		}
		.AP {
		    flushbuffer
		    lappend manual(text) [concat .IP [process-text \
			    "[lindex $rest 0] \\fB[lindex $rest 1]\\fR ([lindex $rest 2])"]]
		}
		.IP {
		    flushbuffer
		    regexp {^(.*) +\d+$} $rest all rest
		    lappend manual(text) ".IP [process-text \
			    [unquote [string trim $rest]]]"
		}
		.TP {
		    flushbuffer
		    while {[is-a-directive [set next [gets $manual(infp)]]]} {
			if {!$verbose} {
			    puts stderr ""
			}
			manerror "ignoring $next after .TP"
		    }
		    if {"$next" ne {'}} {
			lappend manual(text) ".IP [process-text $next]"
		    }
		}
		.OP {
		    flushbuffer
		    lassign $rest cmdName dbName dbClass
		    lappend manual(text) [concat .OP [process-text \
			    "\\fB$cmdName\\fR \\fB$dbName\\fR \\fB$dbClass\\fR"]]
		}
		.PP - .LP {
		    flushbuffer
		    lappend manual(text) {.PP}
		}
		.RS {
		    flushbuffer
		    incr manual(.RS)
		    lappend manual(text) $code
		}
		.RE {
		    flushbuffer
		    incr manual(.RS) -1
		    lappend manual(text) $code
		}
		.SO {
		    flushbuffer
		    incr manual(.SO)
		    if {[llength $rest] == 0} {
			lappend manual(text) "$code options"
		    } else {
			lappend manual(text) "$code [unquote $rest]"
		    }
		}
		.SE {
		    flushbuffer
		    incr manual(.SO) -1
		    lappend manual(text) $code
		}
		.DS {
		    flushbuffer
		    incr manual(.DS)
		    lappend manual(text) $code
		}
		.DE {
		    flushbuffer
		    incr manual(.DS) -1
		    lappend manual(text) $code
		}
		.CS {
		    flushbuffer
		    incr manual(.CS)
		    lappend manual(text) $code
		}
		.CE {
		    flushbuffer
		    incr manual(.CS) -1
		    lappend manual(text) $code
		}
		.de {
		    while {[gets $manual(infp) line] >= 0} {
			if {[string match "..*" $line]} {
			    break
			}
		    }
		}
		.. {
		    if {!$verbose} {
			puts stderr ""
		    }
		    error "found .. outside of .de"
		}
		default {
		    if {!$verbose} {
			puts stderr ""
		    }
		    flushbuffer
		    manerror "unrecognized format directive: $line"
		}
	    }
	}
	flushbuffer
	close $manual(infp)
	# fixups
	if {$manual(.RS) != 0} {
	    if {!$verbose} {
		puts stderr ""
	    }
	    puts "unbalanced .RS .RE"
	}
	if {$manual(.DS) != 0} {
	    if {!$verbose} {
		puts stderr ""
	    }
	    puts "unbalanced .DS .DE"
	}
	if {$manual(.CS) != 0} {
	    if {!$verbose} {
		puts stderr ""
	    }
	    puts "unbalanced .CS .CE"
	}
	if {$manual(.SO) != 0} {
	    if {!$verbose} {
		puts stderr ""
	    }
	    puts "unbalanced .SO .SE"
	}
	# output conversion
	open-text
	set haserror 0
	if {[next-op-is .HS rest]} {
	    set manual($manual(wing-file)-$manual(name)-title) \
		"[join [lrange $rest 1 end] { }] [lindex $rest 0] manual page"
	} elseif {[next-op-is .TH rest]} {
	    set manual($manual(wing-file)-$manual(name)-title) \
		"[lindex $rest 0] manual page - [join [lrange $rest 4 end] { }]"
	} else {
	    set haserror 1
	    if {!$verbose} {
		puts stderr ""
	    }
	    manerror "no .HS or .TH record found"
	}
	if {!$haserror} {
	    while {[more-text]} {
		set line [next-text]
		if {[is-a-directive $line]} {
		    output-directive $line
		} else {
		    man-puts $line
		}
	    }
	    man-puts [copyout $manual(copyrights) "../"]
	    set manual(wing-copyrights) [merge-copyrights \
		    $manual(wing-copyrights) $manual(copyrights)]
	}
	#
	# make the long table of contents for this page
	#
	set manual(toc-$manual(wing-file)-$manual(name)) \
	    [concat <DL> $manual(section-toc) </DL>]
    }
    if {!$verbose} {
	puts stderr ""
    }

    #
    # make the wing table of contents for the section
    #
    set width 0
    foreach name $manual(wing-toc) {
	if {[string length $name] > $width} {
	    set width [string length $name]
	}
    }
    set perline [expr {118 / $width}]
    set nrows [expr {([llength $manual(wing-toc)]+$perline)/$perline}]
    set n 0
    catch {unset rows}
    foreach name [lsort -dictionary $manual(wing-toc)] {
	set tail $manual(name-$name)
	if {[llength $tail] > 1} {
	    manerror "$name is defined in more than one file: $tail"
	    set tail [lindex $tail [expr {[llength $tail]-1}]]
	}
	set tail [file tail $tail]
	append rows([expr {$n%$nrows}]) \
	    "<td> <a href=\"$tail.htm\">$name</a> </td>"
	incr n
    }
    puts $manual(wing-toc-fp) <table>
    foreach row [lsort -integer [array names rows]] {
	puts $manual(wing-toc-fp) <tr>$rows($row)</tr>
    }
    puts $manual(wing-toc-fp) </table>

    #
    # insert wing copyrights
    #
    puts $manual(wing-toc-fp) [copyout $manual(wing-copyrights) "../"]
    puts $manual(wing-toc-fp) "</BODY></HTML>"
    close $manual(wing-toc-fp)
    set manual(merge-copyrights) \
	[merge-copyrights $manual(merge-copyrights) $manual(wing-copyrights)]
}

proc makedirhier {dir} {
    try {
	if {![file isdirectory $dir]} {
	    file mkdir $dir
	}
    } on error msg {
	return -code error "cannot create directory $dir: $msg"

Changes to tools/tcltk-man2html.tcl.

1
2
3
4
5
6
7
8
9
10
#!/bin/sh
# The next line is executed by /bin/sh, but not tcl \
exec tclsh "$0" ${1+"$@"}

package require Tcl 8.6

# Convert Ousterhout format man pages into highly crosslinked hypertext.
#
# Along the way detect many unmatched font changes and other odd things.
#
|
<
<







1


2
3
4
5
6
7
8
#!/usr/bin/env tclsh



package require Tcl 8.6

# Convert Ousterhout format man pages into highly crosslinked hypertext.
#
# Along the way detect many unmatched font changes and other odd things.
#
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
    close $cssfd
    set manual(short-toc-n) 1
    set manual(short-toc-fp) [open $html/[indexfile] w]
    puts $manual(short-toc-fp) [htmlhead $overall_title $overall_title]
    puts $manual(short-toc-fp) "<DL class=\"keylist\">"
    set manual(merge-copyrights) {}

    set LQ \u201c
    set RQ \u201d

    foreach arg $args {
	# preprocess to set up subheader for the rest of the files
	if {![llength $arg]} {
	    continue
	}


	set name [lindex $arg 1]

	set file [lindex $arg 2]

	lappend manual(subheader) $name $file
    }





    foreach arg $args {
	if {![llength $arg]} {
	    continue
	}
	set manual(wing-glob) [lindex $arg 0]
	set manual(wing-name) [lindex $arg 1]
	set manual(wing-file) [lindex $arg 2]
	set manual(wing-description) [lindex $arg 3]
	set manual(wing-copyrights) {}
	makedirhier $html/$manual(wing-file)
	set manual(wing-toc-fp) [open $html/$manual(wing-file)/[indexfile] w]
	# whistle
	puts stderr "scanning section $manual(wing-name)"
	# put the entry for this section into the short table of contents
	puts $manual(short-toc-fp) "<DT><A HREF=\"$manual(wing-file)/[indexfile]\">$manual(wing-name)</A></DT><DD>$manual(wing-description)</DD>"
	# initialize the wing table of contents
	puts $manual(wing-toc-fp) [htmlhead $manual(wing-name) \
		$manual(wing-name) $overall_title "../[indexfile]"]
	# initialize the short table of contents for this section
	set manual(wing-toc) {}
	# initialize the man directory for this section
	makedirhier $html/$manual(wing-file)
	# initialize the long table of contents for this section
	set manual(long-toc-n) 1
	# get the manual pages for this section
	set manual(pages) [lsort -dictionary [glob -nocomplain $manual(wing-glob)]]
	# Some pages have to go first so that their links override others
	foreach pat $process_first_patterns {
	    set n [lsearch -glob $manual(pages) $pat]
	    if {$n >= 0} {
		set f [lindex $manual(pages) $n]
		puts stderr "shuffling [file tail $f] to front of processing queue"
		set manual(pages) \
		    [linsert [lreplace $manual(pages) $n $n] 0 $f]
	    }
	}
	# set manual(pages) [lrange $manual(pages) 0 5]
	foreach manual_page $manual(pages) {
	    set manual(page) [file normalize $manual_page]
	    # whistle
	    if {$verbose} {
		puts stderr "scanning page $manual(page)"
	    } else {
		puts -nonewline stderr .
	    }
	    set manual(tail) [file tail $manual(page)]
	    set manual(name) [file root $manual(tail)]
	    set manual(section) {}
	    if {$manual(name) in $excluded_pages} {
		# obsolete
		if {!$verbose} {
		    puts stderr ""
		}
		manerror "discarding $manual(name)"
		continue
	    }
	    set manual(infp) [open $manual(page)]
	    set manual(text) {}
	    set manual(partial-text) {}
	    foreach p {.RS .DS .CS .SO} {
		set manual($p) 0
	    }
	    set manual(stack) {}
	    set manual(section) {}
	    set manual(section-toc) {}
	    set manual(section-toc-n) 1
	    set manual(copyrights) {}
	    lappend manual(all-pages) $manual(wing-file)/$manual(tail)
	    manreport 100 $manual(name)
	    while {[gets $manual(infp) line] >= 0} {
		manreport 100 $line
		if {[regexp {^[`'][/\\]} $line]} {
		    if {[regexp {Copyright (?:\(c\)|\\\(co).*$} $line copyright]} {
			lappend manual(copyrights) $copyright
		    }
		    # comment
		    continue
		}
		if {"$line" eq {'}} {
		    # comment
		    continue
		}
		if {![parse-directive $line code rest]} {
		    addbuffer $line
		    continue
		}
		switch -exact -- $code {
		    .if - .nr - .ti - .in -
		    .ad - .na - .so - .ne - .AS - .VE - .VS - . {
			# ignore
			continue
		    }
		}
		switch -exact -- $code {
		    .SH - .SS {
			flushbuffer
			if {[llength $rest] == 0} {
			    gets $manual(infp) rest
			}
			lappend manual(text) "$code [unquote $rest]"
		    }
		    .TH {
			flushbuffer
			lappend manual(text) "$code [unquote $rest]"
		    }
		    .QW {
			set rest [regexp -all -inline {\"(?:[^""]+)\"|\S+} $rest]
			addbuffer $LQ [unquote [lindex $rest 0]] $RQ \
			    [unquote [lindex $rest 1]]
		    }
		    .PQ {
			set rest [regexp -all -inline {\"(?:[^""]+)\"|\S+} $rest]
			addbuffer ( $LQ [unquote [lindex $rest 0]] $RQ \
			    [unquote [lindex $rest 1]] ) \
			    [unquote [lindex $rest 2]]
		    }
		    .QR {
			set rest [regexp -all -inline {\"(?:[^""]+)\"|\S+} $rest]
			addbuffer $LQ [unquote [lindex $rest 0]] - \
			    [unquote [lindex $rest 1]] $RQ \
			    [unquote [lindex $rest 2]]
		    }
		    .MT {
			addbuffer $LQ$RQ
		    }
		    .HS - .UL - .ta {
			flushbuffer
			lappend manual(text) "$code [unquote $rest]"
		    }
		    .BS - .BE - .br - .fi - .sp - .nf {
			flushbuffer
			if {"$rest" ne {}} {
			    if {!$verbose} {
				puts stderr ""
			    }
			    manerror "unexpected argument: $line"
			}
			lappend manual(text) $code
		    }
		    .AP {
			flushbuffer
			lappend manual(text) [concat .IP [process-text "[lindex $rest 0] \\fB[lindex $rest 1]\\fR ([lindex $rest 2])"]]
		    }
		    .IP {
			flushbuffer
			regexp {^(.*) +\d+$} $rest all rest
			lappend manual(text) ".IP [process-text [unquote [string trim $rest]]]"
		    }
		    .TP {
			flushbuffer
			while {[is-a-directive [set next [gets $manual(infp)]]]} {
			    if {!$verbose} {
				puts stderr ""
			    }
			    manerror "ignoring $next after .TP"
			}
			if {"$next" ne {'}} {
			    lappend manual(text) ".IP [process-text $next]"
			}
		    }
		    .OP {
			flushbuffer
			lappend manual(text) [concat .OP [process-text \
				"\\fB[lindex $rest 0]\\fR \\fB[lindex $rest 1]\\fR \\fB[lindex $rest 2]\\fR"]]
		    }
		    .PP - .LP {
			flushbuffer
			lappend manual(text) {.PP}
		    }
		    .RS {
			flushbuffer
			incr manual(.RS)
			lappend manual(text) $code
		    }
		    .RE {
			flushbuffer
			incr manual(.RS) -1
			lappend manual(text) $code
		    }
		    .SO {
			flushbuffer
			incr manual(.SO)
			if {[llength $rest] == 0} {
			    lappend manual(text) "$code options"
			} else {
			    lappend manual(text) "$code [unquote $rest]"
			}
		    }
		    .SE {
			flushbuffer
			incr manual(.SO) -1
			lappend manual(text) $code
		    }
		    .DS {
			flushbuffer
			incr manual(.DS)
			lappend manual(text) $code
		    }
		    .DE {
			flushbuffer
			incr manual(.DS) -1
			lappend manual(text) $code
		    }
		    .CS {
			flushbuffer
			incr manual(.CS)
			lappend manual(text) $code
		    }
		    .CE {
			flushbuffer
			incr manual(.CS) -1
			lappend manual(text) $code
		    }
		    .de {
			while {[gets $manual(infp) line] >= 0} {
			    if {[string match "..*" $line]} {
				break
			    }
			}
		    }
		    .. {
			if {!$verbose} {
			    puts stderr ""
			}
			error "found .. outside of .de"
		    }
		    default {
			if {!$verbose} {
			    puts stderr ""
			}
			flushbuffer
			manerror "unrecognized format directive: $line"
		    }
		}
	    }
	    flushbuffer
	    close $manual(infp)
	    # fixups
	    if {$manual(.RS) != 0} {
		if {!$verbose} {
		    puts stderr ""
		}
		puts "unbalanced .RS .RE"
	    }
	    if {$manual(.DS) != 0} {
		if {!$verbose} {
		    puts stderr ""
		}
		puts "unbalanced .DS .DE"
	    }
	    if {$manual(.CS) != 0} {
		if {!$verbose} {
		    puts stderr ""
		}
		puts "unbalanced .CS .CE"
	    }
	    if {$manual(.SO) != 0} {
		if {!$verbose} {
		    puts stderr ""
		}
		puts "unbalanced .SO .SE"
	    }
	    # output conversion
	    open-text
	    set haserror 0
	    if {[next-op-is .HS rest]} {
		set manual($manual(wing-file)-$manual(name)-title) \
		    "[join [lrange $rest 1 end] { }] [lindex $rest 0] manual page"
	    } elseif {[next-op-is .TH rest]} {
		set manual($manual(wing-file)-$manual(name)-title) \
		    "[lindex $rest 0] manual page - [join [lrange $rest 4 end] { }]"
	    } else {
		set haserror 1
		if {!$verbose} {
		    puts stderr ""
		}
		manerror "no .HS or .TH record found"
	    }
	    if {!$haserror} {
		while {[more-text]} {
		    set line [next-text]
		    if {[is-a-directive $line]} {
			output-directive $line
		    } else {
			man-puts $line
		    }
		}
		man-puts [copyout $manual(copyrights) "../"]
		set manual(wing-copyrights) [merge-copyrights \
			$manual(wing-copyrights) $manual(copyrights)]
	    }
	    #
	    # make the long table of contents for this page
	    #
	    set manual(toc-$manual(wing-file)-$manual(name)) \
		    [concat <DL> $manual(section-toc) </DL>]
	}
	if {!$verbose} {
	    puts stderr ""
	}

	#
	# make the wing table of contents for the section
	#
	set width 0
	foreach name $manual(wing-toc) {
	    if {[string length $name] > $width} {
		set width [string length $name]
	    }
	}
	set perline [expr {118 / $width}]
	set nrows [expr {([llength $manual(wing-toc)]+$perline)/$perline}]
	set n 0
        catch {unset rows}
	foreach name [lsort -dictionary $manual(wing-toc)] {
	    set tail $manual(name-$name)
	    if {[llength $tail] > 1} {
		manerror "$name is defined in more than one file: $tail"
		set tail [lindex $tail [expr {[llength $tail]-1}]]
	    }
	    set tail [file tail $tail]
	    append rows([expr {$n%$nrows}]) \
		    "<td> <a href=\"$tail.htm\">$name</a> </td>"
	    incr n
	}
	puts $manual(wing-toc-fp) <table>
        foreach row [lsort -integer [array names rows]] {
	    puts $manual(wing-toc-fp) <tr>$rows($row)</tr>
	}
	puts $manual(wing-toc-fp) </table>

	#
	# insert wing copyrights
	#
	puts $manual(wing-toc-fp) [copyout $manual(wing-copyrights) "../"]
	puts $manual(wing-toc-fp) "</BODY></HTML>"
	close $manual(wing-toc-fp)
	set manual(merge-copyrights) [merge-copyrights \
		$manual(merge-copyrights) $manual(wing-copyrights)]
    }

    ##
    ## build the keyword index.
    ##



    file delete -force -- $html/Keywords
    makedirhier $html/Keywords
    set keyfp [open $html/Keywords/[indexfile] w]
    puts $keyfp [htmlhead "$tcltkdesc Keywords" "$tcltkdesc Keywords" \
		     $overall_title "../[indexfile]"]
    set letters {A B C D E F G H I J K L M N O P Q R S T U V W X Y Z}
    # Create header first







<
<
<





>
>
|
>
|
>


>
>
>
>
>

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





>
>
>







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
    close $cssfd
    set manual(short-toc-n) 1
    set manual(short-toc-fp) [open $html/[indexfile] w]
    puts $manual(short-toc-fp) [htmlhead $overall_title $overall_title]
    puts $manual(short-toc-fp) "<DL class=\"keylist\">"
    set manual(merge-copyrights) {}




    foreach arg $args {
	# preprocess to set up subheader for the rest of the files
	if {![llength $arg]} {
	    continue
	}
	lassign $arg -> name file
	if {[regexp {(.*)(?: Package)? Commands(?:, version .*)?} $name -> pkg]} {
	    set name "$pkg Commands"
	} elseif {[regexp {(.*)(?: Package)? C API(?:, version .*)?} $name -> pkg]} {
	    set name "$pkg C API"
	}
	lappend manual(subheader) $name $file
    }

    ##
    ## parse the manpages in a section of the docs (split by
    ## package) and construct formatted manpages
    ##
    foreach arg $args {































































































	if {[llength $arg]} {











































































































































































































	    make-manpage-section $html $arg







	}






























    }

    ##
    ## build the keyword index.
    ##
    if {!$verbose} {
	puts stderr "Assembling index"
    }
    file delete -force -- $html/Keywords
    makedirhier $html/Keywords
    set keyfp [open $html/Keywords/[indexfile] w]
    puts $keyfp [htmlhead "$tcltkdesc Keywords" "$tcltkdesc Keywords" \
		     $overall_title "../[indexfile]"]
    set letters {A B C D E F G H I J K L M N O P Q R S T U V W X Y Z}
    # Create header first
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
    close $manual(short-toc-fp)

    ##
    ## output man pages
    ##
    unset manual(section)
    if {!$verbose} {
	puts stderr "Rescanning [llength $manual(all-pages)] pages to build cross links"
    }
    foreach path $manual(all-pages) {
	set manual(wing-file) [file dirname $path]
	set manual(tail) [file tail $path]
	set manual(name) [file root $manual(tail)]
	try {
	    set text $manual(output-$manual(wing-file)-$manual(name))
	    set ntext 0
	    foreach item $text {







|

|







354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
    close $manual(short-toc-fp)

    ##
    ## output man pages
    ##
    unset manual(section)
    if {!$verbose} {
	puts stderr "Rescanning [llength $manual(all-pages)] pages to build cross links and write out"
    }
    foreach path $manual(all-pages) wing_name $manual(all-page-domains) {
	set manual(wing-file) [file dirname $path]
	set manual(tail) [file tail $path]
	set manual(name) [file root $manual(tail)]
	try {
	    set text $manual(output-$manual(wing-file)-$manual(name))
	    set ntext 0
	    foreach item $text {
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
	    if {$verbose} {
		puts stderr "rescanning page $manual(name) $ntoc/$ntext"
	    } else {
		puts -nonewline stderr .
	    }
	    set outfd [open $html/$manual(wing-file)/$manual(name).htm w]
	    puts $outfd [htmlhead "$manual($manual(wing-file)-$manual(name)-title)" \
		    $manual(name) $manual(wing-file) "[indexfile]" \
		    $overall_title "../[indexfile]"]
	    if {($ntext > 60) && ($ntoc > 32)} {
		foreach item $toc {
		    puts $outfd $item
		}
	    } elseif {$manual(name) in $forced_index_pages} {
		if {!$verbose} {puts stderr ""}







|







380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
	    if {$verbose} {
		puts stderr "rescanning page $manual(name) $ntoc/$ntext"
	    } else {
		puts -nonewline stderr .
	    }
	    set outfd [open $html/$manual(wing-file)/$manual(name).htm w]
	    puts $outfd [htmlhead "$manual($manual(wing-file)-$manual(name)-title)" \
		    $manual(name) $wing_name "[indexfile]" \
		    $overall_title "../[indexfile]"]
	    if {($ntext > 60) && ($ntoc > 32)} {
		foreach item $toc {
		    puts $outfd $item
		}
	    } elseif {$manual(name) in $forced_index_pages} {
		if {!$verbose} {puts stderr ""}
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
    global build_tcl tcltkdir tcldir
    if {$type ni {n 3}} {
	error "unknown type \"$type\": must be 3 or n"
    }
    if {!$build_tcl} return
    set result {}
    foreach {dir name} $args {
	set globpat $tcltkdir/$tcldir/pkgs/$dir/doc/*.$type
	if {![llength [glob -nocomplain $globpat]]} {
	    # Fallback for manpages generated using doctools
	    set globpat $tcltkdir/$tcldir/pkgs/$dir/doc/man/*.$type
	    if {![llength [glob -nocomplain $globpat]]} {
		continue
	    }
	}


	switch $type {
	    n {
		set title "$name Package Commands"



		set dir [string totitle $dir]Cmd
		set desc \
		    "The additional commands provided by the $name package."
	    }
	    3 {
		set title "$name Package Library"



		set dir [string totitle $dir]Lib
		set desc \
		    "The additional C functions provided by the $name package."
	    }
	}
	lappend result [list $globpat $title $dir $desc]
    }







|


|




>
>



>
>
>





|
>
>
>







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
    global build_tcl tcltkdir tcldir
    if {$type ni {n 3}} {
	error "unknown type \"$type\": must be 3 or n"
    }
    if {!$build_tcl} return
    set result {}
    foreach {dir name} $args {
	set globpat $tcltkdir/$tcldir/pkgs/$dir*/doc/*.$type
	if {![llength [glob -nocomplain $globpat]]} {
	    # Fallback for manpages generated using doctools
	    set globpat $tcltkdir/$tcldir/pkgs/$dir*/doc/man/*.$type
	    if {![llength [glob -nocomplain $globpat]]} {
		continue
	    }
	}
	regexp "pkgs/${dir}(.*)/doc$" [glob $tcltkdir/$tcldir/pkgs/$dir*/doc] \
	    -> version
	switch $type {
	    n {
		set title "$name Package Commands"
		if {$version ne ""} {
		    append title ", version $version"
		}
		set dir [string totitle $dir]Cmd
		set desc \
		    "The additional commands provided by the $name package."
	    }
	    3 {
		set title "$name Package C API"
		if {$version ne ""} {
		    append title ", version $version"
		}
		set dir [string totitle $dir]Lib
		set desc \
		    "The additional C functions provided by the $name package."
	    }
	}
	lappend result [list $globpat $title $dir $desc]
    }
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
set excluded_pages {case menubar pack-old}
set forced_index_pages {GetDash}
set process_first_patterns {*/ttk_widget.n */options.n}
set ensemble_commands {
    after array binary chan clock dde dict encoding file history info interp
    memory namespace package registry self string trace update zlib
    clipboard console font grab grid image option pack place selection tk
    tkwait ttk::style winfo wm
}
array set remap_link_target {
    stdin  Tcl_GetStdChannel
    stdout Tcl_GetStdChannel
    stderr Tcl_GetStdChannel
    safe   {Safe&nbsp;Base}
    style  ttk::style
    {style map} ttk::style













































}
array set exclude_refs_map {

    clock.n		{next}
    history.n		{exec}
    next.n		{unknown}
    zlib.n		{binary close filename text}
    canvas.n		{bitmap text}

    checkbutton.n	{image}
    clipboard.n		{string}






    menu.n		{checkbutton radiobutton}

    options.n		{bitmap image set}
    radiobutton.n	{image}


    scrollbar.n		{set}
    selection.n		{string}
    tcltest.n		{error}
    tkvars.n		{tk}


    ttk_checkbutton.n	{variable}
    ttk_combobox.n	{selection}
    ttk_entry.n		{focus variable}
    ttk_intro.n		{focus}
    ttk_label.n		{font text}
    ttk_labelframe.n	{text}
    ttk_menubutton.n	{flush}
    ttk_notebook.n	{image text}
    ttk_progressbar.n	{variable}
    ttk_radiobutton.n	{variable}
    ttk_scale.n		{variable}







|





<


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


>





>


>
>
>
>
>
>

>


>
>




>
>



|







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
set excluded_pages {case menubar pack-old}
set forced_index_pages {GetDash}
set process_first_patterns {*/ttk_widget.n */options.n}
set ensemble_commands {
    after array binary chan clock dde dict encoding file history info interp
    memory namespace package registry self string trace update zlib
    clipboard console font grab grid image option pack place selection tk
    tkwait ttk::style winfo wm itcl::delete itcl::find itcl::is
}
array set remap_link_target {
    stdin  Tcl_GetStdChannel
    stdout Tcl_GetStdChannel
    stderr Tcl_GetStdChannel

    style  ttk::style
    {style map} ttk::style
    {tk busy}   busy
    library     auto_execok
    safe-tcl    safe
    tclvars     env
    tcl_break   catch
    tcl_continue catch
    tcl_error   catch
    tcl_ok      catch
    tcl_return  catch
    int()       mathfunc
    wide()      mathfunc
    packagens   pkg::create
    pkgMkIndex  pkg_mkIndex
    pkg_mkIndex pkg_mkIndex
    Tcl_Obj     Tcl_NewObj
    Tcl_ObjType Tcl_RegisterObjType
    Tcl_OpenFileChannelProc Tcl_FSOpenFileChannel
    errorinfo 	env
    errorcode 	env
    tcl_pkgpath env
    Tcl_Command Tcl_CreateObjCommand
    Tcl_CmdProc Tcl_CreateObjCommand
    Tcl_CmdDeleteProc Tcl_CreateObjCommand
    Tcl_ObjCmdProc Tcl_CreateObjCommand
    Tcl_Channel Tcl_OpenFileChannel
    Tcl_WideInt Tcl_NewIntObj
    Tcl_ChannelType Tcl_CreateChannel
    Tcl_DString Tcl_DStringInit
    Tcl_Namespace Tcl_AppendExportList
    Tcl_Object  Tcl_NewObjectInstance
    Tcl_Class   Tcl_GetObjectAsClass
    Tcl_Event   Tcl_QueueEvent
    Tcl_Time	Tcl_GetTime
    Tcl_ThreadId Tcl_CreateThread
    Tk_Window	Tk_WindowId
    Tk_3DBorder Tk_Get3DBorder
    Tk_Anchor	Tk_GetAnchor
    Tk_Cursor	Tk_GetCursor
    Tk_Dash	Tk_GetDash
    Tk_Font	Tk_GetFont
    Tk_Image	Tk_GetImage
    Tk_ImageMaster Tk_GetImage
    Tk_ItemType Tk_CreateItemType
    Tk_Justify	Tk_GetJustify
    Ttk_Theme	Ttk_GetTheme
}
array set exclude_refs_map {
    bind.n		{button destroy option}
    clock.n		{next}
    history.n		{exec}
    next.n		{unknown}
    zlib.n		{binary close filename text}
    canvas.n		{bitmap text}
    console.n		{eval}
    checkbutton.n	{image}
    clipboard.n		{string}
    entry.n		{string}
    event.n		{return}
    font.n		{menu}
    getOpenFile.n	{file open text}
    grab.n		{global}
    interp.n		{time}
    menu.n		{checkbutton radiobutton}
    messageBox.n	{error info}
    options.n		{bitmap image set}
    radiobutton.n	{image}
    safe.n		{join split}
    scale.n		{label variable}
    scrollbar.n		{set}
    selection.n		{string}
    tcltest.n		{error}
    tkvars.n		{tk}
    tkwait.n		{variable}
    tm.n		{exec}
    ttk_checkbutton.n	{variable}
    ttk_combobox.n	{selection}
    ttk_entry.n		{focus variable}
    ttk_intro.n		{focus text}
    ttk_label.n		{font text}
    ttk_labelframe.n	{text}
    ttk_menubutton.n	{flush}
    ttk_notebook.n	{image text}
    ttk_progressbar.n	{variable}
    ttk_radiobutton.n	{variable}
    ttk_scale.n		{variable}
857
858
859
860
861
862
863



864
865
866
867
868
869
870
    selection.n {
	clipboard selection
	clipboard ;
    }
    ttk_image.n {
	image imageSpec
    }



}

try {
    # Parse what the user told us to do
    parse_command_line

    # Some strings depend on what options are specified







>
>
>







594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
    selection.n {
	clipboard selection
	clipboard ;
    }
    ttk_image.n {
	image imageSpec
    }
    fontchooser.n {
	tk fontchooser
    }
}

try {
    # Parse what the user told us to do
    parse_command_line

    # Some strings depend on what options are specified
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
    }
    if {$build_tk} {
	append tcltkdesc "Tk"
	append cmdesc "Tk"
	append appdir "$tkdir"
    }

    # Get the list of packages to try, and what their human-readable
    # names are.
    try {
	set packageDirNameMap {}
	if {$build_tcl} {
	    set f [open $tcltkdir/$tcldir/pkgs/package.list.txt]
	    try {
		foreach line [split [read $f] \n] {
		    if {[string trim $line] eq ""} continue
		    if {[string match #* $line]} continue
		    lappend packageDirNameMap {*}$line
		}
	    } finally {
		close $f
	    }
	}
    } trap {POSIX ENOENT} {} {
	set packageDirNameMap {
	    itcl {[incr Tcl]}
	    tdbc {TDBC}
	    Thread Thread
	}
    }

    #
    # Invoke the scraper/converter engine.
    #
    make-man-pages $webdir \
	[list $tcltkdir/{$appdir}/doc/*.1 "$tcltkdesc Applications" UserCmd \
	     "The interpreters which implement $cmdesc."] \
	[plus-base $build_tcl $tcldir/doc/*.n {Tcl Commands} TclCmd \
	     "The commands which the <B>tclsh</B> interpreter implements."] \
	[plus-base $build_tk $tkdir/doc/*.n {Tk Commands} TkCmd \
	     "The additional commands which the <B>wish</B> interpreter implements."] \
	{*}[plus-pkgs n {*}$packageDirNameMap] \
	[plus-base $build_tcl $tcldir/doc/*.3 {Tcl Library} TclLib \
	     "The C functions which a Tcl extended C program may use."] \
	[plus-base $build_tk $tkdir/doc/*.3 {Tk Library} TkLib \
	     "The additional C functions which a Tk extended C program may use."] \
	{*}[plus-pkgs 3 {*}$packageDirNameMap]
} on error {msg opts} {
    # On failure make sure we show what went wrong. We're not supposed
    # to get here though; it represents a bug in the script.
    puts $msg\n[dict get $opts -errorinfo]
    exit 1
}

# Local-Variables:
# mode: tcl
# End:







|
|


















|














|

|








|



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
    }
    if {$build_tk} {
	append tcltkdesc "Tk"
	append cmdesc "Tk"
	append appdir "$tkdir"
    }

    # Get the list of packages to try, and what their human-readable names
    # are. Note that the package directory list should be version-less.
    try {
	set packageDirNameMap {}
	if {$build_tcl} {
	    set f [open $tcltkdir/$tcldir/pkgs/package.list.txt]
	    try {
		foreach line [split [read $f] \n] {
		    if {[string trim $line] eq ""} continue
		    if {[string match #* $line]} continue
		    lappend packageDirNameMap {*}$line
		}
	    } finally {
		close $f
	    }
	}
    } trap {POSIX ENOENT} {} {
	set packageDirNameMap {
	    itcl {[incr Tcl]}
	    tdbc {TDBC}
	    thread Thread
	}
    }

    #
    # Invoke the scraper/converter engine.
    #
    make-man-pages $webdir \
	[list $tcltkdir/{$appdir}/doc/*.1 "$tcltkdesc Applications" UserCmd \
	     "The interpreters which implement $cmdesc."] \
	[plus-base $build_tcl $tcldir/doc/*.n {Tcl Commands} TclCmd \
	     "The commands which the <B>tclsh</B> interpreter implements."] \
	[plus-base $build_tk $tkdir/doc/*.n {Tk Commands} TkCmd \
	     "The additional commands which the <B>wish</B> interpreter implements."] \
	{*}[plus-pkgs n {*}$packageDirNameMap] \
	[plus-base $build_tcl $tcldir/doc/*.3 {Tcl C API} TclLib \
	     "The C functions which a Tcl extended C program may use."] \
	[plus-base $build_tk $tkdir/doc/*.3 {Tk C API} TkLib \
	     "The additional C functions which a Tk extended C program may use."] \
	{*}[plus-pkgs 3 {*}$packageDirNameMap]
} on error {msg opts} {
    # On failure make sure we show what went wrong. We're not supposed
    # to get here though; it represents a bug in the script.
    puts $msg\n[dict get $opts -errorinfo]
    exit 1
}

# Local-Variables:
# mode: tcl
# End:

Changes to tools/uniParse.tcl.

175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
    set f [open [lindex $argv 0] r]
    set data [read $f]
    close $f

    buildTables $data
    puts "X = [llength $pMap]  Y= [llength $pages]  A= [llength $groups]"
    set size [expr {[llength $pMap] + [llength $pages]*(1<<$shift)}]
    puts "shift = 6, space = $size"
    puts "title case count = $titleCount"

    set f [open [file join [lindex $argv 1] tclUniData.c] w]
    fconfigure $f -translation lf
    puts $f "/*
 * tclUniData.c --
 *







|







175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
    set f [open [lindex $argv 0] r]
    set data [read $f]
    close $f

    buildTables $data
    puts "X = [llength $pMap]  Y= [llength $pages]  A= [llength $groups]"
    set size [expr {[llength $pMap] + [llength $pages]*(1<<$shift)}]
    puts "shift = $shift, space = $size"
    puts "title case count = $titleCount"

    set f [open [file join [lindex $argv 1] tclUniData.c] w]
    fconfigure $f -translation lf
    puts $f "/*
 * tclUniData.c --
 *
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
 * Bits 5-7	Case delta type: 000 = identity
 *				 010 = add delta for lower
 *				 011 = add delta for lower, add 1 for title
 *				 100 = subtract delta for title/upper
 *				 101 = sub delta for upper, sub 1 for title
 *				 110 = sub delta for upper, add delta for lower
 *
 * Bits 8-21	Reserved for future use.
 *
 * Bits 22-31	Case delta: delta for case conversions.  This should be the
 *			    highest field so we can easily sign extend.
 */

static const int groups\[\] = {"
    set line "    "
    set last [expr {[llength $groups] - 1}]
    for {set i 0} {$i <= $last} {incr i} {







|

|







260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
 * Bits 5-7	Case delta type: 000 = identity
 *				 010 = add delta for lower
 *				 011 = add delta for lower, add 1 for title
 *				 100 = subtract delta for title/upper
 *				 101 = sub delta for upper, sub 1 for title
 *				 110 = sub delta for upper, add delta for lower
 *
 * Bits 8-14	Reserved for future use.
 *
 * Bits 15-31	Case delta: delta for case conversions.  This should be the
 *			    highest field so we can easily sign extend.
 */

static const int groups\[\] = {"
    set line "    "
    set last [expr {[llength $groups] - 1}]
    for {set i 0} {$i <= $last} {incr i} {
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
	    set delta $tolower
	} else {
	    # noop
	    set case 0
	    set delta 0
	}

	set val [expr {($delta << 22) | ($case << 5) | $type}]

	append line [format "%d" $val]
	if {$i != $last} {
	    append line ", "
	}
	if {[string length $line] > 65} {
	    puts $f [string trimright $line]
	    set line "    "
	}







|
<
<







302
303
304
305
306
307
308
309


310
311
312
313
314
315
316
	    set delta $tolower
	} else {
	    # noop
	    set case 0
	    set delta 0
	}

	append line [expr {($delta << 15) | ($case << 5) | $type}]


	if {$i != $last} {
	    append line ", "
	}
	if {[string length $line] > 65} {
	    puts $f [string trimright $line]
	    set line "    "
	}
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
 * The following macros extract the fields of the character info.  The
 * GetDelta() macro is complicated because we can't rely on the C compiler
 * to do sign extension on right shifts.
 */

#define GetCaseType(info) (((info) & 0xE0) >> 5)
#define GetCategory(info) ((info) & 0x1F)
#define GetDelta(info) (((info) > 0) ? ((info) >> 22) : (~(~((info)) >> 22)))

/*
 * This macro extracts the information about a character from the
 * Unicode character tables.
 */

#define GetUniCharInfo(ch) (groups\[groupMap\[(pageMap\[(((int)(ch)) & 0xffff) >> OFFSET_BITS\] << OFFSET_BITS) | ((ch) & ((1 << OFFSET_BITS)-1))\]\])







|







362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
 * The following macros extract the fields of the character info.  The
 * GetDelta() macro is complicated because we can't rely on the C compiler
 * to do sign extension on right shifts.
 */

#define GetCaseType(info) (((info) & 0xE0) >> 5)
#define GetCategory(info) ((info) & 0x1F)
#define GetDelta(info) (((info) > 0) ? ((info) >> 15) : (~(~((info)) >> 15)))

/*
 * This macro extracts the information about a character from the
 * Unicode character tables.
 */

#define GetUniCharInfo(ch) (groups\[groupMap\[(pageMap\[(((int)(ch)) & 0xffff) >> OFFSET_BITS\] << OFFSET_BITS) | ((ch) & ((1 << OFFSET_BITS)-1))\]\])

Changes to unix/Makefile.in.

311
312
313
314
315
316
317
318

319
320
321
322
323
324
325

OO_OBJS = tclOO.o tclOOBasic.o tclOOCall.o tclOODefineCmds.o tclOOInfo.o \
	tclOOMethod.o tclOOStubInit.o

TOMMATH_OBJS = bncore.o bn_reverse.o bn_fast_s_mp_mul_digs.o \
	bn_fast_s_mp_sqr.o bn_mp_add.o bn_mp_and.o \
        bn_mp_add_d.o bn_mp_clamp.o bn_mp_clear.o bn_mp_clear_multi.o \
        bn_mp_cmp.o bn_mp_cmp_d.o bn_mp_cmp_mag.o bn_mp_copy.o \

	bn_mp_count_bits.o bn_mp_div.o bn_mp_div_d.o bn_mp_div_2.o \
	bn_mp_div_2d.o bn_mp_div_3.o \
        bn_mp_exch.o bn_mp_expt_d.o bn_mp_grow.o bn_mp_init.o \
	bn_mp_init_copy.o bn_mp_init_multi.o bn_mp_init_set.o \
	bn_mp_init_set_int.o bn_mp_init_size.o bn_mp_karatsuba_mul.o \
	bn_mp_karatsuba_sqr.o \
        bn_mp_lshd.o bn_mp_mod.o bn_mp_mod_2d.o bn_mp_mul.o bn_mp_mul_2.o \







|
>







311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326

OO_OBJS = tclOO.o tclOOBasic.o tclOOCall.o tclOODefineCmds.o tclOOInfo.o \
	tclOOMethod.o tclOOStubInit.o

TOMMATH_OBJS = bncore.o bn_reverse.o bn_fast_s_mp_mul_digs.o \
	bn_fast_s_mp_sqr.o bn_mp_add.o bn_mp_and.o \
        bn_mp_add_d.o bn_mp_clamp.o bn_mp_clear.o bn_mp_clear_multi.o \
        bn_mp_cmp.o bn_mp_cmp_d.o bn_mp_cmp_mag.o \
	bn_mp_cnt_lsb.o bn_mp_copy.o \
	bn_mp_count_bits.o bn_mp_div.o bn_mp_div_d.o bn_mp_div_2.o \
	bn_mp_div_2d.o bn_mp_div_3.o \
        bn_mp_exch.o bn_mp_expt_d.o bn_mp_grow.o bn_mp_init.o \
	bn_mp_init_copy.o bn_mp_init_multi.o bn_mp_init_set.o \
	bn_mp_init_set_int.o bn_mp_init_size.o bn_mp_karatsuba_mul.o \
	bn_mp_karatsuba_sqr.o \
        bn_mp_lshd.o bn_mp_mod.o bn_mp_mod_2d.o bn_mp_mul.o bn_mp_mul_2.o \
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
	$(GENERIC_DIR)/tclOOInfo.c \
	$(GENERIC_DIR)/tclOOMethod.c \
	$(GENERIC_DIR)/tclOOStubInit.c

STUB_SRCS = \
	$(GENERIC_DIR)/tclStubLib.c \
	$(GENERIC_DIR)/tclTomMathStubLib.c \
	$(GENERIC_DIR)/tclOOStubLib.o

TOMMATH_SRCS = \
	$(TOMMATH_DIR)/bncore.c \
	$(TOMMATH_DIR)/bn_reverse.c \
	$(TOMMATH_DIR)/bn_fast_s_mp_mul_digs.c \
	$(TOMMATH_DIR)/bn_fast_s_mp_sqr.c \
	$(TOMMATH_DIR)/bn_mp_add.c \
	$(TOMMATH_DIR)/bn_mp_add_d.c \
	$(TOMMATH_DIR)/bn_mp_and.c \
	$(TOMMATH_DIR)/bn_mp_clamp.c \
	$(TOMMATH_DIR)/bn_mp_clear.c \
	$(TOMMATH_DIR)/bn_mp_clear_multi.c \
	$(TOMMATH_DIR)/bn_mp_cmp.c \
	$(TOMMATH_DIR)/bn_mp_cmp_d.c \
	$(TOMMATH_DIR)/bn_mp_cmp_mag.c \
	$(TOMMATH_DIR)/bn_mp_copy.c \

	$(TOMMATH_DIR)/bn_mp_count_bits.c \
	$(TOMMATH_DIR)/bn_mp_div.c \
	$(TOMMATH_DIR)/bn_mp_div_d.c \
	$(TOMMATH_DIR)/bn_mp_div_2.c \
	$(TOMMATH_DIR)/bn_mp_div_2d.c \
	$(TOMMATH_DIR)/bn_mp_div_3.c \
	$(TOMMATH_DIR)/bn_mp_exch.c \







|
















>







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
	$(GENERIC_DIR)/tclOOInfo.c \
	$(GENERIC_DIR)/tclOOMethod.c \
	$(GENERIC_DIR)/tclOOStubInit.c

STUB_SRCS = \
	$(GENERIC_DIR)/tclStubLib.c \
	$(GENERIC_DIR)/tclTomMathStubLib.c \
	$(GENERIC_DIR)/tclOOStubLib.c

TOMMATH_SRCS = \
	$(TOMMATH_DIR)/bncore.c \
	$(TOMMATH_DIR)/bn_reverse.c \
	$(TOMMATH_DIR)/bn_fast_s_mp_mul_digs.c \
	$(TOMMATH_DIR)/bn_fast_s_mp_sqr.c \
	$(TOMMATH_DIR)/bn_mp_add.c \
	$(TOMMATH_DIR)/bn_mp_add_d.c \
	$(TOMMATH_DIR)/bn_mp_and.c \
	$(TOMMATH_DIR)/bn_mp_clamp.c \
	$(TOMMATH_DIR)/bn_mp_clear.c \
	$(TOMMATH_DIR)/bn_mp_clear_multi.c \
	$(TOMMATH_DIR)/bn_mp_cmp.c \
	$(TOMMATH_DIR)/bn_mp_cmp_d.c \
	$(TOMMATH_DIR)/bn_mp_cmp_mag.c \
	$(TOMMATH_DIR)/bn_mp_copy.c \
	$(TOMMATH_DIR)/bn_mp_cnt_lsb.c \
	$(TOMMATH_DIR)/bn_mp_count_bits.c \
	$(TOMMATH_DIR)/bn_mp_div.c \
	$(TOMMATH_DIR)/bn_mp_div_d.c \
	$(TOMMATH_DIR)/bn_mp_div_2.c \
	$(TOMMATH_DIR)/bn_mp_div_2d.c \
	$(TOMMATH_DIR)/bn_mp_div_3.c \
	$(TOMMATH_DIR)/bn_mp_exch.c \
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
	$(SHELL_ENV) ./${TCL_EXE} $(SCRIPT)

# This target can be used to run tclsh inside either gdb or insight
gdb: ${TCL_EXE}
	$(SHELL_ENV) $(GDB) ./${TCL_EXE}

valgrind: ${TCL_EXE} ${TCLTEST_EXE}
	$(SHELL_ENV) $(VALGRIND) $(VALGRINDARGS) ./${TCLTEST_EXE} $(TOP_DIR)/tests/all.tcl -singleproc 1 $(TESTFLAGS)

valgrindshell: ${TCL_EXE}
	$(SHELL_ENV) $(VALGRIND) $(VALGRINDARGS) ./${TCL_EXE} $(SCRIPT)

trace-shell: ${TCL_EXE}
	$(SHELL_ENV) ${TRACE} $(TRACE_OPTS) ./${TCL_EXE} $(SCRIPT)








|







734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
	$(SHELL_ENV) ./${TCL_EXE} $(SCRIPT)

# This target can be used to run tclsh inside either gdb or insight
gdb: ${TCL_EXE}
	$(SHELL_ENV) $(GDB) ./${TCL_EXE}

valgrind: ${TCL_EXE} ${TCLTEST_EXE}
	$(SHELL_ENV) $(VALGRIND) $(VALGRINDARGS) ./${TCLTEST_EXE} $(TOP_DIR)/tests/all.tcl -singleproc 1 -constraints valgrind $(TESTFLAGS)

valgrindshell: ${TCL_EXE}
	$(SHELL_ENV) $(VALGRIND) $(VALGRINDARGS) ./${TCL_EXE} $(SCRIPT)

trace-shell: ${TCL_EXE}
	$(SHELL_ENV) ${TRACE} $(TRACE_OPTS) ./${TCL_EXE} $(SCRIPT)

830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
	@echo "Installing package http 2.8.2 as a Tcl Module";
	@$(INSTALL_DATA) $(TOP_DIR)/library/http/http.tcl "$(SCRIPT_INSTALL_DIR)"/../tcl8/8.6/http-2.8.2.tm;
	@echo "Installing package opt0.4 files to $(SCRIPT_INSTALL_DIR)/opt0.4/";
	@for i in $(TOP_DIR)/library/opt/*.tcl ; \
	    do \
	    $(INSTALL_DATA) $$i "$(SCRIPT_INSTALL_DIR)"/opt0.4; \
	    done;
	@echo "Installing package msgcat 1.4.3 as a Tcl Module";
	@$(INSTALL_DATA) $(TOP_DIR)/library/msgcat/msgcat.tcl "$(SCRIPT_INSTALL_DIR)"/../tcl8/8.5/msgcat-1.4.3.tm;
	@echo "Installing package tcltest 2.3.3 as a Tcl Module";
	@$(INSTALL_DATA) $(TOP_DIR)/library/tcltest/tcltest.tcl "$(SCRIPT_INSTALL_DIR)"/../tcl8/8.5/tcltest-2.3.3.tm;

	@echo "Installing package platform 1.0.9 as a Tcl Module";
	@$(INSTALL_DATA) $(TOP_DIR)/library/platform/platform.tcl "$(SCRIPT_INSTALL_DIR)"/../tcl8/8.4/platform-1.0.9.tm;
	@echo "Installing package platform::shell 1.1.4 as a Tcl Module";
	@$(INSTALL_DATA) $(TOP_DIR)/library/platform/shell.tcl "$(SCRIPT_INSTALL_DIR)"/../tcl8/8.4/platform/shell-1.1.4.tm;

	@echo "Installing library encoding files to $(SCRIPT_INSTALL_DIR)/encoding/";
	@for i in $(TOP_DIR)/library/encoding/*.enc ; do \
		$(INSTALL_DATA) $$i "$(SCRIPT_INSTALL_DIR)"/encoding; \
	done;







|
|



|
|







832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
	@echo "Installing package http 2.8.2 as a Tcl Module";
	@$(INSTALL_DATA) $(TOP_DIR)/library/http/http.tcl "$(SCRIPT_INSTALL_DIR)"/../tcl8/8.6/http-2.8.2.tm;
	@echo "Installing package opt0.4 files to $(SCRIPT_INSTALL_DIR)/opt0.4/";
	@for i in $(TOP_DIR)/library/opt/*.tcl ; \
	    do \
	    $(INSTALL_DATA) $$i "$(SCRIPT_INSTALL_DIR)"/opt0.4; \
	    done;
	@echo "Installing package msgcat 1.4.4 as a Tcl Module";
	@$(INSTALL_DATA) $(TOP_DIR)/library/msgcat/msgcat.tcl "$(SCRIPT_INSTALL_DIR)"/../tcl8/8.5/msgcat-1.4.4.tm;
	@echo "Installing package tcltest 2.3.3 as a Tcl Module";
	@$(INSTALL_DATA) $(TOP_DIR)/library/tcltest/tcltest.tcl "$(SCRIPT_INSTALL_DIR)"/../tcl8/8.5/tcltest-2.3.3.tm;

	@echo "Installing package platform 1.0.10 as a Tcl Module";
	@$(INSTALL_DATA) $(TOP_DIR)/library/platform/platform.tcl "$(SCRIPT_INSTALL_DIR)"/../tcl8/8.4/platform-1.0.10.tm;
	@echo "Installing package platform::shell 1.1.4 as a Tcl Module";
	@$(INSTALL_DATA) $(TOP_DIR)/library/platform/shell.tcl "$(SCRIPT_INSTALL_DIR)"/../tcl8/8.4/platform/shell-1.1.4.tm;

	@echo "Installing library encoding files to $(SCRIPT_INSTALL_DIR)/encoding/";
	@for i in $(TOP_DIR)/library/encoding/*.enc ; do \
		$(INSTALL_DATA) $$i "$(SCRIPT_INSTALL_DIR)"/encoding; \
	done;
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021

regerror.o: $(REGHDRS) $(GENERIC_DIR)/regerrs.h $(GENERIC_DIR)/regerror.c
	$(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/regerror.c

tclAppInit.o: $(UNIX_DIR)/tclAppInit.c
	$(CC) -c $(APP_CC_SWITCHES) $(UNIX_DIR)/tclAppInit.c

# On Unix we want to use the normal malloc/free implementation, so we
# specifically set the USE_TCLALLOC flag.

tclAlloc.o: $(GENERIC_DIR)/tclAlloc.c
	$(CC) -c $(CC_SWITCHES) -DUSE_TCLALLOC=0 $(GENERIC_DIR)/tclAlloc.c

tclAssembly.o: $(GENERIC_DIR)/tclAssembly.c $(COMPILEHDR)
	$(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclAssembly.c

tclAsync.o: $(GENERIC_DIR)/tclAsync.c
	$(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclAsync.c








<
<
<

|







1005
1006
1007
1008
1009
1010
1011



1012
1013
1014
1015
1016
1017
1018
1019
1020

regerror.o: $(REGHDRS) $(GENERIC_DIR)/regerrs.h $(GENERIC_DIR)/regerror.c
	$(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/regerror.c

tclAppInit.o: $(UNIX_DIR)/tclAppInit.c
	$(CC) -c $(APP_CC_SWITCHES) $(UNIX_DIR)/tclAppInit.c




tclAlloc.o: $(GENERIC_DIR)/tclAlloc.c
	$(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclAlloc.c

tclAssembly.o: $(GENERIC_DIR)/tclAssembly.c $(COMPILEHDR)
	$(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclAssembly.c

tclAsync.o: $(GENERIC_DIR)/tclAsync.c
	$(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclAsync.c

1335
1336
1337
1338
1339
1340
1341



1342
1343
1344
1345
1346
1347
1348
	$(CC) -c $(CC_SWITCHES) $(TOMMATH_DIR)/bn_mp_cmp.c

bn_mp_cmp_d.o: $(TOMMATH_DIR)/bn_mp_cmp_d.c $(MATHHDRS)
	$(CC) -c $(CC_SWITCHES) $(TOMMATH_DIR)/bn_mp_cmp_d.c

bn_mp_cmp_mag.o: $(TOMMATH_DIR)/bn_mp_cmp_mag.c $(MATHHDRS)
	$(CC) -c $(CC_SWITCHES) $(TOMMATH_DIR)/bn_mp_cmp_mag.c




bn_mp_copy.o: $(TOMMATH_DIR)/bn_mp_copy.c $(MATHHDRS)
	$(CC) -c $(CC_SWITCHES) $(TOMMATH_DIR)/bn_mp_copy.c

bn_mp_count_bits.o: $(TOMMATH_DIR)/bn_mp_count_bits.c $(MATHHDRS)
	$(CC) -c $(CC_SWITCHES) $(TOMMATH_DIR)/bn_mp_count_bits.c








>
>
>







1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
	$(CC) -c $(CC_SWITCHES) $(TOMMATH_DIR)/bn_mp_cmp.c

bn_mp_cmp_d.o: $(TOMMATH_DIR)/bn_mp_cmp_d.c $(MATHHDRS)
	$(CC) -c $(CC_SWITCHES) $(TOMMATH_DIR)/bn_mp_cmp_d.c

bn_mp_cmp_mag.o: $(TOMMATH_DIR)/bn_mp_cmp_mag.c $(MATHHDRS)
	$(CC) -c $(CC_SWITCHES) $(TOMMATH_DIR)/bn_mp_cmp_mag.c

bn_mp_cnt_lsb.o: $(TOMMATH_DIR)/bn_mp_cnt_lsb.c $(MATHHDRS)
	$(CC) -c $(CC_SWITCHES) $(TOMMATH_DIR)/bn_mp_cnt_lsb.c

bn_mp_copy.o: $(TOMMATH_DIR)/bn_mp_copy.c $(MATHHDRS)
	$(CC) -c $(CC_SWITCHES) $(TOMMATH_DIR)/bn_mp_copy.c

bn_mp_count_bits.o: $(TOMMATH_DIR)/bn_mp_count_bits.c $(MATHHDRS)
	$(CC) -c $(CC_SWITCHES) $(TOMMATH_DIR)/bn_mp_count_bits.c

Changes to unix/README.

162
163
164
165
166
167
168
169
170
171
172
173
you'll see a much more substantial printout for each error. See the README
file in the "tests" directory for more information on the test suite. Note:
don't run the tests as superuser: this will cause several of them to fail. If
a test is failing consistently, please send us a bug report with as much
detail as you can manage. Please use the online database at
	http://tcl.sourceforge.net/

The Tcl test suite is very sensitive to proper implementation of ANSI C
library procedures such as sprintf and sscanf. If the test suite generates
errors, most likely they are due to non-conformance of your system's ANSI C
library; such problems are unlikely to affect any real applications so it's
probably safe to ignore them.







<
<
<
<
<
162
163
164
165
166
167
168





you'll see a much more substantial printout for each error. See the README
file in the "tests" directory for more information on the test suite. Note:
don't run the tests as superuser: this will cause several of them to fail. If
a test is failing consistently, please send us a bug report with as much
detail as you can manage. Please use the online database at
	http://tcl.sourceforge.net/






Changes to unix/configure.

1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345




TCL_VERSION=8.6
TCL_MAJOR_VERSION=8
TCL_MINOR_VERSION=6
TCL_PATCH_LEVEL="b1.2"
VERSION=${TCL_VERSION}

#------------------------------------------------------------------------
# Setup configure arguments for bundled packages
#------------------------------------------------------------------------

PKG_CFG_ARGS="$ac_configure_args ${PKG_CFG_ARGS}"







|







1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345




TCL_VERSION=8.6
TCL_MAJOR_VERSION=8
TCL_MINOR_VERSION=6
TCL_PATCH_LEVEL="b2"
VERSION=${TCL_VERSION}

#------------------------------------------------------------------------
# Setup configure arguments for bundled packages
#------------------------------------------------------------------------

PKG_CFG_ARGS="$ac_configure_args ${PKG_CFG_ARGS}"
6475
6476
6477
6478
6479
6480
6481
6482
6483
6484
6485
6486
6487
6488
6489
6490
6491
6492
6493
6494



6495
6496
6497
6498
6499
6500
6501

    echo "$as_me:$LINENO: checking if compiler supports visibility \"hidden\"" >&5
echo $ECHO_N "checking if compiler supports visibility \"hidden\"... $ECHO_C" >&6
if test "${tcl_cv_cc_visibility_hidden+set}" = set; then
  echo $ECHO_N "(cached) $ECHO_C" >&6
else

	    if test "$GCC" = yes; then

		hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -fvisibility=hidden -Werror"
		cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h.  */
_ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h.  */

int
main ()
{




  ;
  return 0;
}
_ACEOF
rm -f conftest.$ac_objext
if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5







|












>
>
>







6475
6476
6477
6478
6479
6480
6481
6482
6483
6484
6485
6486
6487
6488
6489
6490
6491
6492
6493
6494
6495
6496
6497
6498
6499
6500
6501
6502
6503
6504

    echo "$as_me:$LINENO: checking if compiler supports visibility \"hidden\"" >&5
echo $ECHO_N "checking if compiler supports visibility \"hidden\"... $ECHO_C" >&6
if test "${tcl_cv_cc_visibility_hidden+set}" = set; then
  echo $ECHO_N "(cached) $ECHO_C" >&6
else

	    if test "$SHARED_BUILD" = 1; then

		hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -fvisibility=hidden -Werror"
		cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h.  */
_ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h.  */

int
main ()
{
#if !defined(__GNUC__) || __GNUC__ < 4
#error visibility hidden is not supported for this compiler
#endif

  ;
  return 0;
}
_ACEOF
rm -f conftest.$ac_objext
if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
6546
6547
6548
6549
6550
6551
6552
6553
6554
6555
6556
6557
6558
6559
6560
6561
6562
6563
6564
cat >>confdefs.h <<\_ACEOF
#define MODULE_SCOPE extern
_ACEOF


else


cat >>confdefs.h <<\_ACEOF
#define NO_VIZ
_ACEOF

	hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -Werror"
	cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h.  */
_ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h.  */







<
<
<
<
<







6549
6550
6551
6552
6553
6554
6555





6556
6557
6558
6559
6560
6561
6562
cat >>confdefs.h <<\_ACEOF
#define MODULE_SCOPE extern
_ACEOF


else






	hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -Werror"
	cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h.  */
_ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h.  */
11379
11380
11381
11382
11383
11384
11385

11386
11387
11388
11389
11390
11391
11392
11393


else
  NEED_FAKE_RFC2553=1
fi

if test "x$NEED_FAKE_RFC2553" = "x1"; then

   cat >>confdefs.h <<\_ACEOF
#define NEED_FAKE_RFC2553 1
_ACEOF

   case $LIBOBJS in
    "fake-rfc2553.$ac_objext"   | \
  *" fake-rfc2553.$ac_objext"   | \
    "fake-rfc2553.$ac_objext "* | \







>
|







11377
11378
11379
11380
11381
11382
11383
11384
11385
11386
11387
11388
11389
11390
11391
11392


else
  NEED_FAKE_RFC2553=1
fi

if test "x$NEED_FAKE_RFC2553" = "x1"; then

cat >>confdefs.h <<\_ACEOF
#define NEED_FAKE_RFC2553 1
_ACEOF

   case $LIBOBJS in
    "fake-rfc2553.$ac_objext"   | \
  *" fake-rfc2553.$ac_objext"   | \
    "fake-rfc2553.$ac_objext "* | \

Changes to unix/configure.in.

21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
    /* override */ #undef PACKAGE_TARNAME
    #endif /* _TCLCONFIG */])
])

TCL_VERSION=8.6
TCL_MAJOR_VERSION=8
TCL_MINOR_VERSION=6
TCL_PATCH_LEVEL="b1.2"
VERSION=${TCL_VERSION}

#------------------------------------------------------------------------
# Setup configure arguments for bundled packages
#------------------------------------------------------------------------

PKG_CFG_ARGS="$ac_configure_args ${PKG_CFG_ARGS}"







|







21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
    /* override */ #undef PACKAGE_TARNAME
    #endif /* _TCLCONFIG */])
])

TCL_VERSION=8.6
TCL_MAJOR_VERSION=8
TCL_MINOR_VERSION=6
TCL_PATCH_LEVEL="b2"
VERSION=${TCL_VERSION}

#------------------------------------------------------------------------
# Setup configure arguments for bundled packages
#------------------------------------------------------------------------

PKG_CFG_ARGS="$ac_configure_args ${PKG_CFG_ARGS}"

Changes to unix/install-sh.

1
2
3
4
5
6
7
8
9
10
11
#!/bin/sh
# install - install a program, script, or datafile

scriptversion=2010-02-06.18; # UTC

# This originates from X11R5 (mit/util/scripts/install.sh), which was
# later released in X11R6 (xc/config/util/install.sh) with the
# following copyright and license.
#
# Copyright (C) 1994 X Consortium
#



|







1
2
3
4
5
6
7
8
9
10
11
#!/bin/sh
# install - install a program, script, or datafile

scriptversion=2011-04-20.01; # UTC

# This originates from X11R5 (mit/util/scripts/install.sh), which was
# later released in X11R6 (xc/config/util/install.sh) with the
# following copyright and license.
#
# Copyright (C) 1994 X Consortium
#
116
117
118
119
120
121
122

123
124
125
126
127
128
129
  -c            (ignored)
  -C            install only if different (preserve the last data modification time)
  -d            create directories instead of installing files.
  -g GROUP      $chgrpprog installed files to GROUP.
  -m MODE       $chmodprog installed files to MODE.
  -o USER       $chownprog installed files to USER.
  -s            $stripprog installed files.

  -t DIRECTORY  install into DIRECTORY.
  -T            report an error if DSTFILE is a directory.

Environment variables override the default commands:
  CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
  RMPROG STRIPPROG
"







>







116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
  -c            (ignored)
  -C            install only if different (preserve the last data modification time)
  -d            create directories instead of installing files.
  -g GROUP      $chgrpprog installed files to GROUP.
  -m MODE       $chmodprog installed files to MODE.
  -o USER       $chownprog installed files to USER.
  -s            $stripprog installed files.
  -S            $stripprog installed files.
  -t DIRECTORY  install into DIRECTORY.
  -T            report an error if DSTFILE is a directory.

Environment variables override the default commands:
  CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
  RMPROG STRIPPROG
"
150
151
152
153
154
155
156



157
158
159
160
161
162
163
	esac
	shift;;

    -o) chowncmd="$chownprog $2"
	shift;;

    -s) stripcmd=$stripprog;;




    -t) dst_arg=$2
	shift;;

    -T) no_target_directory=true;;

    --version) echo "$0 $scriptversion"; exit $?;;







>
>
>







151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
	esac
	shift;;

    -o) chowncmd="$chownprog $2"
	shift;;

    -s) stripcmd=$stripprog;;

      -S) stripcmd="$stripprog $2" 
         shift;; 

    -t) dst_arg=$2
	shift;;

    -T) no_target_directory=true;;

    --version) echo "$0 $scriptversion"; exit $?;;

Changes to unix/tcl.m4.

116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
		fi
		done
	    fi
	])

	if test x"${ac_cv_c_tclconfig}" = x ; then
	    TCL_BIN_DIR="# no Tcl configs found"
	    AC_MSG_WARN([Can't find Tcl configuration definitions])
	    exit 0
	else
	    no_tcl=
	    TCL_BIN_DIR="${ac_cv_c_tclconfig}"
	    AC_MSG_RESULT([found ${TCL_BIN_DIR}/tclConfig.sh])
	fi
    fi
])







|
<







116
117
118
119
120
121
122
123

124
125
126
127
128
129
130
		fi
		done
	    fi
	])

	if test x"${ac_cv_c_tclconfig}" = x ; then
	    TCL_BIN_DIR="# no Tcl configs found"
	    AC_MSG_ERROR([Can't find Tcl configuration definitions. Use --with-tcl to specify a directory containing tclConfig.sh])

	else
	    no_tcl=
	    TCL_BIN_DIR="${ac_cv_c_tclconfig}"
	    AC_MSG_RESULT([found ${TCL_BIN_DIR}/tclConfig.sh])
	fi
    fi
])
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
		    fi
		done
	    fi
	])

	if test x"${ac_cv_c_tkconfig}" = x ; then
	    TK_BIN_DIR="# no Tk configs found"
	    AC_MSG_WARN([Can't find Tk configuration definitions])
	    exit 0
	else
	    no_tk=
	    TK_BIN_DIR="${ac_cv_c_tkconfig}"
	    AC_MSG_RESULT([found ${TK_BIN_DIR}/tkConfig.sh])
	fi
    fi
])







|
<







246
247
248
249
250
251
252
253

254
255
256
257
258
259
260
		    fi
		done
	    fi
	])

	if test x"${ac_cv_c_tkconfig}" = x ; then
	    TK_BIN_DIR="# no Tk configs found"
	    AC_MSG_ERROR([Can't find Tk configuration definitions. Use --with-tk to specify a directory containing tkConfig.sh])

	else
	    no_tk=
	    TK_BIN_DIR="${ac_cv_c_tkconfig}"
	    AC_MSG_RESULT([found ${TK_BIN_DIR}/tkConfig.sh])
	fi
    fi
])
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
    if test -f "${TCL_BIN_DIR}/Makefile" ; then
        TCL_LIB_SPEC="${TCL_BUILD_LIB_SPEC}"
        TCL_STUB_LIB_SPEC="${TCL_BUILD_STUB_LIB_SPEC}"
        TCL_STUB_LIB_PATH="${TCL_BUILD_STUB_LIB_PATH}"
    elif test "`uname -s`" = "Darwin"; then
	# If Tcl was built as a framework, attempt to use the libraries
	# from the framework at the given location so that linking works
	# against Tcl.framework installed in an arbitary location.
	case ${TCL_DEFS} in
	    *TCL_FRAMEWORK*)
		if test -f "${TCL_BIN_DIR}/${TCL_LIB_FILE}"; then
		    for i in "`cd "${TCL_BIN_DIR}"; pwd`" \
			     "`cd "${TCL_BIN_DIR}"/../..; pwd`"; do
			if test "`basename "$i"`" = "${TCL_LIB_FILE}.framework"; then
			    TCL_LIB_SPEC="-F`dirname "$i" | sed -e 's/ /\\\\ /g'` -framework ${TCL_LIB_FILE}"







|







301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
    if test -f "${TCL_BIN_DIR}/Makefile" ; then
        TCL_LIB_SPEC="${TCL_BUILD_LIB_SPEC}"
        TCL_STUB_LIB_SPEC="${TCL_BUILD_STUB_LIB_SPEC}"
        TCL_STUB_LIB_PATH="${TCL_BUILD_STUB_LIB_PATH}"
    elif test "`uname -s`" = "Darwin"; then
	# If Tcl was built as a framework, attempt to use the libraries
	# from the framework at the given location so that linking works
	# against Tcl.framework installed in an arbitrary location.
	case ${TCL_DEFS} in
	    *TCL_FRAMEWORK*)
		if test -f "${TCL_BIN_DIR}/${TCL_LIB_FILE}"; then
		    for i in "`cd "${TCL_BIN_DIR}"; pwd`" \
			     "`cd "${TCL_BIN_DIR}"/../..; pwd`"; do
			if test "`basename "$i"`" = "${TCL_LIB_FILE}.framework"; then
			    TCL_LIB_SPEC="-F`dirname "$i" | sed -e 's/ /\\\\ /g'` -framework ${TCL_LIB_FILE}"
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
    if test -f "${TK_BIN_DIR}/Makefile" ; then
        TK_LIB_SPEC="${TK_BUILD_LIB_SPEC}"
        TK_STUB_LIB_SPEC="${TK_BUILD_STUB_LIB_SPEC}"
        TK_STUB_LIB_PATH="${TK_BUILD_STUB_LIB_PATH}"
    elif test "`uname -s`" = "Darwin"; then
	# If Tk was built as a framework, attempt to use the libraries
	# from the framework at the given location so that linking works
	# against Tk.framework installed in an arbitary location.
	case ${TK_DEFS} in
	    *TK_FRAMEWORK*)
		if test -f "${TK_BIN_DIR}/${TK_LIB_FILE}"; then
		    for i in "`cd "${TK_BIN_DIR}"; pwd`" \
			     "`cd "${TK_BIN_DIR}"/../..; pwd`"; do
			if test "`basename "$i"`" = "${TK_LIB_FILE}.framework"; then
			    TK_LIB_SPEC="-F`dirname "$i" | sed -e 's/ /\\\\ /g'` -framework ${TK_LIB_FILE}"







|







384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
    if test -f "${TK_BIN_DIR}/Makefile" ; then
        TK_LIB_SPEC="${TK_BUILD_LIB_SPEC}"
        TK_STUB_LIB_SPEC="${TK_BUILD_STUB_LIB_SPEC}"
        TK_STUB_LIB_PATH="${TK_BUILD_STUB_LIB_PATH}"
    elif test "`uname -s`" = "Darwin"; then
	# If Tk was built as a framework, attempt to use the libraries
	# from the framework at the given location so that linking works
	# against Tk.framework installed in an arbitrary location.
	case ${TK_DEFS} in
	    *TK_FRAMEWORK*)
		if test -f "${TK_BIN_DIR}/${TK_LIB_FILE}"; then
		    for i in "`cd "${TK_BIN_DIR}"; pwd`" \
			     "`cd "${TK_BIN_DIR}"/../..; pwd`"; do
			if test "`basename "$i"`" = "${TK_LIB_FILE}.framework"; then
			    TK_LIB_SPEC="-F`dirname "$i" | sed -e 's/ /\\\\ /g'` -framework ${TK_LIB_FILE}"
1040
1041
1042
1043
1044
1045
1046
1047
1048



1049
1050
1051
1052
1053
1054
1055
1056
    AS_IF([test "$do64bitVIS" = "yes"], [do64bit=yes])

    # Step 0.c: Check if visibility support is available. Do this here so
    # that platform specific alternatives can be used below if this fails.

    AC_CACHE_CHECK([if compiler supports visibility "hidden"],
	tcl_cv_cc_visibility_hidden, [
	    AS_IF([test "$GCC" = yes], [
		hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -fvisibility=hidden -Werror"



		AC_TRY_COMPILE(,, tcl_cv_cc_visibility_hidden=yes,
		    tcl_cv_cc_visibility_hidden=no)
		CFLAGS=$hold_cflags
	    ], [
		tcl_cv_cc_visibility_hidden=no
	    ])
    ])
    AS_IF([test $tcl_cv_cc_visibility_hidden = yes], [







|

>
>
>
|







1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
    AS_IF([test "$do64bitVIS" = "yes"], [do64bit=yes])

    # Step 0.c: Check if visibility support is available. Do this here so
    # that platform specific alternatives can be used below if this fails.

    AC_CACHE_CHECK([if compiler supports visibility "hidden"],
	tcl_cv_cc_visibility_hidden, [
	    AS_IF([test "$SHARED_BUILD" = 1], [
		hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -fvisibility=hidden -Werror"
		AC_TRY_COMPILE(,[#if !defined(__GNUC__) || __GNUC__ < 4
#error visibility hidden is not supported for this compiler
#endif
		], tcl_cv_cc_visibility_hidden=yes,
		    tcl_cv_cc_visibility_hidden=no)
		CFLAGS=$hold_cflags
	    ], [
		tcl_cv_cc_visibility_hidden=no
	    ])
    ])
    AS_IF([test $tcl_cv_cc_visibility_hidden = yes], [
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
#	no include files, so double-check its result just to be safe.
#
# Arguments:
#	none
#
# Results:
#
#	Sets the the following vars:
#		XINCLUDES
#		XLIBSW
#
#--------------------------------------------------------------------

AC_DEFUN([SC_PATH_X], [
    AC_PATH_X







|







2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
#	no include files, so double-check its result just to be safe.
#
# Arguments:
#	none
#
# Results:
#
#	Sets the following vars:
#		XINCLUDES
#		XLIBSW
#
#--------------------------------------------------------------------

AC_DEFUN([SC_PATH_X], [
    AC_PATH_X
3256
3257
3258
3259
3260
3261
3262
3263

3264
3265
3266
3267
3268
3269
3270
		struct sockaddr_storage],,[NEED_FAKE_RFC2553=1],[[
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
]])
if test "x$NEED_FAKE_RFC2553" = "x1"; then
   AC_DEFINE(NEED_FAKE_RFC2553)

   AC_LIBOBJ([fake-rfc2553])
   AC_CHECK_FUNC(strlcpy)
fi
])
# Local Variables:
# mode: autoconf
# End:







|
>







3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
		struct sockaddr_storage],,[NEED_FAKE_RFC2553=1],[[
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
]])
if test "x$NEED_FAKE_RFC2553" = "x1"; then
   AC_DEFINE([NEED_FAKE_RFC2553], 1,
        [Use compat implementation of getaddrinfo() and friends])
   AC_LIBOBJ([fake-rfc2553])
   AC_CHECK_FUNC(strlcpy)
fi
])
# Local Variables:
# mode: autoconf
# End:

Changes to unix/tcl.spec.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# This file is the basis for a binary Tcl RPM for Linux.

%{!?directory:%define directory /usr/local}

Name:          tcl
Summary:       Tcl scripting language development environment
Version:       8.6b1
Release:       2
License:       BSD
Group:         Development/Languages
Source:        http://prdownloads.sourceforge.net/tcl/tcl%{version}-src.tar.gz
URL:           http://www.tcl.tk/
Buildroot:     /var/tmp/%{name}%{version}







|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
# This file is the basis for a binary Tcl RPM for Linux.

%{!?directory:%define directory /usr/local}

Name:          tcl
Summary:       Tcl scripting language development environment
Version:       8.6b2
Release:       2
License:       BSD
Group:         Development/Languages
Source:        http://prdownloads.sourceforge.net/tcl/tcl%{version}-src.tar.gz
URL:           http://www.tcl.tk/
Buildroot:     /var/tmp/%{name}%{version}

Changes to unix/tclAppInit.c.

8
9
10
11
12
13
14


15
16
17
18
19
20
21
 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
 * Copyright (c) 1998-1999 Scriptics Corporation.
 *
 * See the file "license.terms" for information on usage and redistribution of
 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
 */



#include "tcl.h"

#ifdef TCL_TEST
extern Tcl_PackageInitProc Tcltest_Init;
extern Tcl_PackageInitProc Tcltest_SafeInit;
#endif /* TCL_TEST */








>
>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
 * Copyright (c) 1998-1999 Scriptics Corporation.
 *
 * See the file "license.terms" for information on usage and redistribution of
 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
 */

#undef BUILD_tcl
#undef STATIC_BUILD
#include "tcl.h"

#ifdef TCL_TEST
extern Tcl_PackageInitProc Tcltest_Init;
extern Tcl_PackageInitProc Tcltest_SafeInit;
#endif /* TCL_TEST */

29
30
31
32
33
34
35



36

37
38
39
40
41
42
43
 * a #define of TCL_LOCAL_APPINIT instead of rewriting this entire file. The
 * #if checks for that #define and uses Tcl_AppInit if it doesn't exist.
 */

#ifndef TCL_LOCAL_APPINIT
#define TCL_LOCAL_APPINIT Tcl_AppInit
#endif



extern int TCL_LOCAL_APPINIT(Tcl_Interp *interp);


/*
 * The following #if block allows you to change how Tcl finds the startup
 * script, prime the library or encoding paths, fiddle with the argv, etc.,
 * without needing to rewrite Tcl_Main()
 */








>
>
>
|
>







31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
 * a #define of TCL_LOCAL_APPINIT instead of rewriting this entire file. The
 * #if checks for that #define and uses Tcl_AppInit if it doesn't exist.
 */

#ifndef TCL_LOCAL_APPINIT
#define TCL_LOCAL_APPINIT Tcl_AppInit
#endif
#ifndef MODULE_SCOPE
#   define MODULE_SCOPE extern
#endif
MODULE_SCOPE int TCL_LOCAL_APPINIT(Tcl_Interp *);
MODULE_SCOPE int main(int, char **);

/*
 * The following #if block allows you to change how Tcl finds the startup
 * script, prime the library or encoding paths, fiddle with the argv, etc.,
 * without needing to rewrite Tcl_Main()
 */

Changes to unix/tclConfig.h.in.

23
24
25
26
27
28
29



30
31
32
33



34
35
36
37
38
39
40
41
#undef HAVE_COPYFILE

/* Define to 1 if you have the <copyfile.h> header file. */
#undef HAVE_COPYFILE_H

/* Do we have access to Darwin CoreFoundation.framework? */
#undef HAVE_COREFOUNDATION




/* Do we have fts functions? */
#undef HAVE_FTS




/* Define to 1 if getaddrinfo is available. */
#undef HAVE_GETADDRINFO

/* Define to 1 if you have the `getattrlist' function. */
#undef HAVE_GETATTRLIST

/* Define to 1 if you have the `getcwd' function. */
#undef HAVE_GETCWD







>
>
>




>
>
>
|







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
#undef HAVE_COPYFILE

/* Define to 1 if you have the <copyfile.h> header file. */
#undef HAVE_COPYFILE_H

/* Do we have access to Darwin CoreFoundation.framework? */
#undef HAVE_COREFOUNDATION

/* Define to 1 if you have the `freeaddrinfo' function. */
#undef HAVE_FREEADDRINFO

/* Do we have fts functions? */
#undef HAVE_FTS

/* Define to 1 if you have the `gai_strerror' function. */
#undef HAVE_GAI_STRERROR

/* Define to 1 if you have the `getaddrinfo' function. */
#undef HAVE_GETADDRINFO

/* Define to 1 if you have the `getattrlist' function. */
#undef HAVE_GETATTRLIST

/* Define to 1 if you have the `getcwd' function. */
#undef HAVE_GETCWD
74
75
76
77
78
79
80



81
82
83
84
85
86
87
#undef HAVE_GETHOSTBYNAME_R_3

/* Define to 1 if gethostbyname_r takes 5 args. */
#undef HAVE_GETHOSTBYNAME_R_5

/* Define to 1 if gethostbyname_r takes 6 args. */
#undef HAVE_GETHOSTBYNAME_R_6




/* Define to 1 if getpwnam_r is available. */
#undef HAVE_GETPWNAM_R

/* Define to 1 if getpwnam_r takes 4 args. */
#undef HAVE_GETPWNAM_R_4








>
>
>







80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#undef HAVE_GETHOSTBYNAME_R_3

/* Define to 1 if gethostbyname_r takes 5 args. */
#undef HAVE_GETHOSTBYNAME_R_5

/* Define to 1 if gethostbyname_r takes 6 args. */
#undef HAVE_GETHOSTBYNAME_R_6

/* Define to 1 if you have the `getnameinfo' function. */
#undef HAVE_GETNAMEINFO

/* Define to 1 if getpwnam_r is available. */
#undef HAVE_GETPWNAM_R

/* Define to 1 if getpwnam_r takes 4 args. */
#undef HAVE_GETPWNAM_R_4

173
174
175
176
177
178
179



180
181
182









183
184
185
186
187
188
189
#undef HAVE_STRINGS_H

/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H

/* Define to 1 if you have the `strtol' function. */
#undef HAVE_STRTOL




/* Is 'struct dirent64' in <sys/types.h>? */
#undef HAVE_STRUCT_DIRENT64










/* Is 'struct stat64' in <sys/stat.h>? */
#undef HAVE_STRUCT_STAT64

/* Define to 1 if `st_blksize' is member of `struct stat'. */
#undef HAVE_STRUCT_STAT_ST_BLKSIZE








>
>
>



>
>
>
>
>
>
>
>
>







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
#undef HAVE_STRINGS_H

/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H

/* Define to 1 if you have the `strtol' function. */
#undef HAVE_STRTOL

/* Define to 1 if the system has the type `struct addrinfo'. */
#undef HAVE_STRUCT_ADDRINFO

/* Is 'struct dirent64' in <sys/types.h>? */
#undef HAVE_STRUCT_DIRENT64

/* Define to 1 if the system has the type `struct in6_addr'. */
#undef HAVE_STRUCT_IN6_ADDR

/* Define to 1 if the system has the type `struct sockaddr_in6'. */
#undef HAVE_STRUCT_SOCKADDR_IN6

/* Define to 1 if the system has the type `struct sockaddr_storage'. */
#undef HAVE_STRUCT_SOCKADDR_STORAGE

/* Is 'struct stat64' in <sys/stat.h>? */
#undef HAVE_STRUCT_STAT64

/* Define to 1 if `st_blksize' is member of `struct stat'. */
#undef HAVE_STRUCT_STAT_ST_BLKSIZE

240
241
242
243
244
245
246
247
248
249
250
251



252
253
254
255
256
257
258

/* Is there an installed zlib? */
#undef HAVE_ZLIB

/* Is this a Mac I see before me? */
#undef MAC_OSX_TCL

/* Compiler support for module scope symbols */
#undef MODULE_SCOPE

/* Default libtommath precision. */
#undef MP_PREC




/* Is Darwin CoreFoundation unavailable for 64-bit? */
#undef NO_COREFOUNDATION_64

/* Do we have <dirent.h>? */
#undef NO_DIRENT_H








|




>
>
>







261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282

/* Is there an installed zlib? */
#undef HAVE_ZLIB

/* Is this a Mac I see before me? */
#undef MAC_OSX_TCL

/* No Compiler support for module scope symbols */
#undef MODULE_SCOPE

/* Default libtommath precision. */
#undef MP_PREC

/* Use compat implementation of getaddrinfo() and friends */
#undef NEED_FAKE_RFC2553

/* Is Darwin CoreFoundation unavailable for 64-bit? */
#undef NO_COREFOUNDATION_64

/* Do we have <dirent.h>? */
#undef NO_DIRENT_H

302
303
304
305
306
307
308



309
310
311
312
313
314
315
#undef NO_UNAME

/* Do we have a usable 'union wait'? */
#undef NO_UNION_WAIT

/* Do we have <values.h>? */
#undef NO_VALUES_H




/* Do we have wait3() */
#undef NO_WAIT3

/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT








>
>
>







326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
#undef NO_UNAME

/* Do we have a usable 'union wait'? */
#undef NO_UNION_WAIT

/* Do we have <values.h>? */
#undef NO_VALUES_H

/* No visibility attribute */
#undef NO_VIZ

/* Do we have wait3() */
#undef NO_WAIT3

/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT

Changes to unix/tclUnixChan.c.

135
136
137
138
139
140
141

142
143
144
145
146
147
148

#endif	/* !SUPPORTS_TTY */

#define UNSUPPORTED_OPTION(detail) \
    if (interp) {						\
	Tcl_AppendResult(interp, (detail),			\
		" not supported for this platform", NULL);	\

    }

/*
 * Static routines for this file:
 */

static int		FileBlockModeProc(ClientData instanceData, int mode);







>







135
136
137
138
139
140
141
142
143
144
145
146
147
148
149

#endif	/* !SUPPORTS_TTY */

#define UNSUPPORTED_OPTION(detail) \
    if (interp) {						\
	Tcl_AppendResult(interp, (detail),			\
		" not supported for this platform", NULL);	\
	Tcl_SetErrorCode(interp, "TCL", "UNSUPPORTED", NULL);	\
    }

/*
 * Static routines for this file:
 */

static int		FileBlockModeProc(ClientData instanceData, int mode);
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
	    UNSUPPORTED_OPTION("-handshake DTRDSR");
	    return TCL_ERROR;
	} else {
	    if (interp) {
		Tcl_AppendResult(interp, "bad value for -handshake: "
			"must be one of xonxoff, rtscts, dtrdsr or none",
			NULL);


	    }
	    return TCL_ERROR;
	}
	SETIOSTATE(fsPtr->fd, &iostate);
	return TCL_OK;
    }

    /*
     * Option -xchar {\x11 \x13}
     */

    if ((len > 1) && (strncmp(optionName, "-xchar", len) == 0)) {
	Tcl_DString ds;

	if (Tcl_SplitList(interp, value, &argc, &argv) == TCL_ERROR) {
	    return TCL_ERROR;
	} else if (argc != 2) {
	    if (interp) {
		Tcl_AppendResult(interp, "bad value for -xchar: "
			"should be a list of two elements", NULL);


	    }
	    ckfree(argv);
	    return TCL_ERROR;
	}

	GETIOSTATE(fsPtr->fd, &iostate);








>
>




















>
>







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
	    UNSUPPORTED_OPTION("-handshake DTRDSR");
	    return TCL_ERROR;
	} else {
	    if (interp) {
		Tcl_AppendResult(interp, "bad value for -handshake: "
			"must be one of xonxoff, rtscts, dtrdsr or none",
			NULL);
		Tcl_SetErrorCode(interp, "TCL", "OPERATION", "FCONFIGURE",
			"VALUE", NULL);
	    }
	    return TCL_ERROR;
	}
	SETIOSTATE(fsPtr->fd, &iostate);
	return TCL_OK;
    }

    /*
     * Option -xchar {\x11 \x13}
     */

    if ((len > 1) && (strncmp(optionName, "-xchar", len) == 0)) {
	Tcl_DString ds;

	if (Tcl_SplitList(interp, value, &argc, &argv) == TCL_ERROR) {
	    return TCL_ERROR;
	} else if (argc != 2) {
	    if (interp) {
		Tcl_AppendResult(interp, "bad value for -xchar: "
			"should be a list of two elements", NULL);
		Tcl_SetErrorCode(interp, "TCL", "OPERATION", "FCONFIGURE",
			"VALUE", NULL);
	    }
	    ckfree(argv);
	    return TCL_ERROR;
	}

	GETIOSTATE(fsPtr->fd, &iostate);

766
767
768
769
770
771
772


773
774
775
776
777
778
779
	if (Tcl_SplitList(interp, value, &argc, &argv) == TCL_ERROR) {
	    return TCL_ERROR;
	}
	if ((argc % 2) == 1) {
	    if (interp) {
		Tcl_AppendResult(interp, "bad value for -ttycontrol: "
			"should be a list of signal,value pairs", NULL);


	    }
	    ckfree(argv);
	    return TCL_ERROR;
	}

	GETCONTROL(fsPtr->fd, &control);
	for (i = 0; i < argc-1; i += 2) {







>
>







771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
	if (Tcl_SplitList(interp, value, &argc, &argv) == TCL_ERROR) {
	    return TCL_ERROR;
	}
	if ((argc % 2) == 1) {
	    if (interp) {
		Tcl_AppendResult(interp, "bad value for -ttycontrol: "
			"should be a list of signal,value pairs", NULL);
		Tcl_SetErrorCode(interp, "TCL", "OPERATION", "FCONFIGURE",
			"VALUE", NULL);
	    }
	    ckfree(argv);
	    return TCL_ERROR;
	}

	GETCONTROL(fsPtr->fd, &control);
	for (i = 0; i < argc-1; i += 2) {
814
815
816
817
818
819
820


821
822
823
824
825
826
827
		return TCL_ERROR;
#endif /* SETBREAK */
	    } else {
		if (interp) {
		    Tcl_AppendResult(interp, "bad signal \"", argv[i],
			    "\" for -ttycontrol: must be "
			    "DTR, RTS or BREAK", NULL);


		}
		ckfree(argv);
		return TCL_ERROR;
	    }
	} /* -ttycontrol options loop */

	SETCONTROL(fsPtr->fd, &control);







>
>







821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
		return TCL_ERROR;
#endif /* SETBREAK */
	    } else {
		if (interp) {
		    Tcl_AppendResult(interp, "bad signal \"", argv[i],
			    "\" for -ttycontrol: must be "
			    "DTR, RTS or BREAK", NULL);
		    Tcl_SetErrorCode(interp, "TCL", "OPERATION", "FCONFIGURE",
			"VALUE", NULL);
		}
		ckfree(argv);
		return TCL_ERROR;
	    }
	} /* -ttycontrol options loop */

	SETCONTROL(fsPtr->fd, &control);
1377
1378
1379
1380
1381
1382
1383

1384
1385
1386
1387
1388
1389
1390

    i = sscanf(mode, "%d,%c,%d,%d%n", speedPtr, &parity, dataPtr,
	    stopPtr, &end);
    if ((i != 4) || (mode[end] != '\0')) {
	if (interp != NULL) {
	    Tcl_AppendResult(interp, bad, ": should be baud,parity,data,stop",
		    NULL);

	}
	return TCL_ERROR;
    }

    /*
     * Only allow setting mark/space parity on platforms that support it Make
     * sure to allow for the case where strchr is a macro. [Bug: 5089]







>







1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400

    i = sscanf(mode, "%d,%c,%d,%d%n", speedPtr, &parity, dataPtr,
	    stopPtr, &end);
    if ((i != 4) || (mode[end] != '\0')) {
	if (interp != NULL) {
	    Tcl_AppendResult(interp, bad, ": should be baud,parity,data,stop",
		    NULL);
	    Tcl_SetErrorCode(interp, "TCL", "VALUE", "SERIALMODE", NULL);
	}
	return TCL_ERROR;
    }

    /*
     * Only allow setting mark/space parity on platforms that support it Make
     * sure to allow for the case where strchr is a macro. [Bug: 5089]
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
	    Tcl_AppendResult(interp, bad, " parity: should be ",
#if defined(PAREXT) || defined(USE_TERMIO)
		    "n, o, e, m, or s",
#else
		    "n, o, or e",
#endif /* PAREXT|USE_TERMIO */
		    NULL);

	}
	return TCL_ERROR;
    }
    *parityPtr = parity;
    if ((*dataPtr < 5) || (*dataPtr > 8)) {
	if (interp != NULL) {
	    Tcl_AppendResult(interp, bad, " data: should be 5, 6, 7, or 8",
		    NULL);

	}
	return TCL_ERROR;
    }
    if ((*stopPtr < 0) || (*stopPtr > 2)) {
	if (interp != NULL) {
	    Tcl_AppendResult(interp, bad, " stop: should be 1 or 2", NULL);

	}
	return TCL_ERROR;
    }
    return TCL_OK;
}

/*







>








>






>







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
	    Tcl_AppendResult(interp, bad, " parity: should be ",
#if defined(PAREXT) || defined(USE_TERMIO)
		    "n, o, e, m, or s",
#else
		    "n, o, or e",
#endif /* PAREXT|USE_TERMIO */
		    NULL);
	    Tcl_SetErrorCode(interp, "TCL", "VALUE", "SERIALMODE", NULL);
	}
	return TCL_ERROR;
    }
    *parityPtr = parity;
    if ((*dataPtr < 5) || (*dataPtr > 8)) {
	if (interp != NULL) {
	    Tcl_AppendResult(interp, bad, " data: should be 5, 6, 7, or 8",
		    NULL);
	    Tcl_SetErrorCode(interp, "TCL", "VALUE", "SERIALMODE", NULL);
	}
	return TCL_ERROR;
    }
    if ((*stopPtr < 0) || (*stopPtr > 2)) {
	if (interp != NULL) {
	    Tcl_AppendResult(interp, bad, " stop: should be 1 or 2", NULL);
	    Tcl_SetErrorCode(interp, "TCL", "VALUE", "SERIALMODE", NULL);
	}
	return TCL_ERROR;
    }
    return TCL_OK;
}

/*
1828
1829
1830
1831
1832
1833
1834


1835
1836
1837


1838
1839
1840
1841
1842
1843
1844
    chan = Tcl_GetChannel(interp, chanID, &chanMode);
    if (chan == NULL) {
	return TCL_ERROR;
    }
    if ((forWriting) && ((chanMode & TCL_WRITABLE) == 0)) {
	Tcl_AppendResult(interp, "\"", chanID, "\" wasn't opened for writing",
		NULL);


	return TCL_ERROR;
    } else if ((!forWriting) && ((chanMode & TCL_READABLE) == 0)) {
	Tcl_AppendResult(interp, "\"", chanID, "\" wasn't opened for reading",


		NULL);
	return TCL_ERROR;
    }

    /*
     * We allow creating a FILE * out of file based, pipe based and socket
     * based channels. We currently do not allow any other channel types,







>
>



>
>







1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
    chan = Tcl_GetChannel(interp, chanID, &chanMode);
    if (chan == NULL) {
	return TCL_ERROR;
    }
    if ((forWriting) && ((chanMode & TCL_WRITABLE) == 0)) {
	Tcl_AppendResult(interp, "\"", chanID, "\" wasn't opened for writing",
		NULL);
	Tcl_SetErrorCode(interp, "TCL", "VALUE", "CHANNEL", "NOT_WRITABLE",
		NULL);
	return TCL_ERROR;
    } else if ((!forWriting) && ((chanMode & TCL_READABLE) == 0)) {
	Tcl_AppendResult(interp, "\"", chanID, "\" wasn't opened for reading",
		NULL);
	Tcl_SetErrorCode(interp, "TCL", "VALUE", "CHANNEL", "NOT_READABLE",
		NULL);
	return TCL_ERROR;
    }

    /*
     * We allow creating a FILE * out of file based, pipe based and socket
     * based channels. We currently do not allow any other channel types,
1862
1863
1864
1865
1866
1867
1868


1869
1870
1871
1872
1873
1874
1875
1876
1877


1878
1879
1880
1881
1882
1883
1884
	     * writing....
	     */

	    f = fdopen(fd, (forWriting ? "w" : "r"));
	    if (f == NULL) {
		Tcl_AppendResult(interp, "cannot get a FILE * for \"", chanID,
			"\"", NULL);


		return TCL_ERROR;
	    }
	    *filePtr = f;
	    return TCL_OK;
	}
    }

    Tcl_AppendResult(interp, "\"", chanID,
	    "\" cannot be used to get a FILE *", NULL);


    return TCL_ERROR;
}

#ifndef HAVE_COREFOUNDATION	/* Darwin/Mac OS X CoreFoundation notifier is
				 * in tclMacOSXNotify.c */
/*
 *----------------------------------------------------------------------







>
>









>
>







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
	     * writing....
	     */

	    f = fdopen(fd, (forWriting ? "w" : "r"));
	    if (f == NULL) {
		Tcl_AppendResult(interp, "cannot get a FILE * for \"", chanID,
			"\"", NULL);
		Tcl_SetErrorCode(interp, "TCL", "VALUE", "CHANNEL",
			"FILE_FAILURE", NULL);
		return TCL_ERROR;
	    }
	    *filePtr = f;
	    return TCL_OK;
	}
    }

    Tcl_AppendResult(interp, "\"", chanID,
	    "\" cannot be used to get a FILE *", NULL);
    Tcl_SetErrorCode(interp, "TCL", "VALUE", "CHANNEL", "NO_DESCRIPTOR",
	    NULL);
    return TCL_ERROR;
}

#ifndef HAVE_COREFOUNDATION	/* Darwin/Mac OS X CoreFoundation notifier is
				 * in tclMacOSXNotify.c */
/*
 *----------------------------------------------------------------------

Changes to unix/tclUnixFCmd.c.

1479
1480
1481
1482
1483
1484
1485


1486
1487
1488
1489
1490
1491
1492
	Tcl_DStringFree(&ds);

	if (groupPtr == NULL) {
	    if (interp != NULL) {
		Tcl_AppendResult(interp, "could not set group for file \"",
			TclGetString(fileName), "\": group \"", string,
			"\" does not exist", NULL);


	    }
	    return TCL_ERROR;
	}
	gid = groupPtr->gr_gid;
    }

    native = Tcl_FSGetNativePath(fileName);







>
>







1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
	Tcl_DStringFree(&ds);

	if (groupPtr == NULL) {
	    if (interp != NULL) {
		Tcl_AppendResult(interp, "could not set group for file \"",
			TclGetString(fileName), "\": group \"", string,
			"\" does not exist", NULL);
		Tcl_SetErrorCode(interp, "TCL", "OPERATION", "SETGRP",
			"NO_GROUP", NULL);
	    }
	    return TCL_ERROR;
	}
	gid = groupPtr->gr_gid;
    }

    native = Tcl_FSGetNativePath(fileName);
1543
1544
1545
1546
1547
1548
1549


1550
1551
1552
1553
1554
1555
1556
	Tcl_DStringFree(&ds);

	if (pwPtr == NULL) {
	    if (interp != NULL) {
		Tcl_AppendResult(interp, "could not set owner for file \"",
			TclGetString(fileName), "\": user \"", string,
			"\" does not exist", NULL);


	    }
	    return TCL_ERROR;
	}
	uid = pwPtr->pw_uid;
    }

    native = Tcl_FSGetNativePath(fileName);







>
>







1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
	Tcl_DStringFree(&ds);

	if (pwPtr == NULL) {
	    if (interp != NULL) {
		Tcl_AppendResult(interp, "could not set owner for file \"",
			TclGetString(fileName), "\": user \"", string,
			"\" does not exist", NULL);
		Tcl_SetErrorCode(interp, "TCL", "OPERATION", "SETOWN",
			"NO_USER", NULL);
	    }
	    return TCL_ERROR;
	}
	uid = pwPtr->pw_uid;
    }

    native = Tcl_FSGetNativePath(fileName);
1636
1637
1638
1639
1640
1641
1642

1643
1644
1645
1646
1647
1648
1649
	}
	newMode = (mode_t) (buf.st_mode & 0x00007FFF);

	if (GetModeFromPermString(NULL, modeStringPtr, &newMode) != TCL_OK) {
	    if (interp != NULL) {
		Tcl_AppendResult(interp, "unknown permission string format \"",
			modeStringPtr, "\"", NULL);

	    }
	    return TCL_ERROR;
	}
    }

    native = Tcl_FSGetNativePath(fileName);
    result = chmod(native, newMode);		/* INTL: Native. */







>







1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
	}
	newMode = (mode_t) (buf.st_mode & 0x00007FFF);

	if (GetModeFromPermString(NULL, modeStringPtr, &newMode) != TCL_OK) {
	    if (interp != NULL) {
		Tcl_AppendResult(interp, "unknown permission string format \"",
			modeStringPtr, "\"", NULL);
		Tcl_SetErrorCode(interp, "TCL", "VALUE", "PERMISSION", NULL);
	    }
	    return TCL_ERROR;
	}
    }

    native = Tcl_FSGetNativePath(fileName);
    result = chmod(native, newMode);		/* INTL: Native. */

Changes to unix/tclUnixFile.c.

78
79
80
81
82
83
84
85
86
87
88
89
90
91
92

    /*
     * Search through all the directories named in the PATH variable to see if
     * argv[0] is in one of them. If so, use that file name.
     */

    while (1) {
	while (isspace(UCHAR(*p))) {			/* INTL: BUG */
	    p++;
	}
	name = p;
	while ((*p != ':') && (*p != 0)) {
	    p++;
	}
	Tcl_DStringSetLength(&buffer, 0);







|







78
79
80
81
82
83
84
85
86
87
88
89
90
91
92

    /*
     * Search through all the directories named in the PATH variable to see if
     * argv[0] is in one of them. If so, use that file name.
     */

    while (1) {
	while (TclIsSpaceProc(*p)) {
	    p++;
	}
	name = p;
	while ((*p != ':') && (*p != 0)) {
	    p++;
	}
	Tcl_DStringSetLength(&buffer, 0);

Changes to unix/tclUnixSock.c.

16
17
18
19
20
21
22




23
24
25
26
27
28
29
 * what they say on the tin. :-) They also only ever refer to their arguments
 * once, and so can be used without regard to side effects.
 */

#define SET_BITS(var, bits)	((var) |= (bits))
#define CLEAR_BITS(var, bits)	((var) &= ~(bits))





/*
 * This is needed to comply with the strict aliasing rules of GCC, but it also
 * simplifies casting between the different sockaddr types.
 */

typedef union {
    struct sockaddr sa;







>
>
>
>







16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
 * what they say on the tin. :-) They also only ever refer to their arguments
 * once, and so can be used without regard to side effects.
 */

#define SET_BITS(var, bits)	((var) |= (bits))
#define CLEAR_BITS(var, bits)	((var) &= ~(bits))

/* "sock" + a pointer in hex + \0 */
#define SOCK_CHAN_LENGTH 4 + sizeof(void*) * 2 + 1
#define SOCK_TEMPLATE "sock%lx"

/*
 * This is needed to comply with the strict aliasing rules of GCC, but it also
 * simplifies casting between the different sockaddr types.
 */

typedef union {
    struct sockaddr sa;
42
43
44
45
46
47
48
49
50
51



52
53
54











55
56
57
58
59
60
61
    TcpState *statePtr;
    int fd;
    struct TcpFdList *next;
} TcpFdList;

struct TcpState {
    Tcl_Channel channel;	/* Channel associated with this file. */
    TcpFdList *fds;		/* The file descriptors of the sockets. */
    int flags;			/* ORed combination of the bitfields defined
				 * below. */



    Tcl_TcpAcceptProc *acceptProc;
				/* Proc to call on accept. */
    ClientData acceptProcData;	/* The data for the accept proc. */











};

/*
 * These bits may be ORed together into the "flags" field of a TcpState
 * structure.
 */








|


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







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
    TcpState *statePtr;
    int fd;
    struct TcpFdList *next;
} TcpFdList;

struct TcpState {
    Tcl_Channel channel;	/* Channel associated with this file. */
    TcpFdList fds;		/* The file descriptors of the sockets. */
    int flags;			/* ORed combination of the bitfields defined
				 * below. */
    /*
     * Only needed for server sockets
     */
    Tcl_TcpAcceptProc *acceptProc; /* Proc to call on accept. */

    ClientData acceptProcData;     /* The data for the accept proc. */
    /*
     * Only needed for client sockets
     */
    struct addrinfo *addrlist;	 /* addresses to connect to        */
    struct addrinfo *addr;	 /* iterator over addrlist         */
    struct addrinfo *myaddrlist; /* local address                  */
    struct addrinfo *myaddr;	 /* iterator over myaddrlist       */
    int filehandlers;	/* Caches FileHandlers that get set up while
                         * an async socket is not yet connected   */
    int status;         /* Cache status of async socket */
    int cachedBlocking; /* Cache blocking mode of async socket */
};

/*
 * These bits may be ORed together into the "flags" field of a TcpState
 * structure.
 */

85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101

#define SOCKET_BUFSIZE	4096

/*
 * Static routines for this file:
 */

static TcpState *	CreateClientSocket(Tcl_Interp *interp, int port,
			    const char *host, const char *myaddr,
			    int myport, int async);
static void		TcpAccept(ClientData data, int mask);
static int		TcpBlockModeProc(ClientData data, int mode);
static int		TcpCloseProc(ClientData instanceData,
			    Tcl_Interp *interp);
static int		TcpClose2Proc(ClientData instanceData,
			    Tcl_Interp *interp, int flags);
static int		TcpGetHandleProc(ClientData instanceData,







|
|
<







102
103
104
105
106
107
108
109
110

111
112
113
114
115
116
117

#define SOCKET_BUFSIZE	4096

/*
 * Static routines for this file:
 */

static int		CreateClientSocket(Tcl_Interp *interp,
                                           TcpState *state);

static void		TcpAccept(ClientData data, int mask);
static int		TcpBlockModeProc(ClientData data, int mode);
static int		TcpCloseProc(ClientData instanceData,
			    Tcl_Interp *interp);
static int		TcpClose2Proc(ClientData instanceData,
			    Tcl_Interp *interp, int flags);
static int		TcpGetHandleProc(ClientData instanceData,
329
330
331
332
333
334
335




336
337
338
339
340
341
342
343
    TcpState *statePtr = (TcpState *) instanceData;

    if (mode == TCL_MODE_BLOCKING) {
	CLEAR_BITS(statePtr->flags, TCP_ASYNC_SOCKET);
    } else {
	SET_BITS(statePtr->flags, TCP_ASYNC_SOCKET);
    }




    if (TclUnixSetBlockingMode(statePtr->fds->fd, mode) < 0) {
	return errno;
    }
    return 0;
}

/*
 *----------------------------------------------------------------------







>
>
>
>
|







345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
    TcpState *statePtr = (TcpState *) instanceData;

    if (mode == TCL_MODE_BLOCKING) {
	CLEAR_BITS(statePtr->flags, TCP_ASYNC_SOCKET);
    } else {
	SET_BITS(statePtr->flags, TCP_ASYNC_SOCKET);
    }
    if (statePtr->flags & TCP_ASYNC_CONNECT) {
        statePtr->cachedBlocking = mode;
        return 0;
    }
    if (TclUnixSetBlockingMode(statePtr->fds.fd, mode) < 0) {
	return errno;
    }
    return 0;
}

/*
 *----------------------------------------------------------------------
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
    if (statePtr->flags & TCP_ASYNC_CONNECT) {
	if (statePtr->flags & TCP_ASYNC_SOCKET) {
	    timeOut = 0;
	} else {
	    timeOut = -1;
	}
	errno = 0;
	state = TclUnixWaitForFile(statePtr->fds->fd,
		TCL_WRITABLE | TCL_EXCEPTION, timeOut);
	if (state & TCL_EXCEPTION) {
	    return -1;
	}
	if (state & TCL_WRITABLE) {
	    CLEAR_BITS(statePtr->flags, TCP_ASYNC_CONNECT);
	} else if (timeOut == 0) {







|







391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
    if (statePtr->flags & TCP_ASYNC_CONNECT) {
	if (statePtr->flags & TCP_ASYNC_SOCKET) {
	    timeOut = 0;
	} else {
	    timeOut = -1;
	}
	errno = 0;
	state = TclUnixWaitForFile(statePtr->fds.fd,
		TCL_WRITABLE | TCL_EXCEPTION, timeOut);
	if (state & TCL_EXCEPTION) {
	    return -1;
	}
	if (state & TCL_WRITABLE) {
	    CLEAR_BITS(statePtr->flags, TCP_ASYNC_CONNECT);
	} else if (timeOut == 0) {
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
    TcpState *statePtr = (TcpState *) instanceData;
    int bytesRead;

    *errorCodePtr = 0;
    if (WaitForConnect(statePtr, errorCodePtr) != 0) {
	return -1;
    }
    bytesRead = recv(statePtr->fds->fd, buf, (size_t) bufSize, 0);
    if (bytesRead > -1) {
	return bytesRead;
    }
    if (errno == ECONNRESET) {
	/*
	 * Turn ECONNRESET into a soft EOF condition.
	 */







|







444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
    TcpState *statePtr = (TcpState *) instanceData;
    int bytesRead;

    *errorCodePtr = 0;
    if (WaitForConnect(statePtr, errorCodePtr) != 0) {
	return -1;
    }
    bytesRead = recv(statePtr->fds.fd, buf, (size_t) bufSize, 0);
    if (bytesRead > -1) {
	return bytesRead;
    }
    if (errno == ECONNRESET) {
	/*
	 * Turn ECONNRESET into a soft EOF condition.
	 */
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
    TcpState *statePtr = (TcpState *) instanceData;
    int written;

    *errorCodePtr = 0;
    if (WaitForConnect(statePtr, errorCodePtr) != 0) {
	return -1;
    }
    written = send(statePtr->fds->fd, buf, (size_t) toWrite, 0);
    if (written > -1) {
	return written;
    }
    *errorCodePtr = errno;
    return -1;
}








|







494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
    TcpState *statePtr = (TcpState *) instanceData;
    int written;

    *errorCodePtr = 0;
    if (WaitForConnect(statePtr, errorCodePtr) != 0) {
	return -1;
    }
    written = send(statePtr->fds.fd, buf, (size_t) toWrite, 0);
    if (written > -1) {
	return written;
    }
    *errorCodePtr = errno;
    return -1;
}

518
519
520
521
522
523
524
525
526
527
528
529
530





531







532
533
534
535
536
537
538
     * Delete a file handler that may be active for this socket if this is a
     * server socket - the file handler was created automatically by Tcl as
     * part of the mechanism to accept new client connections. Channel
     * handlers are already deleted in the generic IO channel closing code
     * that called this function, so we do not have to delete them here.
     */
    
    for (fds = statePtr->fds; fds != NULL; fds = statePtr->fds) {
	statePtr->fds = fds->next;
	Tcl_DeleteFileHandler(fds->fd);
	if (close(fds->fd) < 0) {
	    errorCode = errno;
	}





	ckfree(fds);







    }
    ckfree(statePtr);
    return errorCode;
}

/*
 *----------------------------------------------------------------------







|
<




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







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
     * Delete a file handler that may be active for this socket if this is a
     * server socket - the file handler was created automatically by Tcl as
     * part of the mechanism to accept new client connections. Channel
     * handlers are already deleted in the generic IO channel closing code
     * that called this function, so we do not have to delete them here.
     */
    
    for (fds = &statePtr->fds; fds != NULL; fds = fds->next) {

	Tcl_DeleteFileHandler(fds->fd);
	if (close(fds->fd) < 0) {
	    errorCode = errno;
	}
    
    }
    fds = statePtr->fds.next;
    while (fds != NULL) {
	TcpFdList *next = fds->next;
        ckfree(fds);
	fds = next;
    }
    if (statePtr->addrlist != NULL) {
        freeaddrinfo(statePtr->addrlist);
    }
    if (statePtr->myaddrlist != NULL) {
        freeaddrinfo(statePtr->myaddrlist);
    }
    ckfree(statePtr);
    return errorCode;
}

/*
 *----------------------------------------------------------------------
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
    default:
        if (interp) {
            Tcl_AppendResult(interp,
                    "Socket close2proc called bidirectionally", NULL);
        }
        return TCL_ERROR;
    }
    if (shutdown(statePtr->fds->fd,sd) < 0) {
	errorCode = errno;
    }

    return errorCode;
}

/*







|







606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
    default:
        if (interp) {
            Tcl_AppendResult(interp,
                    "Socket close2proc called bidirectionally", NULL);
        }
        return TCL_ERROR;
    }
    if (shutdown(statePtr->fds.fd,sd) < 0) {
	errorCode = errno;
    }

    return errorCode;
}

/*
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
    }

    if ((len > 1) && (optionName[1] == 'e') &&
	    (strncmp(optionName, "-error", len) == 0)) {
	socklen_t optlen = sizeof(int);
	int err, ret;


	ret = getsockopt(statePtr->fds->fd, SOL_SOCKET, SO_ERROR,
		(char *)&err, &optlen);
	if (ret < 0) {
	    err = errno;
	}




	if (err != 0) {
	    Tcl_DStringAppend(dsPtr, Tcl_ErrnoMsg(err), -1);
	}
	return TCL_OK;
    }

    if (interp != NULL && Tcl_GetVar(interp, SUPPRESS_RDNS_VAR, 0) != NULL) {
        reverseDNS = NI_NUMERICHOST;
    }
    
    if ((len == 0) ||
	    ((len > 1) && (optionName[1] == 'p') &&
		    (strncmp(optionName, "-peername", len) == 0))) {
        address peername;
        socklen_t size = sizeof(peername);

	if (getpeername(statePtr->fds->fd, &peername.sa, &size) >= 0) {
	    if (len == 0) {
		Tcl_DStringAppendElement(dsPtr, "-peername");
		Tcl_DStringStartSublist(dsPtr);
	    }
            
	    getnameinfo(&peername.sa, size, host, sizeof(host), NULL, 0,
                    NI_NUMERICHOST);







>
|
|
|
|
|
>
>
>
>
















|







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
    }

    if ((len > 1) && (optionName[1] == 'e') &&
	    (strncmp(optionName, "-error", len) == 0)) {
	socklen_t optlen = sizeof(int);
	int err, ret;

        if (statePtr->status == 0) {
            ret = getsockopt(statePtr->fds.fd, SOL_SOCKET, SO_ERROR,
                             (char *)&err, &optlen);
            if (ret < 0) {
                err = errno;
            }
        } else {
            err = statePtr->status;
            statePtr->status = 0;
        }
	if (err != 0) {
	    Tcl_DStringAppend(dsPtr, Tcl_ErrnoMsg(err), -1);
	}
	return TCL_OK;
    }

    if (interp != NULL && Tcl_GetVar(interp, SUPPRESS_RDNS_VAR, 0) != NULL) {
        reverseDNS = NI_NUMERICHOST;
    }
    
    if ((len == 0) ||
	    ((len > 1) && (optionName[1] == 'p') &&
		    (strncmp(optionName, "-peername", len) == 0))) {
        address peername;
        socklen_t size = sizeof(peername);

	if (getpeername(statePtr->fds.fd, &peername.sa, &size) >= 0) {
	    if (len == 0) {
		Tcl_DStringAppendElement(dsPtr, "-peername");
		Tcl_DStringStartSublist(dsPtr);
	    }
            
	    getnameinfo(&peername.sa, size, host, sizeof(host), NULL, 0,
                    NI_NUMERICHOST);
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
        socklen_t size;
	int found = 0;

	if (len == 0) {
	    Tcl_DStringAppendElement(dsPtr, "-sockname");
	    Tcl_DStringStartSublist(dsPtr);
	}
	for (fds = statePtr->fds; fds != NULL; fds = fds->next) {
	    size = sizeof(sockname);
	    if (getsockname(fds->fd, &(sockname.sa), &size) >= 0) {
                int flags = reverseDNS;

		found = 1;
                getnameinfo(&sockname.sa, size, host, sizeof(host), NULL, 0,
                        NI_NUMERICHOST);







|







732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
        socklen_t size;
	int found = 0;

	if (len == 0) {
	    Tcl_DStringAppendElement(dsPtr, "-sockname");
	    Tcl_DStringStartSublist(dsPtr);
	}
	for (fds = &statePtr->fds; fds != NULL; fds = fds->next) {
	    size = sizeof(sockname);
	    if (getsockname(fds->fd, &(sockname.sa), &size) >= 0) {
                int flags = reverseDNS;

		found = 1;
                getnameinfo(&sockname.sa, size, host, sizeof(host), NULL, 0,
                        NI_NUMERICHOST);
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
    ClientData instanceData,	/* The socket state. */
    int mask)			/* Events of interest; an OR-ed combination of
				 * TCL_READABLE, TCL_WRITABLE and
				 * TCL_EXCEPTION. */
{
    TcpState *statePtr = (TcpState *) instanceData;


    /*
     * Make sure we don't mess with server sockets since they will never be
     * readable or writable at the Tcl level. This keeps Tcl scripts from
     * interfering with the -accept behavior.
     */


    if (!statePtr->acceptProc) {
	TcpFdList *fds;




	for (fds = statePtr->fds; fds != NULL; fds = fds->next) {
	    if (mask) {
		Tcl_CreateFileHandler(fds->fd, mask,
			(Tcl_FileProc *) Tcl_NotifyChannel,
			(ClientData) statePtr->channel);
	    } else {
		Tcl_DeleteFileHandler(fds->fd);
	    }
	}
    }
}

/*
 *----------------------------------------------------------------------
 *
 * TcpGetHandleProc --







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







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
    ClientData instanceData,	/* The socket state. */
    int mask)			/* Events of interest; an OR-ed combination of
				 * TCL_READABLE, TCL_WRITABLE and
				 * TCL_EXCEPTION. */
{
    TcpState *statePtr = (TcpState *) instanceData;

    if (statePtr->acceptProc != NULL) {
        /*
         * Make sure we don't mess with server sockets since they will never
         * be readable or writable at the Tcl level. This keeps Tcl scripts
         * from interfering with the -accept behavior (bug #3394732).
         */
    	return;
    }


     
    if (statePtr->flags & TCP_ASYNC_CONNECT) {
        /* Async sockets use a FileHandler internally while connecting, so we
         * need to cache this request until the connection has succeeded. */
        statePtr->filehandlers = mask;
    } else if (mask) {
        Tcl_CreateFileHandler(statePtr->fds.fd, mask,
                              (Tcl_FileProc *) Tcl_NotifyChannel,
                              (ClientData) statePtr->channel);
    } else {
        Tcl_DeleteFileHandler(statePtr->fds.fd);


    }
}

/*
 *----------------------------------------------------------------------
 *
 * TcpGetHandleProc --
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
TcpGetHandleProc(
    ClientData instanceData,	/* The socket state. */
    int direction,		/* Not used. */
    ClientData *handlePtr)	/* Where to store the handle. */
{
    TcpState *statePtr = (TcpState *) instanceData;

    *handlePtr = INT2PTR(statePtr->fds->fd);
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *





















 * CreateSocket --
 *
 *	This function opens a new socket in client or server mode and
 *	initializes the TcpState structure.
 *
 * Results:

 *	Returns a new TcpState, or NULL with an error in the interp's result,
 *	if interp is not NULL.

 *
 * Side effects:
 *	Opens a socket.
 *












 *----------------------------------------------------------------------
 */

static TcpState *
CreateClientSocket(
    Tcl_Interp *interp,		/* For error reporting; can be NULL. */
    int port,			/* Port number to open. */
    const char *host,		/* Name of host on which to open port. */
    const char *myaddr,		/* Optional client-side address.
                                 * NULL implies INADDR_ANY/in6addr_any */
    int myport,			/* Optional client-side port */
    int async)			/* If nonzero and creating a client socket,
				 * attempt to do an async connect. Otherwise
				 * do a synchronous connect or bind. */
{


    int status = -1, connected = 0, sock = -1;
    struct addrinfo *addrlist = NULL, *addrPtr;
                                /* Socket address */
    struct addrinfo *myaddrlist = NULL, *myaddrPtr;
                                /* Socket address for client */
    TcpState *statePtr;
    const char *errorMsg = NULL;

    if (!TclCreateSocketAddress(interp, &addrlist, host, port, 0, &errorMsg)) {

	goto error;
    }
    if (!TclCreateSocketAddress(interp, &myaddrlist, myaddr, myport, 1, &errorMsg)) {
	goto error;
    }



    for (addrPtr = addrlist; addrPtr != NULL;
         addrPtr = addrPtr->ai_next) {
        for (myaddrPtr = myaddrlist; myaddrPtr != NULL;
             myaddrPtr = myaddrPtr->ai_next) {
            int reuseaddr;
            
	    /*
	     * No need to try combinations of local and remote addresses of
	     * different families.
	     */

	    if (myaddrPtr->ai_family != addrPtr->ai_family) {
		continue;
	    }










	    sock = socket(addrPtr->ai_family, SOCK_STREAM, 0);
	    if (sock < 0) {
		continue;
	    }

	    /*
	     * Set the close-on-exec flag so that the socket will not get
	     * inherited by child processes.
	     */
	    
	    fcntl(sock, F_SETFD, FD_CLOEXEC);
	    
	    /*
	     * Set kernel space buffering
	     */
	    
	    TclSockMinimumBuffers(INT2PTR(sock), SOCKET_BUFSIZE);
    
	    if (async) {
		status = TclUnixSetBlockingMode(sock, TCL_MODE_NONBLOCKING);
		if (status < 0) {
		    goto looperror;
		}
	    }

            reuseaddr = 1;
            (void) setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
                    (char *) &reuseaddr, sizeof(reuseaddr));

            status = bind(sock, myaddrPtr->ai_addr, myaddrPtr->ai_addrlen);
            if (status < 0) {
                goto looperror;

            }

	    /*
	     * Attempt to connect. The connect may fail at present with an
	     * EINPROGRESS but at a later time it will complete. The caller
	     * will set up a file handler on the socket if she is interested
	     * in being informed when the connect completes.
	     */
	    

	    status = connect(sock, addrPtr->ai_addr, addrPtr->ai_addrlen);
	    if (status < 0 && errno == EINPROGRESS) {
		status = 0;
	    }

	    if (status == 0) {
		connected = 1;
		break;
	    }
	looperror:
	    if (sock != -1) {



		close(sock);


		sock = -1;
	    }
	}

	if (connected) {
	    break;

	} 
	status = -1;
	if (sock >= 0) {
	    close(sock);
	    sock = -1;
	}
    }
    if (async) {
	/*
	 * Restore blocking mode.
	 */

	status = TclUnixSetBlockingMode(sock, TCL_MODE_BLOCKING);
    }

error:
    if (addrlist) {
	freeaddrinfo(addrlist);
    }
    if (myaddrlist) {
	freeaddrinfo(myaddrlist);






    }









    
    if (status < 0) {





	if (interp != NULL) {
	    Tcl_AppendResult(interp, "couldn't open socket: ",
		    Tcl_PosixError(interp), NULL);
	    if (errorMsg != NULL) {
		Tcl_AppendResult(interp, " (", errorMsg, ")", NULL);
	    }
	}
	if (sock != -1) {
	    close(sock);
	}
	return NULL;
    }

    /*
     * Allocate a new TcpState for this socket.
     */

    statePtr = ckalloc(sizeof(TcpState));
    statePtr->flags = async ? TCP_ASYNC_CONNECT : 0;
    statePtr->fds = ckalloc(sizeof(TcpFdList));
    memset(statePtr->fds, (int) 0, sizeof(TcpFdList));
    statePtr->fds->fd = sock;

    return statePtr;
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_OpenTcpClient --
 *







|






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

|
<


>
|
<
>




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



|


|
<
<
<
<
<
<
<

>
>
|
<
<
<
<
|
<

<
>
|

<
<
|
>
>

|
|
|
|







|



>
>
>
>
>
>
>
>
>
|
|








|





|


|

|




|

>
|

<
>









>
|

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

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







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
TcpGetHandleProc(
    ClientData instanceData,	/* The socket state. */
    int direction,		/* Not used. */
    ClientData *handlePtr)	/* Where to store the handle. */
{
    TcpState *statePtr = (TcpState *) instanceData;

    *handlePtr = INT2PTR(statePtr->fds.fd);
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * TcpAsyncCallback --
 *
 *	Called by the event handler that CreateClientSocket sets up
 *	internally for [socket -async] to get notified when the
 *	asyncronous connection attempt has succeeded or failed.
 *
 *----------------------------------------------------------------------
 */
static void
TcpAsyncCallback(
    ClientData clientData,	/* The socket state. */
    int mask)			/* Events of interest; an OR-ed combination of
				 * TCL_READABLE, TCL_WRITABLE and
				 * TCL_EXCEPTION. */
{
    CreateClientSocket(NULL, clientData);
}

/*
 *----------------------------------------------------------------------
 *
 * CreateClientSocket --
 *
 *	This function opens a new socket in client mode.

 *
 * Results:
 *      TCL_OK, if the socket was successfully connected or an asynchronous
 *      connection is in progress. If an error occurs, TCL_ERROR is returned

 *      and an error message is left in interp.
 *
 * Side effects:
 *	Opens a socket.
 *
 * Remarks:
 *	A single host name may resolve to more than one IP address, e.g. for
 *	an IPv4/IPv6 dual stack host. For handling asyncronously connecting
 *	sockets in the background for such hosts, this function can act as a
 *	coroutine. On the first call, it sets up the control variables for the
 *	two nested loops over the local and remote addresses. Once the first
 *	connection attempt is in progress, it sets up itself as a writable
 *	event handler for that socket, and returns. When the callback occurs,
 *	control is transferred to the "reenter" label, right after the initial
 *	return and the loops resume as if they had never been interrupted.
 *	For syncronously connecting sockets, the loops work the usual way.
 *
 *----------------------------------------------------------------------
 */

static int
CreateClientSocket(
    Tcl_Interp *interp,		/* For error reporting; can be NULL. */
    TcpState *state)







{
    socklen_t optlen;
    int async_callback = (state->addr != NULL);
    int status;




    int async = state->flags & TCP_ASYNC_CONNECT;



    if (async_callback) {
        goto reenter;
    }



    for (state->addr = state->addrlist; state->addr != NULL;
         state->addr = state->addr->ai_next) {

	status = -1;

        for (state->myaddr = state->myaddrlist; state->myaddr != NULL;
             state->myaddr = state->myaddr->ai_next) {
            int reuseaddr;
            
	    /*
	     * No need to try combinations of local and remote addresses of
	     * different families.
	     */

	    if (state->myaddr->ai_family != state->addr->ai_family) {
		continue;
	    }

            /*
             * Close the socket if it is still open from the last unsuccessful
             * iteration.
             */
            if (state->fds.fd >= 0) {
		close(state->fds.fd);
		state->fds.fd = -1;
	    }

	    state->fds.fd = socket(state->addr->ai_family, SOCK_STREAM, 0);
	    if (state->fds.fd < 0) {
		continue;
	    }

	    /*
	     * Set the close-on-exec flag so that the socket will not get
	     * inherited by child processes.
	     */
	    
	    fcntl(state->fds.fd, F_SETFD, FD_CLOEXEC);
	    
	    /*
	     * Set kernel space buffering
	     */
	    
	    TclSockMinimumBuffers(INT2PTR(state->fds.fd), SOCKET_BUFSIZE);
    
	    if (async) {
		status = TclUnixSetBlockingMode(state->fds.fd, TCL_MODE_NONBLOCKING);
		if (status < 0) {
                    continue;
		}
	    }

            reuseaddr = 1;
            (void) setsockopt(state->fds.fd, SOL_SOCKET, SO_REUSEADDR,
                    (char *) &reuseaddr, sizeof(reuseaddr));
            status = bind(state->fds.fd, state->myaddr->ai_addr,
                          state->myaddr->ai_addrlen);
            if (status < 0) {

                continue;
            }

	    /*
	     * Attempt to connect. The connect may fail at present with an
	     * EINPROGRESS but at a later time it will complete. The caller
	     * will set up a file handler on the socket if she is interested
	     * in being informed when the connect completes.
	     */
	    
	    status = connect(state->fds.fd, state->addr->ai_addr,
                             state->addr->ai_addrlen);
	    if (status < 0 && errno == EINPROGRESS) {
                Tcl_CreateFileHandler(state->fds.fd,

                                      TCL_WRITABLE | TCL_EXCEPTION,
                                      TcpAsyncCallback, state);

                return TCL_OK;

            reenter:
                Tcl_DeleteFileHandler(state->fds.fd);
                /*
                 * Read the error state from the socket to see if the async
                 * connection has succeeded or failed. As this clears the
                 * error condition, we cache the status in the socket state
                 * struct for later retrieval by [fconfigure -error].
                 */
                optlen = sizeof(int);


                getsockopt(state->fds.fd, SOL_SOCKET, SO_ERROR,
                           (char *)&status, &optlen);

                state->status = status;
            }
	    if (status == 0) {


                goto out;
	    }
	}




    }


out:




    if (async_callback) {

        /*
         * An asynchonous connection has finally succeeded or failed.
         */
        CLEAR_BITS(state->flags, TCP_ASYNC_CONNECT);
        TcpWatchProc(state, state->filehandlers);
        TclUnixSetBlockingMode(state->fds.fd, state->cachedBlocking);

        /*
         * We need to forward the writable event that brought us here, bcasue
         * upon reading of getsockopt(SO_ERROR), at least some OSes clear the
         * writable state from the socket, and so a subsequent select() on
         * behalf of a script level [fileevent] would not fire. It doesn't
         * hurt that this is also called in the successful case and will save
         * the event mechanism one roundtrip through select().
         */
        Tcl_NotifyChannel(state->channel, TCL_WRITABLE);

    } else if (status != 0) {
        /*
         * Failure for either a synchronous connection, or an async one that
         * failed before it could enter background mode, e.g. because an
         * invalid -myaddr was given.
         */
        if (interp != NULL) {
            Tcl_AppendResult(interp, "couldn't open socket: ",
                             Tcl_PosixError(interp), NULL);


        }




        return TCL_ERROR;
    }











    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_OpenTcpClient --
 *
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
    const char *host,		/* Host on which to open port. */
    const char *myaddr,		/* Client-side address */
    int myport,			/* Client-side port */
    int async)			/* If nonzero, attempt to do an asynchronous
				 * connect. Otherwise we do a blocking
				 * connect. */
{
    TcpState *statePtr;


    char channelName[16 + TCL_INTEGER_SPACE];






























    /*
     * Create a new client socket and wrap it in a channel.
     */

    statePtr = CreateClientSocket(interp, port, host, myaddr, myport, async);
    if (statePtr == NULL) {
	return NULL;
    }

    statePtr->acceptProc = NULL;
    statePtr->acceptProcData = NULL;

    sprintf(channelName, "sock%d", statePtr->fds->fd);

    statePtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
	    statePtr, (TCL_READABLE | TCL_WRITABLE));
    if (Tcl_SetChannelOption(interp, statePtr->channel, "-translation",
	    "auto crlf") == TCL_ERROR) {
	Tcl_Close(NULL, statePtr->channel);
	return NULL;
    }
    return statePtr->channel;
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_MakeTcpClientChannel --
 *







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




<
|
|
|


<
<
<
|

|
|
|

|


|







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
    const char *host,		/* Host on which to open port. */
    const char *myaddr,		/* Client-side address */
    int myport,			/* Client-side port */
    int async)			/* If nonzero, attempt to do an asynchronous
				 * connect. Otherwise we do a blocking
				 * connect. */
{
    TcpState *state;
    const char *errorMsg = NULL;
    struct addrinfo *addrlist = NULL, *myaddrlist = NULL;
    char channelName[SOCK_CHAN_LENGTH];

    /*
     * Do the name lookups for the local and remote addresses.
     */
    if (!TclCreateSocketAddress(interp, &addrlist, host, port, 0, &errorMsg) ||
        !TclCreateSocketAddress(interp, &myaddrlist, myaddr, myport, 1, &errorMsg)) {
        if (addrlist != NULL) {
            freeaddrinfo(addrlist);
        }
        if (interp != NULL) {
            Tcl_AppendResult(interp, "couldn't open socket: ",
                             Tcl_PosixError(interp), NULL);
            if (errorMsg != NULL) {
                Tcl_AppendResult(interp, " (", errorMsg, ")", NULL);
            }
        }
        return NULL;
    }

    /*
     * Allocate a new TcpState for this socket.
     */
    state = ckalloc(sizeof(TcpState));
    memset(state, 0, sizeof(TcpState));
    state->flags = async ? TCP_ASYNC_CONNECT : 0;
    state->cachedBlocking = TCL_MODE_BLOCKING;
    state->addrlist = addrlist;
    state->myaddrlist = myaddrlist;
    state->fds.fd = -1;

    /*
     * Create a new client socket and wrap it in a channel.
     */

    if (CreateClientSocket(interp, state) != TCL_OK) {
        TcpCloseProc(state, NULL);
        return NULL;
    }




    sprintf(channelName, SOCK_TEMPLATE, (long)state);

    state->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
                                       state, (TCL_READABLE | TCL_WRITABLE));
    if (Tcl_SetChannelOption(interp, state->channel, "-translation",
	    "auto crlf") == TCL_ERROR) {
	Tcl_Close(NULL, state->channel);
	return NULL;
    }
    return state->channel;
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_MakeTcpClientChannel --
 *
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
Tcl_Channel
TclpMakeTcpClientChannelMode(
    ClientData sock,		/* The socket to wrap up into a channel. */
    int mode)			/* ORed combination of TCL_READABLE and
				 * TCL_WRITABLE to indicate file mode. */
{
    TcpState *statePtr;
    char channelName[16 + TCL_INTEGER_SPACE];

    statePtr = ckalloc(sizeof(TcpState));
    statePtr->fds = ckalloc(sizeof(TcpFdList));
    memset(statePtr->fds, (int) 0, sizeof(TcpFdList));
    statePtr->fds->fd = PTR2INT(sock);
    statePtr->flags = 0;
    statePtr->acceptProc = NULL;
    statePtr->acceptProcData = NULL;

    sprintf(channelName, "sock%d", statePtr->fds->fd);

    statePtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
	    statePtr, mode);
    if (Tcl_SetChannelOption(NULL, statePtr->channel, "-translation",
	    "auto crlf") == TCL_ERROR) {
	Tcl_Close(NULL, statePtr->channel);
	return NULL;







|


<
|
|

<
<

|







1195
1196
1197
1198
1199
1200
1201
1202
1203
1204

1205
1206
1207


1208
1209
1210
1211
1212
1213
1214
1215
1216
Tcl_Channel
TclpMakeTcpClientChannelMode(
    ClientData sock,		/* The socket to wrap up into a channel. */
    int mode)			/* ORed combination of TCL_READABLE and
				 * TCL_WRITABLE to indicate file mode. */
{
    TcpState *statePtr;
    char channelName[SOCK_CHAN_LENGTH];

    statePtr = ckalloc(sizeof(TcpState));

    memset(statePtr, 0, sizeof(TcpState));
    statePtr->fds.fd = PTR2INT(sock);
    statePtr->flags = 0;



    sprintf(channelName, SOCK_TEMPLATE, (long)statePtr);

    statePtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
	    statePtr, mode);
    if (Tcl_SetChannelOption(NULL, statePtr->channel, "-translation",
	    "auto crlf") == TCL_ERROR) {
	Tcl_Close(NULL, statePtr->channel);
	return NULL;
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
				/* Callback for accepting connections from new
				 * clients. */
    ClientData acceptProcData)	/* Data for the callback. */
{
    int status = 0, sock = -1, reuseaddr = 1, chosenport = 0;
    struct addrinfo *addrlist = NULL, *addrPtr;	/* socket address */
    TcpState *statePtr = NULL;
    char channelName[16 + TCL_INTEGER_SPACE];
    const char *errorMsg = NULL;
    TcpFdList *fds = NULL, *newfds;

    if (!TclCreateSocketAddress(interp, &addrlist, myHost, port, 1, &errorMsg)) {
	goto error;
    }








|







1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
				/* Callback for accepting connections from new
				 * clients. */
    ClientData acceptProcData)	/* Data for the callback. */
{
    int status = 0, sock = -1, reuseaddr = 1, chosenport = 0;
    struct addrinfo *addrlist = NULL, *addrPtr;	/* socket address */
    TcpState *statePtr = NULL;
    char channelName[SOCK_CHAN_LENGTH];
    const char *errorMsg = NULL;
    TcpFdList *fds = NULL, *newfds;

    if (!TclCreateSocketAddress(interp, &addrlist, myHost, port, 1, &errorMsg)) {
	goto error;
    }

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
            }
        }
        status = listen(sock, SOMAXCONN);
        if (status < 0) {
            close(sock);
            continue;
        }
        newfds = ckalloc(sizeof(TcpFdList));
        memset(newfds, (int) 0, sizeof(TcpFdList));
        if (statePtr == NULL) {
            /*
             * Allocate a new TcpState for this socket.
             */
            
            statePtr = ckalloc(sizeof(TcpState));
            statePtr->fds = newfds;
            statePtr->acceptProc = acceptProc;
            statePtr->acceptProcData = acceptProcData;
            sprintf(channelName, "sock%d", sock);

        } else {


            fds->next = newfds;
        }
        newfds->fd = sock;
        newfds->statePtr = statePtr;
        fds = newfds;
	
        /*







<
<






|


|
>

>
>







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
            }
        }
        status = listen(sock, SOMAXCONN);
        if (status < 0) {
            close(sock);
            continue;
        }


        if (statePtr == NULL) {
            /*
             * Allocate a new TcpState for this socket.
             */
            
            statePtr = ckalloc(sizeof(TcpState));
            memset(statePtr, 0, sizeof(TcpState));
            statePtr->acceptProc = acceptProc;
            statePtr->acceptProcData = acceptProcData;
            sprintf(channelName, SOCK_TEMPLATE, (long)statePtr);
            newfds = &statePtr->fds;
        } else {
            newfds = ckalloc(sizeof(TcpFdList));
            memset(newfds, (int) 0, sizeof(TcpFdList));
            fds->next = newfds;
        }
        newfds->fd = sock;
        newfds->statePtr = statePtr;
        fds = newfds;
	
        /*
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
    int mask)			/* Not used. */
{
    TcpFdList *fds = data;	/* Client data of server socket. */
    int newsock;		/* The new client socket */
    TcpState *newSockState;	/* State for new socket. */
    address addr;		/* The remote address */
    socklen_t len;		/* For accept interface */
    char channelName[16 + TCL_INTEGER_SPACE];
    char host[NI_MAXHOST], port[NI_MAXSERV];
    
    len = sizeof(addr);
    newsock = accept(fds->fd, &(addr.sa), &len);
    if (newsock < 0) {
	return;
    }

    /*
     * Set close-on-exec flag to prevent the newly accepted socket from being
     * inherited by child processes.
     */

    (void) fcntl(newsock, F_SETFD, FD_CLOEXEC);

    newSockState = ckalloc(sizeof(TcpState));

    newSockState->flags = 0;
    newSockState->fds = ckalloc(sizeof(TcpFdList));
    memset(newSockState->fds, (int) 0, sizeof(TcpFdList));
    newSockState->fds->fd = newsock;
    newSockState->acceptProc = NULL;
    newSockState->acceptProcData = NULL;

    sprintf(channelName, "sock%d", newsock);
    newSockState->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
	    newSockState, (TCL_READABLE | TCL_WRITABLE));

    Tcl_SetChannelOption(NULL, newSockState->channel, "-translation",
	    "auto crlf");

    if (fds->statePtr->acceptProc != NULL) {







|
















|

<
<
|
<
<

|







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
    int mask)			/* Not used. */
{
    TcpFdList *fds = data;	/* Client data of server socket. */
    int newsock;		/* The new client socket */
    TcpState *newSockState;	/* State for new socket. */
    address addr;		/* The remote address */
    socklen_t len;		/* For accept interface */
    char channelName[SOCK_CHAN_LENGTH];
    char host[NI_MAXHOST], port[NI_MAXSERV];
    
    len = sizeof(addr);
    newsock = accept(fds->fd, &(addr.sa), &len);
    if (newsock < 0) {
	return;
    }

    /*
     * Set close-on-exec flag to prevent the newly accepted socket from being
     * inherited by child processes.
     */

    (void) fcntl(newsock, F_SETFD, FD_CLOEXEC);

    newSockState = ckalloc(sizeof(TcpState));
    memset(newSockState, 0, sizeof(TcpState));
    newSockState->flags = 0;


    newSockState->fds.fd = newsock;



    sprintf(channelName, SOCK_TEMPLATE, (long)newSockState);
    newSockState->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
	    newSockState, (TCL_READABLE | TCL_WRITABLE));

    Tcl_SetChannelOption(NULL, newSockState->channel, "-translation",
	    "auto crlf");

    if (fds->statePtr->acceptProc != NULL) {

Changes to unix/tclUnixThrd.c.

632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
    }
}
#endif /* TCL_THREADS */

/*
 *----------------------------------------------------------------------
 *
 * TclpReaddir, TclpLocaltime, TclpGmtime, TclpInetNtoa --
 *
 *	These procedures replace core C versions to be used in a threaded
 *	environment.
 *
 * Results:
 *	See documentation of C functions.
 *







|







632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
    }
}
#endif /* TCL_THREADS */

/*
 *----------------------------------------------------------------------
 *
 * TclpReaddir, TclpInetNtoa --
 *
 *	These procedures replace core C versions to be used in a threaded
 *	environment.
 *
 * Results:
 *	See documentation of C functions.
 *

Changes to unix/tclooConfig.sh.

12
13
14
15
16
17
18
19
# These are mostly empty because no special steps are ever needed from Tcl 8.6
# onwards; all libraries and include files are just part of Tcl.
TCLOO_LIB_SPEC=""
TCLOO_STUB_LIB_SPEC=""
TCLOO_INCLUDE_SPEC=""
TCLOO_PRIVATE_INCLUDE_SPEC=""
TCLOO_CFLAGS=-DUSE_TCLOO_STUBS
TCLOO_VERSION=0.6.2







|
12
13
14
15
16
17
18
19
# These are mostly empty because no special steps are ever needed from Tcl 8.6
# onwards; all libraries and include files are just part of Tcl.
TCLOO_LIB_SPEC=""
TCLOO_STUB_LIB_SPEC=""
TCLOO_INCLUDE_SPEC=""
TCLOO_PRIVATE_INCLUDE_SPEC=""
TCLOO_CFLAGS=-DUSE_TCLOO_STUBS
TCLOO_VERSION=0.6.3

Changes to win/Makefile.in.

300
301
302
303
304
305
306

307
308
309
310
311
312
313
	bn_mp_and.${OBJEXT} \
	bn_mp_clamp.${OBJEXT} \
	bn_mp_clear.${OBJEXT} \
	bn_mp_clear_multi.${OBJEXT} \
	bn_mp_cmp.${OBJEXT} \
	bn_mp_cmp_d.${OBJEXT} \
	bn_mp_cmp_mag.${OBJEXT} \

	bn_mp_copy.${OBJEXT} \
	bn_mp_count_bits.${OBJEXT} \
	bn_mp_div.${OBJEXT} \
	bn_mp_div_d.${OBJEXT} \
	bn_mp_div_2.${OBJEXT} \
	bn_mp_div_2d.${OBJEXT} \
	bn_mp_div_3.${OBJEXT} \







>







300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
	bn_mp_and.${OBJEXT} \
	bn_mp_clamp.${OBJEXT} \
	bn_mp_clear.${OBJEXT} \
	bn_mp_clear_multi.${OBJEXT} \
	bn_mp_cmp.${OBJEXT} \
	bn_mp_cmp_d.${OBJEXT} \
	bn_mp_cmp_mag.${OBJEXT} \
	bn_mp_cnt_lsb.${OBJEXT} \
	bn_mp_copy.${OBJEXT} \
	bn_mp_count_bits.${OBJEXT} \
	bn_mp_div.${OBJEXT} \
	bn_mp_div_d.${OBJEXT} \
	bn_mp_div_2.${OBJEXT} \
	bn_mp_div_2d.${OBJEXT} \
	bn_mp_div_3.${OBJEXT} \
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
	@echo "Installing package http 2.8.2 as a Tcl Module";
	@$(COPY) $(ROOT_DIR)/library/http/http.tcl $(SCRIPT_INSTALL_DIR)/../tcl8/8.6/http-2.8.2.tm;
	@echo "Installing library opt0.4 directory";
	@for j in $(ROOT_DIR)/library/opt/*.tcl; \
	    do \
	    $(COPY) "$$j" "$(SCRIPT_INSTALL_DIR)/opt0.4"; \
	    done;
	@echo "Installing package msgcat 1.4.3 as a Tcl Module";
	@$(COPY) $(ROOT_DIR)/library/msgcat/msgcat.tcl $(SCRIPT_INSTALL_DIR)/../tcl8/8.5/msgcat-1.4.3.tm;
	@echo "Installing package tcltest 2.3.3 as a Tcl Module";
	@$(COPY) $(ROOT_DIR)/library/tcltest/tcltest.tcl $(SCRIPT_INSTALL_DIR)/../tcl8/8.5/tcltest-2.3.3.tm;
	@echo "Installing package platform 1.0.9 as a Tcl Module";
	@$(COPY) $(ROOT_DIR)/library/platform/platform.tcl $(SCRIPT_INSTALL_DIR)/../tcl8/8.4/platform-1.0.9.tm;
	@echo "Installing package platform::shell 1.1.4 as a Tcl Module";
	@$(COPY) $(ROOT_DIR)/library/platform/shell.tcl $(SCRIPT_INSTALL_DIR)/../tcl8/8.4/platform/shell-1.1.4.tm;
	@echo "Installing encodings";
	@for i in $(ROOT_DIR)/library/encoding/*.enc ; do \
		$(COPY) "$$i" "$(SCRIPT_INSTALL_DIR)/encoding"; \
	done;








|
|


|
|







667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
	@echo "Installing package http 2.8.2 as a Tcl Module";
	@$(COPY) $(ROOT_DIR)/library/http/http.tcl $(SCRIPT_INSTALL_DIR)/../tcl8/8.6/http-2.8.2.tm;
	@echo "Installing library opt0.4 directory";
	@for j in $(ROOT_DIR)/library/opt/*.tcl; \
	    do \
	    $(COPY) "$$j" "$(SCRIPT_INSTALL_DIR)/opt0.4"; \
	    done;
	@echo "Installing package msgcat 1.4.4 as a Tcl Module";
	@$(COPY) $(ROOT_DIR)/library/msgcat/msgcat.tcl $(SCRIPT_INSTALL_DIR)/../tcl8/8.5/msgcat-1.4.4.tm;
	@echo "Installing package tcltest 2.3.3 as a Tcl Module";
	@$(COPY) $(ROOT_DIR)/library/tcltest/tcltest.tcl $(SCRIPT_INSTALL_DIR)/../tcl8/8.5/tcltest-2.3.3.tm;
	@echo "Installing package platform 1.0.10 as a Tcl Module";
	@$(COPY) $(ROOT_DIR)/library/platform/platform.tcl $(SCRIPT_INSTALL_DIR)/../tcl8/8.4/platform-1.0.10.tm;
	@echo "Installing package platform::shell 1.1.4 as a Tcl Module";
	@$(COPY) $(ROOT_DIR)/library/platform/shell.tcl $(SCRIPT_INSTALL_DIR)/../tcl8/8.4/platform/shell-1.1.4.tm;
	@echo "Installing encodings";
	@for i in $(ROOT_DIR)/library/encoding/*.enc ; do \
		$(COPY) "$$i" "$(SCRIPT_INSTALL_DIR)/encoding"; \
	done;

Changes to win/README.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Tcl 8.6 for Windows

1. Introduction
---------------

This is the directory where you configure and compile the Windows
version of Tcl.  This directory also contains source files for Tcl
that are specific to Microsoft Windows.

The information in this file is maintained on the web at:

	http://www.tcl.tk/doc/howto/compile.html#win

The above URL includes a lengthy discussion of compiler macros necessary
when compiling Tcl extensions that will be dynamically loaded.

2. Compiling Tcl
----------------

In order to compile Tcl for Windows, you need the following:

	Tcl 8.6 Source Distribution (plus any patches)














<
<
<







1
2
3
4
5
6
7
8
9
10
11
12
13



14
15
16
17
18
19
20
Tcl 8.6 for Windows

1. Introduction
---------------

This is the directory where you configure and compile the Windows
version of Tcl.  This directory also contains source files for Tcl
that are specific to Microsoft Windows.

The information in this file is maintained on the web at:

	http://www.tcl.tk/doc/howto/compile.html#win




2. Compiling Tcl
----------------

In order to compile Tcl for Windows, you need the following:

	Tcl 8.6 Source Distribution (plus any patches)

Changes to win/configure.

1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
# versions of autoconf incorrectly set SHELL to /bin/bash instead of
# /bin/sh. The bash shell seems to suffer from some strange failures.
SHELL=/bin/sh

TCL_VERSION=8.6
TCL_MAJOR_VERSION=8
TCL_MINOR_VERSION=6
TCL_PATCH_LEVEL="b1.2"
VER=$TCL_MAJOR_VERSION$TCL_MINOR_VERSION

TCL_DDE_VERSION=1.3
TCL_DDE_MAJOR_VERSION=1
TCL_DDE_MINOR_VERSION=3
TCL_DDE_PATCH_LEVEL="2"
DDEVER=$TCL_DDE_MAJOR_VERSION$TCL_DDE_MINOR_VERSION







|







1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
# versions of autoconf incorrectly set SHELL to /bin/bash instead of
# /bin/sh. The bash shell seems to suffer from some strange failures.
SHELL=/bin/sh

TCL_VERSION=8.6
TCL_MAJOR_VERSION=8
TCL_MINOR_VERSION=6
TCL_PATCH_LEVEL="b2"
VER=$TCL_MAJOR_VERSION$TCL_MINOR_VERSION

TCL_DDE_VERSION=1.3
TCL_DDE_MAJOR_VERSION=1
TCL_DDE_MINOR_VERSION=3
TCL_DDE_PATCH_LEVEL="2"
DDEVER=$TCL_DDE_MAJOR_VERSION$TCL_DDE_MINOR_VERSION
3479
3480
3481
3482
3483
3484
3485





































































3486
3487
3488
3489
3490
3491
3492

cat >>confdefs.h <<\_ACEOF
#define HAVE_CAST_TO_UNION 1
_ACEOF

fi







































































# See if declarations like FINDEX_INFO_LEVELS are
# missing from winbase.h. This is known to be
# a problem with VC++ 5.2.

echo "$as_me:$LINENO: checking for FINDEX_INFO_LEVELS in winbase.h" >&5
echo $ECHO_N "checking for FINDEX_INFO_LEVELS in winbase.h... $ECHO_C" >&6







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







3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561

cat >>confdefs.h <<\_ACEOF
#define HAVE_CAST_TO_UNION 1
_ACEOF

fi

# Check to see if struct _stat32i64 exists in mingw's sys/stat.h

echo "$as_me:$LINENO: checking if struct _stat32i64 missing" >&5
echo $ECHO_N "checking if struct _stat32i64 missing... $ECHO_C" >&6
if test "${tcl_struct_stat32i64+set}" = set; then
  echo $ECHO_N "(cached) $ECHO_C" >&6
else
  cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h.  */
_ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h.  */

#include <sys/types.h>
#include <sys/stat.h>

int
main ()
{

  struct _stat32i64 foo;

  ;
  return 0;
}
_ACEOF
rm -f conftest.$ac_objext
if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
  (eval $ac_compile) 2>conftest.er1
  ac_status=$?
  grep -v '^ *+' conftest.er1 >conftest.err
  rm -f conftest.er1
  cat conftest.err >&5
  echo "$as_me:$LINENO: \$? = $ac_status" >&5
  (exit $ac_status); } &&
	 { ac_try='test -z "$ac_c_werror_flag"
			 || test ! -s conftest.err'
  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
  (eval $ac_try) 2>&5
  ac_status=$?
  echo "$as_me:$LINENO: \$? = $ac_status" >&5
  (exit $ac_status); }; } &&
	 { ac_try='test -s conftest.$ac_objext'
  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
  (eval $ac_try) 2>&5
  ac_status=$?
  echo "$as_me:$LINENO: \$? = $ac_status" >&5
  (exit $ac_status); }; }; then
  tcl_struct_stat32i64=no
else
  echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5

tcl_struct_stat32i64=yes
fi
rm -f conftest.err conftest.$ac_objext conftest.$ac_ext

fi
echo "$as_me:$LINENO: result: $tcl_struct_stat32i64" >&5
echo "${ECHO_T}$tcl_struct_stat32i64" >&6
if test "$tcl_struct_stat32i64" = "yes" ; then

cat >>confdefs.h <<\_ACEOF
#define HAVE_NO_STRUCT_STAT32I64 1
_ACEOF

fi


# See if declarations like FINDEX_INFO_LEVELS are
# missing from winbase.h. This is known to be
# a problem with VC++ 5.2.

echo "$as_me:$LINENO: checking for FINDEX_INFO_LEVELS in winbase.h" >&5
echo $ECHO_N "checking for FINDEX_INFO_LEVELS in winbase.h... $ECHO_C" >&6
3694
3695
3696
3697
3698
3699
3700


































































3701
3702
3703
3704
3705
3706
3707
echo "${ECHO_T}$tcl_cv_intrinsics" >&6
if test "$tcl_cv_intrinsics" = "yes"; then

cat >>confdefs.h <<\_ACEOF
#define HAVE_INTRIN_H 1
_ACEOF



































































fi

#--------------------------------------------------------------------
# Determines the correct binary file extension (.o, .obj, .exe etc.)
#--------------------------------------------------------------------









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







3763
3764
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
3776
3777
3778
3779
3780
3781
3782
3783
3784
3785
3786
3787
3788
3789
3790
3791
3792
3793
3794
3795
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
3817
3818
3819
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829
3830
3831
3832
3833
3834
3835
3836
3837
3838
3839
3840
3841
3842
echo "${ECHO_T}$tcl_cv_intrinsics" >&6
if test "$tcl_cv_intrinsics" = "yes"; then

cat >>confdefs.h <<\_ACEOF
#define HAVE_INTRIN_H 1
_ACEOF

fi

# See if the <wspiapi.h> header file is present

echo "$as_me:$LINENO: checking for wspiapi.h" >&5
echo $ECHO_N "checking for wspiapi.h... $ECHO_C" >&6
if test "${tcl_have_wspiapi_h+set}" = set; then
  echo $ECHO_N "(cached) $ECHO_C" >&6
else
  cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h.  */
_ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h.  */

#include <wspiapi.h>

int
main ()
{

  ;
  return 0;
}
_ACEOF
rm -f conftest.$ac_objext
if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
  (eval $ac_compile) 2>conftest.er1
  ac_status=$?
  grep -v '^ *+' conftest.er1 >conftest.err
  rm -f conftest.er1
  cat conftest.err >&5
  echo "$as_me:$LINENO: \$? = $ac_status" >&5
  (exit $ac_status); } &&
	 { ac_try='test -z "$ac_c_werror_flag"
			 || test ! -s conftest.err'
  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
  (eval $ac_try) 2>&5
  ac_status=$?
  echo "$as_me:$LINENO: \$? = $ac_status" >&5
  (exit $ac_status); }; } &&
	 { ac_try='test -s conftest.$ac_objext'
  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
  (eval $ac_try) 2>&5
  ac_status=$?
  echo "$as_me:$LINENO: \$? = $ac_status" >&5
  (exit $ac_status); }; }; then
  tcl_have_wspiapi_h=yes
else
  echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5

tcl_have_wspiapi_h=no
fi
rm -f conftest.err conftest.$ac_objext conftest.$ac_ext

fi
echo "$as_me:$LINENO: result: $tcl_have_wspiapi_h" >&5
echo "${ECHO_T}$tcl_have_wspiapi_h" >&6
if test "$tcl_have_wspiapi_h" = "yes"; then

cat >>confdefs.h <<\_ACEOF
#define HAVE_WSPIAPI_H 1
_ACEOF

fi

#--------------------------------------------------------------------
# Determines the correct binary file extension (.o, .obj, .exe etc.)
#--------------------------------------------------------------------


4266
4267
4268
4269
4270
4271
4272


























































4273
4274
4275
4276
4277
4278
4279
		echo "$as_me:$LINENO: result:    Using 64-bit $MACHINE mode" >&5
echo "${ECHO_T}   Using 64-bit $MACHINE mode" >&6
		;;
	    ia64)
		MACHINE="IA64"
		echo "$as_me:$LINENO: result:    Using 64-bit $MACHINE mode" >&5
echo "${ECHO_T}   Using 64-bit $MACHINE mode" >&6


























































		;;
	esac
    else
	if test "${SHARED_BUILD}" = "0" ; then
	    # static
            echo "$as_me:$LINENO: result: using static flags" >&5
echo "${ECHO_T}using static flags" >&6







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







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
4429
4430
4431
4432
4433
4434
4435
4436
4437
4438
4439
4440
4441
4442
4443
4444
4445
4446
4447
4448
4449
4450
4451
4452
4453
4454
4455
4456
4457
4458
4459
4460
4461
4462
4463
4464
4465
4466
4467
4468
4469
4470
4471
4472
		echo "$as_me:$LINENO: result:    Using 64-bit $MACHINE mode" >&5
echo "${ECHO_T}   Using 64-bit $MACHINE mode" >&6
		;;
	    ia64)
		MACHINE="IA64"
		echo "$as_me:$LINENO: result:    Using 64-bit $MACHINE mode" >&5
echo "${ECHO_T}   Using 64-bit $MACHINE mode" >&6
		;;
	    *)
		cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h.  */
_ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h.  */

			#ifdef _WIN64
			#error 64-bit
			#endif

int
main ()
{

  ;
  return 0;
}
_ACEOF
rm -f conftest.$ac_objext
if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
  (eval $ac_compile) 2>conftest.er1
  ac_status=$?
  grep -v '^ *+' conftest.er1 >conftest.err
  rm -f conftest.er1
  cat conftest.err >&5
  echo "$as_me:$LINENO: \$? = $ac_status" >&5
  (exit $ac_status); } &&
	 { ac_try='test -z "$ac_c_werror_flag"
			 || test ! -s conftest.err'
  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
  (eval $ac_try) 2>&5
  ac_status=$?
  echo "$as_me:$LINENO: \$? = $ac_status" >&5
  (exit $ac_status); }; } &&
	 { ac_try='test -s conftest.$ac_objext'
  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
  (eval $ac_try) 2>&5
  ac_status=$?
  echo "$as_me:$LINENO: \$? = $ac_status" >&5
  (exit $ac_status); }; }; then
  tcl_win_64bit=no
else
  echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5

tcl_win_64bit=yes

fi
rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
		if test "$tcl_win_64bit" = "yes" ; then
			do64bit=amd64
			MACHINE="AMD64"
			echo "$as_me:$LINENO: result:    Using 64-bit $MACHINE mode" >&5
echo "${ECHO_T}   Using 64-bit $MACHINE mode" >&6
		fi
		;;
	esac
    else
	if test "${SHARED_BUILD}" = "0" ; then
	    # static
            echo "$as_me:$LINENO: result: using static flags" >&5
echo "${ECHO_T}using static flags" >&6

Changes to win/configure.in.

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# versions of autoconf incorrectly set SHELL to /bin/bash instead of
# /bin/sh. The bash shell seems to suffer from some strange failures.
SHELL=/bin/sh

TCL_VERSION=8.6
TCL_MAJOR_VERSION=8
TCL_MINOR_VERSION=6
TCL_PATCH_LEVEL="b1.2"
VER=$TCL_MAJOR_VERSION$TCL_MINOR_VERSION

TCL_DDE_VERSION=1.3
TCL_DDE_MAJOR_VERSION=1
TCL_DDE_MINOR_VERSION=3
TCL_DDE_PATCH_LEVEL="2"
DDEVER=$TCL_DDE_MAJOR_VERSION$TCL_DDE_MINOR_VERSION







|







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# versions of autoconf incorrectly set SHELL to /bin/bash instead of
# /bin/sh. The bash shell seems to suffer from some strange failures.
SHELL=/bin/sh

TCL_VERSION=8.6
TCL_MAJOR_VERSION=8
TCL_MINOR_VERSION=6
TCL_PATCH_LEVEL="b2"
VER=$TCL_MAJOR_VERSION$TCL_MINOR_VERSION

TCL_DDE_VERSION=1.3
TCL_DDE_MAJOR_VERSION=1
TCL_DDE_MINOR_VERSION=3
TCL_DDE_PATCH_LEVEL="2"
DDEVER=$TCL_DDE_MAJOR_VERSION$TCL_DDE_MINOR_VERSION
221
222
223
224
225
226
227



















228
229
230
231
232
233
234
        tcl_cv_cast_to_union=no)
)
if test "$tcl_cv_cast_to_union" = "yes"; then
    AC_DEFINE(HAVE_CAST_TO_UNION, 1,
            [Defined when compiler supports casting to union type.])
fi





















# See if declarations like FINDEX_INFO_LEVELS are
# missing from winbase.h. This is known to be
# a problem with VC++ 5.2.

AC_CACHE_CHECK(for FINDEX_INFO_LEVELS in winbase.h,
    tcl_cv_findex_enums,







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







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
        tcl_cv_cast_to_union=no)
)
if test "$tcl_cv_cast_to_union" = "yes"; then
    AC_DEFINE(HAVE_CAST_TO_UNION, 1,
            [Defined when compiler supports casting to union type.])
fi

# Check to see if struct _stat32i64 exists in mingw's sys/stat.h

AC_CACHE_CHECK(if struct _stat32i64 missing,
    tcl_struct_stat32i64,
AC_TRY_COMPILE([
#include <sys/types.h>
#include <sys/stat.h>
],
[
  struct _stat32i64 foo;
],
        tcl_struct_stat32i64=no,
        tcl_struct_stat32i64=yes)
)
if test "$tcl_struct_stat32i64" = "yes" ; then
    AC_DEFINE(HAVE_NO_STRUCT_STAT32I64, 1,
            [Defined when sys/stat.h is missing struct _stat32i64])
fi


# See if declarations like FINDEX_INFO_LEVELS are
# missing from winbase.h. This is known to be
# a problem with VC++ 5.2.

AC_CACHE_CHECK(for FINDEX_INFO_LEVELS in winbase.h,
    tcl_cv_findex_enums,
286
287
288
289
290
291
292















293
294
295
296
297
298
299
        tcl_cv_intrinsics=yes,
        tcl_cv_intrinsics=no)
)
if test "$tcl_cv_intrinsics" = "yes"; then
    AC_DEFINE(HAVE_INTRIN_H, 1,
            [Defined when the compilers supports intrinsics])
fi
















#--------------------------------------------------------------------
# Determines the correct binary file extension (.o, .obj, .exe etc.)
#--------------------------------------------------------------------

AC_OBJEXT
AC_EXEEXT







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







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
        tcl_cv_intrinsics=yes,
        tcl_cv_intrinsics=no)
)
if test "$tcl_cv_intrinsics" = "yes"; then
    AC_DEFINE(HAVE_INTRIN_H, 1,
            [Defined when the compilers supports intrinsics])
fi

# See if the <wspiapi.h> header file is present    

AC_CACHE_CHECK(for wspiapi.h,
    tcl_have_wspiapi_h,
AC_TRY_COMPILE([
#include <wspiapi.h>
], [],
        tcl_have_wspiapi_h=yes,
        tcl_have_wspiapi_h=no)
)
if test "$tcl_have_wspiapi_h" = "yes"; then
    AC_DEFINE(HAVE_WSPIAPI_H, 1,
            [Defined when wspiapi.h exists])
fi

#--------------------------------------------------------------------
# Determines the correct binary file extension (.o, .obj, .exe etc.)
#--------------------------------------------------------------------

AC_OBJEXT
AC_EXEEXT
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

AC_CHECK_TYPE([intptr_t], [
    AC_DEFINE([HAVE_INTPTR_T], 1, [Do we have the intptr_t type?])], [
    AC_CACHE_CHECK([for pointer-size signed integer type], tcl_cv_intptr_t, [
    for tcl_cv_intptr_t in "int" "long" "long long" none; do
	if test "$tcl_cv_intptr_t" != none; then
	    AC_COMPILE_IFELSE([AC_LANG_BOOL_COMPILE_TRY([AC_INCLUDES_DEFAULT],
		    [[sizeof (void *) <= sizeof ($tcl_cv_intptr_t)]])], 
		[tcl_ok=yes], [tcl_ok=no])
	    test "$tcl_ok" = yes && break; fi
    done])
    if test "$tcl_cv_intptr_t" != none; then
	AC_DEFINE_UNQUOTED([intptr_t], [$tcl_cv_intptr_t], [Signed integer
	   type wide enough to hold a pointer.])
    fi
])
AC_CHECK_TYPE([uintptr_t], [
    AC_DEFINE([HAVE_UINTPTR_T], 1, [Do we have the uintptr_t type?])], [
    AC_CACHE_CHECK([for pointer-size unsigned integer type], tcl_cv_uintptr_t, [
    for tcl_cv_uintptr_t in "unsigned int" "unsigned long" "unsigned long long" \
	    none; do
	if test "$tcl_cv_uintptr_t" != none; then
	    AC_COMPILE_IFELSE([AC_LANG_BOOL_COMPILE_TRY([AC_INCLUDES_DEFAULT],
		    [[sizeof (void *) <= sizeof ($tcl_cv_uintptr_t)]])], 
		[tcl_ok=yes], [tcl_ok=no])
	    test "$tcl_ok" = yes && break; fi
    done])
    if test "$tcl_cv_uintptr_t" != none; then
	AC_DEFINE_UNQUOTED([uintptr_t], [$tcl_cv_uintptr_t], [Unsigned integer
	   type wide enough to hold a pointer.])
    fi







|















|







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

AC_CHECK_TYPE([intptr_t], [
    AC_DEFINE([HAVE_INTPTR_T], 1, [Do we have the intptr_t type?])], [
    AC_CACHE_CHECK([for pointer-size signed integer type], tcl_cv_intptr_t, [
    for tcl_cv_intptr_t in "int" "long" "long long" none; do
	if test "$tcl_cv_intptr_t" != none; then
	    AC_COMPILE_IFELSE([AC_LANG_BOOL_COMPILE_TRY([AC_INCLUDES_DEFAULT],
		    [[sizeof (void *) <= sizeof ($tcl_cv_intptr_t)]])],
		[tcl_ok=yes], [tcl_ok=no])
	    test "$tcl_ok" = yes && break; fi
    done])
    if test "$tcl_cv_intptr_t" != none; then
	AC_DEFINE_UNQUOTED([intptr_t], [$tcl_cv_intptr_t], [Signed integer
	   type wide enough to hold a pointer.])
    fi
])
AC_CHECK_TYPE([uintptr_t], [
    AC_DEFINE([HAVE_UINTPTR_T], 1, [Do we have the uintptr_t type?])], [
    AC_CACHE_CHECK([for pointer-size unsigned integer type], tcl_cv_uintptr_t, [
    for tcl_cv_uintptr_t in "unsigned int" "unsigned long" "unsigned long long" \
	    none; do
	if test "$tcl_cv_uintptr_t" != none; then
	    AC_COMPILE_IFELSE([AC_LANG_BOOL_COMPILE_TRY([AC_INCLUDES_DEFAULT],
		    [[sizeof (void *) <= sizeof ($tcl_cv_uintptr_t)]])],
		[tcl_ok=yes], [tcl_ok=no])
	    test "$tcl_ok" = yes && break; fi
    done])
    if test "$tcl_cv_uintptr_t" != none; then
	AC_DEFINE_UNQUOTED([uintptr_t], [$tcl_cv_uintptr_t], [Unsigned integer
	   type wide enough to hold a pointer.])
    fi

Changes to win/makefile.vc.

209
210
211
212
213
214
215









216
217
218
219
220
221
222
TCLREGLIB	= $(OUT_DIR)\$(TCLREGLIBNAME)

TCLDDELIBNAME	= $(PROJECT)dde$(DDEVERSION)$(SUFX:t=).$(EXT)
TCLDDELIB	= $(OUT_DIR)\$(TCLDDELIBNAME)

TCLTEST		= $(OUT_DIR)\$(PROJECT)test.exe
CAT32		= $(OUT_DIR)\cat32.exe










### Make sure we use backslash only.
LIB_INSTALL_DIR		= $(_INSTALLDIR)\lib
BIN_INSTALL_DIR		= $(_INSTALLDIR)\bin
DOC_INSTALL_DIR		= $(_INSTALLDIR)\doc
SCRIPT_INSTALL_DIR	= $(_INSTALLDIR)\lib\tcl$(DOTVERSION)
INCLUDE_INSTALL_DIR	= $(_INSTALLDIR)\include







>
>
>
>
>
>
>
>
>







209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
TCLREGLIB	= $(OUT_DIR)\$(TCLREGLIBNAME)

TCLDDELIBNAME	= $(PROJECT)dde$(DDEVERSION)$(SUFX:t=).$(EXT)
TCLDDELIB	= $(OUT_DIR)\$(TCLDDELIBNAME)

TCLTEST		= $(OUT_DIR)\$(PROJECT)test.exe
CAT32		= $(OUT_DIR)\cat32.exe

# Can we run what we build? IX86 runs on all architectures.
!ifndef TCLSH_NATIVE
!if "$(MACHINE)" == "IX86" || "$(MACHINE)" == "$(NATIVE_ARCH)"
TCLSH_NATIVE	= $(TCLSH)
!else
!error You must explicitly set TCLSH_NATIVE for cross-compilation
!endif
!endif

### Make sure we use backslash only.
LIB_INSTALL_DIR		= $(_INSTALLDIR)\lib
BIN_INSTALL_DIR		= $(_INSTALLDIR)\bin
DOC_INSTALL_DIR		= $(_INSTALLDIR)\doc
SCRIPT_INSTALL_DIR	= $(_INSTALLDIR)\lib\tcl$(DOTVERSION)
INCLUDE_INSTALL_DIR	= $(_INSTALLDIR)\include
349
350
351
352
353
354
355

356
357
358
359
360
361
362
	$(TMP_DIR)\bn_mp_and.obj \
	$(TMP_DIR)\bn_mp_clamp.obj \
	$(TMP_DIR)\bn_mp_clear.obj \
	$(TMP_DIR)\bn_mp_clear_multi.obj \
	$(TMP_DIR)\bn_mp_cmp.obj \
	$(TMP_DIR)\bn_mp_cmp_d.obj \
	$(TMP_DIR)\bn_mp_cmp_mag.obj \

	$(TMP_DIR)\bn_mp_copy.obj \
	$(TMP_DIR)\bn_mp_count_bits.obj \
	$(TMP_DIR)\bn_mp_div.obj \
	$(TMP_DIR)\bn_mp_div_d.obj \
	$(TMP_DIR)\bn_mp_div_2.obj \
	$(TMP_DIR)\bn_mp_div_2d.obj \
	$(TMP_DIR)\bn_mp_div_3.obj \







>







358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
	$(TMP_DIR)\bn_mp_and.obj \
	$(TMP_DIR)\bn_mp_clamp.obj \
	$(TMP_DIR)\bn_mp_clear.obj \
	$(TMP_DIR)\bn_mp_clear_multi.obj \
	$(TMP_DIR)\bn_mp_cmp.obj \
	$(TMP_DIR)\bn_mp_cmp_d.obj \
	$(TMP_DIR)\bn_mp_cmp_mag.obj \
	$(TMP_DIR)\bn_mp_cnt_lsb.obj \
	$(TMP_DIR)\bn_mp_copy.obj \
	$(TMP_DIR)\bn_mp_count_bits.obj \
	$(TMP_DIR)\bn_mp_div.obj \
	$(TMP_DIR)\bn_mp_div_d.obj \
	$(TMP_DIR)\bn_mp_div_2.obj \
	$(TMP_DIR)\bn_mp_div_2d.obj \
	$(TMP_DIR)\bn_mp_div_3.obj \
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
		"$(SCRIPT_INSTALL_DIR)\encoding\"

#" emacs fix

install-tzdata:
	@echo Installing time zone data
	@set TCL_LIBRARY=$(ROOT)/library
	@$(TCLSH) "$(ROOT)/tools/installData.tcl" \
	    "$(ROOT)/library/tzdata" "$(SCRIPT_INSTALL_DIR)/tzdata"

install-msgs:
	@echo Installing message catalogs
	@set TCL_LIBRARY=$(ROOT)/library
	@$(TCLSH) "$(ROOT)/tools/installData.tcl" \
	    "$(ROOT)/library/msgs" "$(SCRIPT_INSTALL_DIR)/msgs"

#---------------------------------------------------------------------
# Clean up
#---------------------------------------------------------------------

tidy:







|





|







1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
		"$(SCRIPT_INSTALL_DIR)\encoding\"

#" emacs fix

install-tzdata:
	@echo Installing time zone data
	@set TCL_LIBRARY=$(ROOT)/library
	@$(TCLSH_NATIVE) "$(ROOT)/tools/installData.tcl" \
	    "$(ROOT)/library/tzdata" "$(SCRIPT_INSTALL_DIR)/tzdata"

install-msgs:
	@echo Installing message catalogs
	@set TCL_LIBRARY=$(ROOT)/library
	@$(TCLSH_NATIVE) "$(ROOT)/tools/installData.tcl" \
	    "$(ROOT)/library/msgs" "$(SCRIPT_INSTALL_DIR)/msgs"

#---------------------------------------------------------------------
# Clean up
#---------------------------------------------------------------------

tidy:

Changes to win/rules.vc.

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
### Assume the normal default.
_INSTALLDIR	= C:\Program Files\Tcl
!else
### Fix the path separators.
_INSTALLDIR	= $(INSTALLDIR:/=\)
!endif

!ifndef MACHINE
!if "$(CPU)" == "" || "$(CPU)" == "i386"
MACHINE		= IX86
!else
MACHINE         = $(CPU)
!endif
!endif

!ifndef CFG_ENCODING
CFG_ENCODING	= \"cp1252\"
!endif

#----------------------------------------------------------
# Set the proper copy method to avoid overwrite questions
# to the user when copying files and selecting the right
# "delete all" method.
#----------------------------------------------------------

!if "$(OS)" == "Windows_NT"







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







23
24
25
26
27
28
29












30
31
32
33
34
35
36
### Assume the normal default.
_INSTALLDIR	= C:\Program Files\Tcl
!else
### Fix the path separators.
_INSTALLDIR	= $(INSTALLDIR:/=\)
!endif













#----------------------------------------------------------
# Set the proper copy method to avoid overwrite questions
# to the user when copying files and selecting the right
# "delete all" method.
#----------------------------------------------------------

!if "$(OS)" == "Windows_NT"
59
60
61
62
63
64
65












































66
67
68
69
70
71
72
CPY	= xcopy /i >_JUNK.OUT # On Win98 NUL does not work here.
COPY	= copy >_JUNK.OUT # On Win98 NUL does not work here.
RMDIR	= deltree /Y
NULL    = \NUL # Used in testing directory existence
ERRNULL = >NUL # Win9x shell cannot redirect stderr
!endif
MKDIR   = mkdir













































!message ===============================================================================

#----------------------------------------------------------
# build the helper app we need to overcome nmake's limiting
# environment.
#----------------------------------------------------------







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







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
CPY	= xcopy /i >_JUNK.OUT # On Win98 NUL does not work here.
COPY	= copy >_JUNK.OUT # On Win98 NUL does not work here.
RMDIR	= deltree /Y
NULL    = \NUL # Used in testing directory existence
ERRNULL = >NUL # Win9x shell cannot redirect stderr
!endif
MKDIR   = mkdir

#------------------------------------------------------------------------------
# Determine the host and target architectures and compiler version.
#------------------------------------------------------------------------------

_HASH=^#
_VC_MANIFEST_EMBED_EXE=
_VC_MANIFEST_EMBED_DLL=
VCVER=0
!if ![echo VCVERSION=_MSC_VER > vercl.x] \
    && ![echo $(_HASH)if defined(_M_IX86) >> vercl.x] \
    && ![echo ARCH=IX86 >> vercl.x] \
    && ![echo $(_HASH)elif defined(_M_AMD64) >> vercl.x] \
    && ![echo ARCH=AMD64 >> vercl.x] \
    && ![echo $(_HASH)endif >> vercl.x] \
    && ![cl -nologo -TC -P vercl.x $(ERRNULL)]
!include vercl.i
!if ![echo VCVER= ^\> vercl.vc] \
    && ![set /a $(VCVERSION) / 100 - 6 >> vercl.vc]
!include vercl.vc
!endif
!endif
!if ![del $(ERRNUL) /q/f vercl.x vercl.i vercl.vc]
!endif

!if ![reg query HKLM\Hardware\Description\System\CentralProcessor\0 /v Identifier | findstr /i x86]
NATIVE_ARCH=IX86
!else
NATIVE_ARCH=AMD64
!endif

# Since MSVC8 we must deal with manifest resources.
!if $(VCVERSION) >= 1400
_VC_MANIFEST_EMBED_EXE=if exist [email protected] mt -nologo -manifest [email protected] -outputresource:$@;1
_VC_MANIFEST_EMBED_DLL=if exist [email protected] mt -nologo -manifest [email protected] -outputresource:$@;2
!endif

!ifndef MACHINE
MACHINE=$(ARCH)
!endif

!ifndef CFG_ENCODING
CFG_ENCODING	= \"cp1252\"
!endif

!message ===============================================================================

#----------------------------------------------------------
# build the helper app we need to overcome nmake's limiting
# environment.
#----------------------------------------------------------
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

LINKERFLAGS     =

!if [nmakehlp -l -ltcg]
LINKERFLAGS     =-ltcg
!endif

#----------------------------------------------------------
# MSVC8 (ships with Visual Studio 2005) generates a manifest
# file that we should link into the binaries. This is how.
#----------------------------------------------------------

_VC_MANIFEST_EMBED_EXE=
_VC_MANIFEST_EMBED_DLL=
VCVER=0
!if ![echo VCVERSION=_MSC_VER > vercl.x] \
    && ![cl -nologo -TC -P vercl.x $(ERRNULL)]
!include vercl.i
!if $(VCVERSION) >= 1600
VCVER=10
!elseif $(VCVERSION) >= 1500
VCVER=9
!elseif $(VCVERSION) >= 1400
VCVER=8
!elseif $(VCVERSION) >= 1300
VCVER=7
!elseif $(VCVERSION) >= 1200
VCVER=6
!endif
!endif

# Since MSVC8 we must deal with manifest resources.
!if $(VCVERSION) >= 1400
_VC_MANIFEST_EMBED_EXE=if exist [email protected] mt -nologo -manifest [email protected] -outputresource:$@;1
_VC_MANIFEST_EMBED_DLL=if exist [email protected] mt -nologo -manifest [email protected] -outputresource:$@;2
!endif

#----------------------------------------------------------
# Decode the options requested.
#----------------------------------------------------------

!if "$(OPTS)" == "" || [nmakehlp -f "$(OPTS)" "none"]
STATIC_BUILD	= 0
TCL_THREADS	= 1







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







203
204
205
206
207
208
209






























210
211
212
213
214
215
216

LINKERFLAGS     =

!if [nmakehlp -l -ltcg]
LINKERFLAGS     =-ltcg
!endif































#----------------------------------------------------------
# Decode the options requested.
#----------------------------------------------------------

!if "$(OPTS)" == "" || [nmakehlp -f "$(OPTS)" "none"]
STATIC_BUILD	= 0
TCL_THREADS	= 1
694
695
696
697
698
699
700

701
702
703
704
#----------------------------------------------------------

!message *** Intermediate directory will be '$(TMP_DIR)'
!message *** Output directory will be '$(OUT_DIR)'
!message *** Suffix for binaries will be '$(SUFX)'
!message *** Optional defines are '$(OPTDEFINES)'
!message *** Compiler version $(VCVER). Target machine is $(MACHINE)

!message *** Compiler options '$(COMPILERFLAGS) $(OPTIMIZATIONS) $(DEBUGFLAGS) $(WARNINGS)'
!message *** Link options '$(LINKERFLAGS)'

!endif







>




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

!message *** Intermediate directory will be '$(TMP_DIR)'
!message *** Output directory will be '$(OUT_DIR)'
!message *** Suffix for binaries will be '$(SUFX)'
!message *** Optional defines are '$(OPTDEFINES)'
!message *** Compiler version $(VCVER). Target machine is $(MACHINE)
!message *** Host architecture is $(NATIVE_ARCH)
!message *** Compiler options '$(COMPILERFLAGS) $(OPTIMIZATIONS) $(DEBUGFLAGS) $(WARNINGS)'
!message *** Link options '$(LINKERFLAGS)'

!endif

Changes to win/tcl.m4.

584
585
586
587
588
589
590















591
592
593
594
595
596
597
	    amd64|x64|yes)
		MACHINE="AMD64" ; # assume AMD64 as default 64-bit build
		AC_MSG_RESULT([   Using 64-bit $MACHINE mode])
		;;
	    ia64)
		MACHINE="IA64"
		AC_MSG_RESULT([   Using 64-bit $MACHINE mode])















		;;
	esac
    else
	if test "${SHARED_BUILD}" = "0" ; then
	    # static
            AC_MSG_RESULT([using static flags])
	    runtime=-MT







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







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
	    amd64|x64|yes)
		MACHINE="AMD64" ; # assume AMD64 as default 64-bit build
		AC_MSG_RESULT([   Using 64-bit $MACHINE mode])
		;;
	    ia64)
		MACHINE="IA64"
		AC_MSG_RESULT([   Using 64-bit $MACHINE mode])
		;;
	    *)
		AC_TRY_COMPILE([
			#ifdef _WIN64
			#error 64-bit
			#endif
		], [],
			tcl_win_64bit=no,
			tcl_win_64bit=yes
		)
		if test "$tcl_win_64bit" = "yes" ; then
			do64bit=amd64
			MACHINE="AMD64"
			AC_MSG_RESULT([   Using 64-bit $MACHINE mode])
		fi
		;;
	esac
    else
	if test "${SHARED_BUILD}" = "0" ; then
	    # static
            AC_MSG_RESULT([using static flags])
	    runtime=-MT

Changes to win/tclWin32Dll.c.

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
 */

#include "tclWinInt.h"
#if defined(HAVE_INTRIN_H)
#   include <intrin.h>
#endif

/*
 * The following data structures are used when loading the thunking library
 * for execing child processes under Win32s.
 */

typedef DWORD (WINAPI UT32PROC)(LPVOID lpBuff, DWORD dwUserDefined,
	LPVOID *lpTranslationList);

typedef BOOL (WINAPI UTREGISTER)(HANDLE hModule, LPCSTR SixteenBitDLL,
	LPCSTR InitName, LPCSTR ProcName, UT32PROC **ThirtyTwoBitThunk,
	FARPROC UT32Callback, LPVOID Buff);

typedef void (WINAPI UTUNREGISTER)(HANDLE hModule);

/*
 * The following variables keep track of information about this DLL on a
 * per-instance basis. Each time this DLL is loaded, it gets its own new data
 * segment with its own copy of all static and global information.
 */

static HINSTANCE hInstance;	/* HINSTANCE of this DLL. */







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







12
13
14
15
16
17
18














19
20
21
22
23
24
25
 */

#include "tclWinInt.h"
#if defined(HAVE_INTRIN_H)
#   include <intrin.h>
#endif















/*
 * The following variables keep track of information about this DLL on a
 * per-instance basis. Each time this DLL is loaded, it gets its own new data
 * segment with its own copy of all static and global information.
 */

static HINSTANCE hInstance;	/* HINSTANCE of this DLL. */
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

#if defined(_MSC_VER) && (_MSC_VER <= 1100)
#define cpuid	__asm __emit 0fh __asm __emit 0a2h
#endif

static Tcl_Encoding winTCharEncoding = NULL;

/*
 * The following function table is used to dispatch to wide-character
 * versions of the operating system calls.
 */

static const TclWinProcs winProcs = {
    1,
    (BOOL (WINAPI *)(const TCHAR *, LPDCB)) BuildCommDCB,
    (TCHAR *(WINAPI *)(TCHAR *)) CharLower,
    (BOOL (WINAPI *)(const TCHAR *, const TCHAR *, BOOL)) CopyFile,
    (BOOL (WINAPI *)(const TCHAR *, LPSECURITY_ATTRIBUTES)) CreateDirectory,
    (HANDLE (WINAPI *)(const TCHAR *, DWORD, DWORD, SECURITY_ATTRIBUTES *,
	    DWORD, DWORD, HANDLE)) CreateFile,
    (BOOL (WINAPI *)(const TCHAR *, TCHAR *, LPSECURITY_ATTRIBUTES,
	    LPSECURITY_ATTRIBUTES, BOOL, DWORD, LPVOID, const TCHAR *,
	    LPSTARTUPINFO, LPPROCESS_INFORMATION)) CreateProcess,
    (BOOL (WINAPI *)(const TCHAR *)) DeleteFile,
    (HANDLE (WINAPI *)(const TCHAR *, WIN32_FIND_DATAT *)) FindFirstFile,
    (BOOL (WINAPI *)(HANDLE, WIN32_FIND_DATAT *)) FindNextFile,
    (BOOL (WINAPI *)(TCHAR *, LPDWORD)) GetComputerName,
    (DWORD (WINAPI *)(DWORD, TCHAR *)) GetCurrentDirectory,
    (DWORD (WINAPI *)(const TCHAR *)) GetFileAttributes,
    (DWORD (WINAPI *)(const TCHAR *, DWORD nBufferLength, TCHAR *,
	    TCHAR **)) GetFullPathName,
    (DWORD (WINAPI *)(const TCHAR *, TCHAR *, DWORD)) GetShortPathName,
    (UINT (WINAPI *)(const TCHAR *, const TCHAR *, UINT uUnique,
	    TCHAR *)) GetTempFileName,
    (DWORD (WINAPI *)(DWORD, TCHAR *)) GetTempPath,
    (BOOL (WINAPI *)(const TCHAR *, TCHAR *, DWORD, LPDWORD, LPDWORD, LPDWORD,
	    TCHAR *, DWORD)) GetVolumeInformation,
    (HINSTANCE (WINAPI *)(const TCHAR *, HANDLE, DWORD)) LoadLibraryEx,
    (BOOL (WINAPI *)(const TCHAR *, const TCHAR *)) MoveFile,
    (BOOL (WINAPI *)(const TCHAR *)) RemoveDirectory,
    (DWORD (WINAPI *)(const TCHAR *, const TCHAR *, const TCHAR *, DWORD,
	    TCHAR *, TCHAR **)) SearchPath,
    (BOOL (WINAPI *)(const TCHAR *)) SetCurrentDirectory,
    (BOOL (WINAPI *)(const TCHAR *, DWORD)) SetFileAttributes,
    (BOOL (WINAPI *)(const TCHAR *, GET_FILEEX_INFO_LEVELS,
	    LPVOID)) GetFileAttributesEx,
    (BOOL (WINAPI *)(const TCHAR *, const TCHAR*,
	    LPSECURITY_ATTRIBUTES)) CreateHardLink,
    (HANDLE (WINAPI *)(const TCHAR*, UINT, LPVOID, UINT,
	    LPVOID, DWORD)) FindFirstFileEx,
    (BOOL (WINAPI *)(const TCHAR*, TCHAR*,
	    DWORD)) GetVolumeNameForVolumeMountPoint,
    (DWORD (WINAPI *)(const TCHAR*, TCHAR*,
	    DWORD)) GetLongPathName,
    /* Security SDK */
    (BOOL (WINAPI *)(LPCTSTR, SECURITY_INFORMATION,
	    PSECURITY_DESCRIPTOR, DWORD, LPDWORD)) GetFileSecurity,
    (BOOL (WINAPI *) (SECURITY_IMPERSONATION_LEVEL)) ImpersonateSelf,
    (BOOL (WINAPI *) (HANDLE, DWORD, BOOL, PHANDLE)) OpenThreadToken,
    (BOOL (WINAPI *) (void)) RevertToSelf,
    (void (WINAPI *) (PDWORD, PGENERIC_MAPPING)) MapGenericMask,
    (BOOL (WINAPI *)(PSECURITY_DESCRIPTOR, HANDLE, DWORD,
	    PGENERIC_MAPPING, PPRIVILEGE_SET, LPDWORD, LPDWORD, LPBOOL)) AccessCheck,
    /* ReadConsole and WriteConsole */
    (BOOL (WINAPI *)(HANDLE, LPVOID, DWORD, LPDWORD, LPVOID)) ReadConsole,
    (BOOL (WINAPI *)(HANDLE, const void*, DWORD, LPDWORD, LPVOID)) WriteConsole,
    (BOOL (WINAPI *)(LPTSTR, LPDWORD)) GetUserName,
    (const TCHAR *(*)(const char *, int, Tcl_DString *)) Tcl_WinUtfToTChar,
    (const char *(*)(const TCHAR *, int, Tcl_DString *)) Tcl_WinTCharToUtf
};

const TclWinProcs *const tclWinProcs = &winProcs;

/*
 * The following declaration is for the VC++ DLL entry point.
 */

BOOL APIENTRY		DllMain(HINSTANCE hInst, DWORD reason,
			    LPVOID reserved);








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







48
49
50
51
52
53
54


































































55
56
57
58
59
60
61

#if defined(_MSC_VER) && (_MSC_VER <= 1100)
#define cpuid	__asm __emit 0fh __asm __emit 0a2h
#endif

static Tcl_Encoding winTCharEncoding = NULL;



































































/*
 * The following declaration is for the VC++ DLL entry point.
 */

BOOL APIENTRY		DllMain(HINSTANCE hInst, DWORD reason,
			    LPVOID reserved);

Changes to win/tclWinChan.c.

993
994
995
996
997
998
999


1000
1001
1002
1003
1004
1005
1006
	 * The handle is of an unknown type, probably /dev/nul equivalent or
	 * possibly a closed handle.
	 */

	channel = NULL;
	Tcl_AppendResult(interp, "couldn't open \"", TclGetString(pathPtr),
		"\": bad file type", NULL);


	break;
    }

    return channel;
}

/*







>
>







993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
	 * The handle is of an unknown type, probably /dev/nul equivalent or
	 * possibly a closed handle.
	 */

	channel = NULL;
	Tcl_AppendResult(interp, "couldn't open \"", TclGetString(pathPtr),
		"\": bad file type", NULL);
	Tcl_SetErrorCode(interp, "TCL", "VALUE", "CHANNEL", "BAD_TYPE",
		NULL);
	break;
    }

    return channel;
}

/*

Changes to win/tclWinConsole.c.

1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150

static DWORD WINAPI
ConsoleReaderThread(
    LPVOID arg)
{
    ConsoleInfo *infoPtr = (ConsoleInfo *)arg;
    HANDLE *handle = infoPtr->handle;
    DWORD count, waitResult;
    HANDLE wEvents[2];

    /* The first event takes precedence. */
    wEvents[0] = infoPtr->stopReader;
    wEvents[1] = infoPtr->startReader;

    for (;;) {







|







1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150

static DWORD WINAPI
ConsoleReaderThread(
    LPVOID arg)
{
    ConsoleInfo *infoPtr = (ConsoleInfo *)arg;
    HANDLE *handle = infoPtr->handle;
    DWORD waitResult;
    HANDLE wEvents[2];

    /* The first event takes precedence. */
    wEvents[0] = infoPtr->stopReader;
    wEvents[1] = infoPtr->startReader;

    for (;;) {
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
	     * The start event was not signaled. It must be the stop event or
	     * an error, so exit this thread.
	     */

	    break;
	}

	count = 0;

	/*
	 * Look for data on the console, but first ignore any events that are
	 * not KEY_EVENTs.
	 */

	if (readConsoleBytes(handle, infoPtr->buffer, CONSOLE_BUFFER_SIZE,
		(LPDWORD) &infoPtr->bytesRead) != FALSE) {







<
<







1159
1160
1161
1162
1163
1164
1165


1166
1167
1168
1169
1170
1171
1172
	     * The start event was not signaled. It must be the stop event or
	     * an error, so exit this thread.
	     */

	    break;
	}



	/*
	 * Look for data on the console, but first ignore any events that are
	 * not KEY_EVENTs.
	 */

	if (readConsoleBytes(handle, infoPtr->buffer, CONSOLE_BUFFER_SIZE,
		(LPDWORD) &infoPtr->bytesRead) != FALSE) {

Changes to win/tclWinDde.c.

135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
 *----------------------------------------------------------------------
 */

int
Dde_Init(
    Tcl_Interp *interp)
{
    ThreadSpecificData *tsdPtr;

    if (!Tcl_InitStubs(interp, "8.1", 0)) {
	return TCL_ERROR;
    }

    Tcl_CreateObjCommand(interp, "dde", DdeObjCmd, NULL, NULL);
    tsdPtr = TCL_TSD_INIT(&dataKey);
    Tcl_CreateExitHandler(DdeExitProc, NULL);
    return Tcl_PkgProvide(interp, TCL_DDE_PACKAGE_NAME, TCL_DDE_VERSION);
}

/*
 *----------------------------------------------------------------------
 *







<
<





<







135
136
137
138
139
140
141


142
143
144
145
146

147
148
149
150
151
152
153
 *----------------------------------------------------------------------
 */

int
Dde_Init(
    Tcl_Interp *interp)
{


    if (!Tcl_InitStubs(interp, "8.1", 0)) {
	return TCL_ERROR;
    }

    Tcl_CreateObjCommand(interp, "dde", DdeObjCmd, NULL, NULL);

    Tcl_CreateExitHandler(DdeExitProc, NULL);
    return Tcl_PkgProvide(interp, TCL_DDE_PACKAGE_NAME, TCL_DDE_VERSION);
}

/*
 *----------------------------------------------------------------------
 *
527
528
529
530
531
532
533

534
535
536
537
538
539
540
    Tcl_Obj *returnPackagePtr;
    int result = TCL_OK;

    if (riPtr->handlerPtr == NULL && Tcl_IsSafe(riPtr->interp)) {
	Tcl_SetObjResult(riPtr->interp, Tcl_NewStringObj("permission denied: "
		"a handler procedure must be defined for use in a safe "
		"interp", -1));

	result = TCL_ERROR;
    }

    if (riPtr->handlerPtr != NULL) {
	/*
	 * Add the dde request data to the handler proc list.
	 */







>







524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
    Tcl_Obj *returnPackagePtr;
    int result = TCL_OK;

    if (riPtr->handlerPtr == NULL && Tcl_IsSafe(riPtr->interp)) {
	Tcl_SetObjResult(riPtr->interp, Tcl_NewStringObj("permission denied: "
		"a handler procedure must be defined for use in a safe "
		"interp", -1));
	Tcl_SetErrorCode(riPtr->interp, "TCL", "DDE", "SECURITY_CHECK", NULL);
	result = TCL_ERROR;
    }

    if (riPtr->handlerPtr != NULL) {
	/*
	 * Add the dde request data to the handler proc list.
	 */
894
895
896
897
898
899
900

901
902
903
904
905
906
907
    DdeFreeStringHandle(ddeInstance, ddeService);
    DdeFreeStringHandle(ddeInstance, ddeTopic);

    if (ddeConv == (HCONV) NULL) {
	if (interp != NULL) {
	    Tcl_AppendResult(interp, "no registered server named \"",
		    name, "\"", NULL);

	}
	return TCL_ERROR;
    }

    *ddeConvPtr = ddeConv;
    return TCL_OK;
}







>







892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
    DdeFreeStringHandle(ddeInstance, ddeService);
    DdeFreeStringHandle(ddeInstance, ddeTopic);

    if (ddeConv == (HCONV) NULL) {
	if (interp != NULL) {
	    Tcl_AppendResult(interp, "no registered server named \"",
		    name, "\"", NULL);
	    Tcl_SetErrorCode(interp, "TCL", "DDE", "NO_SERVER", NULL);
	}
	return TCL_ERROR;
    }

    *ddeConvPtr = ddeConv;
    return TCL_OK;
}
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
 *----------------------------------------------------------------------
 */

static void
SetDdeError(
    Tcl_Interp *interp)	    /* The interp to put the message in. */
{
    const char *errorMessage;

    switch (DdeGetLastError(ddeInstance)) {
    case DMLERR_DATAACKTIMEOUT:
    case DMLERR_EXECACKTIMEOUT:
    case DMLERR_POKEACKTIMEOUT:
	errorMessage = "remote interpreter did not respond";

	break;
    case DMLERR_BUSY:
	errorMessage = "remote server is busy";

	break;
    case DMLERR_NOTPROCESSED:
	errorMessage = "remote server cannot handle this command";

	break;
    default:
	errorMessage = "dde command failed";

    }

    Tcl_SetObjResult(interp, Tcl_NewStringObj(errorMessage, -1));

}

/*
 *----------------------------------------------------------------------
 *
 * DdeObjCmd --
 *







|






>



>



>



>



>







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
 *----------------------------------------------------------------------
 */

static void
SetDdeError(
    Tcl_Interp *interp)	    /* The interp to put the message in. */
{
    const char *errorMessage, *errorCode;

    switch (DdeGetLastError(ddeInstance)) {
    case DMLERR_DATAACKTIMEOUT:
    case DMLERR_EXECACKTIMEOUT:
    case DMLERR_POKEACKTIMEOUT:
	errorMessage = "remote interpreter did not respond";
	errorCode = "TIMEOUT";
	break;
    case DMLERR_BUSY:
	errorMessage = "remote server is busy";
	errorCode = "BUSY";
	break;
    case DMLERR_NOTPROCESSED:
	errorMessage = "remote server cannot handle this command";
	errorCode = "NOCANDO";
	break;
    default:
	errorMessage = "dde command failed";
	errorCode = "FAILED";
    }

    Tcl_SetObjResult(interp, Tcl_NewStringObj(errorMessage, -1));
    Tcl_SetErrorCode(interp, "TCL", "DDE", errorCode, NULL);
}

/*
 *----------------------------------------------------------------------
 *
 * DdeObjCmd --
 *
1351
1352
1353
1354
1355
1356
1357

1358
1359
1360
1361
1362
1363
1364
	int dataLength;
	BYTE *dataString = (BYTE *) Tcl_GetStringFromObj(
		objv[firstArg + 2], &dataLength);

	if (dataLength == 0) {
	    Tcl_SetObjResult(interp,
		    Tcl_NewStringObj("cannot execute null data", -1));

	    result = TCL_ERROR;
	    break;
	}
	hConv = DdeConnect(ddeInstance, ddeService, ddeTopic, NULL);
	DdeFreeStringHandle(ddeInstance, ddeService);
	DdeFreeStringHandle(ddeInstance, ddeTopic);








>







1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
	int dataLength;
	BYTE *dataString = (BYTE *) Tcl_GetStringFromObj(
		objv[firstArg + 2], &dataLength);

	if (dataLength == 0) {
	    Tcl_SetObjResult(interp,
		    Tcl_NewStringObj("cannot execute null data", -1));
	    Tcl_SetErrorCode(interp, "TCL", "DDE", "NULL", NULL);
	    result = TCL_ERROR;
	    break;
	}
	hConv = DdeConnect(ddeInstance, ddeService, ddeTopic, NULL);
	DdeFreeStringHandle(ddeInstance, ddeService);
	DdeFreeStringHandle(ddeInstance, ddeTopic);

1393
1394
1395
1396
1397
1398
1399

1400
1401
1402
1403
1404
1405
1406
    case DDE_REQUEST: {
	const char *itemString = Tcl_GetStringFromObj(objv[firstArg + 2],
		&length);

	if (length == 0) {
	    Tcl_SetObjResult(interp,
		    Tcl_NewStringObj("cannot request value of null data", -1));

	    result = TCL_ERROR;
	    goto cleanup;
	}
	hConv = DdeConnect(ddeInstance, ddeService, ddeTopic, NULL);
	DdeFreeStringHandle(ddeInstance, ddeService);
	DdeFreeStringHandle(ddeInstance, ddeTopic);








>







1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
    case DDE_REQUEST: {
	const char *itemString = Tcl_GetStringFromObj(objv[firstArg + 2],
		&length);

	if (length == 0) {
	    Tcl_SetObjResult(interp,
		    Tcl_NewStringObj("cannot request value of null data", -1));
	    Tcl_SetErrorCode(interp, "TCL", "DDE", "NULL", NULL);
	    result = TCL_ERROR;
	    goto cleanup;
	}
	hConv = DdeConnect(ddeInstance, ddeService, ddeTopic, NULL);
	DdeFreeStringHandle(ddeInstance, ddeService);
	DdeFreeStringHandle(ddeInstance, ddeTopic);

1443
1444
1445
1446
1447
1448
1449

1450
1451
1452
1453
1454
1455
1456
	const char *itemString = Tcl_GetStringFromObj(objv[firstArg + 2],
		&length);
	BYTE *dataString;

	if (length == 0) {
	    Tcl_SetObjResult(interp,
		    Tcl_NewStringObj("cannot have a null item", -1));

	    result = TCL_ERROR;
	    goto cleanup;
	}
	dataString = (BYTE *) Tcl_GetStringFromObj(objv[firstArg + 3],
		&length);

	hConv = DdeConnect(ddeInstance, ddeService, ddeTopic, NULL);







>







1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
	const char *itemString = Tcl_GetStringFromObj(objv[firstArg + 2],
		&length);
	BYTE *dataString;

	if (length == 0) {
	    Tcl_SetObjResult(interp,
		    Tcl_NewStringObj("cannot have a null item", -1));
	    Tcl_SetErrorCode(interp, "TCL", "DDE", "NULL", NULL);
	    result = TCL_ERROR;
	    goto cleanup;
	}
	dataString = (BYTE *) Tcl_GetStringFromObj(objv[firstArg + 3],
		&length);

	hConv = DdeConnect(ddeInstance, ddeService, ddeTopic, NULL);
1485
1486
1487
1488
1489
1490
1491

1492
1493
1494
1495
1496
1497
1498
    case DDE_EVAL: {
	RegisteredInterp *riPtr;
	ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);

	if (serviceName == NULL) {
	    Tcl_SetObjResult(interp,
		    Tcl_NewStringObj("invalid service name \"\"", -1));

	    result = TCL_ERROR;
	    goto cleanup;
	}

	objc -= (async + 3);
	objv += (async + 3);








>







1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
    case DDE_EVAL: {
	RegisteredInterp *riPtr;
	ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);

	if (serviceName == NULL) {
	    Tcl_SetObjResult(interp,
		    Tcl_NewStringObj("invalid service name \"\"", -1));
	    Tcl_SetErrorCode(interp, "TCL", "DDE", "NO_SERVER", NULL);
	    result = TCL_ERROR;
	    goto cleanup;
	}

	objc -= (async + 3);
	objv += (async + 3);

1532
1533
1534
1535
1536
1537
1538


1539
1540
1541
1542
1543
1544
1545
	     * referring to deallocated objects.
	     */

	    if (Tcl_IsSafe(riPtr->interp) && riPtr->handlerPtr == NULL) {
		Tcl_SetResult(riPtr->interp, "permission denied: "
			"a handler procedure must be defined for use in "
			"a safe interp", TCL_STATIC);


		result = TCL_ERROR;
	    }

	    if (result == TCL_OK) {
		if (objc == 1)
		    objPtr = objv[0];
		else {







>
>







1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
	     * referring to deallocated objects.
	     */

	    if (Tcl_IsSafe(riPtr->interp) && riPtr->handlerPtr == NULL) {
		Tcl_SetResult(riPtr->interp, "permission denied: "
			"a handler procedure must be defined for use in "
			"a safe interp", TCL_STATIC);
		Tcl_SetErrorCode(interp, "TCL", "DDE", "SECURITY_CHECK",
			NULL);
		result = TCL_ERROR;
	    }

	    if (result == TCL_OK) {
		if (objc == 1)
		    objPtr = objv[0];
		else {
1596
1597
1598
1599
1600
1601
1602

1603
1604
1605
1606
1607
1608
1609
	     */

	    if (MakeDdeConnection(interp, serviceName, &hConv) != TCL_OK) {
	    invalidServerResponse:
		Tcl_SetObjResult(interp,
			Tcl_NewStringObj("invalid data returned from server",
			-1));

		result = TCL_ERROR;
		goto cleanup;
	    }

	    objPtr = Tcl_ConcatObj(objc, objv);
	    string = Tcl_GetStringFromObj(objPtr, &length);
	    ddeItemData = DdeCreateDataHandle(ddeInstance,







>







1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
	     */

	    if (MakeDdeConnection(interp, serviceName, &hConv) != TCL_OK) {
	    invalidServerResponse:
		Tcl_SetObjResult(interp,
			Tcl_NewStringObj("invalid data returned from server",
			-1));
		Tcl_SetErrorCode(interp, "TCL", "DDE", "BAD_RESPONSE", NULL);
		result = TCL_ERROR;
		goto cleanup;
	    }

	    objPtr = Tcl_ConcatObj(objc, objv);
	    string = Tcl_GetStringFromObj(objPtr, &length);
	    ddeItemData = DdeCreateDataHandle(ddeInstance,

Changes to win/tclWinFCmd.c.

1649
1650
1651
1652
1653
1654
1655


1656
1657
1658
1659
1660
1661
1662
    splitPath = Tcl_FSSplitPath(fileName, &pathc);

    if (splitPath == NULL || pathc == 0) {
	if (interp != NULL) {
	    Tcl_AppendResult(interp, "could not read \"",
		    Tcl_GetString(fileName), "\": no such file or directory",
		    (char *) NULL);


	}
	goto cleanup;
    }

    /*
     * We will decrement this again at the end.	 It is safer to do this in
     * case any of the calls below retain a reference to splitPath.







>
>







1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
    splitPath = Tcl_FSSplitPath(fileName, &pathc);

    if (splitPath == NULL || pathc == 0) {
	if (interp != NULL) {
	    Tcl_AppendResult(interp, "could not read \"",
		    Tcl_GetString(fileName), "\": no such file or directory",
		    (char *) NULL);
	    errno = ENOENT;
	    Tcl_PosixError(interp);
	}
	goto cleanup;
    }

    /*
     * We will decrement this again at the end.	 It is safer to do this in
     * case any of the calls below retain a reference to splitPath.
1940
1941
1942
1943
1944
1945
1946


1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
    int objIndex,		/* The index of the attribute. */
    Tcl_Obj *fileName,		/* The name of the file. */
    Tcl_Obj *attributePtr)	/* The new value of the attribute. */
{
    Tcl_AppendResult(interp, "cannot set attribute \"",
	    tclpFileAttrStrings[objIndex], "\" for file \"",
	    Tcl_GetString(fileName), "\": attribute is readonly", NULL);


    return TCL_ERROR;
}


/*
 *---------------------------------------------------------------------------
 *
 * TclpObjListVolumes --
 *
 *	Lists the currently mounted volumes







>
>


<







1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952

1953
1954
1955
1956
1957
1958
1959
    int objIndex,		/* The index of the attribute. */
    Tcl_Obj *fileName,		/* The name of the file. */
    Tcl_Obj *attributePtr)	/* The new value of the attribute. */
{
    Tcl_AppendResult(interp, "cannot set attribute \"",
	    tclpFileAttrStrings[objIndex], "\" for file \"",
	    Tcl_GetString(fileName), "\": attribute is readonly", NULL);
    errno = EINVAL;
    Tcl_PosixError(interp);
    return TCL_ERROR;
}


/*
 *---------------------------------------------------------------------------
 *
 * TclpObjListVolumes --
 *
 *	Lists the currently mounted volumes

Changes to win/tclWinFile.c.

8
9
10
11
12
13
14



15
16
17
18
19
20
21
 *
 * Copyright (c) 1995-1998 Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution of
 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
 */




#include "tclWinInt.h"
#include "tclFileSystem.h"
#include <winioctl.h>
#include <sys/stat.h>
#include <shlobj.h>
#include <lm.h>		/* For TclpGetUserHome(). */








>
>
>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 *
 * Copyright (c) 1995-1998 Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution of
 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
 */

#ifndef _WIN64
#   define _USE_32BIT_TIME_T
#endif
#include "tclWinInt.h"
#include "tclFileSystem.h"
#include <winioctl.h>
#include <sys/stat.h>
#include <shlobj.h>
#include <lm.h>		/* For TclpGetUserHome(). */

245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261

	TclWinConvertError(GetLastError());
    } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) == 0) {
	/*
	 * It is a file.
	 */

	if (CreateHardLink == NULL) {
	    Tcl_SetErrno(ENOTDIR);
	} else if (linkAction & TCL_CREATE_HARD_LINK) {
	    if (CreateHardLink(linkSourcePath, linkTargetPath, NULL)) {
		/*
		 * Success!
		 */

		return 0;
	    }







<
<
|







248
249
250
251
252
253
254


255
256
257
258
259
260
261
262

	TclWinConvertError(GetLastError());
    } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) == 0) {
	/*
	 * It is a file.
	 */



	if (linkAction & TCL_CREATE_HARD_LINK) {
	    if (CreateHardLink(linkSourcePath, linkTargetPath, NULL)) {
		/*
		 * Success!
		 */

		return 0;
	    }
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
	if (norm != NULL) {
	    /*
	     * Match a single file directly.
	     */

	    int len;
	    DWORD attr;

	    const char *str = Tcl_GetStringFromObj(norm,&len);

	    native = Tcl_FSGetNativePath(pathPtr);

	    if (GetFileAttributesEx == NULL) {
		attr = GetFileAttributes(native);
		if (attr == INVALID_FILE_ATTRIBUTES) {
		    return TCL_OK;
		}
	    } else {
		WIN32_FILE_ATTRIBUTE_DATA data;

		if (GetFileAttributesEx(native,
			GetFileExInfoStandard, &data) != TRUE) {
		    return TCL_OK;
		}
		attr = data.dwFileAttributes;
	    }

	    if (NativeMatchType(WinIsDrive(str,len), attr, native, types)) {
		Tcl_ListObjAppendElement(interp, resultPtr, pathPtr);
	    }
	}
	return TCL_OK;
    } else {







>




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







919
920
921
922
923
924
925
926
927
928
929
930








931
932
933
934
935

936
937
938
939
940
941
942
	if (norm != NULL) {
	    /*
	     * Match a single file directly.
	     */

	    int len;
	    DWORD attr;
	    WIN32_FILE_ATTRIBUTE_DATA data;
	    const char *str = Tcl_GetStringFromObj(norm,&len);

	    native = Tcl_FSGetNativePath(pathPtr);









	    if (GetFileAttributesEx(native,
		    GetFileExInfoStandard, &data) != TRUE) {
		return TCL_OK;
	    }
	    attr = data.dwFileAttributes;


	    if (NativeMatchType(WinIsDrive(str,len), attr, native, types)) {
		Tcl_ListObjAppendElement(interp, resultPtr, pathPtr);
	    }
	}
	return TCL_OK;
    } else {
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031

	    dirName = Tcl_DStringAppend(&dsOrig, pattern, -1);
	} else {
	    dirName = Tcl_DStringAppend(&dsOrig, "*.*", 3);
	}

	native = Tcl_WinUtfToTChar(dirName, -1, &ds);
	if (FindFirstFileEx == NULL || (types == NULL)
		|| (types->type != TCL_GLOB_TYPE_DIR)) {
	    handle = FindFirstFile(native, &data);
	} else {
	    /*
	     * We can be more efficient, for pure directory requests.
	     */

	    handle = FindFirstFileEx(native,







<
|







1009
1010
1011
1012
1013
1014
1015

1016
1017
1018
1019
1020
1021
1022
1023

	    dirName = Tcl_DStringAppend(&dsOrig, pattern, -1);
	} else {
	    dirName = Tcl_DStringAppend(&dsOrig, "*.*", 3);
	}

	native = Tcl_WinUtfToTChar(dirName, -1, &ds);

	if ((types == NULL) || (types->type != TCL_GLOB_TYPE_DIR)) {
	    handle = FindFirstFile(native, &data);
	} else {
	    /*
	     * We can be more efficient, for pure directory requests.
	     */

	    handle = FindFirstFileEx(native,

Changes to win/tclWinInt.h.

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

#ifdef _WIN64
#         define TCL_I_MODIFIER        "I"
#else
#         define TCL_I_MODIFIER        ""
#endif

/*
 * The following structure keeps track of whether we are using the
 * multi-byte or the wide-character interfaces to the operating system.
 * System calls should be made through the following function table.
 */

typedef union {
    WIN32_FIND_DATAA a;
    WIN32_FIND_DATAW w;
} WIN32_FIND_DATAT;

typedef struct TclWinProcs {
    int useWide;
    BOOL (WINAPI *buildCommDCBProc)(const TCHAR *, LPDCB);
    TCHAR * (WINAPI *charLowerProc)(TCHAR *);
    BOOL (WINAPI *copyFileProc)(const TCHAR *, const TCHAR *, BOOL);
    BOOL (WINAPI *createDirectoryProc)(const TCHAR *, LPSECURITY_ATTRIBUTES);
    HANDLE (WINAPI *createFileProc)(const TCHAR *, DWORD, DWORD,
	    LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE);
    BOOL (WINAPI *createProcessProc)(const TCHAR *, TCHAR *,
	    LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES, BOOL, DWORD,
	    LPVOID, const TCHAR *, LPSTARTUPINFO, LPPROCESS_INFORMATION);
    BOOL (WINAPI *deleteFileProc)(const TCHAR *);
    HANDLE (WINAPI *findFirstFileProc)(const TCHAR *, WIN32_FIND_DATAT *);
    BOOL (WINAPI *findNextFileProc)(HANDLE, WIN32_FIND_DATAT *);
    BOOL (WINAPI *getComputerNameProc)(TCHAR *, LPDWORD);
    DWORD (WINAPI *getCurrentDirectoryProc)(DWORD, TCHAR *);
    DWORD (WINAPI *getFileAttributesProc)(const TCHAR *);
    DWORD (WINAPI *getFullPathNameProc)(const TCHAR *, DWORD, TCHAR *,
	    TCHAR **);
    DWORD (WINAPI *getShortPathNameProc)(const TCHAR *, TCHAR *, DWORD);
    UINT (WINAPI *getTempFileNameProc)(const TCHAR *, const TCHAR *, UINT,
	    TCHAR *);
    DWORD (WINAPI *getTempPathProc)(DWORD, TCHAR *);
    BOOL (WINAPI *getVolumeInformationProc)(const TCHAR *, TCHAR *, DWORD,
	    LPDWORD, LPDWORD, LPDWORD, TCHAR *, DWORD);
    HINSTANCE (WINAPI *loadLibraryExProc)(const TCHAR *, HANDLE, DWORD);
    BOOL (WINAPI *moveFileProc)(const TCHAR *, const TCHAR *);
    BOOL (WINAPI *removeDirectoryProc)(const TCHAR *);
    DWORD (WINAPI *searchPathProc)(const TCHAR *, const TCHAR *,
	    const TCHAR *, DWORD, TCHAR *, TCHAR **);
    BOOL (WINAPI *setCurrentDirectoryProc)(const TCHAR *);
    BOOL (WINAPI *setFileAttributesProc)(const TCHAR *, DWORD);
    /*
     * These two function pointers will only be set when
     * Tcl_FindExecutable is called.  If you don't ever call that
     * function, the application will crash whenever WinTcl tries to call
     * functions through these null pointers.  That is not a bug in Tcl
     * -- Tcl_FindExecutable is obligatory in recent Tcl releases.
     */
    BOOL (WINAPI *getFileAttributesExProc)(const TCHAR *,
	    GET_FILEEX_INFO_LEVELS, LPVOID);
    BOOL (WINAPI *createHardLinkProc)(const TCHAR *, const TCHAR *,
	    LPSECURITY_ATTRIBUTES);

    /* These two are also NULL at start; see comment above */
    HANDLE (WINAPI *findFirstFileExProc)(const TCHAR *, UINT,
	    LPVOID, UINT, LPVOID, DWORD);
    BOOL (WINAPI *getVolumeNameForVMPProc)(const TCHAR *, TCHAR *, DWORD);
    DWORD (WINAPI *getLongPathNameProc)(const TCHAR *, TCHAR *, DWORD);
    /*
     * These six are for the security sdk to get correct file
     * permissions on NT, 2000, XP, etc.  On 95,98,ME they are
     * always null.
     */
    BOOL (WINAPI *getFileSecurityProc)(LPCTSTR, SECURITY_INFORMATION,
	    PSECURITY_DESCRIPTOR, DWORD, LPDWORD);
    BOOL (WINAPI *impersonateSelfProc) (SECURITY_IMPERSONATION_LEVEL);
    BOOL (WINAPI *openThreadTokenProc) (HANDLE, DWORD, BOOL, PHANDLE);
    BOOL (WINAPI *revertToSelfProc) (void);
    void (WINAPI *mapGenericMaskProc) (PDWORD, PGENERIC_MAPPING);
    BOOL (WINAPI *accessCheckProc)(PSECURITY_DESCRIPTOR, HANDLE, DWORD,
		    PGENERIC_MAPPING, PPRIVILEGE_SET, LPDWORD, LPDWORD, LPBOOL);
    /*
     * Unicode console support. WriteConsole and ReadConsole
     */
    BOOL (WINAPI *readConsoleProc)(HANDLE, LPVOID, DWORD, LPDWORD, LPVOID);
    BOOL (WINAPI *writeConsoleProc)(HANDLE, const void *, DWORD, LPDWORD,
	    LPVOID);
    BOOL (WINAPI *getUserName)(LPTSTR, LPDWORD);
    const TCHAR *(*utf2tchar)(const char *, int, Tcl_DString *);
    const char *(*tchar2utf)(const TCHAR *, int, Tcl_DString *);
} TclWinProcs;

MODULE_SCOPE const TclWinProcs *const tclWinProcs;

/*
 * Declarations of functions that are not accessible by way of the
 * stubs table.
 */

MODULE_SCOPE char	TclWinDriveLetterForVolMountPoint(
			    const TCHAR *mountPoint);







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







29
30
31
32
33
34
35






















































































36
37
38
39
40
41
42

#ifdef _WIN64
#         define TCL_I_MODIFIER        "I"
#else
#         define TCL_I_MODIFIER        ""
#endif























































































/*
 * Declarations of functions that are not accessible by way of the
 * stubs table.
 */

MODULE_SCOPE char	TclWinDriveLetterForVolMountPoint(
			    const TCHAR *mountPoint);

Changes to win/tclWinLoad.c.

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
	 * because Windows seems to only return ERROR_MOD_NOT_FOUND for just
	 * about any problem, but it's better than nothing. It'd be even
	 * better if there was a way to get what DLLs
	 */

	switch (lastError) {
	case ERROR_MOD_NOT_FOUND:


	case ERROR_DLL_NOT_FOUND:


	    Tcl_AppendResult(interp, "this library or a dependent library"
		    " could not be found in library path", NULL);
	    break;
	case ERROR_PROC_NOT_FOUND:

	    Tcl_AppendResult(interp, "A function specified in the import"
		    " table could not be resolved by the system.  Windows"
		    " is not telling which one, I'm sorry.", NULL);
	    break;
	case ERROR_INVALID_DLL:

	    Tcl_AppendResult(interp, "this library or a dependent library"
		    " is damaged", NULL);
	    break;
	case ERROR_DLL_INIT_FAILED:

	    Tcl_AppendResult(interp, "the library initialization"
		    " routine failed", NULL);
	    break;
	default:
	    TclWinConvertError(lastError);
	    Tcl_AppendResult(interp, Tcl_PosixError(interp), NULL);
	}
	return TCL_ERROR;

    } else {




	handlePtr = ckalloc(sizeof(struct Tcl_LoadHandle_));
	handlePtr->clientData = (ClientData) hInstance;
	handlePtr->findSymbolProcPtr = &FindSymbol;
	handlePtr->unloadFileProcPtr = &UnloadFile;
	*loadHandle = handlePtr;
	*unloadProcPtr = &UnloadFile;
    }
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * FindSymbol --







>
>

>
>




>





>




>








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







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
	 * because Windows seems to only return ERROR_MOD_NOT_FOUND for just
	 * about any problem, but it's better than nothing. It'd be even
	 * better if there was a way to get what DLLs
	 */

	switch (lastError) {
	case ERROR_MOD_NOT_FOUND:
	    Tcl_SetErrorCode(interp, "WIN_LOAD", "MOD_NOT_FOUND", NULL);
	    goto notFoundMsg;
	case ERROR_DLL_NOT_FOUND:
	    Tcl_SetErrorCode(interp, "WIN_LOAD", "DLL_NOT_FOUND", NULL);
	notFoundMsg:
	    Tcl_AppendResult(interp, "this library or a dependent library"
		    " could not be found in library path", NULL);
	    break;
	case ERROR_PROC_NOT_FOUND:
	    Tcl_SetErrorCode(interp, "WIN_LOAD", "PROC_NOT_FOUND", NULL);
	    Tcl_AppendResult(interp, "A function specified in the import"
		    " table could not be resolved by the system.  Windows"
		    " is not telling which one, I'm sorry.", NULL);
	    break;
	case ERROR_INVALID_DLL:
	    Tcl_SetErrorCode(interp, "WIN_LOAD", "INVALID_DLL", NULL);
	    Tcl_AppendResult(interp, "this library or a dependent library"
		    " is damaged", NULL);
	    break;
	case ERROR_DLL_INIT_FAILED:
	    Tcl_SetErrorCode(interp, "WIN_LOAD", "DLL_INIT_FAILED", NULL);
	    Tcl_AppendResult(interp, "the library initialization"
		    " routine failed", NULL);
	    break;
	default:
	    TclWinConvertError(lastError);
	    Tcl_AppendResult(interp, Tcl_PosixError(interp), NULL);
	}
	return TCL_ERROR;
    }

    /*
     * Succeded; package everything up for Tcl.
     */

    handlePtr = ckalloc(sizeof(struct Tcl_LoadHandle_));
    handlePtr->clientData = (ClientData) hInstance;
    handlePtr->findSymbolProcPtr = &FindSymbol;
    handlePtr->unloadFileProcPtr = &UnloadFile;
    *loadHandle = handlePtr;
    *unloadProcPtr = &UnloadFile;

    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * FindSymbol --
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
		wcscpy(dllDirectoryName, name);
	    }
	}
	Tcl_MutexUnlock(&loadMutex);
    }
    if (dllDirectoryName == NULL) {
	Tcl_AppendResult(interp, "couldn't create temporary directory: ",
			 Tcl_PosixError(interp), NULL);
    }
    fileName = TclpNativeToNormalized(dllDirectoryName);
    tail = TclPathPart(interp, path, TCL_PATH_TAIL);
    if (tail == NULL) {
	Tcl_DecrRefCount(fileName);
	return NULL;
    } else {







|







351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
		wcscpy(dllDirectoryName, name);
	    }
	}
	Tcl_MutexUnlock(&loadMutex);
    }
    if (dllDirectoryName == NULL) {
	Tcl_AppendResult(interp, "couldn't create temporary directory: ",
		Tcl_PosixError(interp), NULL);
    }
    fileName = TclpNativeToNormalized(dllDirectoryName);
    tail = TclPathPart(interp, path, TCL_PATH_TAIL);
    if (tail == NULL) {
	Tcl_DecrRefCount(fileName);
	return NULL;
    } else {

Changes to win/tclWinPipe.c.

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
PipeSetupProc(
    ClientData data,		/* Not used. */
    int flags)			/* Event flags as passed to Tcl_DoOneEvent. */
{
    PipeInfo *infoPtr;
    Tcl_Time blockTime = { 0, 0 };
    int block = 1;
    WinFile *filePtr;
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);

    if (!(flags & TCL_FILE_EVENTS)) {
	return;
    }

    /*
     * Look to see if any events are already pending.  If they are, poll.
     */

    for (infoPtr = tsdPtr->firstPipePtr; infoPtr != NULL;
	    infoPtr = infoPtr->nextPtr) {
	if (infoPtr->watchMask & TCL_WRITABLE) {
	    filePtr = (WinFile*) infoPtr->writeFile;
	    if (WaitForSingleObject(infoPtr->writable, 0) != WAIT_TIMEOUT) {
		block = 0;
	    }
	}
	if (infoPtr->watchMask & TCL_READABLE) {
	    filePtr = (WinFile*) infoPtr->readFile;
	    if (WaitForRead(infoPtr, 0) >= 0) {
		block = 0;
	    }
	}
    }
    if (!block) {
	Tcl_SetMaxBlockTime(&blockTime);







<













<





<







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
PipeSetupProc(
    ClientData data,		/* Not used. */
    int flags)			/* Event flags as passed to Tcl_DoOneEvent. */
{
    PipeInfo *infoPtr;
    Tcl_Time blockTime = { 0, 0 };
    int block = 1;

    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);

    if (!(flags & TCL_FILE_EVENTS)) {
	return;
    }

    /*
     * Look to see if any events are already pending.  If they are, poll.
     */

    for (infoPtr = tsdPtr->firstPipePtr; infoPtr != NULL;
	    infoPtr = infoPtr->nextPtr) {
	if (infoPtr->watchMask & TCL_WRITABLE) {

	    if (WaitForSingleObject(infoPtr->writable, 0) != WAIT_TIMEOUT) {
		block = 0;
	    }
	}
	if (infoPtr->watchMask & TCL_READABLE) {

	    if (WaitForRead(infoPtr, 0) >= 0) {
		block = 0;
	    }
	}
    }
    if (!block) {
	Tcl_SetMaxBlockTime(&blockTime);
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
static void
PipeCheckProc(
    ClientData data,		/* Not used. */
    int flags)			/* Event flags as passed to Tcl_DoOneEvent. */
{
    PipeInfo *infoPtr;
    PipeEvent *evPtr;
    WinFile *filePtr;
    int needEvent;
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);

    if (!(flags & TCL_FILE_EVENTS)) {
	return;
    }








<







368
369
370
371
372
373
374

375
376
377
378
379
380
381
static void
PipeCheckProc(
    ClientData data,		/* Not used. */
    int flags)			/* Event flags as passed to Tcl_DoOneEvent. */
{
    PipeInfo *infoPtr;
    PipeEvent *evPtr;

    int needEvent;
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);

    if (!(flags & TCL_FILE_EVENTS)) {
	return;
    }

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

	/*
	 * Queue an event if the pipe is signaled for reading or writing.
	 */

	needEvent = 0;
	filePtr = (WinFile*) infoPtr->writeFile;
	if ((infoPtr->watchMask & TCL_WRITABLE) &&
		(WaitForSingleObject(infoPtr->writable, 0) != WAIT_TIMEOUT)) {
	    needEvent = 1;
	}

	filePtr = (WinFile*) infoPtr->readFile;
	if ((infoPtr->watchMask & TCL_READABLE) &&
		(WaitForRead(infoPtr, 0) >= 0)) {
	    needEvent = 1;
	}

	if (needEvent) {
	    infoPtr->flags |= PIPE_PENDING;







<





<







390
391
392
393
394
395
396

397
398
399
400
401

402
403
404
405
406
407
408
	}

	/*
	 * Queue an event if the pipe is signaled for reading or writing.
	 */

	needEvent = 0;

	if ((infoPtr->watchMask & TCL_WRITABLE) &&
		(WaitForSingleObject(infoPtr->writable, 0) != WAIT_TIMEOUT)) {
	    needEvent = 1;
	}


	if ((infoPtr->watchMask & TCL_READABLE) &&
		(WaitForRead(infoPtr, 0) >= 0)) {
	    needEvent = 1;
	}

	if (needEvent) {
	    infoPtr->flags |= PIPE_PENDING;
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
 */

static int
TempFileName(
    TCHAR name[MAX_PATH])	/* Buffer in which name for temporary file
				 * gets stored. */
{
    TCHAR *prefix = TEXT("TCL");
    if (GetTempPath(MAX_PATH, name) != 0) {
	if (GetTempFileName(name, prefix, 0, name) != 0) {
	    return 1;
	}
    }
    name[0] = '.';
    name[1] = '\0';







|







465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
 */

static int
TempFileName(
    TCHAR name[MAX_PATH])	/* Buffer in which name for temporary file
				 * gets stored. */
{
    const TCHAR *prefix = TEXT("TCL");
    if (GetTempPath(MAX_PATH, name) != 0) {
	if (GetTempFileName(name, prefix, 0, name) != 0) {
	    return 1;
	}
    }
    name[0] = '.';
    name[1] = '\0';
1132
1133
1134
1135
1136
1137
1138


1139
1140
1141
1142
1143
1144
1145
	    createFlags = DETACHED_PROCESS;
	}

	if (applType == APPL_DOS) {
	    Tcl_AppendResult(interp,
		    "DOS application process not supported on this platform",
		    (char *) NULL);


	    goto end;
	}
    }

    /*
     * cmdLine gets the full command line used to invoke the executable,
     * including the name of the executable itself. The command line arguments







>
>







1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
	    createFlags = DETACHED_PROCESS;
	}

	if (applType == APPL_DOS) {
	    Tcl_AppendResult(interp,
		    "DOS application process not supported on this platform",
		    (char *) NULL);
	    Tcl_SetErrorCode(interp, "TCL", "OPERATION", "EXEC", "DOS_APP",
		    NULL);
	    goto end;
	}
    }

    /*
     * cmdLine gets the full command line used to invoke the executable,
     * including the name of the executable itself. The command line arguments
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
PipeEventProc(
    Tcl_Event *evPtr,		/* Event to service. */
    int flags)			/* Flags that indicate what events to
				 * handle, such as TCL_FILE_EVENTS. */
{
    PipeEvent *pipeEvPtr = (PipeEvent *)evPtr;
    PipeInfo *infoPtr;
    WinFile *filePtr;
    int mask;
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);

    if (!(flags & TCL_FILE_EVENTS)) {
	return 0;
    }








<







2229
2230
2231
2232
2233
2234
2235

2236
2237
2238
2239
2240
2241
2242
PipeEventProc(
    Tcl_Event *evPtr,		/* Event to service. */
    int flags)			/* Flags that indicate what events to
				 * handle, such as TCL_FILE_EVENTS. */
{
    PipeEvent *pipeEvPtr = (PipeEvent *)evPtr;
    PipeInfo *infoPtr;

    int mask;
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);

    if (!(flags & TCL_FILE_EVENTS)) {
	return 0;
    }

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

    /*
     * Check to see if the pipe is readable. Note that we can't tell if a pipe
     * is writable, so we always report it as being writable unless we have
     * detected EOF.
     */

    filePtr = (WinFile*) ((PipeInfo*)infoPtr)->writeFile;
    mask = 0;
    if ((infoPtr->watchMask & TCL_WRITABLE) &&
	    (WaitForSingleObject(infoPtr->writable, 0) != WAIT_TIMEOUT)) {
	mask = TCL_WRITABLE;
    }

    filePtr = (WinFile*) ((PipeInfo*)infoPtr)->readFile;
    if ((infoPtr->watchMask & TCL_READABLE) && (WaitForRead(infoPtr,0) >= 0)) {
	if (infoPtr->readFlags & PIPE_EOF) {
	    mask = TCL_READABLE;
	} else {
	    mask |= TCL_READABLE;
	}
    }







<






<







2265
2266
2267
2268
2269
2270
2271

2272
2273
2274
2275
2276
2277

2278
2279
2280
2281
2282
2283
2284

    /*
     * Check to see if the pipe is readable. Note that we can't tell if a pipe
     * is writable, so we always report it as being writable unless we have
     * detected EOF.
     */


    mask = 0;
    if ((infoPtr->watchMask & TCL_WRITABLE) &&
	    (WaitForSingleObject(infoPtr->writable, 0) != WAIT_TIMEOUT)) {
	mask = TCL_WRITABLE;
    }


    if ((infoPtr->watchMask & TCL_READABLE) && (WaitForRead(infoPtr,0) >= 0)) {
	if (infoPtr->readFlags & PIPE_EOF) {
	    mask = TCL_READABLE;
	} else {
	    mask |= TCL_READABLE;
	}
    }
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
	const char *string = Tcl_GetStringFromObj(basenameObj, &length);

	Tcl_WinUtfToTChar(string, length, &buf);
	memcpy(namePtr, Tcl_DStringValue(&buf), Tcl_DStringLength(&buf));
	namePtr += Tcl_DStringLength(&buf);
	Tcl_DStringFree(&buf);
    } else {
	TCHAR *baseStr = TEXT("TCL");
	int length = 3 * sizeof(TCHAR);

	memcpy(namePtr, baseStr, length);
	namePtr += length;
    }
    counter = TclpGetClicks() % 65533;
    counter2 = 1024;			/* Only try this many times! Prevents







|







3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
	const char *string = Tcl_GetStringFromObj(basenameObj, &length);

	Tcl_WinUtfToTChar(string, length, &buf);
	memcpy(namePtr, Tcl_DStringValue(&buf), Tcl_DStringLength(&buf));
	namePtr += Tcl_DStringLength(&buf);
	Tcl_DStringFree(&buf);
    } else {
	const TCHAR *baseStr = TEXT("TCL");
	int length = 3 * sizeof(TCHAR);

	memcpy(namePtr, baseStr, length);
	namePtr += length;
    }
    counter = TclpGetClicks() % 65533;
    counter2 = 1024;			/* Only try this many times! Prevents

Changes to win/tclWinPort.h.

33
34
35
36
37
38
39



40
41
42
43
44
45
46

/*
 * Ask for the winsock function typedefs, also.
 */
#define INCL_WINSOCK_API_TYPEDEFS   1
#include <winsock2.h>
#include <ws2tcpip.h>




#ifdef CHECK_UNICODE_CALLS
#   define _UNICODE
#   define UNICODE
#   define __TCHAR_DEFINED
    typedef float *_TCHAR;
#   define _TCHAR_DEFINED







>
>
>







33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

/*
 * Ask for the winsock function typedefs, also.
 */
#define INCL_WINSOCK_API_TYPEDEFS   1
#include <winsock2.h>
#include <ws2tcpip.h>
#ifdef HAVE_WSPIAPI_H
#   include <wspiapi.h>
#endif

#ifdef CHECK_UNICODE_CALLS
#   define _UNICODE
#   define UNICODE
#   define __TCHAR_DEFINED
    typedef float *_TCHAR;
#   define _TCHAR_DEFINED
76
77
78
79
80
81
82



83
84
85
86
87
88
89
#include <malloc.h>
#include <process.h>
#include <signal.h>
#include <limits.h>

#ifdef __CYGWIN__
#   include <unistd.h>



#   ifndef _wcsicmp
#	define _wcsicmp wcscasecmp
#   endif
#else
#   ifndef strncasecmp
#	define strncasecmp strnicmp
#   endif







>
>
>







79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#include <malloc.h>
#include <process.h>
#include <signal.h>
#include <limits.h>

#ifdef __CYGWIN__
#   include <unistd.h>
#   ifndef _vsnprintf
#	define _vsnprintf vsnprintf
#   endif
#   ifndef _wcsicmp
#	define _wcsicmp wcscasecmp
#   endif
#else
#   ifndef strncasecmp
#	define strncasecmp strnicmp
#   endif
105
106
107
108
109
110
111

























112
113
114
115
116
117
118
#   else
#	include <sys/utime.h>
#   endif /* __BORLANDC__ */
#endif /* __MWERKS__ */

#include <time.h>


























/*
 * The following defines redefine the Windows Socket errors as
 * BSD errors so Tcl_PosixError can do the right thing.
 */

#ifndef ENOTEMPTY
#   define ENOTEMPTY 	41	/* Directory not empty */







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







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
#   else
#	include <sys/utime.h>
#   endif /* __BORLANDC__ */
#endif /* __MWERKS__ */

#include <time.h>

/*
 * Not all mingw32 versions have this struct.
 */
#if !defined(__BORLANDC__) && !defined(_MSC_VER) && !defined(_WIN64) && defined(HAVE_NO_STRUCT_STAT32I64)
  struct _stat32i64 {
    dev_t st_dev;
    ino_t st_ino;
    unsigned short st_mode;
    short st_nlink;
    short st_uid;
    short st_gid;
    dev_t st_rdev;
    __int64 st_size;
#ifdef __CYGWIN__
    struct {long tv_sec;} st_atim;
    struct {long tv_sec;} st_mtim;
    struct {long tv_sec;} st_ctim;
#else
    long st_atime;
    long st_mtime;
    long st_ctime;
#endif
  };
#endif

/*
 * The following defines redefine the Windows Socket errors as
 * BSD errors so Tcl_PosixError can do the right thing.
 */

#ifndef ENOTEMPTY
#   define ENOTEMPTY 	41	/* Directory not empty */
215
216
217
218
219
220
221

222
223
224
225
226
227
228
229
230
231
232
233
#endif
#ifndef EOPNOTSUPP
#   define EOPNOTSUPP	130	/* Operation not supported on socket */
#endif
#ifndef EOTHER
#   define EOTHER	131	/* Other error */
#endif

#ifndef EOVERFLOW
#   define EOVERFLOW	132	/* File too big */
#endif
#ifndef EOWNERDEAD
#   define EOWNERDEAD	133	/* File too big */
#endif
#ifndef EPROTO
#   define EPROTO	134	/* Protocol error */
#endif
#ifndef EPROTONOSUPPORT
#   define EPROTONOSUPPORT 135	/* Protocol not supported */
#endif







>
|
|
<

|







246
247
248
249
250
251
252
253
254
255

256
257
258
259
260
261
262
263
264
#endif
#ifndef EOPNOTSUPP
#   define EOPNOTSUPP	130	/* Operation not supported on socket */
#endif
#ifndef EOTHER
#   define EOTHER	131	/* Other error */
#endif
/* workaround for mingw-w64 bug 3407992 */
#undef EOVERFLOW
#define EOVERFLOW	132	/* File too big */

#ifndef EOWNERDEAD
#   define EOWNERDEAD	133	/* Owner dead */
#endif
#ifndef EPROTO
#   define EPROTO	134	/* Protocol error */
#endif
#ifndef EPROTONOSUPPORT
#   define EPROTONOSUPPORT 135	/* Protocol not supported */
#endif
419
420
421
422
423
424
425

426

427
428
429
430
431
432
433
 * Visual C++ has some odd names for common functions, so we need to
 * define a few macros to handle them.  Also, it defines EDEADLOCK and
 * EDEADLK as the same value, which confuses Tcl_ErrnoId().
 */

#if defined(_MSC_VER) || defined(__MINGW32__)
#   define environ _environ

#   define hypot _hypot

#   define exception _exception
#   undef EDEADLOCK
#   if defined(__MINGW32__) && !defined(__MSVCRT__)
#	define timezone _timezone
#   endif
#endif /* _MSC_VER || __MINGW32__ */








>
|
>







450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
 * Visual C++ has some odd names for common functions, so we need to
 * define a few macros to handle them.  Also, it defines EDEADLOCK and
 * EDEADLK as the same value, which confuses Tcl_ErrnoId().
 */

#if defined(_MSC_VER) || defined(__MINGW32__)
#   define environ _environ
#   if defined(_MSC_VER) && (_MSC_VER < 1600)
#	define hypot _hypot
#   endif
#   define exception _exception
#   undef EDEADLOCK
#   if defined(__MINGW32__) && !defined(__MSVCRT__)
#	define timezone _timezone
#   endif
#endif /* _MSC_VER || __MINGW32__ */

Changes to win/tclWinReg.c.

417
418
419
420
421
422
423

424
425
426
427
428
429
430
	ckfree(buffer);
	return TCL_ERROR;
    }

    if (*keyName == '\0') {
	Tcl_SetObjResult(interp,
		Tcl_NewStringObj("bad key: cannot delete root keys", -1));

	ckfree(buffer);
	return TCL_ERROR;
    }

    tail = strrchr(keyName, '\\');
    if (tail) {
	*tail++ = '\0';







>







417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
	ckfree(buffer);
	return TCL_ERROR;
    }

    if (*keyName == '\0') {
	Tcl_SetObjResult(interp,
		Tcl_NewStringObj("bad key: cannot delete root keys", -1));
	Tcl_SetErrorCode(interp, "WIN_REG", "DEL_ROOT_KEY", NULL);
	ckfree(buffer);
	return TCL_ERROR;
    }

    tail = strrchr(keyName, '\\');
    if (tail) {
	*tail++ = '\0';
1119
1120
1121
1122
1123
1124
1125

1126
1127
1128
1129
1130
1131
1132
	}
    } else {
	rootName = name;
    }
    if (!rootName) {
	Tcl_AppendResult(interp, "bad key \"", name,
		"\": must start with a valid root", NULL);

	return TCL_ERROR;
    }

    /*
     * Split the root into root and subkey portions.
     */








>







1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
	}
    } else {
	rootName = name;
    }
    if (!rootName) {
	Tcl_AppendResult(interp, "bad key \"", name,
		"\": must start with a valid root", NULL);
	Tcl_SetErrorCode(interp, "WIN_REG", "NO_ROOT_KEY", NULL);
	return TCL_ERROR;
    }

    /*
     * Split the root into root and subkey portions.
     */

Changes to win/tclWinSerial.c.

1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445

HANDLE
TclWinSerialReopen(
    HANDLE handle,
    const TCHAR *name,
    DWORD access)
{
    ThreadSpecificData *tsdPtr;

    tsdPtr = SerialInit();

    /*
     * Multithreaded I/O needs the overlapped flag set otherwise
     * ClearCommError blocks under Windows NT/2000 until serial output is
     * finished
     */








<
<
|







1429
1430
1431
1432
1433
1434
1435


1436
1437
1438
1439
1440
1441
1442
1443

HANDLE
TclWinSerialReopen(
    HANDLE handle,
    const TCHAR *name,
    DWORD access)
{


    SerialInit();

    /*
     * Multithreaded I/O needs the overlapped flag set otherwise
     * ClearCommError blocks under Windows NT/2000 until serial output is
     * finished
     */

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
    /*
     * Option -mode baud,parity,databits,stopbits
     */

    if ((len > 2) && (strncmp(optionName, "-mode", len) == 0)) {
	if (!GetCommState(infoPtr->handle, &dcb)) {
	    if (interp != NULL) {

		Tcl_AppendResult(interp, "can't get comm state", NULL);

	    }
	    return TCL_ERROR;
	}
	native = Tcl_WinUtfToTChar(value, -1, &ds);
	result = BuildCommDCB(native, &dcb);
	Tcl_DStringFree(&ds);

	if (result == FALSE) {
	    if (interp != NULL) {
		Tcl_AppendResult(interp, "bad value \"", value,
			"\" for -mode: should be baud,parity,data,stop", NULL);

	    }
	    return TCL_ERROR;
	}

	/*
	 * Default settings for serial communications.
	 */

	dcb.fBinary = TRUE;
	dcb.fErrorChar = FALSE;
	dcb.fNull = FALSE;
	dcb.fAbortOnError = FALSE;

	if (!SetCommState(infoPtr->handle, &dcb)) {
	    if (interp != NULL) {

		Tcl_AppendResult(interp, "can't set comm state", NULL);

	    }
	    return TCL_ERROR;
	}
	return TCL_OK;
    }

    /*
     * Option -handshake none|xonxoff|rtscts|dtrdsr
     */

    if ((len > 1) && (strncmp(optionName, "-handshake", len) == 0)) {
	if (!GetCommState(infoPtr->handle, &dcb)) {
	    if (interp != NULL) {

		Tcl_AppendResult(interp, "can't get comm state", NULL);

	    }
	    return TCL_ERROR;
	}

	/*
	 * Reset all handshake options. DTR and RTS are ON by default.
	 */







>
|
>











>















>
|
>













>
|
>







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
    /*
     * Option -mode baud,parity,databits,stopbits
     */

    if ((len > 2) && (strncmp(optionName, "-mode", len) == 0)) {
	if (!GetCommState(infoPtr->handle, &dcb)) {
	    if (interp != NULL) {
		TclWinConvertError(GetLastError());
		Tcl_AppendResult(interp, "can't get comm state: ",
			Tcl_PosixError(interp), NULL);
	    }
	    return TCL_ERROR;
	}
	native = Tcl_WinUtfToTChar(value, -1, &ds);
	result = BuildCommDCB(native, &dcb);
	Tcl_DStringFree(&ds);

	if (result == FALSE) {
	    if (interp != NULL) {
		Tcl_AppendResult(interp, "bad value \"", value,
			"\" for -mode: should be baud,parity,data,stop", NULL);
		Tcl_SetErrorCode(interp, "TCL", "VALUE", "SERIALMODE", NULL);
	    }
	    return TCL_ERROR;
	}

	/*
	 * Default settings for serial communications.
	 */

	dcb.fBinary = TRUE;
	dcb.fErrorChar = FALSE;
	dcb.fNull = FALSE;
	dcb.fAbortOnError = FALSE;

	if (!SetCommState(infoPtr->handle, &dcb)) {
	    if (interp != NULL) {
		TclWinConvertError(GetLastError());
		Tcl_AppendResult(interp, "can't set comm state: ",
			Tcl_PosixError(interp), NULL);
	    }
	    return TCL_ERROR;
	}
	return TCL_OK;
    }

    /*
     * Option -handshake none|xonxoff|rtscts|dtrdsr
     */

    if ((len > 1) && (strncmp(optionName, "-handshake", len) == 0)) {
	if (!GetCommState(infoPtr->handle, &dcb)) {
	    if (interp != NULL) {
		TclWinConvertError(GetLastError());
		Tcl_AppendResult(interp, "can't get comm state: ",
			Tcl_PosixError(interp), NULL);
	    }
	    return TCL_ERROR;
	}

	/*
	 * Reset all handshake options. DTR and RTS are ON by default.
	 */
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
	    dcb.fOutxDsrFlow = TRUE;
	    dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
	} else {
	    if (interp != NULL) {
		Tcl_AppendResult(interp, "bad value \"", value,
			"\" for -handshake: must be one of xonxoff, rtscts, "
			"dtrdsr or none", NULL);

	    }
	    return TCL_ERROR;
	}

	if (!SetCommState(infoPtr->handle, &dcb)) {
	    if (interp != NULL) {

		Tcl_AppendResult(interp, "can't set comm state", NULL);

	    }
	    return TCL_ERROR;
	}
	return TCL_OK;
    }

    /*
     * Option -xchar {\x11 \x13}
     */

    if ((len > 1) && (strncmp(optionName, "-xchar", len) == 0)) {
	if (!GetCommState(infoPtr->handle, &dcb)) {
	    if (interp != NULL) {

		Tcl_AppendResult(interp, "can't get comm state", NULL);

	    }
	    return TCL_ERROR;
	}

	if (Tcl_SplitList(interp, value, &argc, &argv) == TCL_ERROR) {
	    return TCL_ERROR;
	}
	if (argc != 2) {
	badXchar:
	    if (interp != NULL) {
		Tcl_AppendResult(interp, "bad value for -xchar: should be "
			"a list of two elements with each a single character",
			NULL);

	    }
	    ckfree(argv);
	    return TCL_ERROR;
	}

	/*
	 * These dereferences are safe, even in the zero-length string cases,







>






>
|
>













>
|
>













>







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
	    dcb.fOutxDsrFlow = TRUE;
	    dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
	} else {
	    if (interp != NULL) {
		Tcl_AppendResult(interp, "bad value \"", value,
			"\" for -handshake: must be one of xonxoff, rtscts, "
			"dtrdsr or none", NULL);
		Tcl_SetErrorCode(interp, "TCL", "VALUE", "HANDSHAKE", NULL);
	    }
	    return TCL_ERROR;
	}

	if (!SetCommState(infoPtr->handle, &dcb)) {
	    if (interp != NULL) {
		TclWinConvertError(GetLastError());
		Tcl_AppendResult(interp, "can't set comm state: ",
			Tcl_PosixError(interp), NULL);
	    }
	    return TCL_ERROR;
	}
	return TCL_OK;
    }

    /*
     * Option -xchar {\x11 \x13}
     */

    if ((len > 1) && (strncmp(optionName, "-xchar", len) == 0)) {
	if (!GetCommState(infoPtr->handle, &dcb)) {
	    if (interp != NULL) {
		TclWinConvertError(GetLastError());
		Tcl_AppendResult(interp, "can't get comm state: ",
			Tcl_PosixError(interp), NULL);
	    }
	    return TCL_ERROR;
	}

	if (Tcl_SplitList(interp, value, &argc, &argv) == TCL_ERROR) {
	    return TCL_ERROR;
	}
	if (argc != 2) {
	badXchar:
	    if (interp != NULL) {
		Tcl_AppendResult(interp, "bad value for -xchar: should be "
			"a list of two elements with each a single character",
			NULL);
		Tcl_SetErrorCode(interp, "TCL", "VALUE", "XCHAR", NULL);
	    }
	    ckfree(argv);
	    return TCL_ERROR;
	}

	/*
	 * These dereferences are safe, even in the zero-length string cases,
1823
1824
1825
1826
1827
1828
1829

1830

1831
1832
1833
1834
1835
1836
1837
	    }
	    dcb.XoffChar = (char) character;
	}
	ckfree(argv);

	if (!SetCommState(infoPtr->handle, &dcb)) {
	    if (interp != NULL) {

		Tcl_AppendResult(interp, "can't set comm state", NULL);

	    }
	    return TCL_ERROR;
	}
	return TCL_OK;
    }

    /*







>
|
>







1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
	    }
	    dcb.XoffChar = (char) character;
	}
	ckfree(argv);

	if (!SetCommState(infoPtr->handle, &dcb)) {
	    if (interp != NULL) {
		TclWinConvertError(GetLastError());
		Tcl_AppendResult(interp, "can't set comm state: ",
			Tcl_PosixError(interp), NULL);
	    }
	    return TCL_ERROR;
	}
	return TCL_OK;
    }

    /*
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
	    return TCL_ERROR;
	}
	if ((argc % 2) == 1) {
	    if (interp != NULL) {
		Tcl_AppendResult(interp, "bad value \"", value,
			"\" for -ttycontrol: should be a list of "
			"signal,value pairs", NULL);

	    }
	    ckfree(argv);
	    return TCL_ERROR;
	}

	for (i = 0; i < argc - 1; i += 2) {
	    if (Tcl_GetBoolean(interp, argv[i+1], &flag) == TCL_ERROR) {
		result = TCL_ERROR;
		break;
	    }
	    if (strncasecmp(argv[i], "DTR", strlen(argv[i])) == 0) {
		if (!EscapeCommFunction(infoPtr->handle,
			(DWORD) (flag ? SETDTR : CLRDTR))) {
		    if (interp != NULL) {
			Tcl_AppendResult(interp, "can't set DTR signal", NULL);


		    }
		    result = TCL_ERROR;
		    break;
		}
	    } else if (strncasecmp(argv[i], "RTS", strlen(argv[i])) == 0) {
		if (!EscapeCommFunction(infoPtr->handle,
			(DWORD) (flag ? SETRTS : CLRRTS))) {
		    if (interp != NULL) {
			Tcl_AppendResult(interp, "can't set RTS signal", NULL);


		    }
		    result = TCL_ERROR;
		    break;
		}
	    } else if (strncasecmp(argv[i], "BREAK", strlen(argv[i])) == 0) {
		if (!EscapeCommFunction(infoPtr->handle,
			(DWORD) (flag ? SETBREAK : CLRBREAK))) {
		    if (interp != NULL) {
			Tcl_AppendResult(interp,"can't set BREAK signal",NULL);


		    }
		    result = TCL_ERROR;
		    break;
		}
	    } else {
		if (interp != NULL) {
		    Tcl_AppendResult(interp, "bad signal name \"", argv[i],
			    "\" for -ttycontrol: must be DTR, RTS or BREAK",


			    NULL);
		}
		result = TCL_ERROR;
		break;
	    }
	}








>















>
>









>
>









>
>








>
>







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
	    return TCL_ERROR;
	}
	if ((argc % 2) == 1) {
	    if (interp != NULL) {
		Tcl_AppendResult(interp, "bad value \"", value,
			"\" for -ttycontrol: should be a list of "
			"signal,value pairs", NULL);
		Tcl_SetErrorCode(interp, "TCL", "VALUE", "TTYCONTROL", NULL);
	    }
	    ckfree(argv);
	    return TCL_ERROR;
	}

	for (i = 0; i < argc - 1; i += 2) {
	    if (Tcl_GetBoolean(interp, argv[i+1], &flag) == TCL_ERROR) {
		result = TCL_ERROR;
		break;
	    }
	    if (strncasecmp(argv[i], "DTR", strlen(argv[i])) == 0) {
		if (!EscapeCommFunction(infoPtr->handle,
			(DWORD) (flag ? SETDTR : CLRDTR))) {
		    if (interp != NULL) {
			Tcl_AppendResult(interp, "can't set DTR signal", NULL);
			Tcl_SetErrorCode(interp, "TCL", "OPERATION",
				"FCONFIGURE", "TTY_SIGNAL", NULL);
		    }
		    result = TCL_ERROR;
		    break;
		}
	    } else if (strncasecmp(argv[i], "RTS", strlen(argv[i])) == 0) {
		if (!EscapeCommFunction(infoPtr->handle,
			(DWORD) (flag ? SETRTS : CLRRTS))) {
		    if (interp != NULL) {
			Tcl_AppendResult(interp, "can't set RTS signal", NULL);
			Tcl_SetErrorCode(interp, "TCL", "OPERATION",
				"FCONFIGURE", "TTY_SIGNAL", NULL);
		    }
		    result = TCL_ERROR;
		    break;
		}
	    } else if (strncasecmp(argv[i], "BREAK", strlen(argv[i])) == 0) {
		if (!EscapeCommFunction(infoPtr->handle,
			(DWORD) (flag ? SETBREAK : CLRBREAK))) {
		    if (interp != NULL) {
			Tcl_AppendResult(interp,"can't set BREAK signal",NULL);
			Tcl_SetErrorCode(interp, "TCL", "OPERATION",
				"FCONFIGURE", "TTY_SIGNAL", NULL);
		    }
		    result = TCL_ERROR;
		    break;
		}
	    } else {
		if (interp != NULL) {
		    Tcl_AppendResult(interp, "bad signal name \"", argv[i],
			    "\" for -ttycontrol: must be DTR, RTS or BREAK",
			    NULL);
		    Tcl_SetErrorCode(interp, "TCL", "VALUE", "TTY_SIGNAL",
			    NULL);
		}
		result = TCL_ERROR;
		break;
	    }
	}

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
	ckfree(argv);

	if ((argc < 1) || (argc > 2) || (inSize <= 0) || (outSize <= 0)) {
	    if (interp != NULL) {
		Tcl_AppendResult(interp, "bad value \"", value,
			"\" for -sysbuffer: should be a list of one or two "
			"integers > 0", NULL);

	    }
	    return TCL_ERROR;
	}

	if (!SetupComm(infoPtr->handle, inSize, outSize)) {
	    if (interp != NULL) {

		Tcl_AppendResult(interp, "can't setup comm buffers", NULL);

	    }
	    return TCL_ERROR;
	}
	infoPtr->sysBufRead  = inSize;
	infoPtr->sysBufWrite = outSize;

	/*
	 * Adjust the handshake limits. Yes, the XonXoff limits seem to
	 * influence even hardware handshake.
	 */

	if (!GetCommState(infoPtr->handle, &dcb)) {
	    if (interp != NULL) {

		Tcl_AppendResult(interp, "can't get comm state", NULL);

	    }
	    return TCL_ERROR;
	}
	dcb.XonLim = (WORD) (infoPtr->sysBufRead*1/2);
	dcb.XoffLim = (WORD) (infoPtr->sysBufRead*1/4);
	if (!SetCommState(infoPtr->handle, &dcb)) {
	    if (interp != NULL) {

		Tcl_AppendResult(interp, "can't set comm state", NULL);

	    }
	    return TCL_ERROR;
	}
	return TCL_OK;
    }

    /*







>






>
|
>













>
|
>







>
|
>







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
	ckfree(argv);

	if ((argc < 1) || (argc > 2) || (inSize <= 0) || (outSize <= 0)) {
	    if (interp != NULL) {
		Tcl_AppendResult(interp, "bad value \"", value,
			"\" for -sysbuffer: should be a list of one or two "
			"integers > 0", NULL);
		Tcl_SetErrorCode(interp, "TCL", "VALUE", "SYS_BUFFER", NULL);
	    }
	    return TCL_ERROR;
	}

	if (!SetupComm(infoPtr->handle, inSize, outSize)) {
	    if (interp != NULL) {
		TclWinConvertError(GetLastError());
		Tcl_AppendResult(interp, "can't setup comm buffers: ",
			Tcl_PosixError(interp), NULL);
	    }
	    return TCL_ERROR;
	}
	infoPtr->sysBufRead  = inSize;
	infoPtr->sysBufWrite = outSize;

	/*
	 * Adjust the handshake limits. Yes, the XonXoff limits seem to
	 * influence even hardware handshake.
	 */

	if (!GetCommState(infoPtr->handle, &dcb)) {
	    if (interp != NULL) {
		TclWinConvertError(GetLastError());
		Tcl_AppendResult(interp, "can't get comm state: ",
			Tcl_PosixError(interp), NULL);
	    }
	    return TCL_ERROR;
	}
	dcb.XonLim = (WORD) (infoPtr->sysBufRead*1/2);
	dcb.XoffLim = (WORD) (infoPtr->sysBufRead*1/4);
	if (!SetCommState(infoPtr->handle, &dcb)) {
	    if (interp != NULL) {
		TclWinConvertError(GetLastError());
		Tcl_AppendResult(interp, "can't set comm state: ",
			Tcl_PosixError(interp), NULL);
	    }
	    return TCL_ERROR;
	}
	return TCL_OK;
    }

    /*
1986
1987
1988
1989
1990
1991
1992

1993

1994
1995
1996
1997
1998
1999
2000

	if (Tcl_GetInt(interp, value, &msec) != TCL_OK) {
	    return TCL_ERROR;
	}
	tout.ReadTotalTimeoutConstant = msec;
	if (!SetCommTimeouts(infoPtr->handle, &tout)) {
	    if (interp != NULL) {

		Tcl_AppendResult(interp, "can't set comm timeouts", NULL);

	    }
	    return TCL_ERROR;
	}

	return TCL_OK;
    }








>
|
>







2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031

	if (Tcl_GetInt(interp, value, &msec) != TCL_OK) {
	    return TCL_ERROR;
	}
	tout.ReadTotalTimeoutConstant = msec;
	if (!SetCommTimeouts(infoPtr->handle, &tout)) {
	    if (interp != NULL) {
		TclWinConvertError(GetLastError());
		Tcl_AppendResult(interp, "can't set comm timeouts: ",
			Tcl_PosixError(interp), NULL);
	    }
	    return TCL_ERROR;
	}

	return TCL_OK;
    }

2053
2054
2055
2056
2057
2058
2059

2060

2061
2062
2063
2064
2065
2066
2067
    if (len==0 || (len>2 && (strncmp(optionName, "-mode", len) == 0))) {
	char parity;
	const char *stop;
	char buf[2 * TCL_INTEGER_SPACE + 16];

	if (!GetCommState(infoPtr->handle, &dcb)) {
	    if (interp != NULL) {

		Tcl_AppendResult(interp, "can't get comm state", NULL);

	    }
	    return TCL_ERROR;
	}

	valid = 1;
	parity = 'n';
	if (dcb.Parity <= 4) {







>
|
>







2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
    if (len==0 || (len>2 && (strncmp(optionName, "-mode", len) == 0))) {
	char parity;
	const char *stop;
	char buf[2 * TCL_INTEGER_SPACE + 16];

	if (!GetCommState(infoPtr->handle, &dcb)) {
	    if (interp != NULL) {
		TclWinConvertError(GetLastError());
		Tcl_AppendResult(interp, "can't get comm state: ",
			Tcl_PosixError(interp), NULL);
	    }
	    return TCL_ERROR;
	}

	valid = 1;
	parity = 'n';
	if (dcb.Parity <= 4) {
2121
2122
2123
2124
2125
2126
2127

2128

2129
2130
2131
2132
2133
2134
2135
    }
    if (len==0 || (len>1 && strncmp(optionName, "-xchar", len) == 0)) {
	char buf[4];
	valid = 1;

	if (!GetCommState(infoPtr->handle, &dcb)) {
	    if (interp != NULL) {

		Tcl_AppendResult(interp, "can't get comm state", NULL);

	    }
	    return TCL_ERROR;
	}
	sprintf(buf, "%c", dcb.XonChar);
	Tcl_DStringAppendElement(dsPtr, buf);
	sprintf(buf, "%c", dcb.XoffChar);
	Tcl_DStringAppendElement(dsPtr, buf);







>
|
>







2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
    }
    if (len==0 || (len>1 && strncmp(optionName, "-xchar", len) == 0)) {
	char buf[4];
	valid = 1;

	if (!GetCommState(infoPtr->handle, &dcb)) {
	    if (interp != NULL) {
		TclWinConvertError(GetLastError());
		Tcl_AppendResult(interp, "can't get comm state: ",
			Tcl_PosixError(interp), NULL);
	    }
	    return TCL_ERROR;
	}
	sprintf(buf, "%c", dcb.XonChar);
	Tcl_DStringAppendElement(dsPtr, buf);
	sprintf(buf, "%c", dcb.XoffChar);
	Tcl_DStringAppendElement(dsPtr, buf);
2197
2198
2199
2200
2201
2202
2203

2204

2205
2206
2207
2208
2209
2210
2211
     */

    if (len>4 && strncmp(optionName, "-ttystatus", len)==0) {
	DWORD status;

	if (!GetCommModemStatus(infoPtr->handle, &status)) {
	    if (interp != NULL) {

		Tcl_AppendResult(interp, "can't get tty status", NULL);

	    }
	    return TCL_ERROR;
	}
	valid = 1;
	SerialModemStatusStr(status, dsPtr);
    }








>
|
>







2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
     */

    if (len>4 && strncmp(optionName, "-ttystatus", len)==0) {
	DWORD status;

	if (!GetCommModemStatus(infoPtr->handle, &status)) {
	    if (interp != NULL) {
		TclWinConvertError(GetLastError());
		Tcl_AppendResult(interp, "can't get tty status: ",
			Tcl_PosixError(interp), NULL);
	    }
	    return TCL_ERROR;
	}
	valid = 1;
	SerialModemStatusStr(status, dsPtr);
    }

Changes to win/tclWinSock.c.

283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298

static void
InitSockets(void)
{
    DWORD id;
    WSADATA wsaData;
    DWORD err;
    ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
	    TclThreadDataKeyGet(&dataKey);

    if (!initialized) {
	initialized = 1;
	TclCreateLateExitHandler(SocketExitHandler, NULL);

	/*
	 * Create the async notification window with a new class. We must







|
<







283
284
285
286
287
288
289
290

291
292
293
294
295
296
297

static void
InitSockets(void)
{
    DWORD id;
    WSADATA wsaData;
    DWORD err;
    ThreadSpecificData *tsdPtr = TclThreadDataKeyGet(&dataKey);


    if (!initialized) {
	initialized = 1;
	TclCreateLateExitHandler(SocketExitHandler, NULL);

	/*
	 * Create the async notification window with a new class. We must
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
 *
 *----------------------------------------------------------------------
 */

void
TclpFinalizeSockets(void)
{
    ThreadSpecificData *tsdPtr;

    tsdPtr = (ThreadSpecificData *) TclThreadDataKeyGet(&dataKey);
    if (tsdPtr != NULL) {
	if (tsdPtr->socketThread != NULL) {
	    if (tsdPtr->hwnd != NULL) {
		PostMessage(tsdPtr->hwnd, SOCKET_TERMINATE, 0, 0);

		/*
		 * Wait for the thread to exit. This ensures that we are







|

<







477
478
479
480
481
482
483
484
485

486
487
488
489
490
491
492
 *
 *----------------------------------------------------------------------
 */

void
TclpFinalizeSockets(void)
{
    ThreadSpecificData *tsdPtr = TclThreadDataKeyGet(&dataKey);


    if (tsdPtr != NULL) {
	if (tsdPtr->socketThread != NULL) {
	    if (tsdPtr->hwnd != NULL) {
		PostMessage(tsdPtr->hwnd, SOCKET_TERMINATE, 0, 0);

		/*
		 * Wait for the thread to exit. This ensures that we are
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820

static int
TcpBlockProc(
    ClientData instanceData,	/* The socket to block/un-block. */
    int mode)			/* TCL_MODE_BLOCKING or
				 * TCL_MODE_NONBLOCKING. */
{
    SocketInfo *infoPtr = (SocketInfo *) instanceData;

    if (mode == TCL_MODE_NONBLOCKING) {
	infoPtr->flags |= SOCKET_ASYNC;
    } else {
	infoPtr->flags &= ~(SOCKET_ASYNC);
    }
    return 0;







|







804
805
806
807
808
809
810
811
812
813
814
815
816
817
818

static int
TcpBlockProc(
    ClientData instanceData,	/* The socket to block/un-block. */
    int mode)			/* TCL_MODE_BLOCKING or
				 * TCL_MODE_NONBLOCKING. */
{
    SocketInfo *infoPtr = instanceData;

    if (mode == TCL_MODE_NONBLOCKING) {
	infoPtr->flags |= SOCKET_ASYNC;
    } else {
	infoPtr->flags &= ~(SOCKET_ASYNC);
    }
    return 0;
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854

    /* ARGSUSED */
static int
TcpCloseProc(
    ClientData instanceData,	/* The socket to close. */
    Tcl_Interp *interp)		/* Unused. */
{
    SocketInfo *infoPtr = (SocketInfo *) instanceData;
    /* TIP #218 */
    int errorCode = 0;
    /* ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); */

    /*
     * Check that WinSock is initialized; do not call it if not, to prevent
     * system crashes. This can happen at exit time if the exit handler for







|







838
839
840
841
842
843
844
845
846
847
848
849
850
851
852

    /* ARGSUSED */
static int
TcpCloseProc(
    ClientData instanceData,	/* The socket to close. */
    Tcl_Interp *interp)		/* Unused. */
{
    SocketInfo *infoPtr = instanceData;
    /* TIP #218 */
    int errorCode = 0;
    /* ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); */

    /*
     * Check that WinSock is initialized; do not call it if not, to prevent
     * system crashes. This can happen at exit time if the exit handler for
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

static int
TcpClose2Proc(
    ClientData instanceData,	/* The socket to close. */
    Tcl_Interp *interp,		/* For error reporting. */
    int flags)			/* Flags that indicate which side to close. */
{
    SocketInfo *infoPtr = (SocketInfo *) instanceData;
    int errorCode = 0;
    int sd;

    /*
     * Shutdown the OS socket handle.
     */
    switch(flags)
	{
	case TCL_CLOSE_READ:
	    sd=SD_RECEIVE;
	    break;
	case TCL_CLOSE_WRITE:
	    sd=SD_SEND;
	    break;
	default:
	    if (interp) {

		Tcl_AppendResult(interp, "Socket close2proc called bidirectionally", NULL);
	    }
	    return TCL_ERROR;
	}
    if (shutdown(infoPtr->sockets->fd,sd) == SOCKET_ERROR) {
	TclWinConvertWSAError((DWORD) WSAGetLastError());
	errorCode = Tcl_GetErrno();
    }







|
















>
|







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

static int
TcpClose2Proc(
    ClientData instanceData,	/* The socket to close. */
    Tcl_Interp *interp,		/* For error reporting. */
    int flags)			/* Flags that indicate which side to close. */
{
    SocketInfo *infoPtr = instanceData;
    int errorCode = 0;
    int sd;

    /*
     * Shutdown the OS socket handle.
     */
    switch(flags)
	{
	case TCL_CLOSE_READ:
	    sd=SD_RECEIVE;
	    break;
	case TCL_CLOSE_WRITE:
	    sd=SD_SEND;
	    break;
	default:
	    if (interp) {
		Tcl_AppendResult(interp,
			"Socket close2proc called bidirectionally", NULL);
	    }
	    return TCL_ERROR;
	}
    if (shutdown(infoPtr->sockets->fd,sd) == SOCKET_ERROR) {
	TclWinConvertWSAError((DWORD) WSAGetLastError());
	errorCode = Tcl_GetErrno();
    }
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
				 * progress. */
    unsigned short chosenport = 0;
    struct addrinfo *addrlist = NULL, *addrPtr;	/* socket address */
    struct addrinfo *myaddrlist = NULL, *myaddrPtr; /* Socket address for client */
    const char *errorMsg = NULL;
    SOCKET sock = INVALID_SOCKET;
    SocketInfo *infoPtr = NULL;	/* The returned value. */
    ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
	    TclThreadDataKeyGet(&dataKey);

    /*
     * Check that WinSock is initialized; do not call it if not, to prevent
     * system crashes. This can happen at exit time if the exit handler for
     * WinSock ran before other exit handlers that want to use sockets.
     */








|
<







1013
1014
1015
1016
1017
1018
1019
1020

1021
1022
1023
1024
1025
1026
1027
				 * progress. */
    unsigned short chosenport = 0;
    struct addrinfo *addrlist = NULL, *addrPtr;	/* socket address */
    struct addrinfo *myaddrlist = NULL, *myaddrPtr; /* Socket address for client */
    const char *errorMsg = NULL;
    SOCKET sock = INVALID_SOCKET;
    SocketInfo *infoPtr = NULL;	/* The returned value. */
    ThreadSpecificData *tsdPtr = TclThreadDataKeyGet(&dataKey);


    /*
     * Check that WinSock is initialized; do not call it if not, to prevent
     * system crashes. This can happen at exit time if the exit handler for
     * WinSock ran before other exit handlers that want to use sockets.
     */

1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
		newfds->infoPtr = infoPtr;
		newfds->next = NULL;
		fds->next = newfds;
		fds = newfds;
	    }
	}
    } else {
        for (addrPtr = addrlist; addrPtr != NULL;
             addrPtr = addrPtr->ai_next) {
            for (myaddrPtr = myaddrlist; myaddrPtr != NULL;
                 myaddrPtr = myaddrPtr->ai_next) {
		/*
		 * No need to try combinations of local and remote addresses
		 * of different families.
		 */
		if (myaddrPtr->ai_family != addrPtr->ai_family) {
		    continue;
		}







|
|
|
|







1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
		newfds->infoPtr = infoPtr;
		newfds->next = NULL;
		fds->next = newfds;
		fds = newfds;
	    }
	}
    } else {
	for (addrPtr = addrlist; addrPtr != NULL;
		addrPtr = addrPtr->ai_next) {
	    for (myaddrPtr = myaddrlist; myaddrPtr != NULL;
		    myaddrPtr = myaddrPtr->ai_next) {
		/*
		 * No need to try combinations of local and remote addresses
		 * of different families.
		 */
		if (myaddrPtr->ai_family != addrPtr->ai_family) {
		    continue;
		}
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
WaitForSocketEvent(
    SocketInfo *infoPtr,	/* Information about this socket. */
    int events,			/* Events to look for. */
    int *errorCodePtr)		/* Where to store errors? */
{
    int result = 1;
    int oldMode;
    ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
	    TclThreadDataKeyGet(&dataKey);

    /*
     * Be sure to disable event servicing so we are truly modal.
     */

    oldMode = Tcl_SetServiceMode(TCL_SERVICE_NONE);








|
<







1359
1360
1361
1362
1363
1364
1365
1366

1367
1368
1369
1370
1371
1372
1373
WaitForSocketEvent(
    SocketInfo *infoPtr,	/* Information about this socket. */
    int events,			/* Events to look for. */
    int *errorCodePtr)		/* Where to store errors? */
{
    int result = 1;
    int oldMode;
    ThreadSpecificData *tsdPtr = TclThreadDataKeyGet(&dataKey);


    /*
     * Be sure to disable event servicing so we are truly modal.
     */

    oldMode = Tcl_SetServiceMode(TCL_SERVICE_NONE);

1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
    char channelName[16 + TCL_INTEGER_SPACE];
    ThreadSpecificData *tsdPtr;

    if (TclpHasSockets(NULL) != TCL_OK) {
	return NULL;
    }

    tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);

    /*
     * Set kernel space buffering and non-blocking.
     */

    TclSockMinimumBuffers((ClientData) sock, TCP_BUFFER_SIZE);








|







1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
    char channelName[16 + TCL_INTEGER_SPACE];
    ThreadSpecificData *tsdPtr;

    if (TclpHasSockets(NULL) != TCL_OK) {
	return NULL;
    }

    tsdPtr = TclThreadDataKeyGet(&dataKey);

    /*
     * Set kernel space buffering and non-blocking.
     */

    TclSockMinimumBuffers((ClientData) sock, TCP_BUFFER_SIZE);

1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
{
    SOCKET newSocket;
    SocketInfo *newInfoPtr;
    SocketInfo *infoPtr = fds->infoPtr;
    SOCKADDR_IN addr;
    int len;
    char channelName[16 + TCL_INTEGER_SPACE];
    ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
	    TclThreadDataKeyGet(&dataKey);

    /*
     * Accept the incoming connection request.
     */

    len = sizeof(SOCKADDR_IN);








|
<







1602
1603
1604
1605
1606
1607
1608
1609

1610
1611
1612
1613
1614
1615
1616
{
    SOCKET newSocket;
    SocketInfo *newInfoPtr;
    SocketInfo *infoPtr = fds->infoPtr;
    SOCKADDR_IN addr;
    int len;
    char channelName[16 + TCL_INTEGER_SPACE];
    ThreadSpecificData *tsdPtr = TclThreadDataKeyGet(&dataKey);


    /*
     * Accept the incoming connection request.
     */

    len = sizeof(SOCKADDR_IN);

1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
static int
TcpInputProc(
    ClientData instanceData,	/* The socket state. */
    char *buf,			/* Where to store data. */
    int toRead,			/* Maximum number of bytes to read. */
    int *errorCodePtr)		/* Where to store error codes. */
{
    SocketInfo *infoPtr = (SocketInfo *) instanceData;
    int bytesRead;
    DWORD error;
    ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
	    TclThreadDataKeyGet(&dataKey);

    *errorCodePtr = 0;

    /*
     * Check that WinSock is initialized; do not call it if not, to prevent
     * system crashes. This can happen at exit time if the exit handler for
     * WinSock ran before other exit handlers that want to use sockets.







|


|
<







1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725

1726
1727
1728
1729
1730
1731
1732
static int
TcpInputProc(
    ClientData instanceData,	/* The socket state. */
    char *buf,			/* Where to store data. */
    int toRead,			/* Maximum number of bytes to read. */
    int *errorCodePtr)		/* Where to store error codes. */
{
    SocketInfo *infoPtr = instanceData;
    int bytesRead;
    DWORD error;
    ThreadSpecificData *tsdPtr = TclThreadDataKeyGet(&dataKey);


    *errorCodePtr = 0;

    /*
     * Check that WinSock is initialized; do not call it if not, to prevent
     * system crashes. This can happen at exit time if the exit handler for
     * WinSock ran before other exit handlers that want to use sockets.
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
static int
TcpOutputProc(
    ClientData instanceData,	/* The socket state. */
    const char *buf,		/* Where to get data. */
    int toWrite,		/* Maximum number of bytes to write. */
    int *errorCodePtr)		/* Where to store error codes. */
{
    SocketInfo *infoPtr = (SocketInfo *) instanceData;
    int bytesWritten;
    DWORD error;
    ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
	    TclThreadDataKeyGet(&dataKey);

    *errorCodePtr = 0;

    /*
     * Check that WinSock is initialized; do not call it if not, to prevent
     * system crashes. This can happen at exit time if the exit handler for
     * WinSock ran before other exit handlers that want to use sockets.







|


|
<







1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862

1863
1864
1865
1866
1867
1868
1869
static int
TcpOutputProc(
    ClientData instanceData,	/* The socket state. */
    const char *buf,		/* Where to get data. */
    int toWrite,		/* Maximum number of bytes to write. */
    int *errorCodePtr)		/* Where to store error codes. */
{
    SocketInfo *infoPtr = instanceData;
    int bytesWritten;
    DWORD error;
    ThreadSpecificData *tsdPtr = TclThreadDataKeyGet(&dataKey);


    *errorCodePtr = 0;

    /*
     * Check that WinSock is initialized; do not call it if not, to prevent
     * system crashes. This can happen at exit time if the exit handler for
     * WinSock ran before other exit handlers that want to use sockets.
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
static int
TcpSetOptionProc(
    ClientData instanceData,	/* Socket state. */
    Tcl_Interp *interp,		/* For error reporting - can be NULL. */
    const char *optionName,	/* Name of the option to set. */
    const char *value)		/* New value for option. */
{

    SocketInfo *infoPtr;
    SOCKET sock;


    /*
     * Check that WinSock is initialized; do not call it if not, to prevent
     * system crashes. This can happen at exit time if the exit handler for
     * WinSock ran before other exit handlers that want to use sockets.
     */

    if (!SocketsEnabled()) {
	if (interp) {
	    Tcl_AppendResult(interp, "winsock is not initialized", NULL);
	}
	return TCL_ERROR;
    }

    infoPtr = (SocketInfo *) instanceData;
    sock = infoPtr->sockets->fd;

#ifdef TCL_FEATURE_KEEPALIVE_NAGLE
    if (!strcasecmp(optionName, "-keepalive")) {
	BOOL val = FALSE;
	int boolVar, rtn;

	if (Tcl_GetBoolean(interp, value, &boolVar) != TCL_OK) {
	    return TCL_ERROR;
	}







>
|

>














|


<







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
static int
TcpSetOptionProc(
    ClientData instanceData,	/* Socket state. */
    Tcl_Interp *interp,		/* For error reporting - can be NULL. */
    const char *optionName,	/* Name of the option to set. */
    const char *value)		/* New value for option. */
{
#ifdef TCL_FEATURE_KEEPALIVE_NAGLE
    SocketInfo *infoPtr = instanceData;
    SOCKET sock;
#endif /*TCL_FEATURE_KEEPALIVE_NAGLE*/

    /*
     * Check that WinSock is initialized; do not call it if not, to prevent
     * system crashes. This can happen at exit time if the exit handler for
     * WinSock ran before other exit handlers that want to use sockets.
     */

    if (!SocketsEnabled()) {
	if (interp) {
	    Tcl_AppendResult(interp, "winsock is not initialized", NULL);
	}
	return TCL_ERROR;
    }

#ifdef TCL_FEATURE_KEEPALIVE_NAGLE
    sock = infoPtr->sockets->fd;


    if (!strcasecmp(optionName, "-keepalive")) {
	BOOL val = FALSE;
	int boolVar, rtn;

	if (Tcl_GetBoolean(interp, value, &boolVar) != TCL_OK) {
	    return TCL_ERROR;
	}
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
    Tcl_Interp *interp,		/* For error reporting - can be NULL */
    const char *optionName,	/* Name of the option to retrieve the value
				 * for, or NULL to get all options and their
				 * values. */
    Tcl_DString *dsPtr)		/* Where to store the computed value;
				 * initialized by caller. */
{
    SocketInfo *infoPtr;
    char host[NI_MAXHOST], port[NI_MAXSERV];
    SOCKET sock;
    size_t len = 0;
    int reverseDNS = 0;
#define SUPPRESS_RDNS_VAR "::tcl::unsupported::noReverseDNS"

    /*
     * Check that WinSock is initialized; do not call it if not, to prevent
     * system crashes. This can happen at exit time if the exit handler for
     * WinSock ran before other exit handlers that want to use sockets.
     */

    if (!SocketsEnabled()) {
	if (interp) {
	    Tcl_AppendResult(interp, "winsock is not initialized", NULL);
	}
	return TCL_ERROR;
    }

    infoPtr = (SocketInfo *) instanceData;
    sock = infoPtr->sockets->fd;
    if (optionName != NULL) {
	len = strlen(optionName);
    }

    if ((len > 1) && (optionName[1] == 'e') &&
	    (strncmp(optionName, "-error", len) == 0)) {







|



















<







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
    Tcl_Interp *interp,		/* For error reporting - can be NULL */
    const char *optionName,	/* Name of the option to retrieve the value
				 * for, or NULL to get all options and their
				 * values. */
    Tcl_DString *dsPtr)		/* Where to store the computed value;
				 * initialized by caller. */
{
    SocketInfo *infoPtr = instanceData;
    char host[NI_MAXHOST], port[NI_MAXSERV];
    SOCKET sock;
    size_t len = 0;
    int reverseDNS = 0;
#define SUPPRESS_RDNS_VAR "::tcl::unsupported::noReverseDNS"

    /*
     * Check that WinSock is initialized; do not call it if not, to prevent
     * system crashes. This can happen at exit time if the exit handler for
     * WinSock ran before other exit handlers that want to use sockets.
     */

    if (!SocketsEnabled()) {
	if (interp) {
	    Tcl_AppendResult(interp, "winsock is not initialized", NULL);
	}
	return TCL_ERROR;
    }


    sock = infoPtr->sockets->fd;
    if (optionName != NULL) {
	len = strlen(optionName);
    }

    if ((len > 1) && (optionName[1] == 'e') &&
	    (strncmp(optionName, "-error", len) == 0)) {
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
	    TclWinConvertWSAError(err);
	    Tcl_DStringAppend(dsPtr, Tcl_ErrnoMsg(Tcl_GetErrno()), -1);
	}
	return TCL_OK;
    }

    if (interp != NULL && Tcl_GetVar(interp, SUPPRESS_RDNS_VAR, 0) != NULL) {
        reverseDNS = NI_NUMERICHOST;
    }

    if ((len == 0) || ((len > 1) && (optionName[1] == 'p') &&
	    (strncmp(optionName, "-peername", len) == 0))) {
	address peername;
	socklen_t size = sizeof(peername);
	if (getpeername(sock, (LPSOCKADDR) &(peername.sa), &size) == 0) {
	    if (len == 0) {
		Tcl_DStringAppendElement(dsPtr, "-peername");
		Tcl_DStringStartSublist(dsPtr);
	    }

	    getnameinfo(&(peername.sa), size, host, sizeof(host),
                        NULL, 0, NI_NUMERICHOST);
	    Tcl_DStringAppendElement(dsPtr, host);
	    getnameinfo(&(peername.sa), size, host, sizeof(host),
                        port, sizeof(port), reverseDNS | NI_NUMERICSERV);
	    Tcl_DStringAppendElement(dsPtr, host);
	    Tcl_DStringAppendElement(dsPtr, port);
	    if (len == 0) {
		Tcl_DStringEndSublist(dsPtr);
	    } else {
		return TCL_OK;
	    }







|













|


|







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
	    TclWinConvertWSAError(err);
	    Tcl_DStringAppend(dsPtr, Tcl_ErrnoMsg(Tcl_GetErrno()), -1);
	}
	return TCL_OK;
    }

    if (interp != NULL && Tcl_GetVar(interp, SUPPRESS_RDNS_VAR, 0) != NULL) {
	reverseDNS = NI_NUMERICHOST;
    }

    if ((len == 0) || ((len > 1) && (optionName[1] == 'p') &&
	    (strncmp(optionName, "-peername", len) == 0))) {
	address peername;
	socklen_t size = sizeof(peername);
	if (getpeername(sock, (LPSOCKADDR) &(peername.sa), &size) == 0) {
	    if (len == 0) {
		Tcl_DStringAppendElement(dsPtr, "-peername");
		Tcl_DStringStartSublist(dsPtr);
	    }

	    getnameinfo(&(peername.sa), size, host, sizeof(host),
		    NULL, 0, NI_NUMERICHOST);
	    Tcl_DStringAppendElement(dsPtr, host);
	    getnameinfo(&(peername.sa), size, host, sizeof(host),
		    port, sizeof(port), reverseDNS | NI_NUMERICSERV);
	    Tcl_DStringAppendElement(dsPtr, host);
	    Tcl_DStringAppendElement(dsPtr, port);
	    if (len == 0) {
		Tcl_DStringEndSublist(dsPtr);
	    } else {
		return TCL_OK;
	    }
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
2221
2222
2223
2224
2225
2226
2227
2228
2229
		return TCL_ERROR;
	    }
	}
    }

    if ((len == 0) || ((len > 1) && (optionName[1] == 's') &&
	    (strncmp(optionName, "-sockname", len) == 0))) {

	TcpFdList *fds;
        address sockname;
        socklen_t size;
	int found = 0;

	if (len == 0) {
	    Tcl_DStringAppendElement(dsPtr, "-sockname");
	    Tcl_DStringStartSublist(dsPtr);
	}
	for (fds = infoPtr->sockets; fds != NULL; fds = fds->next) {
	    sock = fds->fd;
	    size = sizeof(sockname);
	    if (getsockname(sock, &(sockname.sa), &size) >= 0) {
		int flags = reverseDNS;
		found = 1;

		getnameinfo(&sockname.sa, size, host, sizeof(host),
			    NULL, 0, NI_NUMERICHOST);
		Tcl_DStringAppendElement(dsPtr, host);

		/*
		 * We don't want to resolve INADDR_ANY and sin6addr_any; they
		 * can sometimes cause problems (and never have a name).
		 */
		flags |= NI_NUMERICSERV;
		if (sockname.sa.sa_family == AF_INET) {
		    if (sockname.sa4.sin_addr.s_addr == INADDR_ANY) {
			flags |= NI_NUMERICHOST;
		    }
		} else if (sockname.sa.sa_family == AF_INET6) {
		    if ((IN6_ARE_ADDR_EQUAL(&sockname.sa6.sin6_addr,
					    &in6addr_any))
			|| (IN6_IS_ADDR_V4MAPPED(&sockname.sa6.sin6_addr) &&
			    sockname.sa6.sin6_addr.s6_addr[12] == 0 &&
			    sockname.sa6.sin6_addr.s6_addr[13] == 0 &&
			    sockname.sa6.sin6_addr.s6_addr[14] == 0 &&
			    sockname.sa6.sin6_addr.s6_addr[15] == 0)) {
			flags |= NI_NUMERICHOST;
		    }
		}
		getnameinfo(&sockname.sa, size, host, sizeof(host),
			    port, sizeof(port), flags);
		Tcl_DStringAppendElement(dsPtr, host);
		Tcl_DStringAppendElement(dsPtr, port);
	    }
	}
	if (found) {
	    if (len == 0) {
		Tcl_DStringEndSublist(dsPtr);
	    } else {
		return TCL_OK;
	    }
	} else {
	    if (interp) {
		TclWinConvertWSAError((DWORD) WSAGetLastError());
		Tcl_AppendResult(interp, "can't get sockname: ",
				 Tcl_PosixError(interp), NULL);
	    }
	    return TCL_ERROR;
	}
    }

#ifdef TCL_FEATURE_KEEPALIVE_NAGLE
    if (len == 0 || !strncmp(optionName, "-keepalive", len)) {







<

|
|














|













|
|
|
|
|
|




|














|







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
2221
2222
		return TCL_ERROR;
	    }
	}
    }

    if ((len == 0) || ((len > 1) && (optionName[1] == 's') &&
	    (strncmp(optionName, "-sockname", len) == 0))) {

	TcpFdList *fds;
	address sockname;
	socklen_t size;
	int found = 0;

	if (len == 0) {
	    Tcl_DStringAppendElement(dsPtr, "-sockname");
	    Tcl_DStringStartSublist(dsPtr);
	}
	for (fds = infoPtr->sockets; fds != NULL; fds = fds->next) {
	    sock = fds->fd;
	    size = sizeof(sockname);
	    if (getsockname(sock, &(sockname.sa), &size) >= 0) {
		int flags = reverseDNS;
		found = 1;

		getnameinfo(&sockname.sa, size, host, sizeof(host),
			NULL, 0, NI_NUMERICHOST);
		Tcl_DStringAppendElement(dsPtr, host);

		/*
		 * We don't want to resolve INADDR_ANY and sin6addr_any; they
		 * can sometimes cause problems (and never have a name).
		 */
		flags |= NI_NUMERICSERV;
		if (sockname.sa.sa_family == AF_INET) {
		    if (sockname.sa4.sin_addr.s_addr == INADDR_ANY) {
			flags |= NI_NUMERICHOST;
		    }
		} else if (sockname.sa.sa_family == AF_INET6) {
		    if ((IN6_ARE_ADDR_EQUAL(&sockname.sa6.sin6_addr,
				&in6addr_any)) ||
			    (IN6_IS_ADDR_V4MAPPED(&sockname.sa6.sin6_addr)
			    && sockname.sa6.sin6_addr.s6_addr[12] == 0
			    && sockname.sa6.sin6_addr.s6_addr[13] == 0
			    && sockname.sa6.sin6_addr.s6_addr[14] == 0
			    && sockname.sa6.sin6_addr.s6_addr[15] == 0)) {
			flags |= NI_NUMERICHOST;
		    }
		}
		getnameinfo(&sockname.sa, size, host, sizeof(host),
			port, sizeof(port), flags);
		Tcl_DStringAppendElement(dsPtr, host);
		Tcl_DStringAppendElement(dsPtr, port);
	    }
	}
	if (found) {
	    if (len == 0) {
		Tcl_DStringEndSublist(dsPtr);
	    } else {
		return TCL_OK;
	    }
	} else {
	    if (interp) {
		TclWinConvertWSAError((DWORD) WSAGetLastError());
		Tcl_AppendResult(interp, "can't get sockname: ",
			Tcl_PosixError(interp), NULL);
	    }
	    return TCL_ERROR;
	}
    }

#ifdef TCL_FEATURE_KEEPALIVE_NAGLE
    if (len == 0 || !strncmp(optionName, "-keepalive", len)) {
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
	int optlen;
	BOOL opt = FALSE;

	if (len == 0) {
	    Tcl_DStringAppendElement(dsPtr, "-nagle");
	}
	optlen = sizeof(BOOL);
	getsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&opt,
		&optlen);
	if (opt) {
	    Tcl_DStringAppendElement(dsPtr, "0");
	} else {
	    Tcl_DStringAppendElement(dsPtr, "1");
	}
	if (len > 0) {
	    return TCL_OK;







|
<







2242
2243
2244
2245
2246
2247
2248
2249

2250
2251
2252
2253
2254
2255
2256
	int optlen;
	BOOL opt = FALSE;

	if (len == 0) {
	    Tcl_DStringAppendElement(dsPtr, "-nagle");
	}
	optlen = sizeof(BOOL);
	getsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&opt, &optlen);

	if (opt) {
	    Tcl_DStringAppendElement(dsPtr, "0");
	} else {
	    Tcl_DStringAppendElement(dsPtr, "1");
	}
	if (len > 0) {
	    return TCL_OK;
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
static void
TcpWatchProc(
    ClientData instanceData,	/* The socket state. */
    int mask)			/* Events of interest; an OR-ed combination of
				 * TCL_READABLE, TCL_WRITABLE and
				 * TCL_EXCEPTION. */
{
    SocketInfo *infoPtr = (SocketInfo *) instanceData;

    /*
     * Update the watch events mask. Only if the socket is not a server
     * socket. Fix for SF Tcl Bug #557878.
     */

    if (!infoPtr->acceptProc) {







|







2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
static void
TcpWatchProc(
    ClientData instanceData,	/* The socket state. */
    int mask)			/* Events of interest; an OR-ed combination of
				 * TCL_READABLE, TCL_WRITABLE and
				 * TCL_EXCEPTION. */
{
    SocketInfo *infoPtr = instanceData;

    /*
     * Update the watch events mask. Only if the socket is not a server
     * socket. Fix for SF Tcl Bug #557878.
     */

    if (!infoPtr->acceptProc) {
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364

static int
TcpGetHandleProc(
    ClientData instanceData,	/* The socket state. */
    int direction,		/* Not used. */
    ClientData *handlePtr)	/* Where to store the handle. */
{
    SocketInfo *statePtr = (SocketInfo *) instanceData;

    *handlePtr = INT2PTR(statePtr->sockets->fd);
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------







|







2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356

static int
TcpGetHandleProc(
    ClientData instanceData,	/* The socket state. */
    int direction,		/* Not used. */
    ClientData *handlePtr)	/* Where to store the handle. */
{
    SocketInfo *statePtr = instanceData;

    *handlePtr = INT2PTR(statePtr->sockets->fd);
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
 */

static DWORD WINAPI
SocketThread(
    LPVOID arg)
{
    MSG msg;
    ThreadSpecificData *tsdPtr = (ThreadSpecificData *) arg;

    /*
     * Create a dummy window receiving socket events.
     */

    tsdPtr->hwnd = CreateWindow(classname, classname,
	    WS_TILED, 0, 0, 0, 0, NULL, NULL, windowClass.hInstance, arg);







|







2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
 */

static DWORD WINAPI
SocketThread(
    LPVOID arg)
{
    MSG msg;
    ThreadSpecificData *tsdPtr = arg;

    /*
     * Create a dummy window receiving socket events.
     */

    tsdPtr->hwnd = CreateWindow(classname, classname,
	    WS_TILED, 0, 0, 0, 0, NULL, NULL, windowClass.hInstance, arg);
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789

static void
TcpThreadActionProc(
    ClientData instanceData,
    int action)
{
    ThreadSpecificData *tsdPtr;
    SocketInfo *infoPtr = (SocketInfo *) instanceData;
    int notifyCmd;

    if (action == TCL_CHANNEL_THREAD_INSERT) {
	/*
	 * Ensure that socket subsystem is initialized in this thread, or else
	 * sockets will not work.
	 */







|







2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781

static void
TcpThreadActionProc(
    ClientData instanceData,
    int action)
{
    ThreadSpecificData *tsdPtr;
    SocketInfo *infoPtr = instanceData;
    int notifyCmd;

    if (action == TCL_CHANNEL_THREAD_INSERT) {
	/*
	 * Ensure that socket subsystem is initialized in this thread, or else
	 * sockets will not work.
	 */

Changes to win/tclooConfig.sh.

12
13
14
15
16
17
18
19
# These are mostly empty because no special steps are ever needed from Tcl 8.6
# onwards; all libraries and include files are just part of Tcl.
TCLOO_LIB_SPEC=""
TCLOO_STUB_LIB_SPEC=""
TCLOO_INCLUDE_SPEC=""
TCLOO_PRIVATE_INCLUDE_SPEC=""
TCLOO_CFLAGS=-DUSE_TCLOO_STUBS
TCLOO_VERSION=0.6.2







|
12
13
14
15
16
17
18
19
# These are mostly empty because no special steps are ever needed from Tcl 8.6
# onwards; all libraries and include files are just part of Tcl.
TCLOO_LIB_SPEC=""
TCLOO_STUB_LIB_SPEC=""
TCLOO_INCLUDE_SPEC=""
TCLOO_PRIVATE_INCLUDE_SPEC=""
TCLOO_CFLAGS=-DUSE_TCLOO_STUBS
TCLOO_VERSION=0.6.3